Use an OpenAPI specification to define API Gateway APIs. This is good practice because:
- The specification forces you to think about the design upfront before touching code which is expensive to correct later
- This contract first approach allows frontend, backend, and test developers to work in parallel
- Endpoints can be mocked for developers and testers to test against
- Serverless Application Model (SAM) uses the specification to configure the API Gateway API, this makes it living documentation, evolving alongside code and infrastructure.
TL;DR
- Create an OpenAPI specification with API Gateway Extensions to OpenAPI
- Copy the file to an S3 bucket
- Define an API Gateway (AWS::Serverless::Api) resource in your SAM template
- Use the AWS::Include transform to include and transform the OpenAPI specification from S3
- Assign the AWS::Include transform function to the DefinitionBody property of the API Gateway resource
- Package and deploy your SAM application
Source Code
The source code and instructions to build and deploy this example to AWS can be found here: https://github.com/karlkyck/api-gateway-openapi. Running this example on AWS will incur costs so be sure to delete the CloudFormation stacks when you are finished experimenting.
OpenAPI Definition
Start by creating your OpenAPI specification in a dedicated file.
The following OpenAPI specification defines one RESTful endpoint with two operations on that endpoint.
---
openapi: 3.0.3
...
x-amazon-apigateway-policy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
Condition:
IpAddress:
'aws:SourceIp':
Ref: AllowedIpsList
...
Where AllowedIpsList is a comma separated list of IPs or CIDR blocks defined as a parameter in your CloudFormation template.
Rationale
When it comes to accessing and consuming resources on the cloud a least privileged approach is best. IP restriction on your API Gateway APIs can help.
It is possible to apply an API Gateway Resource Policy to an API Gateway API during deployment via CloudFormation.
CloudFormation Template
Your API Gateway API definition and reference to your OpenAPI specification is defined in your SAM (Serverless Application Model) template.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
AllowedIpsList:
Type: List<String>
Globals:
Function:
Runtime: nodejs12.x
Timeout: 30
AutoPublishAlias: live
Resources:
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: live
EndpointConfiguration: REGIONAL
DefinitionBody:
openapi: 3.0.3
info:
title: API Gateway IP Filtering Example API
version: 1.0.0
x-amazon-apigateway-policy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
Condition:
IpAddress:
'aws:SourceIp':
Ref: AllowedIpsList
paths:
/api/example:
get:
summary: Example API Endpoint
operationId: example
responses:
'200':
description: Success
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ExampleFunction.Arn}:live/invocations
httpMethod: POST
type: aws_proxy
ExampleFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
InlineCode: |
exports.handler = (event, context, callback) => {
callback(
null,
{
statusCode: 200,
body: JSON.stringify({
message: 'Hello World'
})
});
};
Events:
ApiGatewayApiEvent:
Type: Api
Properties:
RestApiId: !Ref ApiGatewayApi
Path: /api/example
Method: get
The DefinitionBody property of the ApiGatewayApi allows you to specify an OpenAPI specification definition which is transformed and applied by CloudFormation upon deployment.
The list of allowed IPs is passed to the SAM template as the AllowedIpsList parameter. This parameter is referenced from within the OpenAPI specification using the Ref function.
OpenAPI Specification
The OpenAPI specification, embedded in the CloudFormation template above, contains the definition of your API. The API Gateway Resource Policy is declared in the specification as an API Gateway Extension to OpenAPI.
---
openapi: 3.0.3
info:
title: API Gateway IP Filtering Example API
version: 1.0.0
x-amazon-apigateway-policy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
Condition:
IpAddress:
'aws:SourceIp':
Ref: AllowedIpsList
paths:
/api/example:
get:
summary: Example API Endpoint
operationId: example
responses:
'200':
description: Success
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ExampleFunction.Arn}:live/invocations
httpMethod: POST
type: aws_proxy
Here we see the Ref function referring to the AllowedIpsList parameter.
This API Gateway Resource Policy is allowing all invocations where the source IP is in the list of IPs supplied.
Source Code
The source code and instructions to build and deploy this example to AWS can be found here: https://github.com/karlkyck/api-gateway-ip-filtering. Running this example on AWS will incur costs so be sure to delete the CloudFormation stacks when you are finished experimenting.
Conclusion
This is a simple, cheap way to allow access to your API Gateway APIs only from certain IP addresses. AWS WAF is an alternative, but it incurs costs.