AWS CloudFormation give EC2 instance SSH Keys to other servers

amazon-cloudformationamazon-web-servicesssh-keys

I'm creating an EC2 instance using CloudFormation. The first thing I want to do is checkout a git repository containing puppet manifests. To do this I need an SSH key.

What is the best way to get the key on to the server? This is what I've considered:

  • Using KMS, but that doesn't seem to allow you to "store a key for later use"
  • Using EC2 key pairs, but this also doesn't seem to allow you to get the private key later
  • Writing the key into the UserData property, but (despite it's name) this seems like the wrong place to store any kind of data, let alone sensitive data
  • Storing it in an S3 bucket, but I'm not 100% sure how to set the permissions on the bucket to allow the EC2 instance to pull the data using the aws cli tool

This seems like it'd be a common thing to do, however I must be searching for the wrong things because I can't find a sensible answer.

Best Answer

A straightforward way of handling this is to store your secrets (like the SSH key) in a dedicated S3 bucket, and then give the EC2 instances access to that bucket.

You can start by creating an IAM role:

"DeploymentRole" : {
  "Type" : "AWS::IAM::Role",
  "Properties" : {
    "Policies" : [{
      "PolicyName" : "SecretsBucketPolicy",
      "PolicyDocument" : {
        "Version" : "2012-10-17",
        "Statement" : [{
          "Resource" : "arn:aws:s3:::wherever-the-secrets-are-stored/*",
          "Action" : ["s3:GetObject"],
          "Effect" : "Allow"
        }]
      }
    }],
    "Path" : "/",
    "AssumeRolePolicyDocument" : {
      "Version" : "2012-10-17",
      "Statement" : [{
        "Action" : ["sts:AssumeRole"],
        "Principal" : {"Service": ["ec2.amazonaws.com"]},
        "Effect" : "Allow"
      }]
    }
  }
}

This role defines a policy that lets it read the secret bucket, and allows EC2 to assume this role.

You then create an instance profile for this role:

"DeploymentProfile" : {
  "Type" : "AWS::IAM::InstanceProfile",
  "Properties" : {
    "Roles" : [{"Ref" : "DeploymentRole"}],
    "Path" : "/"
  }
}

For your EC2 instance or launch configuration you can now use the IamInstanceProfile property to assign this profile to the instance(s).

The secret bucket should then be readable.