Search code examples
amazon-web-servicesaws-api-gatewayaws-sam-cli

How to attach authorization/api key to the sam cli generated api?


I used sam cli , to create a project. when I package this and deploy , it creates the lambda and also the api gateway with stage and prod stages, policy, roles e.t.c by default, without having to explicitly define in the cloudformation template ( see code below) . as it generates the api gateway automatically, how do i add/attach say if i wanted to add a api key or some kind of authorization for my api generated by template below?

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  simple-node-api
  Sample SAM Template for simple-node-api

Globals:
  Function:
    Timeout: 3

Resources:
 ServerlessHttpApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        ApiKeyRequired: true # sets for all methods
      DefinitionBody:
        swagger:2.0
        paths:
          "/myresource":
              post:
                 x-amazon-apigateway-integration
                    httpMethod: post
                    type: aws_proxy
                    uri: ...

 ApiKey: 
    Type: AWS::ApiGateway::ApiKey
    Properties: 
      Name: !Join ["", [{"Ref": "AWS::StackName"}, "-apikey"]]
      Description: "CloudFormation API Key V1"
      Enabled: true
      GenerateDistinctId: false
      Value: abcdefg123456
      StageKeys:
        - RestApiId: !Ref ServerlessHttpApi
          StageName: Prod

  ApiUsagePlan:
    Type: "AWS::ApiGateway::UsagePlan"
    Properties:
      ApiStages: 
        - ApiId: !Ref ServerlessHttpApi
          Stage: Prod
      Description: !Join [" ", [{"Ref": "AWS::StackName"}, "usage plan"]]
      Quota:
        Limit: 1000
        Period: MONTH
      UsagePlanName: !Join ["", [{"Ref": "AWS::StackName"}, "-usage-plan"]]

  ApiUsagePlanKey:
    Type: "AWS::ApiGateway::UsagePlanKey"
    DependsOn: 
      - ServerlessHttpApi
    Properties:
      KeyId: !Ref ApiKey
      KeyType: API_KEY
      UsagePlanId: !Ref ApiUsagePlan

  HelloWorldfunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: python3.7
      Events:
        HelloWorld:
          Type: Api
          Properties:
            RestApiId: !Ref ServerlessHttpApi
            Path: /hello
            Method: get

Outputs:
  ServerlessHttpApi:
    Description: API Gateway endpoint URL for Prod stage for Hello World function
    Value:
      Fn::Sub: https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldfunction:
    Description: Express Backend Lambda Function ARN
    Value: !Sub HelloWorldfunction.Arn
  HelloWorldFunctionIamRole:
    Description: Implicit IAM Role created for Hello World function
    Value: !Sub HelloWorldFunctionRole.Arn

Solution

  • I modified your code to use the API keys as shown here.

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: >
      simple-node-api
      Sample SAM Template for simple-node-api
    
    Globals:
      Function:
        Timeout: 3
    
    Resources:
    
      ServerlessHttpApi:
        Type: AWS::Serverless::Api
        Properties:
          StageName: Prod
          Auth:
            ApiKeyRequired: true # sets for all methods
    
      ApiKey: 
        Type: AWS::ApiGateway::ApiKey
        DependsOn: [ApiUsagePlan]
        Properties: 
          Name: !Join ["", [{"Ref": "AWS::StackName"}, "-apikey"]]
          Description: "CloudFormation API Key V1"
          Enabled: true
          GenerateDistinctId: false
          Value: abcdefg123456665ffghsdghfgdhfgdh4565
          StageKeys:
            - RestApiId: !Ref ServerlessHttpApi
              StageName: Prod
    
      ApiUsagePlan:
        Type: "AWS::ApiGateway::UsagePlan"
        DependsOn:
          - ServerlessHttpApiProdStage
        Properties:
          ApiStages: 
            - ApiId: !Ref ServerlessHttpApi
              Stage: Prod
          Description: !Join [" ", [{"Ref": "AWS::StackName"}, "usage plan"]]
          Quota:
            Limit: 1000
            Period: MONTH
          UsagePlanName: !Join ["", [{"Ref": "AWS::StackName"}, "-usage-plan"]]
    
      ApiUsagePlanKey:
        Type: "AWS::ApiGateway::UsagePlanKey"
        DependsOn: 
          - ServerlessHttpApi
        Properties:
          KeyId: !Ref ApiKey
          KeyType: API_KEY
          UsagePlanId: !Ref ApiUsagePlan
    
      HelloWorldfunction:
        Type: AWS::Serverless::Function
        Properties:
          #CodeUri: hello-world/
          CodeUri: ./
          Handler: app.lambdaHandler
          Runtime: python3.7
          Events:
            HelloWorld:
              Type: Api
              Properties:
                RestApiId: !Ref ServerlessHttpApi
                Path: /hello
                Method: get
    
    Outputs:
      ServerlessHttpApi:
        Description: API Gateway endpoint URL for Prod stage for Hello World function
        Value:
          Fn::Sub: https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
      HelloWorldfunction:
        Description: Express Backend Lambda Function ARN
        Value: !Sub HelloWorldfunction.Arn
      HelloWorldFunctionIamRole:
        Description: Implicit IAM Role created for Hello World function
        Value: !Sub HelloWorldFunctionRole.Arn
    

    I commented out some parts so that I can run the code, and I can confirm that it deploys and the API auth is set and API key present:

    enter image description here

    enter image description here