I am developping lambda with CloudFormation by SAM
My template.yaml is here.
It can be deployed, however this lambda is not set in VPC.
I want to put the lambda in default VPC (to access RDS)
Any setting can be used here or I should do something another??
(And, template makes IAmRole automatically, is there any way I can attach policy to it?? for example RDSFullAccess)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
python3.9 Sample SAM Template for chatbot-sam
Parameters:
DBNAME:
Type: String
DBUSER:
Type: String
DBPASSWORD:
Type: String
DBHOST:
Type: String
DBPORT:
Type: String
LINELONGLIVETOKEN:
Type: String
Globals:
Function:
Timeout: 30
Environment:
Variables:
DBNAME: !Ref DBNAME
DBUSER: !Ref DBUSER
DBPASSWORD: !Ref DBPASSWORD
DBHOST: !Ref DBHOST
DBPORT: !Ref DBPORT
LINELONGLIVETOKEN: !Ref LINELONGLIVETOKEN
Resources:
WebhookFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
Architectures:
- x86_64
Events:
Webhook:
Type: Api
Properties:
Path: /webhook
Method: post
Metadata:
Dockerfile: Dockerfile.webhook
DockerContext: ./chatbotapp
DockerTag: python3.9-v1
Outputs:
WebhookApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/webhook/"
WebhookFunction:
Description: "Webhook Lambda Function ARN"
Value: !GetAtt WebhookFunction.Arn
WebhookFunctionIamRole:
Description: "Implicit IAM Role created for Webhook function"
Value: !GetAtt WebhookFunctionRole.Arn
I updated.
Attaches VpcConfig and Policies , however it doesn't look change.
lambda -> setting -> vpc, there is no vpc setting and can't find the clue it belongs to SecurityGroup and Subnet
Policies: AWSLambdaVPCAccessExecutionRole
VpcConfig:
SubnetIds:
- subnet-fb6fa4d0
- subnet-bf8ab8e4
SecurityGroupIds:
- sg-0641506b4ec3782de
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
python3.9 Sample SAM Template for chatbot-sam
Parameters:
DBNAME:
Type: String
DBUSER:
Type: String
DBPASSWORD:
Type: String
DBHOST:
Type: String
DBPORT:
Type: String
LINELONGLIVETOKEN:
Type: String
Globals:
Function:
Timeout: 30
Environment:
Variables:
DBNAME: !Ref DBNAME
DBUSER: !Ref DBUSER
DBPASSWORD: !Ref DBPASSWORD
DBHOST: !Ref DBHOST
DBPORT: !Ref DBPORT
LINELONGLIVETOKEN: !Ref LINELONGLIVETOKEN
Resources:
WebhookFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
Architectures:
- x86_64
Events:
Webhook:
Type: Api
Properties:
Path: /webhook
Method: post
Policies: AWSLambdaVPCAccessExecutionRole
VpcConfig:
SubnetIds:
- subnet-fb6fa4d0
- subnet-bf8ab8e4
SecurityGroupIds:
- sg-0641506b4ec3782de
Metadata:
Dockerfile: Dockerfile.webhook
DockerContext: ./chatbotapp
DockerTag: python3.9-v1
Outputs:
WebhookApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/webhook/"
WebhookFunction:
Description: "Webhook Lambda Function ARN"
Value: !GetAtt WebhookFunction.Arn
WebhookFunctionIamRole:
Description: "Implicit IAM Role created for Webhook function"
Value: !GetAtt WebhookFunctionRole.Arn
You'll need to add a VpcConfig to the properties of your function definition. You can see an example of how to use that here.
You can also add policies to the default role that is made for the function, or you can supply your own role, in which case the default role will not be created.
Related
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 used sam cli , to create a project. when I package this and deploy , it creates the lambda and also the api gateway with stage and prod stages, policy, roles e.t.c by default, without having to explicitly define in the cloudformation template ( see code below) . as it generates the api gateway automatically, how do i add/attach say if i wanted to add a api key or some kind of authorization for my api generated by template below?
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
simple-node-api
Sample SAM Template for simple-node-api
Globals:
Function:
Timeout: 3
Resources:
ServerlessHttpApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
ApiKeyRequired: true # sets for all methods
DefinitionBody:
swagger:2.0
paths:
"/myresource":
post:
x-amazon-apigateway-integration
httpMethod: post
type: aws_proxy
uri: ...
ApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Name: !Join ["", [{"Ref": "AWS::StackName"}, "-apikey"]]
Description: "CloudFormation API Key V1"
Enabled: true
GenerateDistinctId: false
Value: abcdefg123456
StageKeys:
- RestApiId: !Ref ServerlessHttpApi
StageName: Prod
ApiUsagePlan:
Type: "AWS::ApiGateway::UsagePlan"
Properties:
ApiStages:
- ApiId: !Ref ServerlessHttpApi
Stage: Prod
Description: !Join [" ", [{"Ref": "AWS::StackName"}, "usage plan"]]
Quota:
Limit: 1000
Period: MONTH
UsagePlanName: !Join ["", [{"Ref": "AWS::StackName"}, "-usage-plan"]]
ApiUsagePlanKey:
Type: "AWS::ApiGateway::UsagePlanKey"
DependsOn:
- ServerlessHttpApi
Properties:
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref ApiUsagePlan
HelloWorldfunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: python3.7
Events:
HelloWorld:
Type: Api
Properties:
RestApiId: !Ref ServerlessHttpApi
Path: /hello
Method: get
Outputs:
ServerlessHttpApi:
Description: API Gateway endpoint URL for Prod stage for Hello World function
Value:
Fn::Sub: https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldfunction:
Description: Express Backend Lambda Function ARN
Value: !Sub HelloWorldfunction.Arn
HelloWorldFunctionIamRole:
Description: Implicit IAM Role created for Hello World function
Value: !Sub HelloWorldFunctionRole.Arn
I modified your code to use the API keys as shown here.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
simple-node-api
Sample SAM Template for simple-node-api
Globals:
Function:
Timeout: 3
Resources:
ServerlessHttpApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
ApiKeyRequired: true # sets for all methods
ApiKey:
Type: AWS::ApiGateway::ApiKey
DependsOn: [ApiUsagePlan]
Properties:
Name: !Join ["", [{"Ref": "AWS::StackName"}, "-apikey"]]
Description: "CloudFormation API Key V1"
Enabled: true
GenerateDistinctId: false
Value: abcdefg123456665ffghsdghfgdhfgdh4565
StageKeys:
- RestApiId: !Ref ServerlessHttpApi
StageName: Prod
ApiUsagePlan:
Type: "AWS::ApiGateway::UsagePlan"
DependsOn:
- ServerlessHttpApiProdStage
Properties:
ApiStages:
- ApiId: !Ref ServerlessHttpApi
Stage: Prod
Description: !Join [" ", [{"Ref": "AWS::StackName"}, "usage plan"]]
Quota:
Limit: 1000
Period: MONTH
UsagePlanName: !Join ["", [{"Ref": "AWS::StackName"}, "-usage-plan"]]
ApiUsagePlanKey:
Type: "AWS::ApiGateway::UsagePlanKey"
DependsOn:
- ServerlessHttpApi
Properties:
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref ApiUsagePlan
HelloWorldfunction:
Type: AWS::Serverless::Function
Properties:
#CodeUri: hello-world/
CodeUri: ./
Handler: app.lambdaHandler
Runtime: python3.7
Events:
HelloWorld:
Type: Api
Properties:
RestApiId: !Ref ServerlessHttpApi
Path: /hello
Method: get
Outputs:
ServerlessHttpApi:
Description: API Gateway endpoint URL for Prod stage for Hello World function
Value:
Fn::Sub: https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldfunction:
Description: Express Backend Lambda Function ARN
Value: !Sub HelloWorldfunction.Arn
HelloWorldFunctionIamRole:
Description: Implicit IAM Role created for Hello World function
Value: !Sub HelloWorldFunctionRole.Arn
I commented out some parts so that I can run the code, and I can confirm that it deploys and the API auth is set and API key present:
You have to mention it in your AWS SAM template. Below is an example:
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
ApiKeyRequired: true # sets for all methods
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Handler: index.handler
Runtime: nodejs12.x
Events:
ApiKey:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /
Method: get
Auth:
ApiKeyRequired: true
You can read more about it here
I'm trying to deploy a parent and nested stacks to AWS with cloudformation. The parent stack looks like this
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
VPC:
Description: Choose which VPC the Lambda-functions should be deployed to
Type: AWS::EC2::VPC::Id
Default: vpc-sdjkfnsdjklfn
Subnets:
Description: Choose which subnets Lambda-functions should be deployed to
Type: CommaDelimitedList
Default: "subnet-sdoifno, subnet-sdofjnsdo"
SecurityGroup:
Description: Select the Security Group to use for the Lambda-functions
Type: AWS::EC2::SecurityGroup::Id
Default: sg-sdklfnsdkl
Role:
Description: Role for Lambda functions
Type: String
Default: arn:aws:iam::dlfksd:role/ssdfnsdo
Resources:
RestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: "my-api"
Description: "SPP Lambda API"
Stack1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: 'https://s3.amazonaws.com/bucket/template1.yml'
Parameters:
VPC: !Ref VPC
Subnets: !Join
- ','
- !Ref Subnets
SecurityGroup: !Ref SecurityGroup
Role: !Ref Role
RestApi: !Ref RestApi
ApiResourceParent: !GetAtt "RestApi.RootResourceId"
The child stack looks like this
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
VPC:
Type: AWS::EC2::VPC::Id
Subnets:
Type: CommaDelimitedList
SecurityGroup:
Type: AWS::EC2::SecurityGroup::Id
Role:
Type: String
RestApi:
Type: AWS::ApiGateway::RestApi
ApiResourceParent:
Type: AWS::ApiGateway::Resource
Resources:
Fucntion:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: bucket
S3Key: node_lambdas.zip
Handler: Function.handler
Role: !Ref Role
Runtime: nodejs6.10
Timeout: 300
VpcConfig:
SecurityGroupIds:
- !Ref SecurityGroup
SubnetIds: !Ref Subnets
#Policies: AWSLambdaDynamoDBExecutionRole
Permission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt "Function.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApi}/*/*/*"
Resource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref RestApi
ParentId: !Ref ApiResourceParent
PathPart: addadjustments
When I run aws cloudformation deploy --template-file parent-stack.yml --stack-name spp-lambda --region us-east-1 --capabilities CAPABILITY_IAM I get the following error
Embedded stack
arn:aws:cloudformation:us-east-1:771653148224:stack/spp-lambda-Stack1-97M9BLBUM3A5/4a454a50-c274-11e8-b49c-500c28903236
was not successfully created: Parameter validation failed: parameter
type AWS::ApiGateway::RestApi for parameter name RestApi does not
exist, parameter type AWS::ApiGateway::Resource for parameter name
ApiResourceParent does not exist
It doesn't complain about the parameters that are explicitly defined in the parent template. I want the parameters it is complaining about to be created and passed dynamically as I won't know the values before hand. What am I doing wrong?
Although some of the AWS resource type are supported as a cloudformation parameter type, it doesn't mean all resource type are supported.
You are trying to reference API gateway value as an AWS-specific parameter type, but it is not supported: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html#aws-specific-parameter-types
I believe using String as the type is sufficient.
I am trying to deploy my lambda functions using CloudFormation StackSets to multiple AWS accounts and regions. But failed because of the below error
ResourceLogicalId:OfficeHoursAutoScalingStart, ResourceType:AWS::Lambda::Function, ResourceStatusReason:Error occurred while GetObject. S3 Error Code: AuthorizationHeaderMalformed. S3 Error Message: The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'ap-southeast-1'
It seems like its a permissions thing? How do I resolve this?
My template:
AWSTemplateFormatVersion : '2010-09-09'
Description: 'Skynet. AWS Management Assistant'
Parameters:
AppName:
Type: String
Description: Prefix for resources
Default: skynet-lambda-stackset
ArtifactsBucket:
Type: String
Description: S3 bucket storing lambda function zip
ArtifactZipPath:
Type: String
Description: Path to lambda function zip
CostCenter:
Type: String
Description: Cost center
Default: Admin
Owner:
Type: String
Description: Owner
Default: Jiew Meng
Resources:
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${AppName}-lambda'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- apigateway.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonEC2FullAccess'
- 'arn:aws:iam::aws:policy/AWSLambdaFullAccess'
- 'arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess'
- 'arn:aws:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess'
- 'arn:aws:iam::aws:policy/CloudWatchLogsFullAccess'
NewEc2AutoTag:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ArtifactsBucket
S3Key: !Ref ArtifactZipPath
Handler: ec2/newEc2_autoTag.handler
Runtime: nodejs6.10
FunctionName: 'NewEC2_AutoTag'
Description: 'Auto tag new EC2 instances with Owner tag'
Timeout: 30
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: Cost Center
Value: !Ref CostCenter
- Key: Owner
Value: !Ref Owner
NewEc2Event:
Type: AWS::Events::Rule
Properties:
Name: !Sub ${AppName}-newEc2
Description: On new EC2 instance created
EventPattern:
source:
- 'aws.ec2'
detail-type:
- 'AWS API Call via CloudTrail'
detail:
eventName:
- RunInstances
Targets:
- !Ref NewEc2AutoTag
AfterhoursEc2Shutdown:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ArtifactsBucket
S3Key: !Ref ArtifactZipPath
Handler: ec2/afterHours_shutdown.handler
Runtime: nodejs6.10
FunctionName: 'Afterhours_Shutdown'
Description: 'Shutdown instances tagged Auto Shutdown: true'
Timeout: 30
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: Cost Center
Value: !Ref CostCenter
- Key: Owner
Value: !Ref Owner
AfterHoursEvent:
Type: AWS::Events::Rule
Properties:
Name: !Sub ${AppName}-afterHours
Description: Triggered on weekdays 2400 SGT
ScheduleExpression: cron(0 16 ? * MON,TUE,WED,THUR,FRI *)
Targets:
- !Ref AfterhoursEc2Shutdown
- !Ref AfterhoursAutoScalingShutdown
OfficeHoursEc2Start:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ArtifactsBucket
S3Key: !Ref ArtifactZipPath
Handler: ec2/officeHours_start.handler
Runtime: nodejs6.10
FunctionName: 'OfficeHours_Start'
Description: 'Starts instances with Auto Shutdown: true'
Timeout: 30
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: Cost Center
Value: !Ref CostCenter
- Key: Owner
Value: !Ref Owner
OfficeHoursEvent:
Type: AWS::Events::Rule
Properties:
Name: !Sub ${AppName}-officeHours
Description: Triggered on 7AM SGT weekdays
ScheduleExpression: cron(0 23 ? * SUN,MON,TUE,WED,THU *)
Targets:
- !Ref OfficeHoursEc2Start
- !Ref OfficeHoursAutoScalingStart
StartedEc2ConfigureDns:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ArtifactsBucket
S3Key: !Ref ArtifactZipPath
Handler: ec2/started_configureDns.handler
Runtime: nodejs6.10
FunctionName: 'StartedEc2_ConfigureDns'
Description: 'When EC2 started, configure DNS if required'
Timeout: 30
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: Cost Center
Value: !Ref CostCenter
- Key: Owner
Value: !Ref Owner
Ec2StartedEvent:
Type: AWS::Events::Rule
Properties:
Name: !Sub ${AppName}-ec2-started
Description: Triggered on EC2 starts
EventPattern:
source:
- 'aws.ec2'
detail-type:
- 'EC2 Instance State-change Notification'
detail:
state:
- running
Targets:
- !Ref StartedEc2ConfigureDns
AfterhoursAutoScalingShutdown:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ArtifactsBucket
S3Key: !Ref ArtifactZipPath
Handler: autoscaling/afterHours_shutdown.handler
Runtime: nodejs6.10
FunctionName: 'Afterhours_AutoScalingShutdown'
Description: 'Scales down autoscaling groups tagged Auto Shutdown: true'
Timeout: 30
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: Cost Center
Value: !Ref CostCenter
- Key: Owner
Value: !Ref Owner
OfficeHoursAutoScalingStart:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ArtifactsBucket
S3Key: !Ref ArtifactZipPath
Handler: autoscaling/officeHours_start.handler
Runtime: nodejs6.10
FunctionName: 'OfficeHours_AutoScalingStart'
Description: 'Scales up auto scaling groups that are scaled down to 0 and tagged autostart: true'
Timeout: 30
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: Cost Center
Value: !Ref CostCenter
- Key: Owner
Value: !Ref Owner
NewAutoScalingGroupEvent:
Type: AWS::Events::Rule
Properties:
Name: !Sub ${AppName}-autoscaling-new
Description: Triggered when new autoscaling group created
EventPattern:
source:
- 'aws.autoscaling'
detail-type:
- 'AWS API Call via CloudTrail'
detail:
eventName:
- CreateAutoScalingGroup
Targets:
- !Ref NewAutoScalingGroupAutoTag
NewAutoScalingGroupAutoTag:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref ArtifactsBucket
S3Key: !Ref ArtifactZipPath
Handler: autoscaling/new_autoTag.handler
Runtime: nodejs6.10
FunctionName: 'NewAutoScalingGroup_AutoTag'
Description: 'Tags new autoscaling groups with owner and autoshutdown tags if not existing'
Timeout: 30
Role: !GetAtt LambdaRole.Arn
Tags:
- Key: Cost Center
Value: !Ref CostCenter
- Key: Owner
Value: !Ref Owner
Looks like you have created the s3 bucket (referenced by variable ArtifactsBucket in your template) in AWS region ap-southeast-1.
Using AWS Stacksets, You have selected us-east-1 as one of the regions in Deployment Order.
The AWS Stackset passes the SAME parameters to all the stacks which it tries to create in multiple regions/accounts.
So when it is trying to create the lambda function OfficeHoursAutoScalingStart in us-east-1 region, It is tryin to access the s3 bucket(GETObject request) in us-east-1 region itself, with the same bucket name.
ie. It is presuming that the s3 bucket with name passed by ArtifactsBucketparameter, is present in us-east-1 itself.But since the source code of the lambda function is actually in the bucket present in region ap-southeast-1,the header malformed error is thrown. In this case the bucket name is matching, but the region is not.
Currently, when you create lambda function using CloudFormation, there is a restriction that the S3 bucket that contains the source code of your Lambda function must be in the SAME region as the STACK which you are creating. Doc Reference Link
If this is the issue, then as a fix, you can think of creating s3 buckets (add region-name as a prefix to the bucket name) in the required regions and use them in the template based on the region.
Example:
us-east-1-lambdabkt
us-east-2-lambdabkt
ap-southeast-1-lambdabkt
I have an SAM template that creates an API Gateway API exporting the API Endpoint:
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'API Server for Skynet: AWS Management Assistant'
Resources:
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: swagger.yml
StageName: prod
Variables:
Region: !Ref AWS::Region
AccountId: !Ref AWS::AccountId
Outputs:
ApiEndpoint:
Description: API Endpoint
Value: !Sub
- 'https://${ApiId}.execute-api.${AWS::Region}.amazonaws.com/prod'
- {ApiId: !Ref ApiGatewayApi}
Export:
Name: !Sub '${AWS::StackName}-ApiEndpoint'
In my CodePipeline/CodeBuild stack: I am referencing it:
CodeBuildWeb:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub '${PipelineName}-web'
Artifacts:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/nodejs:7.0.0
Type: LINUX_CONTAINER
EnvironmentVariables:
- Name: S3_BUCKET
Value: !Ref S3WebBucket
- Name: API_URL
Value: Fn::ImportValue
!Sub '${PipelineName}-server-ApiEndpoint'
ServiceRole: !Ref CodeBuildRole
Source:
BuildSpec: 'web/buildspec.yml'
Type: CODEPIPELINE
Problem is, its not expanding, in my code, I see ApiEndpoint as Fn::ImportValue !Sub '${PipelineName}-server-ApiEndpoint' whats wrong here?
OK, I found my mistake:
- Name: API_URL
Value: Fn::ImportValue:
!Sub '${PipelineName}-server-ApiEndpoint'
I should add a : after Fn::ImportValue