Search code examples
amazon-web-servicesaws-cloudformationaws-api-gatewayserverless-application-model

How to make sure the API Gateway token authorizer is invoked only for specific paths


We have an API Gateway utilising a custom Token authoriser. We have 2 lambdas - Greetings and GenerateToken.

We only want the Greetings lambda to be behind a authoriser - requires to be called in the following way utilising SAM:

curl -X GET \
  https://<apigatewayid>.execute-api.eu-west-1.amazonaws.com/Prod/generateToken \
  -H 'X-API-KEY: allow'

How can we achieve that the GenerateToken path does not require a HTTP token for authenticating?

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: API Gateway with Lambda Token Authorizer
Resources:
  GreetingsApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      DefinitionBody:
        swagger: 2.0
        x-amazon-apigateway-policy:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Principal: "*"
              Action: execute-api:Invoke
              Resource:
                - execute-api:/*/*/*
        paths:
          "/hello":
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GreetingsLambda.Arn}/invocations
              responses: {}
          "/generateToken":
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GenerateTokenLambda.Arn}/invocations
              responses: {}
      Auth:
        DefaultAuthorizer: CustomAuthorizer
        Authorizers:
          MyAuthorizer:
            FunctionArn: !GetAtt AuthLambda.Arn
            Identity:
              Header: X-API-KEY

  GenerateTokenLambda:
    Type: AWS::Serverless::Function
    Properties:
      Role: !GetAtt LambdaRole.Arn
      CodeUri: "s3://<bucket-name>/code.zip"
      Handler: src/generateToken.handler
      Events:
        GetRoot:
          Type: Api
          Properties:
            RestApiId: !Ref GreetingsApiGateway
            Path: /generateToken
            Method: get

  GreetingsLambda:
    Type: AWS::Serverless::Function
    Properties:
      Role: !GetAtt LambdaRole.Arn
      CodeUri: "s3://<bucket-name>/code.zip"
      Handler: src/greetings.handler
      Events:
        GetRoot:
          Type: Api
          Properties:
            RestApiId: !Ref GreetingsApiGateway
            Path: /hello
            Method: get

  AuthLambda:
    Type: AWS::Serverless::Function
    Properties:
      Role: !GetAtt LambdaRole.Arn
      CodeUri: "s3://<bucket-name>/code.zip"
      Handler: src/auth.handler

Globals:
  Function:
    Runtime: nodejs8.10

Outputs:
  ApiURL:
    Description: "OUR API URL"
    Value: !Sub "https://${GreetingsApiGateway}.execute-api.${AWS::Region}.amazonaws.com/Prod/"

Solution

  • We can achieve this via swagger within API Gateway:

    The World lambda is a public API and the Hello lambda resides behind the AuthLambda authorizer

    
      OurApiGateway:
        Type: AWS::Serverless::Api
        Properties:
          StageName: Prod
          Auth:
            Authorizers:
              MyAuthorizer:
                FunctionPayloadType: REQUEST
                FunctionArn: !GetAtt AuthLambda.Arn
          DefinitionBody:
            swagger: 2.0
            basePath: /prod
            info:
              title: AwsSamExample
            x-amazon-apigateway-policy:
              Version: "2012-10-17"
              Statement:
                - Effect: Allow
                  Principal: "*"
                  Action: execute-api:Invoke
                  Resource:
                    - execute-api:/*/*/*
            schemes:
              - https
            paths:
              "/hello":
                get:
                  x-amazon-apigateway-integration:
                    httpMethod: POST
                    type: aws_proxy
                    uri:
                      Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloLambda.Arn}/invocations
                  responses: {}
                  security:
                    - MyAuthorizer: []
              "/world":
                get:
                  x-amazon-apigateway-integration:
                    httpMethod: POST
                    type: aws_proxy
                    uri:
                      Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WorldLambda.Arn}/invocations
                  responses: {}
                  security: []