<p>We avoid terraform handle our secrets. Even if you manage to inject secrets by a var file "secrtes.tfvars" as pointed out above, these secrets will be stored in your terraform (remote-)state.</p>

<p>You can protect remote-state files by using e.g. S3 authorization, or you can gitignore local state files but we decided not to rely on this kind of protection.</p>

CC BY-SA 3.0
2017-10-02T19:34:13.230Z
Also check https://github.com/hashicorp/terraform/issues/516 which is where they track the issue of tfstate leaking secrets
jottr
CC BY-SA 3.0
2017-09-15T19:10:53.623Z
2017-09-15T20:05:13.667Z
2017-09-15T20:05:13.667Z
jerger
<p>To import secrets into .tf files, you can also use an <a href="https://www.terraform.io/docs/providers/external/data_source.html" rel="nofollow noreferrer">external data source</a>. This could be e.g. a script which decrypts your secrets.</p>

CC BY-SA 4.0
2020-02-06T10:52:32.530Z
A downside to this is that any resource with an attribute relying on a value from the external data source will be "calculated" so likely be modified by terraform on every run even if the secret hasn't changed. That might be OK but in some cases might take a while or at worst break stuff.
Davos
CC BY-SA 3.0
2018-02-15T07:31:16.887Z
2018-02-15T07:31:16.887Z
jofel
<p>I looked at a few different ways but I particularly liked git-crypt for an adhoc thing to do before implementing something bigger like Vault.</p>

CC BY-SA 3.0
2017-10-02T19:43:11.343Z
to thoe who downvoted, please explain why.
jottr
CC BY-SA 3.0
2017-02-28T20:01:28.683Z
2017-02-28T20:01:28.683Z
Naphta
<p>If you're on AWS, then have a look at <a href="https://aws.amazon.com/blogs/mt/the-right-way-to-store-secrets-using-parameter-store/" rel="noreferrer">"The Right Way to Manage Secrets"</a> by <a href="https://segment.io" rel="noreferrer">Segment.io</a> on the AWS Blog. We advocate using <a href="https://github.com/segmentio/chamber" rel="noreferrer"><code>chamber</code></a> to all of our customers for managing secrets. It works by leveraging the AWS Systems Manager Parameter Store (SSM) together with KMS keys. This ensures secrets are encrypted at rest (and in transit), secured with IAM, auditable with CloudTrails, and only exposed as environment variables at run-time. </p>

<p>After <a href="https://docs.cloudposse.com/secrets-management/aws-kms-ssm/" rel="noreferrer">configuring chamber</a> and setting up the KMS key, we write the secrets to the parameter store. </p>

<pre><code>chamber write db TF_VAR_DB_USER foobar
chamber write db TF_VAR_DB_PASS secret
</code></pre>

<p>Then use those secrets when you call terraform.</p>

<pre><code>chamber exec db -- terraform plan
</code></pre>

<p>This assumes you've defined a variable called <code>DB_USER</code> and <code>DB_PASS</code> in your HCL code. </p>

<p>For example, you could add this to <code>variables.tf</code></p>

<pre><code>variable "DB_USER" { }
variable "DB_PASS" { }
</code></pre>

<p><strong>NOTE:</strong> <code>chamber</code> will always export environment variables in uppercase</p>

<p>We provide a terraform module called <a href="https://github.com/cloudposse/terraform-aws-kms-key" rel="noreferrer"><code>terraform-aws-kms-key</code></a> to make provisioning the KMS key easy. Check out our detailed documentation with examples of how to use <a href="https://docs.cloudposse.com/tools/chamber/" rel="noreferrer"><code>chamber</code></a> with multiple namespaces as well as <a href="https://docs.cloudposse.com/secrets-management/aws-kms-ssm/" rel="noreferrer">how to use chamber with terraform</a> to manage secrets. See our <a href="https://github.com/cloudposse/terraform-root-modules/tree/master/aws/chamber" rel="noreferrer">complete reference example</a> for provisioning chamber dependencies. </p>

<p>As for <code>.tfstate</code>, you bring up a really good point about the existence of plain-text secrets in the state file. There's really no way around this. In order for terraform to calculate changes to build a plan, it needs to know the "before" and "after" state. For this reason, we recommend using an encrypted S3 bucket with mandatory versioning. Use the <a href="https://github.com/cloudposse/terraform-aws-tfstate-backend" rel="noreferrer"><code>terraform-aws-tfstate-backend</code></a> module to provision a bucket and DynamoDB locking table according to best practices. </p>

