TIL - Using CloudFormation cross stack references
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
The solution is very simple and is divided in 3 steps:
- Export the desired value in the
Outputs
section of the production stack - Create a variable in the
Parameters
section 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
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 describe-stacks
command
aws cloudFormation describe-stacks --stack-name stack-name --query "Stacks[0].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 deploy
command:
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[0].Outputs[?OutputKey=='NgnrLogRoleArn'].OutputValue" --output=text)
Thanks for coming to my TED talk.