When we integrate third-party services into a Rails application, we need to handle the secret credentials related to those services. API tokens and secret access keys are examples of secret credentials.
In this blog, we will understand the encrypted credentials approach introduced in Rails 5.2 and dive into its most recent upgrade to the multi-environment setup in Rails 6.
In addition to adding an extra layer of security for our secret tokens by encrypting them, this will also allow us to handle our secret tokens and credentials in a way that prevents them from being accessible from outside the organisation or visible in our remote repository for all the environments that our application runs on.
Encrypted Credentials in Rails 5.2
It introduced two new files:
config/credentials.yml.enc: contains encrypted credentials data.
master.key: contains the key used to encrypt and decrypt the
master.key is added in the
.gitignore file to prevent the master key from being exposed to the remote repository.
credentials.yml.enc file with
To decrypt and open the
config/credentials.yml.enc file in edit mode in the editor of your choice, use the command below:
EDITOR="code --wait" rails credentials:edit
Here, we have used VS Code as an editor. You can use any other editor as well to open and edit
Using single file for all environments:
As Rails 5.2 supports only one encrypted credentials file at a time, one must explicitly define the environments and make it the main key to fit tokens for all environments in that single file.
development: cloudflare: access_key_id: devxyztoken321 secret_access_key: devxyztoken543 production: cloudflare: access_key_id: prodxyztoken321 secret_access_key: prodxyztoken543
Accessing secret credentials from
# Taking the example of Cloudflare secret credentials. Rails.application.credentials.development[:cloudflare][:access_key_id]
- All our secret tokens and keys are encrypted in a single file which can only be accessed by the master key.
- We will have the
credentials.yml.encin the remote repository and hence, we will have a history of the changes.
- Every token for all environments can be handled from a single file.
- Single Point of Failure: Using a single master key to decrypt the secret tokens for all environments could result in cascading production failures, as external services won't be able to access their secret tokens via the master key if the master key is lost or deleted.
- Access to production secret tokens: Every developer who would want to access development tokens would also get access to production tokens. Production tokens are very sensitive and should be accessible to only a few people.
Multi-environment encrypted credentials with >= Rails 6:
Rails 6 came up with the concept of multi-environment credentials which enabled storing secret tokens in environment-specific encrypted YAML files and having separate master keys for each encrypted file.
Creating environment-specific encrypted credentials file:
If we want to create an encrypted credentials file and master key for any specific environment say
staging, we can run:
# command used for creating as well as editing <environment>.yml.enc EDITOR="code --wait" rails credentials:edit --environment=staging
Same command is used to decrypt and edit the encrypted file in the specified code editor.
config credentials development.yml.enc development.key staging.yml.enc staging.key production.yml.enc production.key
Accessing secret credentials from
When accessing tokens in Rails 6, we no longer have to specify the environment as the major key, we can simply use:
# Taking the example of Cloudflare secret credentials: Rails.application.credentials.dig(:cloudflare, :secret_access_key) OR Rails.application.credentials.cloudflare[:secret_access_key]
Advantages of Rails 6 multi-environment setup:
- Eliminates single point of failure: It saves us from having all environment tokens in a single file.
- Different keys for different environments: It allows us to have different keys to decrypt and edit different environments' encrypted files.
- Not exposing sensitive keys: Now we just need to share the development key with all the contributors without sharing the keys for other environments, hence keeping them safe and secure.
- Git ignores
.keyfiles: It adds
".gitignore"file, to avoid tracking keys.
Handling master key for code running on remote services(Heroku/Circle CI):
Set config.require_master_key = true: By setting
config.require_master_key = truein the application or environment settings, we ensure that we have a valid master key(
RAILS_MASTER_KEY) for the environment in which the application is being run.
Set RAILS_MASTER_KEY: The development key is kept locally in the file
config/credentials/development.key. Since we don't push the test or staging keys to the remote repository for Heroku and Circle CI, the keys aren't kept in the specified directory. To get around this, we need to add
RAILS_MASTER_KEYto Heroku/Circle CI's ENV configuration variables with the value holding the necessary key.
- Rails pull request discussion for adding multi-env support - Add support for multi environment credentials
- Rails guide on custom credentials
- Web-Crunch youtube video on Guide to Ruby on Rails Encrypted Credentials