Is there a way to create some kind of random or unique value in a CloudFormation template?
Why I need this. In our templates we have a number of custom-named resources, for instance AWS::AutoScaling::LaunchConfiguration
with specified LaunchConfigurationName
or AWS::AutoScaling::AutoScalingGroup
with specified AutoScalingGroupName
.
When updating stacks, we often get the following error:
CloudFormation cannot update a stack when a custom-named resource requires replacing. Rename some-stack-launch-configuration and update the stack again.
We don't want to rename resources just because we need to update them.
We also don't want to drop custom names in our resources. We won't mind however having some random suffix in our custom names.
With a "random generator" the solution might look something like:
MyAutoScalingGroup:
Type: 'AWS::AutoScaling::AutoScalingGroup'
Properties:
AutoScalingGroupName: !Sub 'my-auto-scaling-group-${AWS::Random}'
If you just need a random ID (no passwords, no fancy requirements), the way I'd recommend is using a portion of AWS::StackId, which is in the following format:
arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123
So in order to get the last portion, you would need two splits, e.g.:
AutoScalingGroupName:
Fn::Join:
- '-'
- - my-auto-scaling-group
- Fn::Select:
- 4
- Fn::Split:
- '-'
- Fn::Select:
- 2
- Fn::Split:
- /
- Ref: AWS::StackId
Equivalent shorter syntax:
AutoScalingGroupName: !Join ['-', ['my-auto-scaling-group', !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]]
Meaning:
AWS::StackId
, e.g.: arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123
/
and select 2th portion (0-indexed): 51af3dc0-da77-11e4-872e-1234567db123
-
and select 4th portion (0-indexed): 1234567db123
my-auto-scaling-group-1234567db123
.Advantages: I prefer this way than creating a CustomResource, because for large AWS environments and many stacks, you might end up with several lambdas, making governance a bit harder.
Disadvantages: It's more verbose (Fn::Join
, Fn::Select
, and Fn::Split
).
EDIT 2022-02-17:
As observed by @teuber789's comment, if you need multiple resources of the same type, e.g.: my-auto-scaling-group-<random_1>
and my-auto-scaling-group-<random_2>
, this approach won't work as AWS::StackId
is the same for whole stack.
In my opinion, the most elegant way to implement such logic (if you don't want to rename resources) is to use Cloudformation Macros. They're like a custom resource, but you call them implicitly during template transformation. So, I will try to provide some example, but you can investigate more in AWS Documentation.
First of all, you create the function (with all required permissions and so on) that will do the magic (something like LiuChang mentioned).
Then, you should create a macro from this Function:
Resources:
Macro:
Type: AWS::CloudFormation::Macro
Properties:
Name: <MacroName>
Description: <Your description>
FunctionName: <Function ARN>
And then use this Macro in your resources definition:
MyAutoScalingGroup:
Type: 'AWS::AutoScaling::AutoScalingGroup'
Properties:
AutoScalingGroupName:
'Fn::Transform':
- Name: <MacroName>
Parameters:
InputString: <Input String>
...<Some other parameters like operation type or you can skip this>
Also, to use macros, you should specify the CAPABILITY_AUTO_EXPAND capability during stack creation/updation.
And that's it. It should just work, but of course one of the drawbacks of this approach - you should maintain additional lambda function.
this is similar to https://stackoverflow.com/a/67162053/2660313 but shorter:
Value: !Select [2, !Split ['/', !Ref AWS::StackId]]
I think you need to create a Lambda
function to do this.
Here's a GitHub project cloudformation-random-string, which has a Lambda function and a simple tutorial.
Here's another tutorial Generate Passwords in AWS CloudFormation Template.
You can refer to the Lambda function above and make it work for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With