Using ejson to store secrets for Terraform
I’ve been using Terraform to provision and configure some application deployed on Heroku, as well as some other infrastructure pieces on AWS. Since these configurations are kept on a git repository, I do not want any configuration values stored in clear text, to avoid having any sensitive information leaked. For this reason, I’ve searched for a solution to keep these secrets stored in a safe manner without too much configuration overhead. I’ve decided to give EJSON a try for this particular use case, for a couple of reasons:
- It performs asymmetric encryption on the secrets with a pair of keys that are
easy to share with your team, since the public key is actually stored on the
.ejsonfile and the private key is just a string;
- It’s installation is pretty simple, since EJSON is a Go binary and it’s
actually available on rubygems, so you can
gem install ejson;
- It does not require any other piece of infrastructure besides your workstation;
- The secrets are kept in JSON files, with the keys in clear text and the values encrypted.
This last bit is actually more interesting than it might look, since Terraform’s
.tfvars files, which store the configurations’ variables, are either JSON or
HCL files. As such, we can simply decrypt our EJSON file without any
other transformation or adaptation and pass it directly to Terraform!
With all that being said, let’s go through how to achieve this setup and how to use it efficiently.
Assuming you’re on macOS, here’s how to install all the required tools:
brew install terraform gem install ejson
Now we need to generate a keypair for EJSON. By default, these are stored at
/opt/ejson/keys. To keep it simple and to keep everything in your user’s home,
we’ll add an alias for
ejson that defaults to
~/.ejson/keys. Adapt the last
command to fit your particular shell setup.
mkdir -p ~/.ejson/keys alias ejson='ejson --keydir ~/.ejson/keys' echo "alias ejson='ejson --keydir ~/.ejson/keys'" >> ~/.bash_profile
Using an encrypted
First, we need to create a new keypair:
ejson keygen -w
Now add the following to a
variables.tfvars.ejson file, replacing
__OUTPUT_FROM_EJSON_KEYGEN__ with the public key outputted from the previous command:
As you see, this format is immediately usable by Terraform, as it’s just a JSON file, with key-value pairs that hold our Terraform variables.
To encrypt the file, it’s as easy as running:
$ ejson encrypt variables.tfvars.ejson Wrote 211 bytes to variables.tfvars.ejson.
This is the file that you should add to your repository to save the variables safely.
It’s also pretty easy to decrypt it:
ejson decrypt variables.tfvars.ejson -o variables.tfvars
You should add these
.tfvars files to your
.gitignore so that they don’t end
up in your repository:
This will keep the encrypted file intact and create a new, decrypted file.
At this point, you’d be able to run a
terraform plan as per usual:
terraform plan -var-file variables.tfvars
Streamline it with
We can create a very simple
Makefile to stream line this process after the
So now, you just need to run
make plan and
make apply to use your safely
This is just a very simple way to keep your infrastructure’s configuration secrets on a git repository, whilst keeping them readily available for Terraform to consume. I would use this strategy for simple bootstrapping and infrastructure provision and use tools such as Vault for more complex scenarios, for instance, applications dynamically fetching their configurations on startup.
If you’d like to discuss this post, please drop me a line using any of my contacts.
- EJSON on Github