Encrypting secrets in AWS CloudFormation

Cloud Migration Scenarios

Four scenarios to migrate to AWS – from infrastructure to ML

Last year, I wrote a blog about generating secrets in your CloudFormation template and storing them in the Parameter Store. This works when the secret is ours to choose. But what if you are given a secret? For instance an API key or password to be used for authentication at a third party? With the latest feature of the Custom Secret Provider, we allow you to specify an Encrypted secret which will be decrypted before it is
stored in the Parameter store.

How does it work?

It is quite easy: you specify the encrypted value in your CloudFormation Custom::Secret resource as EncryptedContent:

Resources:
  ApiKey:
    Type: Custom::Secret
    Properties:
      Name: /datadog/api-key
      EncryptedContent: AQICAHgefwksukJYA7L2AkPMZLGjZsGxHbvY9AoVs55dcju1AwEZui/8lNbnGAhv63Wh0heUAAAA3zCB3AYJKoZIhvcNAQcGoIHOMIHLAgEAMIHFBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDOXKKVZ4ft75/oZ2TQIBEICBlzf5j1M3w6OH+iphx59kFLnNoKb+u1RCLfIqEitrt6VGu13/jDlnDcPE2DfkZFkW3fnmNn5OXfgt1L9j4XYdIQTEwexorNqUr5pUtMfS9YX8yL9DbArH+XBv/OQPSj8VsuWRcwFP5EwZKB9O4X3l1pZlPafp2Y/ndWXgC1o6YgfplnmjufoUUTy8wi4P5glbwnqGP/iyc7g=
      ReturnSecret: true
      RefreshOnUpdate: true
      ServiceToken: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:binxio-cfn-secret-provider'

The value should be encrypted with the KMS key alias/cmk/cfn-secrets for the provider to be able to decrypt it.

After the deployment, the API key can be found in the EC Parameter Store with the name /datadog/api-key as type SecureString. The value is
available to you in clear text. If you need to access the secret in your cloudformation module, you need to specify ReturnSecret and
reference it as the attribute Secret.

     DATADOG_API_KEY: !GetAtt 'ApiKey.Secret'

Installation

To install this Custom Resource, type:

git checkout https://github.com/binxio/cfn-secret-provider
cd cfn-secret-provider

aws cloudformation create-stack \
 --capabilities CAPABILITY_IAM \
 --stack-name cfn-secret-provider \
 --template-body \
 file://cloudformation/cfn-custom-resource-provider.json 

aws cloudformation wait stack-create-complete  \
 --stack-name cfn-secret-provider 

This CloudFormation template will use our pre-packaged provider from s3://binxio-public/lambdas/cfn-secret-provider-0.13.0.zip

This custom provider is only allowed to decrypt values from the key with the alias alias/cmk/cfn-secrets created together with the provider. If
you wish to use different keys, add Decrypt permissions to the Lamdba Policy.

Encrypting values

After the CloudFormation provider is deployed, you can encrypt values by using the 4 line python utility encrypt-secret.

$ ./encrypt-secret my-secret-api-key

Demo

To install the simple sample of the Custom Resource, type:

API_KEY=replace-me-with-your-key

aws cloudformation create-stack \
 --stack-name cfn-secret-provider-demo \
 --template-body file://cloudformation/demo-stack.json \
 --parameters ParameterKey=ApiKey,ParameterValue=$(./encrypt-secret $API_KEY)

aws cloudformation wait stack-create-complete  \
 --stack-name cfn-secret-provider-demo

Of course in this case the secret is passed in as a parameter, as it depends on the key.
to validate that your key was stored in the parameter store,type:

aws ssm get-parameter --name /cfn-secret-provider-demo-api-key --with-decryption

Conclusion

By using the Encrypted content option of the CloudFormation Secret provider, you can
specify given secrets in CloudFormation and deploy them safely to the SSM parameter store.

Got to here? You probably like deploying private key pairs and deploying ACM certificates with CloudFormation.

Mark van Holsteijn is a senior software systems architect, and CTO of binx.io. He is passionate about removing waste in the software delivery process and keeping things clear and simple.
Share this article: Tweet this post / Post on LinkedIn