I've created a CloudFormation template that successfully creates an IAM user and an AccessKey and assigns that AccessKey to the IAM user. Right now I am getting the AccessKey's secret by outputting it in the Outputs
section of the CloudFormation template.
I'd like to know if there is a more secure way to create the AccessKey and fetch its corresponding secret without spitting it out in plain text in the Outputs
section.
I'm a bit confused by this because AWS doesn't have much info on doing this, and what little docs it does have directly contradict each other. Here AWS suggests doing what I've described above "One way to retrieve the secret key is to put it into an Output value". This seems like a security issue, and is confirmed by another AWS doc Here where it says "We strongly recommend you don't use this section to output sensitive information, such as passwords or secrets".
Am I misunderstanding their documentation or is this a direct contradiction? I've seen a S/O comment Here suggesting the use of AWS secrets manager but I'm having trouble figuring out how to get the AccessKey secret into Secrets Manager, where it can be stored and fetched more securely by something like boto3. Any example of this would be super helpful. My CloudFormation template is below for reference.
{
"Description": "My CloudFormation Template",
"Outputs": {
"UserAccessKeyId": {
"Description": "The value for the User's access key id.",
"Value": {
"Ref": "UserAccessKey"
}
},
"UserSecretKey": {
"Description": "The value for the User's secret key.",
"Value": {
"Fn::GetAtt": [
"UserAccessKey",
"SecretAccessKey"
]
}
}
},
"Resources": {
"User": {
"Properties": {
"UserName": "myNewUser"
},
"Type": "AWS::IAM::User"
},
"PrimaryUserAccessKey": {
"DependsOn": "User",
"Properties": {
"Status": "Active",
"UserName": "myNewUser"
},
"Type": "AWS::IAM::AccessKey"
}
}
}
I would recommend putting it in a Secret. You can have the CloudFormation write the value to Secrets Manager in the stack, and then you can access it via code. That allows you to have a secret that no person has to see or touch to use it.
I think something like this should work (note: I haven't actually tried this).
AccessKey:
Type: AWS::IAM::AccessKey
Properties:
Serial: 1
Status: Active
UserName: 'joe'
AccessKeySecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: JoeAccessKey
Description: Joes Access Key
SecretString: !Sub '{"AccessKeyId":"${AccessKey}","SecretAccessKey":"${AccessKey.SecretAccessKey}"}'