1
votes

I have some userdata scripts which are currently used by standalone EC2 instances. I'd like to be able to use these with cloudformation and include calls to the 'cfn-' helper scripts to signal the cloudformation stack of the progress. Essentially, I'd like to be able to prepend some data to the userdata script, and append some data to it. To do so I planned to take the existing script and use sed to remove the leading shebang/script line, and pass that slightly modified script into cloudformation as a parameter. This script needs to be base64 encoded before being passed as a parameter. I base64 encode and then split based on a 4096 byte size (the parameter size limit). My cloudformation template has 4 'userdata' parameter fields that I can pass data into. This currently works in existing scripts:

"UserData" : { "Fn::Join" : [ "", [ { "Ref" : "UserData" }, { "Ref" : "UserData2" }, { "Ref" : "UserData3" }, { "Ref" : "UserData4" }]]},

Note: I don't have to use the base64 intrinsic function here as the individual parameters are already base64 encoded.

I've been trying this, but I'm getting an error (show further down):

        "UserData" : {
      "Fn::Join": [
        "", [
          { "Fn::Base64": 
            { "Fn::Join": [
              "", [
                "#!/bin/bash\n",
                {"Fn::Join": ["", ["AWS_REGION=",{ "Ref" : "AWS::Region" },"\n"]]},
                {"Fn::Join": ["", ["STACKNAME=",{ "Ref" : "AWS::StackName" },"\n"]]},
                "LAUNCHCONFIG=LaunchConfig\n",
                "# # Signalling cloudformation\n",
                {"Fn::Join": ["", ["/opt/aws/bin/cfn-init -v --stack ",{ "Ref" : "AWS::StackName" }," --resource LaunchConfig --region ",{ "Ref" : "AWS::Region" },"\n"]]},
              ]
            ]}
          },
          { "Ref" : "UserData" },
          { "Ref" : "UserData2" },
          { "Ref" : "UserData3" },
          { "Ref" : "UserData4" },
          { "Fn::Base64": 
            { "Fn::Join": [
              "", [
                {"Fn::Join": ["", ["/opt/aws/bin/cfn-signal -e $? --stack ",{ "Ref" : "AWS::StackName" }," --resource AutoScalingGroup --region ",{ "Ref" : "AWS::Region" },"\n"]]},
              ]
            ]}
          }
        ]
      ]
    },

The error received is:

UserData does not appear to be base64 encoded (Service: AmazonAutoScaling; Status Code: 400; Error Code: ValidationError

I want to avoid the situation where I need to know the appropriate parameters ahead of time - and thus generating a new userdata script including that detail which could be passed as a parameter - as I would like to avoid generating a custom userdata file specifically to use with cloudformation.

I've passed in empty values for the four 'userdata' parameters, so it appears that the leading and trailing elements in the join are not being base64 encoded. I appreciate any insight into this, or how I might accomplish what I have described.

2

2 Answers

0
votes

I normally see:

    "UserData": {
      "Fn::Base64": {
        "Fn::Join": [
          "",
          [

Try to keep the base64 conversion as the outermost level, with the inner-level scripts not being encoded.

-1
votes

If I understand, you are passing in userdata that has already been base64 encoded. I think that is incorrect with your setup. The value of the userdata param should not be pre-encoded. It should be plain text. Cloudformation does the encoding. It needs to be encoded as delivered to the EC2 instance, but not in the configuration. You should be joining plain text.

Else, remove the Fn::Base64 block from your script. That may resolve it. Though that is just a straight up guess.