Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform and cleartext password in (remote) state file

There are many Git issues opened on the Terraform repo about this issue, with lots of interesting comments, but as of now I still see no solution to this issue.

Terraform stores plain text values, including passwords, in tfstate files.

Most users are required to store them remotely so the team can work concurrently on the same infrastructure with most of them storing the state files in S3.

So how do you hide your passwords?

Is there anyone here using Terraform for production? Do you keep you passwords in plain text? Do you have a special workflow to remove or hide them? What happens when you run a terraform apply then?

I've considered the following options:

  • store them in Consul - I don't use Consul
  • remove them from the state file - this requires another process to be executed each time and I don't know how Terraform will handle the resource with an empty/unreadable/not working password
  • store a default password that is then changed (so Terraform will have a not working password in the tfstate file) - same as above
  • use the Vault resource - sounds it's not a complete workflow yet
  • store them in Git with git-repo-crypt - Git is not an option either
  • globally encrypt the S3 bucket - this will not prevent people from seeing plain text passwords if they have access to AWS as a "manager" level but it seems to be the best option so far

From my point of view, this is what I would like to see:

  • state file does not include passwords
  • state file is encrypted
  • passwords in the state file are "pointers" to other resources, like "vault:backend-type:/path/to/password"
  • each Terraform run would gather the needed passwords from the specified provider

This is just a wish.

But to get back to the question - how do you use Terraform in production?

like image 880
Prune Avatar asked Feb 06 '17 20:02

Prune


People also ask

Can Terraform still expose these sensitive values like passwords in the state file?

Terraform state can contain sensitive data, depending on the resources in use and your definition of "sensitive." The state contains resource IDs and all resource attributes. For resources such as databases, this may contain initial passwords. When using local state, state is stored in plain-text JSON files.

How do I secure a state file in Terraform?

Encrypting your stateWith the encryption key, you can configure Terraform to use this key by setting an environment variable GOOGLE_ENCRYPTION_KEY or by setting the value in the backends.tf file as shown below. Once you have configured your backend you can issue the terraform init command to initialize the backend.

Does Terraform store secrets in state?

Terraform State Files Must Be SecureTerraform will store your secrets in plain text inside the state files. Yes, you can check the open issue on this, it was created in 2014! To avoid this issue, the best thing you can do is store your state files on a place that supports encryption.


2 Answers

I would like to know what to do about best practice, but let me share about my case, although it is a limited way to AWS. Basically I do not manage credentials with Terraform.

  • Set an initial password for RDS, ignore the difference with lifecycle hook and change it later. The way to ignore the difference is as follows:

     resource "aws_db_instance" "db_instance" {
       ...
       password = "hoge"
    
       lifecycle {
         ignore_changes = ["password"]
       }
     }
    
  • IAM users are managed by Terraform, but IAM login profiles including passwords are not. I believe that IAM password should be managed by individuals and not by the administrator.

  • API keys used by applications are also not managed by Terraform. They are encrypted with AWS KMS(Key Management Service) and the encrypted data is saved in the application's git repository or S3 bucket. The advantage of KMS encryption is that decryption permissions can be controlled by the IAM role. There is no need to manage keys for decryption.

  • Although I have not tried yet, recently I noticed that aws ssm put-parameter --key-id can be used as a simple key value store supporting KMS encryption, so this might be a good alternative as well.

I hope this helps you.

like image 116
minamijoyo Avatar answered Sep 28 '22 05:09

minamijoyo


The whole remote state stuff is being reworked for 0.9 which should open things up for locking of remote state and potentially encrypting of the whole state file/just secrets.

Until then we simply use multiple AWS accounts and write state for the stuff that goes into that account into an S3 bucket in that account. In our case we don't really care too much about the secrets that end up in there because if you have access to read the bucket then you normally have a fair amount of access in that account. Plus our only real secrets kept in state files are RDS database passwords and we restrict access on the security group level to just the application instances and the Jenkins instances that build everything so there is no direct access from the command line on people's workstations anyway.

I'd also suggest adding encryption at rest on the S3 bucket (just because it's basically free) and versioning so you can retrieve older state files if necessary.

To take it further, if you are worried about people with read access to your S3 buckets containing state you could add a bucket policy that explicitly denies access from anyone other than some whitelisted roles/users which would then be taken into account above and beyond any IAM access. Extending the example from a related AWS blog post we might have a bucket policy that looks something like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::MyTFStateFileBucket",
        "arn:aws:s3:::MyTFStateFileBucket/*"
      ],
      "Condition": {
        "StringNotLike": {
          "aws:userId": [
            "AROAEXAMPLEID:*",
            "AIDAEXAMPLEID"
          ]
        }
      }
    }
  ]
}

Where AROAEXAMPLEID represents an example role ID and AIDAEXAMPLEID represents an example user ID. These can be found by running:

aws iam get-role -–role-name ROLE-NAME

and

aws iam get-user -–user-name USER-NAME

respectively.

If you really want to go down the encrypting the state file fully then you'd need to write a wrapper script that makes Terraform interact with the state file locally (rather than remotely) and then have your wrapper script manage the remote state, encrypting it before it is uploaded to S3 and decrypting it as it's pulled.

like image 32
ydaetskcoR Avatar answered Sep 28 '22 04:09

ydaetskcoR