Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disabling security for one method resource endpoint in API Gateway via AWS SAM template

I'm using AWS Serverless to create an API Gateway backed with Lambda functions.

I have the following resources and methods defined:

/projects
   -> GET (should require API key)
   -> OPTIONS (should not, since it is used for CORS preflight)

I'm having issues with CORS and requiring an API key. The frontend client code is getting a 403 Forbidden error when it initiates the preflight CORS OPTIONS request, since the API Key Required in the AWS Management console is set to True for the OPTIONS method.

I want to disable security specifically for the OPTIONS request, but keep it for all other methods (GET, POST, etc.). Here are my resource definitions (you can see I have set a default ApiKeyRequired: true in my Auth object:

  MyApi:
    Type: 'AWS::Serverless::Api'
    Name: MyApi
    Properties:
      Auth:
        AddDefaultAuthorizerToCorsPreflight: true
        ApiKeyRequired: true # sets for all methods
      Cors:
        AllowCredentials: true
        AllowHeaders: '"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"'
        AllowMethods: '"POST,GET,OPTION"'
        AllowOrigin: '"*"'
        MaxAge: '"600"'
      StageName: !Ref StageName
      DefinitionBody:
        swagger: 2.0
        info:
          title: !Sub API-Lambda-${StageName}
          description: "API for MyApi"
          version: "1.0.0"
        paths:
          /projects:
            get:
              produces:
                - application/json
              responses:
                "200":
                  description: OK
              x-amazon-apigateway-any-method:
                produces:
                  - application/json
              x-amazon-apigateway-integration:
                httpMethod: post
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetAllProjectsFunction.Arn}/invocations
            options:
              consumes:
                - application/json
              produces:
                - application/json
              responses:
                '200':
                  description: 200 response
                  headers:
                    Access-Control-Allow-Origin:
                      type: string
                    Access-Control-Allow-Methods:
                      type: string
                    Access-Control-Allow-Headers:
                      type: string
              x-amazon-apigateway-integration:
                responses:
                  default:
                    statusCode: 200
                    responseParameters:
                      method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
                      method.response.header.Access-Control-Allow-Headers: "'Content-Type,mode,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                passthroughBehavior: when_no_match
                requestTemplates:
                  application/json: "{\"statusCode\": 200}"
                type: mock
          /projects/{userId}:
            get:
              responses:
                "200":
                  description: OK
              x-amazon-apigateway-any-method:
                produces:
                  - application/json
              x-amazon-apigateway-integration:
                httpMethod: post
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetProjectsForUserFunction.Arn}/invocations
            options:
              consumes:
                - application/json
              responses:
                '200':
                  description: 200 response
                  headers:
                    Access-Control-Allow-Origin:
                      type: string
                    Access-Control-Allow-Methods:
                      type: string
                    Access-Control-Allow-Headers:
                      type: string
              x-amazon-apigateway-integration:
                responses:
                  default:
                    statusCode: 200
                    responseParameters:
                      method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
                      method.response.header.Access-Control-Allow-Headers: "'Content-Type,mode,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                passthroughBehavior: when_no_match
                requestTemplates:
                  application/json: "{\"statusCode\": 200}"
                type: mock

I know that the Swagger documentation says I can override security by adding a security object for each resource method. This SO post also suggests I can disable security by making the security object an empty list.

However, I tried the following approaches:

        options:
          consumes:
            - application/json
          produces:
            - application/json
          security:
            -
          responses: ...

And also simply making security a None object:

        options:
          consumes:
            - application/json
          produces:
            - application/json
          security:
          responses: ...

In both cases, I get the following error when attempting to deploy with aws sam deploy:

Waiting for changeset to be created.. Error: Failed to create changeset for the stack: my-app, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Internal transform failure.

Which seems to that my security definition is wrong. How do I disable security for one method of a resource (namely the OPTIONS method)?

UPDATE:

I got the template to deploy by using the following syntax:

    options:
      consumes:
        - application/json
      produces:
        - application/json
      security:
        - {}
      responses:

However, even after deploying, I still have this in my console:

enter image description here

I'm honestly at a loss right now because this is so easy to do with a regular AWS::ApiGateway::Method resource (just set ApiKeyRequired to true).

like image 834
Yu Chen Avatar asked Jan 08 '20 15:01

Yu Chen


People also ask

How do I protect my gateway API endpoint?

You can protect your API using strategies like generating SSL certificates, configuring a web application firewall, setting throttling targets, and only allowing access to your API from a Virtual Private Cloud (VPC).

Which of the following can you setup as access control mechanisms for AWS API gateway?

API Gateway supports multiple mechanisms of access control using AWS Identity and Access Management (IAM), AWS Lambda authorizers, and Amazon Cognito.

Which of the following API gateway supports multiple mechanisms for controlling and managing access to your API?

API Gateway supports multiple mechanisms for controlling and managing access to your HTTP API: Lambda authorizers use Lambda functions to control access to APIs. For more information, see Working with AWS Lambda authorizers for HTTP APIs. JWT authorizers use JSON web tokens to control access to APIs.


2 Answers

You can simply set AddDefaultAuthorizerToCorsPreflight: false that will cause OPTIONS requests to be unsecured as you wished.

See this part of documentation:

If the DefaultAuthorizer and Cors properties are set, then setting AddDefaultAuthorizerToCorsPreflight will cause the default authorizer to be added to the Options property in the OpenAPI section.

Ref: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-apiauth.html

like image 129
iaforek Avatar answered Sep 30 '22 06:09

iaforek


Not great but I think you'll have to disable api_key on every OPTIONS method -- provide definition of the method with openapi and skip/omit 'security' key in it

like image 25
okigan Avatar answered Sep 30 '22 06:09

okigan