Today I learned how to use cross-stack references in AWS CloudFormation.
Long story short: I needed to add permissions to a staging lambda function.
Looking at the CloudFormation docs for lambda permissions, we get the following:
permission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !Ref FunctionName Principal: 29302903920
My project has two stacks, defined in two templates: one for staging and one for production.
The problem I had was that I wanted to dynamically populate the
Principal field using the ARN of an IAM role I had created in the production stack.
I didn’t want to copy and paste the role’s ARN everywhere, so I looked around for an elegant solution and discovered cross-stack references.
The solution is very simple and is divided in 3 steps:
- Export the desired value in the
Outputssection of the production stack
- Create a variable in the
Parameterssection of the staging stack
- Retrieve the value at runtime and pass it to the staging template when deploying
Step 1: Export the value
In the production stack add the following block to the bottom of the template file:
Outputs: NgnrLogRoleArn: Value: !GetAtt NgnrApiLogsRole.Arn Description: Arn for the cloudwatch logs role
Step 2: Create a variable in the staging stack
In the staging template, add a new variable under
Parameters: NgnrLogRoleArn: Type: string
then reference it in the permission block
permission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !Ref FunctionName Principal: !Ref NgnrLogRoleArn
Step 3: Retrieve the value dynamically with the CLI
To retrieve the output value of a stack, we can use the
aws cloudFormation describe-stacks --stack-name stack-name --query "Stacks.Outputs[?OutputKey=='NgnrLogRoleArn'].OutputValue" --output text
This will get the metadata for the given
stack-name then filter the results based on the given condition
In plain English:
For the first item in the
Stacks list, look at the
Outputs list. Give me the one whose key is
NgnrLogRoleArn and output the corresponding value in plain text.
Deploy the stack
You can now use the above command to fetch whatever value you need and dynamically pass it to the stack.
Putting everything together we get the following
aws cloudformation deploy --template-file staging.infra.cf.yaml --stack-name ngnr-club-staging --region us-east-1 --capabilities CAPABILITY_NAMED_IAM --parameter-overrides NgnrLogRoleArn=(aws cloudformation describe-stacks --stack-name ngnr-club --query "Stacks.Outputs[?OutputKey=='NgnrLogRoleArn'].OutputValue" --output=text)
Thanks for coming to my TED talk.