CC BY-SA 4.0
2018-07-27T08:21:27.143Z
This is highly tied to AWS services, which the question doesn't mention and sounds not really an answer for on premise infrastructures or any other cloud.
Tensibai
CC BY-SA 4.0
2018-07-27T20:42:25.440Z
@tensibai, you are correct. The original question does not provide enough information to ascertain the operating platform in order to make the best recommendation. Every platform will be different depending on platform capabilities. On prem or baremetal users may want to consider using a combination of Vault and Terraform Enterprise. The scope of implementing that will be much, much greater. :)
Erik Osterman
CC BY-SA 4.0
2019-01-21T16:19:06.620Z
I already use AWS Secrets Manager and dont want to use chamber and Parameter Store. Is it possible to do this same thing with Secrets Manager too?
red888
CC BY-SA 4.0
2018-07-27T05:03:52.553Z
2018-07-27T05:03:52.553Z
Erik Osterman
<p>you can store values in the parameter store and use them in terraform resources by fetching values using data resources.</p>
<pre><code>data &quot;aws_ssm_parameter&quot; &quot;rds_password&quot; {
  name = &quot;/${var.project_name}/DB_PASSWORD&quot;
}

resource &quot;aws_db_instance&quot; &quot;rds&quot; {
  ...
  password = data.aws_ssm_parameter.rds_password.value
  ...
}
</code></pre>

CC BY-SA 4.0
2020-09-29T14:48:06.227Z
2020-09-29T14:48:06.227Z
Piyush Sonigra
<p>You can utilize the <a href="https://www.terraform.io/docs/providers/external/data_source.html" rel="nofollow noreferrer">external data source</a> to import secrets to Terraform and encrypt the secret files with <code>gpg</code>.</p>

<p>For instance, this what a terraform file would like for creating an rds instance with password <code>foobarbaz</code></p>

<pre><code>data "external" "rds" {
  program  = [ "cat", ".secrets/rds.json"]
}


resource "aws_db_instance" "default" {
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t2.micro"
  name                 = "mydb"
  username             = "foo"
  password             = "${data.external.rds.result.password}"
  parameter_group_name = "default.mysql5.7"
}
</code></pre>

<p>You can check <a href="http://issamben.com/how-to-encrypt-terraform-secrets/" rel="nofollow noreferrer">this post</a> that explains in detail how to do this. </p>

<p><strong><a href="http://issamben.com/how-to-encrypt-terraform-secrets/" rel="nofollow noreferrer">How to encrypt terraform secrets</a></strong></p>

CC BY-SA 4.0
2022-04-27T12:39:37.070Z
`.tfstate` will still contain the secrets un-encrypted.
Valerij Dobler
CC BY-SA 4.0
2020-02-22T19:42:05.477Z
2020-02-22T19:42:05.477Z
sam ben
<p>Terraform <a href="https://www.terraform.io/intro/getting-started/variables.html" rel="noreferrer">supports</a> adding an additional file with variables during invocation.</p>

<p><sup>documentation: <a href="https://www.terraform.io/intro/getting-started/variables.html#from-a-file" rel="noreferrer">https://www.terraform.io/intro/getting-started/variables.html#from-a-file</a></sup></p>

<p>We are using that feature to provide a <code>secrets.tfvars</code> file on each invocation of Terraform. We also use a script to wrap the command so that its invocation is consistent, and all team members avoid having to make the same mistakes. The wrapper synchronizes <code>.tfstate</code> with S3 before an execution, and pushes <code>.tfstate</code> back to S3 at the end. I also hear of people doing the same thing with state stored in Consul, even adding a kind of semaphore in consul to prevent two people from starting Terraform at the same time.</p>

<p>When you avoid setting a default value in a <code>variables.tf</code> file, it forces the user to input the value. It can be either entered manually or using the <code>-var-file</code> command option like described above. Not setting a default on your secrets is a good way to enforce changes that require a change in secrets.</p>

