Secret Rails Configurations
Last time,
I looked at keeping environment specific configuration using YAML
files and Rails.application.config_for
. One big issue with this
approach is security. It’s very common to have different sets of API
keys and API settings for different environments. A simple example is
credit card processing. Outside of production you use a sandbox and
test cards. Only in production are live API credentials needed.
We need a way to securely handle this information.
First there is the Rails way. Starting with Rails 4, there is a file
config/secrets.yml
. The file follows the environment format of
database.yml:
1 2 3 4 5 6 7 8 |
|
and automatically loads them in to:
1 2 3 4 5 |
|
But, as it say right in the generated secrets.yml
file, you
shouldn’t actually keep secrets in it. Instead, the recommendation is
to set them in environmental variables in the web server
configuration, which is a pain in the neck. (SECRET_KEY_BASE
is
magically generated as part of the deploy process, so it’s go that
going for it).
Really, this environmental variables are how secrets have always been
managed in Rails, secrets.yml
just simplifies accessing them,
especially in development.
The better way is to use the sekrets gem which I’ve covered before. A short recap:
Install the sekrets gem (you know how), run:
1
|
|
to generate a random password in .sekrets.key
, and add it to your
.gitignore
:
1
|
|
Which allows you to read and write files encrypted with the key:
1 2 |
|
Your sekrets.yml
might look something like:
1 2 3 4 5 6 7 8 |
|
Normally, you’d then run a Rake task to set up an initializer that
loads, the contents of sekrets.yml
in to a global constant SEKRETS,
however we can instead do follow the same pattern we have been using
for other config files. In config/application.rb, add:
1 2 3 4 |
|
Sekrets.settings_for
returns the whole file, [Rails.env] || {}
emulates Rails.application.config_for
by returning only the current
environment or an empty hash if nothing is set for that environment.
Sekrets gives you a Map, so you can use things like:
1
|
|
right out of the box.
For production, you either set the SEKRETS_KEY in your web servers environment
or, if you use Capistrano, you can add require ‘sekrets/capistrano’ to
your Capfile which will upload .sekrets.key
as part of the deploy.
Now you secrets are both encrypted and easily access in you app.
Note there’s an open proposal to add encrypted version of secrets.yml to rails that would provide the same functionality as Sekrets. Consider supporting it.