Arun Kamalanathan
Arun Kamalanathan

Reputation: 8593

Setting SSM parameter as an Environment variable for EC2 - Does not work

I am trying to get and export an SSM parameter as an environment variable to an EC2 using the UserData section of Cloudformation.

The script is trying to append for e.g export WHATS_HER_NAME=Sherlyn to the /etc/profile file. But all i see in the /etc/profile is export WHATS_HER_NAME=. The value is not present. I use amazon linux 2 ami.

here is my cloudformation template.

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "Ec2Instance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "IamInstanceProfile": {
          "Ref": "Ec2instanceProfileTest"
        },
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [
              "\n",
              [
                "#!/bin/bash -xe",
                "yum update -y aws-cfn-bootstrap",
                {
                  "Fn::Sub": "/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource Ec2Instance --configsets default --region ${AWS::Region}"
                },
                {
                  "Fn::Sub": "/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region}"
                },
                {
                  "Fn::Sub": "echo \"export WHATS_HER_NAME=$(aws ssm get-parameter --name WhatsHerName --region ${AWS::Region} --query 'Parameter.Value')\" >> /etc/profile"
                }
              ]
            ]
          }
        }
      }
    },
    "GetSSMParameterPolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "GetSsmProperty",
        "PolicyDocument": {
          "Statement": [
            {
              "Effect": "Allow",
              "Resource": "arn:aws:ssm:ap-southeast-2:012345678901:parameter/WhatsHerName",
              "Action": [
                "ssm:GetParameters",
                "ssm:GetParameter"
              ]
            },
            {
              "Effect": "Allow",
              "Resource": "*",
              "Action": [
                "ssm:DescribeParameters"
              ]
            }
          ]
        },
        "Roles": [
          {
            "Ref": "InstanceRole"
          }
        ]
      }
    },
    "InstanceRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "ec2.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/"
      }
    },
    "BasicParameter": {
      "Type": "AWS::SSM::Parameter",
      "Properties": {
        "Name": "WhatsHerName",
        "Type": "String",
        "Value": "Sherlyn"
      }
    }
  }
}

any help would be highly appreciated.

Upvotes: 0

Views: 2759

Answers (2)

kichik
kichik

Reputation: 34734

I see two issues:

  1. Your instance doesn't depend on the parameter so the parameter can be created after the instance. When the instance is trying to read the empty parameter, it's just not there. Use DependsOn: [ BasicParameter ].
  2. You didn't include Ec2instanceProfileTest in your sample code. Are you sure it properly uses GetSSMParameterPolicy? If you run that aws ssm get-parameter command after the stack is done, can you get the value properly? If you can't, there might be a permission error. Check the result.

Upvotes: 0

George Rushby
George Rushby

Reputation: 1345

I am not a fan of using JSON for CloudFormation templates so I cannot offer the solution in JSON, but here it is in YAML.

UserData:
  Fn::Base64: !Sub
  - |
    #!/bin/bash -xe
    yum update -y aws-cfn-bootstrap
    /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource Ec2Instance --configsets default --region ${AWS::Region}
    /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region}
    echo export WHATS_HER_NAME=${WhatsHerNameParameter} >> /etc/profile
  - WhatsHerNameParameter: {{resolve:ssm:WhatsHerName:1}}

You can read more about using AWS Systems Manager Parameter Store Secure String parameters in AWS CloudFormation templates

The snippet above is substituting ${AWS::StackName} and ${AWS::Region} and when it gets to ${WhatsHerNameParameter} it checks for the SSM parameter and substitutes that into the UserData.

This mean that the UserData is complete before it gets to the EC2 instance.

Upvotes: 2

Related Questions