How to pass the Arn of a Step function to another function in a CloudFormation stack? - aws-lambda

I created a step function in a CloudFormation stack, and I need to call that function from another function in the stack once it's deployed. I have no idea how to do that, and I'm getting circular dependencies.
Basically I'm trying to pass an environment variable to the function that's the ARN of the step function.
Here's the CloudFormation code :
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
reports stack
Globals:
Function:
Timeout: 120
MemorySize: 2048
Runtime: python3.9
Environment:
Variables:
STEP_FUNCTION: !GetAtt Research.Arn ### =====> how do i do that ?
Parameters:
ProjectName:
Description: Name of the Project
Type: String
Default: Project
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
TracingEnabled: true
Cors:
AllowMethods: "'DELETE,GET,HEAD,OPTIONS,POST,PUT'"
AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
AllowOrigin: "'*'"
List:
DependsOn: VideoResearch
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/
Handler: get.get
Events:
List:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: /reports
Method: GET
Policies:
(...)
################ STEP FUNCTION ################
Research:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/
Handler: runResearch.research
Policies:
(...)
StepFunctionToHandleResearchRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- !Sub states.${AWS::Region}.amazonaws.com
Action: "sts:AssumeRole"
Path: "/"
Policies:
(...)
#
StepFunctionToHandleVideosResearch:
Type: "AWS::StepFunctions::StateMachine"
Properties:
DefinitionString: !Sub |
{
"StartAt": "Research",
"States": {
"Research": {
"Type": "Task",
"Resource": "${VideoResearch.Arn}",
"End": true
}
}
}
RoleArn: !GetAtt [ StepFunctionToHandleResearchRole, Arn ]
Outputs:
(...)
# I also tried to export the arn of the function
In my function's code I have :
stepFunctionARN = os.environ['STEP_FUNCTION']

#Anthony B. posted the answer in the comments : the problem was related to the fact I added the dependency as global variables, it created a circular dependency (API=> local function <= API looking for function's ARN => doesn't work).
If you remove the global variable and add a local variable, with a "DependsOn: Research" than everything works.
API=>created => creates first function, get Arn => than creates other functions and provide ARN

Related

Reference lambda function Arn from another nested Stack

I have two sam applications one 'App1' having a lambda function and another one 'App2' that will consume its Arn to create a permission like the following:
App2 template:
Parameters:
LambdaFunctionArnFromApp1:
Type: String
Description: The shared value will be passed to this parameter by parent stack.
DACAdminsLoginPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: LambdaFunctionArnFromApp1
Principal: apigateway.amazonaws.com
SourceArn: !Sub arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpWebServer}/*/*/digitalatcore/admins/login
App1 template:
LambdaFunctionArnFromApp1:
Type: AWS::Serverless::Function
Properties:
CodeUri: 'URL'
Runtime: nodejs12.x
Handler: app.handler
Outputs:
LambdaFunctionArnFromApp1:
Value: !GetAtt LambdaFunctionFromApp1.Arn
Export:
Name: LambdaFunctionArnFromApp1
When i try to deploy the full stack with sam i get the following error :
"*** was not successfully created: The following resource(s) failed to create: [DACAdminsLoginPermission]. ROLLBACK_IN_PROGRESS"
Can anyone please help me with this.
thank you.
Assuming both nested stacks have the same parent stack, you can pass the output from the App1 stack to the App2 stack like this:
App1Stack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: app1-template.yaml
App2Stack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: app2-template.yaml
Parameters:
LambdaFunctionArnFromApp1: !GetAtt App1Stack.Outputs.LambdaFunctionArnFromApp1
Another option could be to use the ImportValue intrinsic function in your App2 template to get the export that you defined in the App1 template: FunctionName: !ImportValue LambdaFunctionArnFromApp1

AWS Automation Document not updating Lambda Alias