<p>The <code>secrets.tfvars</code> file is a symbolic link to one of the files with secrets which are not stored in version control. We have several, one per environment, like so <code>secrets-prod.tfvars</code>, <code>secrets-dev.tfvars</code>, <code>secrets-stg.tfvars</code>, etc...</p>

<p>An even better practice would be to generate these secrets files during the wrapper script based on data in Vault or some other way to <em>share</em> secrets. Since currently when the format of secrets changes, or secrets themselves, we need to communicate it to the team outside the version control channel - and this doesn't always work well, to be honest. But secrets do change infrequently.</p>

CC BY-SA 3.0
2017-04-03T09:31:04.530Z
Link to code - https://gist.github.com/kesor/21f942be0350559b44f7ad1f9d846e7c
Evgeny Zislis
CC BY-SA 3.0
2017-03-01T01:36:58.157Z
2017-03-02T15:37:00.370Z
2017-03-02T15:37:00.370Z
Evgeny Zislis
<p>I would like to use the Terraform <a href="https://www.terraform.io/docs/providers/mysql/index.html" rel="noreferrer">MySQL Provider</a> to keep a list of mysql users and grants handy for creating new test environments. The <code>.tf</code> and <code>.tfstate</code> files both seem to want to store the MySQL passwords in plaintext.</p>

<p><strong>Concerning .tf:</strong></p>

<p>It is my understanding that <code>.tf</code> files live in revision control and are maintained by a team.  How does that practice differ when secrets are in the <code>.tf</code>? It is possible to encrypt these values at all?</p>

<p><strong>Concerning .tfstate:</strong></p>

<p>I can store the <code>.tfstate</code> securely somewhere after running Terraform apply, but it would be preferable for this use case to not store it at all?</p>

<terraform><security>
How can I manage secrets in .tf and .tfstate?
Anthony Neace
# How can I manage secrets in .tf and .tfstate?

(Asked by: username_0 on 2017-02-28)

