Every app has configuration — at Rainforest we store ours in environment variables and some of it is more sensitive than others. For example, there is usually no good reason for most developers in a company to have access to production database config. So why do they?
After talking people about how we store our config in git, they’re usually surprised even though it’s not complicated.
Here’s what we’re doing.
Four simple steps
- We store environment variables in private/env in the project, in a file called .txt; we have production, qa, staging, test and development.
- We add the sensitive environments to .gitignore; for us this is production.txt, qa.txt and staging.txt. These are never committed. The scripts decrypt.sh and reencrypt.sh take the ignored (non-committed) files and GPG / un-GPG them with the specified developers GPG keys. Anyone specified in the list of keys can decrypt the environment variables.
- A per environment script (e.g. update_production.sh) which decrypts and update the environment variables in bulk; if it’s not in the gpg’d file, it’s not valid. If we try a new addon, it gets added and the variable added to the correct environment. It also strips comments, which is handy and Heroku doesn’t like these.
This works and we can still get shit done because:
- We use Heroku and environment variables persist between releases
- We use CircleCI to do continuous integration and delivery, so not all developers need access to production apps
- We get a history of changes in git (though it’s way more of a pain to use as you have to decrypt different versions)
- It’s trivial to add someone new to the list of keys
- It’s trivial to add new variables
Our scripts are pretty simple and could be improved in the following ways, but for now we’re posting them as a gist.
- Store the list of developers keys in a single file, rather than repeated
- Change update_.sh to be a single script that takes an argument for the environment and gets the app name from a config file
- Change reencrypt.sh to allow specifying a single environment, rather than all — it’s dumb to have to commit n new files instead of just one
I would love feedback via twitter or HN — got a better way? did we miss something obvious?