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:
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).
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).
API Gateway supports multiple mechanisms of access control using AWS Identity and Access Management (IAM), AWS Lambda authorizers, and Amazon Cognito.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With