I would like to use the Terraform [MySQL Provider](https://www.terraform.io/docs/providers/mysql/index.html) to keep a list of mysql users and grants handy for creating new test environments. The `.tf` and `.tfstate` files both seem to want to store the MySQL passwords in plaintext.

**Concerning .tf:**

It is my understanding that `.tf` files live in revision control and are maintained by a team. How does that practice differ when secrets are in the `.tf`? It is possible to encrypt these values at all?

**Concerning .tfstate:**

I can store the `.tfstate` securely somewhere after running Terraform apply, but it would be preferable for this use case to not store it at all?

**Tags:** terraform, security


---

## 7 answers

### Answer by username_12 on 2017-03-01. Score: 30 | Accepted answer

Terraform [supports](https://www.terraform.io/intro/getting-started/variables.html) adding an additional file with variables during invocation.

documentation: <https://www.terraform.io/intro/getting-started/variables.html#from-a-file>

We are using that feature to provide a `secrets.tfvars` file on each invocation of Terraform. We also use a script to wrap the command so that its invocation is consistent, and all team members avoid having to make the same mistakes. The wrapper synchronizes `.tfstate` with S3 before an execution, and pushes `.tfstate` back to S3 at the end. I also hear of people doing the same thing with state stored in Consul, even adding a kind of semaphore in consul to prevent two people from starting Terraform at the same time.

When you avoid setting a default value in a `variables.tf` file, it forces the user to input the value. It can be either entered manually or using the `-var-file` command option like described above. Not setting a default on your secrets is a good way to enforce changes that require a change in secrets.

The `secrets.tfvars` file is a symbolic link to one of the files with secrets which are not stored in version control. We have several, one per environment, like so `secrets-prod.tfvars`, `secrets-dev.tfvars`, `secrets-stg.tfvars`, etc...

An even better practice would be to generate these secrets files during the wrapper script based on data in Vault or some other way to *share* secrets. Since currently when the format of secrets changes, or secrets themselves, we need to communicate it to the team outside the version control channel - and this doesn't always work well, to be honest. But secrets do change infrequently.

> **Comments:**
> **username_12**: Link to code - https://gist.github.com/kesor/21f942be0350559b44f7ad1f9d846e7c  

---

### Answer by username_6 on 2018-07-27. Score: 11

If you're on AWS, then have a look at "The Right Way to Manage Secrets" by Segment.io on the AWS Blog. We advocate using chamber to all of our customers for managing secrets. It works by leveraging the AWS Systems Manager Parameter Store (SSM) together with KMS keys. This ensures secrets are encrypted at rest (and in transit), secured with IAM, auditable with CloudTrails, and only exposed as environment variables at run-time. 
After configuring chamber and setting up the KMS key, we write the secrets to the parameter store. 
chamber write db TF_VAR_DB_USER foobar
chamber write db TF_VAR_DB_PASS secret

Then use those secrets when you call terraform.
chamber exec db -- terraform plan

This assumes you've defined a variable called DB_USER and DB_PASS in your HCL code. 
For example, you could add this to variables.tf
variable "DB_USER" { }
variable "DB_PASS" { }

NOTE: chamber will always export environment variables in uppercase
We provide a terraform module called terraform-aws-kms-key to make provisioning the KMS key easy. Check out our detailed documentation with examples of how to use chamber with multiple namespaces as well as how to use chamber with terraform to manage secrets. See our complete reference example for provisioning chamber dependencies. 
As for .tfstate, you bring up a really good point about the existence of plain-text secrets in the state file. There's really no way around this. In order for terraform to calculate changes to build a plan, it needs to know the "before" and "after" state. For this reason, we recommend using an encrypted S3 bucket with mandatory versioning. Use the terraform-aws-tfstate-backend module to provision a bucket and DynamoDB locking table according to best practices.

> **Comments:**
> **username_7**: This is highly tied to AWS services, which the question doesn't mention and sounds not really an answer for on premise infrastructures or any other cloud.  
> **username_6**: @tensibai, you are correct. The original question does not provide enough information to ascertain the operating platform in order to make the best recommendation. Every platform will be different depending on platform capabilities. On prem or baremetal users may want to consider using a combination of Vault and Terraform Enterprise. The scope of implementing that will be much, much greater. :)  
> **username_8**: I already use AWS Secrets Manager and dont want to use chamber and Parameter Store. Is it possible to do this same thing with Secrets Manager too?  

---

### Answer by username_1 on 2017-09-15. Score: 8

We avoid terraform handle our secrets. Even if you manage to inject secrets by a var file "secrtes.tfvars" as pointed out above, these secrets will be stored in your terraform (remote-)state.

You can protect remote-state files by using e.g. S3 authorization, or you can gitignore local state files but we decided not to rely on this kind of protection.

> **Comments:**
> **username_2**: Also check https://github.com/hashicorp/terraform/issues/516 which is where they track the issue of tfstate leaking secrets  

---

### Answer by username_3 on 2018-02-15. Score: 3

To import secrets into .tf files, you can also use an [external data source](https://www.terraform.io/docs/providers/external/data_source.html). This could be e.g. a script which decrypts your secrets.

> **Comments:**
> **username_4**: A downside to this is that any resource with an attribute relying on a value from the external data source will be "calculated" so likely be modified by terraform on every run even if the secret hasn't changed. That might be OK but in some cases might take a while or at worst break stuff.  

---

### Answer by username_5 on 2017-02-28. Score: 2

I looked at a few different ways but I particularly liked git-crypt for an adhoc thing to do before implementing something bigger like Vault.

> **Comments:**
> **username_2**: to thoe who downvoted, please explain why.  

---

### Answer by username_9 on 2020-09-29. Score: 0

you can store values in the parameter store and use them in terraform resources by fetching values using data resources.
data "aws_ssm_parameter" "rds_password" {
  name = "/${var.project_name}/DB_PASSWORD"
}

resource "aws_db_instance" "rds" {
  ...
  password = data.aws_ssm_parameter.rds_password.value
  ...
}


---

### Answer by username_10 on 2020-02-22. Score: 0

You can utilize the external data source to import secrets to Terraform and encrypt the secret files with gpg.
For instance, this what a terraform file would like for creating an rds instance with password foobarbaz
data "external" "rds" {
  program  = [ "cat", ".secrets/rds.json"]
}


resource "aws_db_instance" "default" {
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t2.micro"
  name                 = "mydb"
  username             = "foo"
  password             = "${data.external.rds.result.password}"
  parameter_group_name = "default.mysql5.7"
}

You can check this post that explains in detail how to do this. 
How to encrypt terraform secrets

> **Comments:**
> **username_11**: `.tfstate` will still contain the secrets un-encrypted.  

---

