Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keeping secrets out of Terraform state

Tags:

terraform

I'm trying to avoid having secrets in Terraform state.

Is there a better way of setting an RDS password from a secret in Secrets Manager that does this?

resource "null_resource" "master_password" {
  triggers = {
    db_host = module.myrdsdatabase.cluster_id
  }

  provisioner "local-exec" {
    command = <<TOF
    password=$(aws secretsmanager get-secret-value --secret-id myrdscreds | jq '.SecretString | fromjson | .password' | tr -d '"')
    aws rds modify-db-cluster --db-cluster-identifier ${module.myrdsdatabase.cluster_id} --master-user-password $password --apply-immediately
    TOF

    interpreter = ["bash", "-c"]
  }
}
like image 685
Ken Jenney Avatar asked Jan 26 '26 16:01

Ken Jenney


2 Answers

There is no concrete solution to this issue. There is nearly 7 year old, still active, discussion on TF github issue about handling secrets in TF.

In your question you are already avoiding aws_secretsmanager_secret_version which is good practice. aws_secretsmanager_secret_version will not protect your secrets from being in plain text in TF state file!

Generally, there are two things people do to keep the secrets secret:

  1. Store your TF state in a remote backend. Such as S3 with strict IAM and bucket policy controls, along with encryption at rest.
  2. Use external procedure to set the passwords for your database. One way is local-exec, other could be using remote lambda through aws_lambda_invocation.

Other ways are possible, such as creating RDS databases through CloudFormation (CFN) from your TF. CFN has a proper way of accessing secret manager securely through dynamic references.

like image 132
Marcin Avatar answered Jan 29 '26 12:01

Marcin


We have to accept that the secrets are in the state and manage access and encryption to the remote state accordingly.

You can get a value right out of secrets manager with the aws_secretsmanager_secret_version data source

your local-exec can be simplified a bit by using jq --raw-format or -r

 password=$(aws secretsmanager get-secret-value --secret-id myrdscreds | jq -r .SecretString | jq -r .password)

I prefer to fetch and then pass in the secret in a variable from a build script, rather than local-exec. It seems cleaner, in some cases the trigger on the null resource may not fire when the secret value has been changed.

like image 21
thekbb Avatar answered Jan 29 '26 13:01

thekbb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!