I've created an Automation Document using cloud formation to update the live alias for a given function. It runs ok without any errors and I'm not seeing anything cloud trail. But when I check which version is set to alias:live it is left unchanged.
template.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: "AWS CloudFormation Template for Response Plans"
Parameters:
Environment:
Type: String
Default: "sandbox"
Domain:
Type: String
Team:
Type: String
NotificationARN:
Type: AWS::SSM::Parameter::Value<String>
Resources:
ResponsePlan:
Type: AWS::SSMIncidents::ResponsePlan
Properties:
Actions:
- SsmAutomation:
RoleArn: !GetAtt Role.Arn
DocumentName: UpdateAliasDocument
DisplayName: "UpdateLambdaAlias"
IncidentTemplate:
Impact: 3
NotificationTargets:
- SnsTopicArn:
Ref: NotificationARN
Summary: "String"
Title: "String"
Name: "UpdateLambdaAlias"
Tags:
- Key: "Team"
Value: !Ref Team
- Key: "Domain"
Value: !Ref Domain
- Key: "Environment"
Value: !Ref Environment
Document:
Type: AWS::SSM::Document
Properties:
Content:
schemaVersion: "2.2"
parameters:
FunctionVersion:
type: "String"
default: "1"
FunctionName:
type: "String"
mainSteps:
- name: "UpdateLambdaAlias"
action: aws:runShellScript
inputs:
runCommand:
- aws lambda update-alias --function-name {{FunctionName}} --name live --function-version {{FunctionVersion}}
DocumentType: "Command"
TargetType: /
Tags:
- Key: "Team"
Value: !Ref Team
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: EC2Instances
PolicyDocument:
Statement:
- Effect: Allow
Action:
- ec2:*
Resource:
- !Sub arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:instance/*
- PolicyName: UpdateAliasPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- lambda:UpdateFunctionConfiguration
Resource:
- !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${Environment}-*
Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0c2b8ca1dad447f8a
InstanceType: t2.micro
Monitoring: true
Tags:
- Key: "Team"
Value: !Ref Team
Update
Looks like not target is being found to run the script on
It looks like your Role entry does not have the required permissions to execute the update-alias command. Your policy only allows for lambda:UpdateFunctionConfiguration.
You will at least need the lambda:UpdateAlias permission as well. If this is not enough, you could try being very permissive with your role and then reducing the permissions afterwards.

Specify resources allowed to call a function in its AWS SAM Function template

TL; DR: How should I edit the template below so that it can be triggered by a user pool trigger?
I try to crate a CloudFormation template for a Lambda function defining both the services the function can call and be called from. It should be run with a Cognito User Pool trigger.
To do that, I've defined a resource in template of type AWS::Serverless::Function briefly as follows. Watch out the Policies section:
Resources:
MyFunctionResource:
Type: AWS::Serverless::Function
Properties:
FunctionName: MyFunctionName
CodeUri: ./
Handler: "lambda_function.lambda_handler"
MemorySize: 128
Runtime: python3.7
Timeout: 3
Policies:
- Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "cognito-idp:*"
- "logs:*"
...
Resource: "*"
- Version: "2012-10-17"
Statement:
- Effect: Allow
Action: "lambda:InvokeFunction"
Principal:
Service: cognito-idp.amazonaws.com
Resource: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:MyFunctionName"
The second policy I have inserted for restricting the resources can call my function fails during the stack creation:
Policy document should not specify a principal. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
When I remove that policy with principal, the access to the function through the user pool trigger is denied.
I figured out that the permissions should be created as a separate resource with type AWS::Lambda::Permission which can take the function name or arn it will be attached to.
Thus, the following logic creates the function with permissions (a.k.a. Function Policy) successfully:
Resources:
MyFunctionResource:
Type: AWS::Serverless::Function
Properties:
FunctionName: MyFunctionName
CodeUri: ./
Handler: "lambda_function.lambda_handler"
MemorySize: 128
Runtime: python3.7
Timeout: 3
Policies:
- Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "cognito-idp:*"
- "logs:*"
...
Resource: "*"
## Remove this section
# - Version: "2012-10-17"
# Statement:
# - Effect: Allow
# Action: "lambda:InvokeFunction"
# Principal:
# Service: cognito-idp.amazonaws.com
# Resource: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:MyFunctionName"
## Add this instead
MyFunctionPermissions:
Type: AWS::Lambda::Permission
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt MyFunctionResource.Arn
Principal: "cognito-idp.amazonaws.com"
SourceArn: !Sub "arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/*"

Can i add a codecommit trigger to my lambda function via CloudFormation

Im writing a lambda function that i want to be triggered by somebody updating the master branch of a repo. The repo already exists on the account.
Is there a way in cloudformation that i can add the trigger to the lambda function? I guess at a snip i could cretae some cloudwatch rule to trigger the lambda, but would rather keep it all inside the lambda.
Thanks
R
If you are using AWS serverless transform then you can self contain it within the lambda. Although the transform generates the cloudwatch rule and the lambda permission, so it's basically the same you mentioned.
nevertheless here's an example to do what you want
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Pipeline which triggers lambda for codecommit changes
Parameters:
BranchName:
Default: master
Description: The GIT branch
Type: String
RepositoryName:
Description: The GIT repository
Type: String
StackOwner:
Description: The stack owner
Type: String
Resources:
BasicLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Path: "/"
Policies:
- PolicyName: root
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: logs:*
Resource: arn:aws:logs:*:*:*
- Effect: Allow
Action: '*'
Resource: '*'
PipelineTriggerFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/trigger
Handler: codetrigger.handler
MemorySize: 256
Role: !GetAtt BasicLambdaRole.Arn
Runtime: python3.6
Timeout: 900
Environment:
Variables:
TestVariable: "TestValue"
Events:
CodeCommitPushEvent:
Type: CloudWatchEvent
Properties:
Pattern:
source:
- aws.codecommit
resources:
- !Sub 'arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}'
detail:
event:
- referenceCreated
- referenceUpdated
repositoryName:
- !Ref RepositoryName
referenceName:
- !Ref BranchName
Tags:
'owner': !Ref StackOwner
'task': !Ref RepositoryName
Obviously, specify the lambda role better and not give all permissions as provided in the example.

SAM template "Invalid template property or properties [MyApi]"

I am getting the following error after running CLI command aws cloudformation deploy (after sam package)
"Failed to create the changeset: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Invalid template property or properties [MyApi]"
This is the template. I cannot get information about which is the invalid property. Is this possible? Else what is wrong with this template?
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:`enter code here`
Handler: main
Runtime: go1.x
Events:
GetEvent:
Type: Api
Properties:
Path: /
Method: post
#RestApiId: !Ref ApiGateway1
LambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt
- HelloFunction
- Arn
Action: 'lambda:InvokeFunction'
Principal: apigateway.amazonaws.com
SourceAccount: !Ref 'AWS::AccountId'
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: default
EndpointConfiguration: REGIONAL
DefinitionBody:
swagger: "2.0"
info:
title: "TestAPI"
paths:
/:
get:
# parameters:
# - name: "id"
# in: "query"
# required: true
# type: "string"
# x-amazon-apigateway-request-validator: "Validate query string parameters and\
# \ headers"
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloFunction.Arn}/invocations
responses: {}
httpMethod: "POST"
type: "aws_proxy"
Outputs:
FunctioArn:
Value: !GetAtt HelloFunction.Arn
Export:
Name: HelloFunctionArn
There is an indentation error at MyApi. Use the following:
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:`enter code here`
Handler: main
Runtime: go1.x
Events:
GetEvent:
Type: Api
Properties:
Path: /
Method: post
#RestApiId: !Ref ApiGateway1
LambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt
- HelloFunction
- Arn
Action: 'lambda:InvokeFunction'
Principal: apigateway.amazonaws.com
SourceAccount: !Ref 'AWS::AccountId'
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: default
EndpointConfiguration: REGIONAL
DefinitionBody:
swagger: "2.0"
info:
title: "TestAPI"
paths:
/:
get:
# parameters:
# - name: "id"
# in: "query"
# required: true
# type: "string"
# x-amazon-apigateway-request-validator: "Validate query string parameters and\
# \ headers"
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloFunction.Arn}/invocations
responses: {}
httpMethod: "POST"
type: "aws_proxy"
Outputs:
FunctioArn:
Value: !GetAtt HelloFunction.Arn
Export:
Name: HelloFunctionArn

Resources