serverless-application-model
serverless-application-model copied to clipboard
When using an inline swagger, api+method+path authorizers do not get added
Description:
My expectation was that when using the Auth
functionality in SAM against an API and Function, when no default
authorizer is configured then the Authorizer would be assigned against the Functions path
I've also noticed that when using a Default Authorizer, all methods on the API get the Authorizer assigned, configuring
NONE
authorizer against an API Event does not prevent the authorizer getting assigned.
Steps to reproduce the issue:
Given a SAM Template that includes a an inline swagger document, an Authorizer and Auth configured on the DELETE and POST events
template.yaml
---
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: python3.6
MemorySize: 128
Timeout: 15
Resources:
Create:
Type: AWS::Serverless::Function
Properties:
CodeUri: example
Handler: service.example
Events:
Create:
Type: Api
Properties:
Method: post
Path: /
RestApiId: !Ref API
Auth:
Authorizer: ExampleAuth
List:
Type: AWS::Serverless::Function
Properties:
CodeUri: example
Handler: service.example
Events:
Create:
Type: Api
Properties:
Method: get
Path: /
RestApiId: !Ref API
Delete:
Type: AWS::Serverless::Function
Properties:
CodeUri: example
Handler: service.example
Events:
AddTenant:
Type: Api
Properties:
Method: delete
Path: /{id}
RestApiId: !Ref API
Auth:
Authorizer: ExampleAuth
Retrieve:
Type: AWS::Serverless::Function
Properties:
CodeUri: example
Handler: service.example
Events:
AddTenant:
Type: Api
Properties:
Method: post
Path: /{id}
RestApiId: !Ref API
Auth:
Type: AWS::Serverless::Function
Properties:
CodeUri: example
Handler: service.example
API:
Type: AWS::Serverless::Api
Properties:
Name: ExampleAPI
EndpointConfiguration: REGIONAL
StageName: v1
Auth:
Authorizers:
ExampleAuth:
FunctionPayloadType: TOKEN
FunctionArn: !GetAtt Auth.Arn
Identity:
Header: Authorization
ValidationExpression: Bearer.*
ReauthorizeEvery: 0
DefinitionBody:
swagger: "2.0"
info:
title: Example
version: "1"
parameters:
id:
name: id
in: path
required: true
type: string
paths:
/:
post:
parameters:
- in: body
name: item
schema:
type: object
responses:
"201":
description: Created
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
passthroughBehavior: when_no_match
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Create.Arn}/invocations
get:
responses:
"200":
description: Got
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
passthroughBehavior: when_no_match
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${List.Arn}/invocations
/{id}:
get:
parameters:
- $ref: '#/parameters/id'
responses:
"200":
description: Got
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
passthroughBehavior: when_no_match
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Retrieve.Arn}/invocations
delete:
parameters:
- $ref: '#/parameters/id'
responses:
"200":
description: Deleted
x-amazon-apigateway-integration:
type: aws_proxy
httpMethod: POST
passthroughBehavior: when_no_match
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Delete.Arn}/invocations
example/service.py
def example(event, context):
print(event)
return 200
example/__init__.py
__version__ = "1.0.0"
Deploy this SAM Template
sam package --template-file template.yaml --s3-bucket "${S3_BUCKET}" > template-export.yaml
sam deploy --template-file template-export.yaml --stack-name "${STACK_NAME}" --capabilities CAPABILITY_IAM
Observed result:
No Authorizers are assigned to any of the methods
Expected result:
My expectation was that the GET Methods on the path /
and /{id}
would not have an authorizer assigned, but POST /
and DELETE /{id}
do not have authorizer assigned
We plan on adding a feature to merge your defined Swagger with the generated Swagger from SAM. This should resolve this issue also.
A workaround exists where if the name of the Authorizer
defined in the SAM template matches the name of a securityDefinitions
in the swagger document, AND the endpoint refers to that named security definition, then the correct authorizer will be assigned to the endpoint.
This is often what is desired, because if you have security requirements for the endpoint, you probably want to define them (as best you can) in the swagger doc.
SAM snippet below:
myApi:
Type: AWS::Serverless::Api
Properties:
EndpointConfiguration: REGIONAL
StageName: master
DefinitionBody:
swagger: '2.0'
info:
title: Test
version: 1.0.0
description: Only a test
schemes:
- https
paths:
"/sayHello":
get:
operationId: hello
description: Says "Hello"
produces:
- text/html
responses:
'200':
description: OK
default:
description: Error
security:
- keyAuth: [] # refers to security definition in this swagger doc
x-amazon-apigateway-integration:
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Function.Arn}/invocations
httpMethod: POST
type: aws_proxy
securityDefinitions:
keyAuth: #matches name of Auth/Authorizer defined on the Api
description: Authentication will be performed using a custom authenticator
type: apiKey
name: Authorization
in: header
Auth:
Authorizers:
keyAuth: # Name of this authorizer; becomes the name of the authorizer in API Gateway console
Identity:
Headers:
- Authorization
ReauthorizeEvery: 600
FunctionPayloadType: REQUEST
FunctionArn: !Ref CustomAuthArn
The result of the above is that the authorizer is created with expected properties in the API, and the endpoint is configured to use that authorizer.
Untested are the effects of setting the Serverless::Function/Events/Auth/Authorizer
to NONE
or setting the DefaultAuthorizer
property on the Serverless::Api/Auth/Authorizers
A workaround exists where if the name of the
Authorizer
defined in the SAM template matches the name of asecurityDefinitions
in the swagger document, AND the endpoint refers to that named security definition, then the correct authorizer will be assigned to the endpoint.This is often what is desired, because if you have security requirements for the endpoint, you probably want to define them (as best you can) in the swagger doc.
SAM snippet below:
myApi: Type: AWS::Serverless::Api Properties: EndpointConfiguration: REGIONAL StageName: master DefinitionBody: swagger: '2.0' info: title: Test version: 1.0.0 description: Only a test schemes: - https paths: "/sayHello": get: operationId: hello description: Says "Hello" produces: - text/html responses: '200': description: OK default: description: Error security: - keyAuth: [] # refers to security definition in this swagger doc x-amazon-apigateway-integration: uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Function.Arn}/invocations httpMethod: POST type: aws_proxy securityDefinitions: keyAuth: #matches name of Auth/Authorizer defined on the Api description: Authentication will be performed using a custom authenticator type: apiKey name: Authorization in: header Auth: Authorizers: keyAuth: # Name of this authorizer; becomes the name of the authorizer in API Gateway console Identity: Headers: - Authorization ReauthorizeEvery: 600 FunctionPayloadType: REQUEST FunctionArn: !Ref CustomAuthArn
The result of the above is that the authorizer is created with expected properties in the API, and the endpoint is configured to use that authorizer.
Untested are the effects of setting the
Serverless::Function/Events/Auth/Authorizer
toNONE
or setting theDefaultAuthorizer
property on theServerless::Api/Auth/Authorizers
This solution worked perfectly for me. Thank you!
Consider the following example, when custom swagger definition is commented out, the API resource has custom authorizer configured. When the comments are removed, it seems that we ignore the generated swagger definition and use custom swagger definition, which caused this problem.
Transform: AWS::Serverless-2016-10-31
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
# DefinitionBody:
# swagger: "2.0"
# info:
# title: Example
# version: "1"
# paths:
# /test:
# get:
# x-amazon-apigateway-integration:
# httpMethod: "GET"
# type: "aws_proxy"
# uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations"
Auth:
Authorizers:
MyAuthorizer:
UserPoolArn: !GetAtt MyCognitoUserPool.Arn
MyFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs14.x
InlineCode: |
exports.handler = async (event, context, callback) => {
return {
statusCode: 200,
body: 'Success'
}
}
Events:
MyEventV1:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /test
Method: get
Auth:
Authorizer: MyAuthorizer
MyCognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: MyCognitoUserPoolRandomName
MyCognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId:
Ref: MyCognitoUserPool
ClientName: MyCognitoUserPoolClient
GenerateSecret: false
Will bring this up and discuss with the team.
Introducing MergeDefinitions
property in AWS::Serverless::Api
. This property is default to False. Setting this property to True will allow the following:
Merge SAM generated swagger definition into inline swagger definition if a specific API+Path+Method is defined both in SAM API and API event source:
- for a conflicting key, use SAM generated value
- otherwise include key-value pairs from both definitions
https://github.com/aws/serverless-application-model/pull/2943 Changes are pending release. It should take around a week for the changes to roll out to production. Marking this issue closed now. Feel free to re-open it if you have any additional questions.