I have an API that is defined as IaC with AWS SAM usign AWS::Serverless::Api for the API Gateway and API Event Source for the Methods.
I developed a method that requires a non lambda proxy integration and some mapping templates in the integration response, so to implement these functionalities in IaC I had to use AWS::ApiGateway::Method from Cloud Formation Templates.
The problem is with the ResourceId property, because is a third level resource in the API, Cloud Formation expects a reference to a AWS::ApiGateway::Resource but the upper levels were implicitly created by AWS SAM with the following code:
PrismShiftDayMacroserviceLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Ref ServiceName
CodeUri: !Ref ServicePath
Role: !Sub 'arn:aws:iam::${AWS::AccountId}:role/lambda_execution_role'
Events:
GetShiftDay:
Type: Api
Properties:
Method: GET
Path: /api/shiftDays/{id}
RequestParameters:
- method.request.path.id
RestApiId: !Ref PrismShiftDayMacroserviceApi
PostShiftDay:
Type: Api
Properties:
RestApiId: !Ref PrismShiftDayMacroserviceApi
Path: /api/shiftDays
Method: POST
SearchShiftDay:
Type: Api
Properties:
RestApiId: !Ref PrismShiftDayMacroserviceApi
Path: /api/shiftDays
Method: GET
PatchShiftDay:
Type: Api
Properties:
RestApiId: !Ref PrismShiftDayMacroserviceApi
Path: /api/shiftDays/{id}
Method: PATCH
Is it possible to get a reference to the resource that was implicitly created by AWS SAM?
I am using AWS SAM to test my Api gateway and lambdas locally.
When executing sam local start-api and calling a lambda, I'd like the event to be of version 2.0 format instead of version 1.
I am using CDK HttpApi construct from #aws-cdk/aws-apigatewayv2 hence there is now inconsistency between my local testing and what's deployed.
I am new to Sam config, my template.yml file is:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
MyFunction:
Type: 'AWS::Serverless::Function'
Properties:
Handler: index.handler
Runtime: nodejs14.x
CodeUri: .output/healthz
Timeout: 10
Events:
ApiEvent:
Type: Api
Properties:
Path: /health
Method: GET
Globals:
HttpApi:
CorsConfiguration:
AllowOrigin: "'http://localhost:3000'"
AllowMethods: "'POST, OPTIONS, GET, PUT'"
AllowHeaders: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
I've tried various setups (Api, HttpApi) using those AWS Docs for SAM but always manage to get only version 1 event.
Can you point me to what I am doing wrong or how to specify the version?
I found the resolution in this post.
It is necessary to specify PayloadFormatVersion: "2.0" (value as string) in the configuration of HttpApi.
Example yml:
Resources:
MyFunction:
Type: 'AWS::Serverless::Function'
Properties:
Handler: index.handler
Runtime: nodejs14.x
CodeUri: .output/healthz
Timeout: 10
Events:
ApiEvent:
Type: HttpApi
Properties:
PayloadFormatVersion: "2.0"
Path: /health
Method: GET
Auth:
Authorizer: NONE
I'm taking over a SAM template where the previous dev has an authorizer on API Gateway which forces every lambda function to pass along a Cognito token in order to secure the API.
Auth:
DefaultAuthorizer: AuthStackCognitoAuthorizer
AddDefaultAuthorizerToCorsPreflight: False
Authorizers:
AuthStackCognitoAuthorizer:
UserPoolArn:
Fn::ImportValue:
Fn::Sub: "${AuthStack}-UserPoolArn"
The problem comes in when I want one specific lambda function attached to API Gateway to NOT have an authorizer. Is there a way I can modify my lambda so that it's not requiring the overarching APIGateway Authorizer?
PostFeedbackLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/endpoints/feedback/post
Handler: index.handler
Description: Returns feedback.
Layers:
- !Ref CommonUtilsLayer
Events:
ApiEvent:
Type: Api
Properties:
Method: POST
Path: /feedback
RestApiId: !Ref ApiGatewayApi
I am trying to set up an event on my lambda function in my SAM template, but I want the event source to be an explicit API endpoint.
The documentation shows an event with an implicit API as an event source:
GetFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.get
Runtime: nodejs6.10
CodeUri: s3://bucket/api_backend.zip
Policies: AmazonDynamoDBReadOnlyAccess
Environment:
Variables:
TABLE_NAME: !Ref Table
Events:
GetResource:
Type: Api
Properties:
Path: /resource/{resourceId}
Method: get
This would be the explicit API definition:
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionUri: swagger.yml
How do I explicitly set the event source to be MyApi?
I needed to add the RestApiId under the event definition like so:
Events:
GetResource:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /resource/{resourceId}
Method: get
How can I create an API with AWS SAM that does authorization using Cognito User Pools authorizer?
Theres AWS::ApiGateway::Authorizer. But ...
{
"Type" : "AWS::ApiGateway::Authorizer",
"Properties" : {
"AuthorizerCredentials" : String,
"AuthorizerResultTtlInSeconds" : Integer,
"AuthorizerUri" : String,
"IdentitySource" : String,
"IdentityValidationExpression" : String,
"Name" : String,
"ProviderARNs" : [ String, ... ],
"RestApiId" : String,
"Type" : String
}
}
it looks like RestApiId refers to the API which uses this authorizer? But with AWS SAM, my APIs are defined like
Resources:
Ec2Index:
Type: AWS::Serverless::Function
Properties:
Handler: ec2/index.handler
Runtime: nodejs6.10
CodeUri: ./src
FunctionName: 'ApiEc2IndexHandler'
Description: 'List EC2 resources'
Timeout: 30
Role: 'arn:aws:iam::598545985414:role/awsmanagement-lambda-management'
Events:
Ec2Index:
Type: Api
Properties:
Path: /ec2
Method: get
I dont get how do I associate them together?
You can now reference the implicitly created api gateway with 'ServerlessRestApi'.
So in your SAM template add this piece of regular Cloudformation and everything will work fine
ApiCognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
IdentitySource: 'method.request.header.Authorization'
Name: ApiCognitoAuthorizer
ProviderARNs:
- 'arn:aws:cognito-idp:{region}:{userpoolIdentifier}'
RestApiId: !Ref ServerlessRestApi
Type: COGNITO_USER_POOLS
I'm not certain you can specify an authorizer in SAM but you can embed Swagger in SAM files which can do this. It's a new feature as of Feb. 17 [ref].
I'm definitely not an expert on Swagger or SAM but it seems like you would want something like:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Simple API Endpoint configured using Swagger specified inline and backed by a Lambda function
Resources:
Ec2Index:
Type: AWS::Serverless::Api
Properties:
StageName: <stage>
DefinitionBody:
swagger: 2.0
info:
title:
Ref: AWS::StackName
securityDefinitions:
cognitoUserPool:
type: apiKey,
name: "Authorization"
in: header
x-amazon-apigateway-authtype: cognito_user_pools
x-amazon-apigateway-authorizer:
type: cognito_user_pools
providerARNs:
- arn:aws:cognito-idp:${AWS::Region}:{AWS::AccountId}:userpool/<user_pool_id>
paths:
"/ec2":
get:
security:
- cognitoUserPool: []
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Ec2IndexLamb.Arn}/invocations
responses: {}
swagger: '2.0'
Ec2IndexLamb:
Type: AWS::Serverless::Function
Properties:
Handler: ec2/index.handler
Runtime: nodejs6.10
CodeUri: ./src
FunctionName: 'ApiEc2IndexHandler'
Description: 'List EC2 resources'
Timeout: 30
Role: 'arn:aws:iam::598545985414:role/awsmanagement-lambda-management'
Events:
Ec2Index:
Type: Api
Properties:
Path: /ec2
Method: get
References:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html#apigateway-enable-cognito-user-pool
https://github.com/awslabs/serverless-application-model/blob/master/examples/2016-10-31/inline_swagger/template.yaml
Edit: Fixed Swagger 2.0 syntax for the 'security' section, it should be a list.
Since AWS SAM v1.8.0, you can do it using the following syntax. You can refer to this article for more information.
In short, define a Cognito Authorizer for your API using API Authorizer Object. Then, set the Auth of your lambda function to refers to this API.
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
DefaultAuthorizer: MyCognitoAuth # OPTIONAL
Authorizers:
MyCognitoAuth:
# Can also accept an array
UserPoolArn: !GetAtt MyCognitoUserPool.Arn
Identity: # OPTIONAL
# OPTIONAL; Default: 'Authorization'
Header: MyAuthorizationHeader
# OPTIONAL
ValidationExpression: myAuthValidationExp
MyFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: MyFunction
...
Events:
Post:
Type: Api
Properties:
Path: /compute
Method: POST
RestApiId: !Ref MyApi
Auth:
Authorizer: MyCognitoAuth
As #simones mentioned, the following will create the Cognito User Pool authorizer (CF template).
ApiCognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
IdentitySource: 'method.request.header.Authorization'
Name: ApiCognitoAuthorizer
ProviderARNs:
- 'arn:aws:cognito-idp:{region}:{userpoolIdentifier}'
RestApiId: !Ref ServerlessRestApi
Type: COGNITO_USER_POOLS
To attach it to a resource method, the following works (in Swagger file):
securityDefinitions:
ApiCognitoAuthorizer:
type: apiKey
name: Authorization
in: header
x-amazon-apigateway-authtype: cognito_user_pools
x-amazon-apigateway-authorizer:
type: cognito_user_pools
providerARNs:
- arn:aws:cognito-idp:{region}:{userpoolIdentifier}
Then, add to specific methods (in Swagger file):
security:
- ApiCognitoAuthorizer: []
You can add your Cognito User Authorizer directly to your SAM AWS::Serverless::Api.
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Cors: "'*'"
Auth:
DefaultAuthorizer: MyCognitoAuthorizer
Authorizers:
MyCognitoAuthorizer:
UserPoolArn: 'arn:aws:cognito-.....' # YOUR COGNITO USER POOL ARN
and on your AWS::Serverless::Function you can add a function authorizer if you have not set the default one. Or you can deactivate it using Authorizer: 'NONE'.
Auth:
Authorizer: MyCognitoAuthorizer
see also documentation.