0
votes

I recently starting porting part of my infrastructure to AWS CDK. Previously, I did some experiments with Cloudformation templates directly.

I am currently facing the problem that I want to encode some values (namely the product version) in a user-data script of an EC2 launch template and these values should only be loaded at deployment time. With Cloudformation this was quite simple, I was just building my JSON file from functions like Fn::Base64 and Fn::Join. E.g. it looked like this (simplified)

"MyLaunchTemplate": {
    "Type": "AWS::EC2::LaunchTemplate",
        "Properties": {
            "LaunchTemplateData": {
                "ImageId": "ami-xxx",
                "UserData": {
                    "Fn::Base64": {
                        "Fn::Join": [
                            "#!/bin/bash -xe",
                            {"Fn::Sub": "echo \"${SomeParameter}\""},
                        ]
                    }
                }
            }
        }
    }
}

This way I am able to define the parameter SomeParameter on launch of the cloudformation template.

With CDK we can access values from the AWS Parameter Store either at deploy time or at synthesis time. If we use them at deploy time, we only get a token, otherwise we get the actual value.

I have achieved so far to read a value for synthesis time and directly encode the user-data script as base64 like this:

product_version = ssm.StringParameter.value_from_lookup(
    self, f'/Prod/MyProduct/Deploy/Version')

launch_template = ec2.CfnLaunchTemplate(self, 'My-LT', launch_template_data={
    'imageId': my_ami,
    'userData': base64.b64encode(
        f'echo {product_version}'.encode('utf-8')).decode('utf-8'),
})

With this code, however, the version gets read during synthesis time and will be hardcoded into the user-data script.

In order to be able to use dynamic values that are only resolved at deploy time (value_for_string_parameter) I would somehow need to tell CDK to write a Cloudformation template similar to what I have done manually before (using Fn::Base64 only in Cloudformation, not in Python). However, I did not find a way to do this.

If I read a value that is only to be resolved at deploy time like follows, how can I use it in the UserData field of a launch template?

latest_string_token = ssm.StringParameter.value_for_string_parameter(
    self, "my-plain-parameter-name", 1)