Search code examples
aws-lambdaserverless

Serverless Whitelist IP in AWS Gateway using existing policy


I'm using AWS infrastructure (AWS API Gateway + Lambda) and I want to block the external access to my Development environment, I've created a policy using IAM to filter IPs Based on the Source IP:

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Deny",
        "Action": "execute-api:Invoke",
        "Resource": "*",
        "Condition": {
            "NotIpAddress": {
                "aws:SourceIp": [
                    "192.168.0.1"
                ]
            },
            "Bool": {
                "aws:ViaAWSService": "false"
            }
        }
    }
}

What I'm trying to do now is to attach that policy to the lambdas that I'm deploying with serverless; I've tried this:

provider:
  name: aws
  runtime: nodejs12.x
  resourcePolicy:
    - arn:aws:iam::1234567890:policy/myCustomPolicy

But it's not working...

I know that some people, following the Serverless documentation, is directly creating and assigning the resource policy during the lambda deployment, but I don't want to do it in that way because I want to manage the policy from AWS (I don't want to re-deploy the Serverless every time that I've to change the policy).

Does anyone has a working example / recommendation about this?


Solution

  • After quite extensive internet research apparently there is no way to reference from the Gateway to an existing policy.

    The main reason is that gateway policy is a resource policy not an IAM Policy more details here.

    As an alternative solution, what I finally did is to extract that policy to a common file, my repository now looks as follow:

    │
    ├── services
    │   └── service-api
    │     └── handler.js, serverless.yml
    │
    ├── serverless-common.yml
    └──.gitlab-ci.yml
    

    In the serverless.yml file inside each service I'm referencing to a policy in the serverless-common.yml:

    provider:
      name: aws
      runtime: nodejs12.x
      apiGateway:
        resourcePolicy: ${file(../../serverless.common.yml):custom.resourcePolicies.${opt:stage, 'none'}}
    
    functions:
      hello:
        handler: handler.hello
        events:
          - http: 
              path: health
              method: get
    
    

    And in the serverless-common.yml

    custom:
      resourcePolicies:
        dev:
          - Effect: Allow
            Principal: "*"
            Action: execute-api:Invoke
            Resource:
              - execute-api:/*/*/*
            Condition:
              IpAddress:
                aws:SourceIp: 
                  - "176.25.129.133" # Whitelisted IP
        pro:
          - Effect: Allow
            Principal: "*"
            Action: execute-api:Invoke
            Resource:
              - execute-api:/*/*/*
    
    

    This is the clearest solution I have been able to find, since the framework and AWS do not allow you to refer to an external policy, at least in this way you can have the whitelisted IP only in one place and refer to it from the serverless deployment.