Terraform doesn't provide any built-in way of securing your state
file. Neither is there a way to secure only some part of it or even provide encrypted data inside your templates. And it's a shame because sooner or later you will have to use some kind of secrets with your templates: passwords, API keys, and others. If you plan to store your state
file in the git
repository, it's important to protect it. The easiest solution is to encrypt the whole state
file, store the encrypted version in the repository, and distribute the key for decryption with your team members.
You could make this task easier with the help of a tool named terrahelp
. Terrahelp is a small CLI written in Go that simplifies the encryption and decryption of your Terraform state files (and not only the state
files). It has a nice integration with Vault, yet another HashiCorp tool, this time in order to manage secrets. Don't worry, we won't use Vault, it's rather a complex tool that deserves it's own book.
Download terrahelp binary from GitHub Releases at https://github.com/opencredo/terrahelp/releases, and make it available in your $PATH
. Now you can use the terrahelp encrypt
command to encrypt the complete state
file like this:
$> terrahelp encrypt -file terraform.tfstate --simple-key AES256Key-32Characters0987654321
After you run it, your terraform.tfstate
file will look similar to this:
@terrahelp-encrypted(90EYsi7dEgTqcwN63AePssKjIUF3nqJq4c9hFFnvNQ63eJwL0ZmMZL
8AUmUjsqCpho3af13DKjKTU3vQ8K8qMqgm70ToYBVYki6+8vq7nmPt5MGojhfPclAkrLmiestZ
SsTYVhmDbsykX/4zkCME29...many-more-symbols
The unencrypted version was put in a file named terraform.tfstate.terrahelpbkp
for your convenience, in case you forget your encryption key. To avoid creating this file, add the --nobackup
option:
$> terrahelp encrypt -file terraform.tfstate --simple-key
AES256Key-32Characters0987654321 --nobackup
The encrypted state
file can be safely stored in a remote repository, only people who know the key (AES256Key-32Characters0987654321
) will be able to decrypt it. The workflow for your Terraform procedure is the following:
remote
repository.state
file.terraform apply
command.state
file with the same key.Many things can go wrong during this process. You could forget to encrypt the file and push
the plain text to the repository. You could streamline this workflow by providing a good old Makefile
, but it would not completely prevent bad things from happening. It would be much nicer to encrypt and decrypt state
file automatically, without any additional actions from the developer who modifies the Terraform templates.
That's where a tool named git-crypt
becomes very handy as it implements exactly the mechanism just described. It's stored on GitHub at https://github.com/AGWA/git-crypt and written in C++. Sadly, there are not ready-to-use packages of git-crypt
; we have to compile it ourselves.
Before installing, you should have a C++ compiler (for example, gcc
), Make and OpenSSL development files (libssl-dev
or openssl-devel
package, depending on your Linux distribution) installed. You also need Git newer than 1.7.2. Installation is easy after all requirements are met:
$> git clone https://github.com/AGWA/git-crypt.git $> cd git-crypt $> make $> sudo make install PREFIX=/usr/local
Verify successful installation with git-crypt help
command.
To configure git-crypt
to manage the state
file, we need to create a .gitattributes
file in out repository with this content:
*.tfstate filter=git-crypt diff=git-crypt *.tfstate.backup filter=git-crypt diff=git-crypt
Run git-crypt init
at the root of Terraform repository. There are two ways you can use git-crypt
: with a key shared among your colleagues or by encrypting data with the personal key of each colleague. You should use the second option, but for the purpose of this demonstration, we will stick with the first one. Create somewhere a text file with a key in it (for example, generate it with the ssh-keygen
command) and use this file to set up the encryption:
$> git-crypt export-key /path/to/secret/file
Because the git commit
history already has state
file in it, you need to force encryption the first time you use git-crypt
:
$> git-crypt status -f
Now add the changed state
file and the backup of it to new commit
and push
them to your repository: you will note that it's impossible to see its contents on GitLab. If you clone the repository to your machine, the file will also be encrypted until you unlock
it:
$> git-crypt unlock /path/to/secret/file
You need to do it just once. After the initial setup, your files will be automatically encrypted when you commit
and push
them and decrypted when you pull it from the remote
repository. No chance for accidental plain text secret data commits! It's the same thing you would do with terrahelp
and Makefile
, but completely transparent.
Storing both the templates
and state
files in a git
repository works well when you have just a few people working on them. You can always see who changed what in templates and the state of the infrastructure. Git is not the only state file storage supported by Terraform though. There are many other options for remote storage and other full APIs for working with them.
3.143.228.40