Rails Credentials can be Confusing

Rails’ encrypted credentials feature is neat but can be a bit confusing and docs are quite minimal. For my own future’s sake, here are a brief set of explanations and conventions to follow.

For backwards compatibility reasons and history, your app may have a ‘global’ credentials file. This consists of the file pair:

~/config/credentials.yml.enc
~/config/master.key

Additionally, Rails 6 brought environment-specific credentials files consisting of credential file-pairs in ~/config/credentials/ such as:

~/config/credentials/development.yml.enc
~/config/credentials/development.key
~/config/credentials/production.yml.enc
~/config/credentials/production.yml.enc

If the environment-specific yml files exist they will take precedence over the ‘global’ file. So even if you’re just doing local development, the presence of development.yml.enc will cause Rails to load that file, not the global credentials.yml.enc.

You may edit your environment-specific credentials files by passing -e=<ENV> to rails credentials:edit and only by passing that flag (or its more verbose variant). Setting the RAILS_ENV does not control credentials:edit like basically all other rails tasks. E.g.

RAILS_ENV=production rails credentials:edit

Will not edit the production credentials file. Strange right? Basically every other Rails command follows RAILS_ENV, but not this one. Beware, this can catch you really off guard. You need to pass the environment you want to edit as a specific argument to the task:

rails credentials:edit -e production
# or
rails credentials:edit --environment production

There’s a bit of an ongoing discussion as to why this is the case, but as George Claghorn summarized, one shouldn’t have to boot the Rails app in Production mode (which may not be possible to do locally) just to edit the production credentials. It makes sense, but having a Rails task that doesn’t adhere to RAILS_ENV leaves a bit of a tension 🤔

Beyond that, having a mix of the ‘global’ credentials file and some environment-specific credentials files can also be a bit of a foot-gun. Forgetting which is which, when/where each is loaded, and that we need to add credentials to more than one file can make for a not-fun-day. I’d recommend either using the global credentials configuration (single pair of files, all environments share the same keys) or environment-specific credentials files with no global file so that each environment gets their own keys without having to worry about which credentials file gets loaded into the app.

Finally, environments that aren’t suitable for transfering a *.key file to (staging, prod, remote environemnts) need to use the environment variable RAILS_MASTER_KEY, which, despite using the name ‘master key’ should actually just contain the decryption key for that environment (the same string of characters contained within that environment’s *.key file).

Join the Conversation

Latest Blog Posts