IP filtering with API Gateway Resource Policies cover image

Use an API Gateway Resource Policy to allow access to your APIs only from certain IPs. This is a handy approach for locking down your non-production APIs so that they are not publicly accessible.

TL;DR

Use an OpenAPI specification with the x-amazon-apigateway-policy API Gateway Extension to OpenAPI to apply an API Gateway Resource Policy when deploying:

---
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.

About the author

Hi, I'm Karl Kyck a cloud architect specialising in building sustainable serverless architectures on AWS.