Reputation: 7490
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).
Upvotes: 7
Views: 4007
Reputation: 1
AddDefaultAuthorizerToCorsPreflight: false
does omit the default Authorizer, which can be one of CognitoAuthorizer | LambdaTokenAuthorizer | LambdaRequestAuthorizer
, but unfortunately it does not omit the ApiKeyRequired
. ApiKey would still be required on preflight requests. However, browsers do not attach X-API-Key
Header to OPTIONS
request.
Skipping ApiKey requirement manually for each preflight request seems to be the only option. Unfortunately I have no idea how to do that other than through the console manually after each deployment.
I have opened an issue on github here: https://github.com/aws/aws-sam-cli/issues/3735
Upvotes: 0
Reputation: 3108
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.
Upvotes: 9
Reputation: 1629
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
Upvotes: 1