You never want to keep your secrets in plaintext and you never want to keep your plaintext secrets in source control!
With terraform
a lot of the time you are creating objects and you can use the random
resource to generate a secret and either push to output
or to a secure service to store it (We use parameter store
/ssm
).
But in some cases you may have to add a secret into terraform that has already been created and there comes the problem! below is a possible solution for AWS
using aws-kms
and ssm
.
Pre-reqs
- A
aws-kms
to connect to and generate yoursecrets
from aws-cli
installed (> v2
in the below examples)
Generate plaintext file
Create a temporary text
file, this will contain your secret
in plaintext and uses key
: value
pairing.
`We will delete after generating our secret file!`
Example file
An example file would be:
password: examplepassword
Generate secret file
Run the below command, updating the following:
profile
=aws named profile
or remove line if you usedefault
key-id
= thekey-id
of yourkms
, you can get this from theconsole
or output fromterraform
region
= the region yourkms
is stored inplaintext
= the location of the file with theplaintext secret
aws kms encrypt \
--profile mgmt-eks \
--key-id 346e8eab-39a6-455b-ac88-fcd8a6cf7043 \
--region eu-west-2 \
--plaintext fileb://user.yml \
--output text \
--query CiphertextBlob
This will generate the secret
, copy the output to a file named: password.yml.encrypted
and save it (I put my secrets in a folder with the same name as the tf
file)
Delete the `plaintext` secret!
Update TF
Now we have a secret
that can be saved to source control
. Add a data source
pointing to the file
data "aws_kms_secrets" "myapp" {
secret {
name = "password"
payload = file("${path.module}/myapp/password.yml.encrypted")
}
}
Add a local call to the decrypted answer. In the below example im just taking the secret
and saving it to ssm
this can then be called in tf
or any other app and never be hardcoded.
locals {
myapppass = yamldecode(data.aws_kms_secrets.myapp.plaintext["password"])
}
resource "aws_ssm_parameter" "myapp_password" {
name = "/myapp/user/admin/password"
description = "password for admin user"
type = "SecureString"
value = local.myapppass.password
tags = {
"Terraform" = "true"
"myapp" = "true"
}
}
There we have it. You are ready to terraform apply
This will leave your source control
clean and your secrets safe.
There are other options for how to do keep your secrets safe. But this is the easiest to set up and run with.