I'm using the Serverless framework and one of my lambda functions needs to know the API gateway id. I tried setting an envierment varable like the following.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: nodejs6.10
Environment:
Variables:
API_GATEWAY: !Ref ApiGatewayRestApi
Resources:
Test:
Type: AWS::Serverless::Function
Properties:
Handler: LeadLambda.test
CodeUri: ./Lead
Events:
GetResource:
Type: Api
Properties:
Path: /
Method: get
But when I try and deploy I get a circular dependency error.
Failed to create the changeset: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Circular dependency between resources: [TestGetResourcePermissionProd, ServerlessRestApi, Test, TestGetResourcePermissionTest, ServerlessRestApiDeploymentb5240aa4ca, ServerlessRestApiProdStage]
The solution I ended up using was to hard code the integration uri in the API instead of referencing the Lambda.
Globals:
Function:
Runtime: nodejs6.10
Environment:
Variables:
API: !Sub https://${Api}.execute-api.${AWS::Region}.amazonaws.com/prod
Resources:
Entry:
Type: AWS::Serverless::Function
Properties:
FunctionName: prompt-stack-Entry
Handler: LeadLambda.entry
CodeUri: s3://ddg-prompt/LeadLambda.zip
Role: !GetAtt LeadRole.Arn
Events:
GetResource:
Type: Api
Properties:
Path: /lead
Method: POST
RestApiId: !Ref Api
Api:
Type: AWS::Serverless::Api
Properties:
StageName: prod
DefinitionBody:
swagger: 2.0
info:
title:
Ref: AWS::StackName
paths:
/lead:
post:
responses:
'200':
description: Successful operation
responseTemplates:
application/json: ""
x-amazon-apigateway-integration:
httpMethod: POST
type: aws
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:prompt-stack-Entry/invocations
responses:
default:
statusCode: '200'
responseTemplates:
application/json: ''
Related
The following is my template.yaml configuration. For some reason, even without the proper credentials, my HelloWorldFunction still returns a response.
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description:
Globals:
Api:
Cors:
AllowMethods: "'GET,POST,OPTIONS'"
AllowHeaders: "'content-type'"
AllowOrigin: "'http://127.0.0.1:8887'"
AllowCredentials: true
Resources:
HelloWorldApi:
Type: AWS::Serverless::Api
Properties:
StageName: dev
Auth:
DefaultAuthorizer: MyCognitoAuthorizer
Authorizers:
MyCognitoAuthorizer:
UserPoolArn: !GetAtt MyCognitoUserPool.Arn
MyCognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: <pool name here>
Policies:
PasswordPolicy:
MinimumLength: 8
UsernameAttributes:
- email
Schema:
- AttributeDataType: String
Name: email
Required: false
MyCognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId: !Ref MyCognitoUserPool
ClientName: <client name here>
GenerateSecret: false
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./
Handler: index.helloWorldHandler
Runtime: nodejs14.x
Events:
ApiEvent:
Type: Api
Properties:
Path: /hello
Method: get
RestApiId: !Ref HelloWorldApi
LabUIAuth:
Type: AWS::Serverless::Function
Properties:
Timeout: 100
CodeUri: ./
Handler: index.authHandler
Runtime: nodejs14.x
Events:
CreateUser:
Type: Api
Properties:
Path: /auth/create-user
Method: post
ConfirmUser:
Type: Api
Properties:
Path: /auth/confirm-user
Method: post
Login:
Type: Api
Properties:
Path: /auth/login
Method: post
Refresh:
Type: Api
Properties:
Path: /auth/refresh
Method: get
I followed the AWS documentation as best I could, but my endpoint remains open. I added the UserPool and UserPoolClient with correct references and names, but it doesn't look like anything is happening. What do I need to change to protect my endpoint?
I am trying to integrate a custom domain to the HTTP API I am developing with AWS API Gateway and AWS Lambda. I m using the AWS SAM template. There I have a root stack and nested stacks.
For this question I will use a code piece with a one nested stack. There, this is how I want the URL end points to be
root stack - api.example.com
nested stack - api.example.com/nested
Below is my code
Root stack
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 5
VpcConfig:
SecurityGroupIds:
- sg-041f24xxxx921e8e
SubnetIds:
- subnet-0xxxxx2d
Parameters:
FirebaseProjectId:
Type: String
#Dont create this domain in the AWS Console manually, so it will fail here
DomainName:
Type: String
Default: api.example.com
Resources:
AuthGatewayHttpApi:
Type: AWS::Serverless::HttpApi
Properties:
Domain:
DomainName: !Ref DomainName
EndpointConfiguration: REGIONAL
CertificateArn: arn:aws:acm:us-east-1:xxxx:certificate/xxxx-420d-xxxx-b40d-xxxx
Route53:
HostedZoneId: xxxxxxxxxxx
Auth:
Authorizers:
FirebaseAuthorizer:
IdentitySource: $request.header.Authorization
JwtConfiguration:
audience:
- !Ref FirebaseProjectId
issuer: !Sub https://securetoken.google.com/${FirebaseProjectId}
DefaultAuthorizer: FirebaseAuthorizer
AuthFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/testfile.lambdaHandler
Runtime: nodejs14.x
Events:
Gateway:
Type: HttpApi
Properties:
ApiId: !Ref AuthGatewayHttpApi
Path: /hello
Method: get
NestedStackTwo:
DependsOn: AuthGatewayHttpApi
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: nested_stack.yaml
Parameters:
FirebaseProjectId: !Ref FirebaseProjectId
DomainName: !Ref DomainName
Nested stack
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
Globals:
Function:
Timeout: 5
VpcConfig:
SecurityGroupIds:
- sg-xxxxxxxxxxxx
SubnetIds:
- subnet-xxxxxxxxxxx
Parameters:
FirebaseProjectId:
Type: String
DomainName:
Type: String
Resources:
AuthGatewayHttpApi2:
Type: AWS::Serverless::HttpApi
Properties:
Domain:
DomainName: !Ref DomainName
BasePath: two
EndpointConfiguration: REGIONAL
CertificateArn: arn:aws:acm:us-east-1:xxxxx:certificate/xxxxx-xxxx-xxxx-xxxx-xxxx
Route53:
HostedZoneId: xxxxxxxxxxxxx
Auth:
Authorizers:
FirebaseAuthorizer:
IdentitySource: $request.header.Authorization
JwtConfiguration:
audience:
- !Ref FirebaseProjectId
issuer: !Sub https://securetoken.google.com/${FirebaseProjectId}
DefaultAuthorizer: FirebaseAuthorizer
GetAllPromotionsFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/promotions/promotions-getall.getAllPromotions
Runtime: nodejs14.x
Events:
GetAllPromotionsAPIEvent:
Type: HttpApi # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /promotions/getall
Method: get
ApiId: !Ref AuthGatewayHttpApi2
However I cant get this to work because the nested stack fails to create. Below is the error
CREATE_FAILED AWS::CloudFormation::Stack NestedStackTwo
Embedded stack arn:aws:cloudformation:us-east-1 xxxxx:stack/aws-restapi-NestedStackTwo-8KBISZRAVYBX/a3fcc010-0ce4-11ec-9c90-0e8a861a6983 was not successfully created:
The following resource(s) failed to create: [ApiGatewayDomainNameV234ac706a57]
I believe this is happening because the root stack creates the domain and the nested stack is trying to re-create it instead of reusing the same.
But, here is the fun fact; if i use the AWS API GATEWAY web console, I can do this in no time.
How can I get this to work in aws-sam ?
UPDATE
Following the advice from the user LRutten, I came up with the following code for the nested stack.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
Globals:
Function:
Timeout: 5
VpcConfig:
SecurityGroupIds:
- sg-xxxxxx
SubnetIds:
- subnet-xxxxx
Parameters:
FirebaseProjectId:
Type: String
DomainName:
Type: String
Resources:
AuthGatewayHttpApi2:
Type: AWS::Serverless::HttpApi
Properties:
Auth:
Authorizers:
FirebaseAuthorizer:
IdentitySource: $request.header.Authorization
JwtConfiguration:
audience:
- !Ref FirebaseProjectId
issuer: !Sub https://securetoken.google.com/${FirebaseProjectId}
DefaultAuthorizer: FirebaseAuthorizer
MyApiMapping:
Type: 'AWS::ApiGatewayV2::ApiMapping'
Properties:
DomainName: !Ref DomainName
ApiId: !Ref AuthGatewayHttpApi2
Stage: prod
MyDomainName:
Type: 'AWS::ApiGatewayV2::DomainName'
Properties:
DomainName: !Ref DomainName
DomainNameConfigurations:
- EndpointType: REGIONAL
CertificateArn: arn:aws:acm:us-east-1:716460586643:certificate/bac44716-420d-431b-b40d-01378f20432d
GetAllPromotionsFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/promotions/promotions-getall.getAllPromotions
Runtime: nodejs14.x
Events:
GetAllPromotionsAPIEvent:
Type: HttpApi # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /promotions/getall
Method: get
ApiId: !Ref AuthGatewayHttpApi2
This ended up with the following error
Embedded stack arn:aws:cloudformation:us-east-1:716460586643:stack/aws-restapi-NestedStackTwo-14SAYLRO1WD1D/62336020-xx-xx-a04e-x was not successfully created:
The following resource(s) failed to create: [MyDomainName, MyApiMapping].
Indeed SAM always creates the domain when you specify it's name there. It stated in the docs as well.
To get around this, you can omit the whole domain configuration in the AWS::Serverless::HttpApi resource and write the resources created by SAM yourself. So add a section with
Type: AWS::ApiGatewayV2::ApiMapping
Properties:
ApiId: String
ApiMappingKey: String
DomainName: String
Stage: String
Docs
Make sure the Stage property in the ApiMapping is also present in the StageName property of the API.
And a
Type: AWS::ApiGatewayV2::DomainName
Properties:
DomainName: String
DomainNameConfigurations:
- DomainNameConfiguration
MutualTlsAuthentication:
MutualTlsAuthentication
Tags: Json
Docs
Manually adding these without having the domain itself defined twice should do the trick.
Edit: woops wasn't really thinking straight. You should of course only have the mapping, not the domain name itself again :P.
I want to integrate Cognito token in my application.
How can i do it in AWS Sam Template ?
To update my template, I look on https://docs.aws.amazon.com/fr_fr/apigateway/latest/developerguide/apigateway-enable-cognito-user-pool.html?shortFooter=true
Info:
My UserPool is created in the AWS console (on web)
I test with Postman without header: if it worked I should be refused ==> reallity: I have results (my Authorizer doesn't work)
=========================
My question is : why Authorizer doesn't work ?
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Globals:
Function:
Runtime: nodejs6.10
Handler: index.handler
Timeout: 30
Resources:
GRApi:
Type: 'AWS::Serverless::Api'
Properties:
Name: 'Myname'
StageName: !Ref Stage
Cors: "'*'"
EndpointConfiguration: REGIONAL
DefinitionBody:
swagger: "2.0"
info:
version: "1.0"
title: "myTitle"
host: !Ref Host
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..."
schemes:
- "https"
consumes:
- application/json
produces:
- application/json
paths:
/project:
get:
responses: {}
security:
- cognitoUserPool: []
x-amazon-apigateway-integration:
uri:
- 'arn:aws:apigateway:....Arn'
passthroughBehavior: "when_no_match"
httpMethod: "POST"
type: "aws_proxy"
GetAllProjectsFunction:
Type: 'AWS::Serverless::Function'
Properties:
CodeUri: URI/
Handler: index.handler
Runtime: nodejs8.10
MemorySize: 128
Timeout: 30
Role: 'arn:....role'
Events:
GetAllProjects:
Type: Api
Properties:
Path: /project
Method: get
RestApiId: !Ref GRApi
Outputs:
...
Now I have my lambda just echoing the event object:
def lambda_handler(event, context):
pprint(event)
I have been using the event object in the code to get the path like this event['path']
When I run sam local to start up the api gateway locally like this, when I hit the locally running api gateway the lambda dumps an event object like i would expect and I can read the path from it:
sam local start-api
But When I deploy the SAM template to aws and test it in the api gateway console "event" is empty.
Why is event empty on aws and not locally? Do I need to do something to pass the full event? This is my template:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
lambdafunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/build/
Handler: app.lambda_handler
Runtime: python2.7
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
Variables:
PARAM1: VALUE
Events:
# More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
testMethod:
Type: Api
Properties:
RestApiId: !Ref ApiGatewayApi
Path: /testMethod
Method: GET
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
DefinitionBody:
swagger: "2.0"
info:
version: "2018-09-12T06:21:35Z"
title: mytest
schemes:
- "https"
paths:
/testMethod:
x-amazon-apigateway-any-method:
produces:
- "application/json"
responses:
'200':
description: "200 response"
schema:
$ref: "#/definitions/Empty"
security:
- sigv4: []
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${lambdafunction}/invocations
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
httpMethod: "POST"
contentHandling: "CONVERT_TO_TEXT"
type: "aws"
securityDefinitions:
sigv4:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "awsSigv4"
definitions:
Empty:
type: "object"
title: "Empty Schema"
I'm totally lost on this circular dependency issue with Cloudformation. I wrote this template, and it works great with run from the CLI, but when I try to launch it from the browser as a Stack, I get this circular dependency issue.
Can someone tell me where the dependency is coming from ?
This is the Error I get
Circular dependency between resources: [VehiclesLambda, HelloAPI, AuthorizerFuncPerm]
Here is my template
AWSTemplateFormatVersion: '2010-09-09'
Description: Yes you can use SAM to create an Authorizer
Parameters:
Environment:
Type: String
Default: dev
Outputs:
ExampleAPIUrl:
Value: !Sub "https://${HelloAPI}.execute-api.${AWS::Region}.amazonaws.com/${Environment}/"
Resources:
HelloAPI:
Type: AWS::Serverless::Api
Properties:
StageName: !Sub ${Environment}
DefinitionBody:
swagger: 2.0
info:
title:
Ref: AWS::StackName
securityDefinitions:
test-authorizer:
type: apiKey
name: Authorization
in: header
x-amazon-apigateway-authtype: custom
x-amazon-apigateway-authorizer:
type: token
authorizerUri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthorizerFunc.Arn}/invocations
authorizerResultTtlInSeconds: 5
paths:
/vehicles:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
!Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${VehiclesLambda.Arn}/invocations
responses: {}
security:
- test-authorizer: []
VehiclesLambda:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs4.3
CodeUri: 's3://companyrentalaws/vehicles.zip'
MemorySize: 128
Timeout: 30
Policies:
- AWSLambdaBasicExecutionRole
Events:
MyEndpoint:
Type: Api
Properties:
Path: /vehicles
Method: GET
RestApiId:
Ref: HelloAPI
AuthorizerFunc:
Type: AWS::Serverless::Function
Properties:
Handler: authorizer.authorizer
Runtime: nodejs4.3
CodeUri: 's3://companyrentalaws/authorizer.zip'
AuthorizerFuncPerm:
Type: AWS::Lambda::Permission
DependsOn:
- HelloAPI
- AuthorizerFunc
Properties:
Action: lambda:InvokeFunction
FunctionName:
Ref: AuthorizerFunc
Principal: apigateway.amazonaws.com
Sorry for posting so much code, but didn't want to leave anything out.
VehiclesLambda has a property RestApiId which refs HelloAPI.
RestApiId:
Ref: HelloAPI
HelloAPI Fn:GetAttr's VehiclesLambda's Arn
!Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${VehiclesLambda.Arn}/invocations
There is your circular dependency.