Deploying secret API keys or other secret configuration to a production environment can become quite a hassle. You normally don’t want to commit them unencrypted to your repository. And you also want to share them with other developers.
Rails 5.1 introduces a solution for this. You still have to store one central encryption key on your server and on all development systems, but that’s it. All other secrets are encrypted with that key and can be stored safely in your code repository.
We start with a new rails application:
$ rails new shop
$ cd shop
A fresh Rails application doesn’t provide a secret store. It has to be generated
with the command rails secrets:setup
:
$ rails secrets:setup
Adding config/secrets.yml.key to store the encryption key: 413f24df7b871e4947c774aab68553e0
Save this in a password manager your team can access.
If you lose the key, no one, including you, can access any encrypted secrets.
create config/secrets.yml.key
Ignoring config/secrets.yml.key so it won't end up in Git history:
append .gitignore
Adding config/secrets.yml.enc to store secrets that needs to be encrypted.
create config/secrets.yml.enc
For now the file contains this but it's been encrypted with the generated key:
# See `secrets.yml` for tips on generating suitable keys.
# production:
# external_api_key: 1466aac22e6a869134be3d09b9e89232fc2c2289…
You can edit encrypted secrets with `bin/rails secrets:edit`.
Add this to your config/environments/production.rb:
config.read_encrypted_secrets = true
$
In this example the secret key is 413f24df7b871e4947c774aab68553e0
. It is
very important to keep this key securely. Anyone who has it can decrypt
your secrets and if you lose it you can not decrypt your secrets any more.
The key is stored in the file config/secrets.yml.key
and this file was added
to the .gitignore
file so that you don’t accidentally upload it to your
git repository.
The file config/secrets.yml.enc
contains the encrypted secrets.
$ cat config/secrets.yml.enc
O89/vvmOYTYVbNzJ4edPTe18hn7WofvNDuiojPW4OeNMGE0ftBQjD/qPRKMGbZ
2pf4U174LKmwYeDVINYKjxDgMRfbAXB0vDTzln4hZ0basdfjDniJqhw74Yq7Rx
+14ozBYELE42K7hPeSKXykN1jaxJUZQ8ZoHNr2BEtyrtB08ovd9asddqIToww
Xgn6T+A==--zpsOu6QPvE4ZmEYN--4eqnwCSZSYnTDGTRI7fvlQ==
You’re Rails application has the keys but can not use it until you set
config.read_encrypted_secrets = true
in the configuration of your environment.
By default this is already the case in the production environment:
[...]
# Attempt to read encrypted secrets from `config/secrets.yml.enc`.
# Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
# `config/secrets.yml.key`.
config.read_encrypted_secrets = true
[...]
You have to add this configuration to the config/environments/development.rb
file if you want to have access to it in the development environment too.
Because config/secrets.yml.enc
is encrypted you can’t edit it directly. You
can to do it via rails secrets:edit
. In case you are using the bash
shell
and don’t have the env variable EDITOR
already set you can edit your secrets
with this command:
$ EDITOR=vim rails secrets:edit
Secrets are saved in the YAML format.
You can create secrets for any environment and you can share them too. Here is an example:
shared:
abc: "I am shared"
production:
zzz: "I am in production"
You can access a secret with the format
AppName::Application.secrets.name_of_the_secret
. Here is an example for the
above configuration:
$ rails console production
Running via Spring preloader in process 19662
Loading production environment (Rails 5.1.0)
>> Shop::Application.secrets.abc
=> "I am shared"
>> Shop::Application.secrets.zzz
=> "I am in production"
>> exit