Rails Credentials can be Confusing
3 min read | February 26 2022
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:
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
You may edit your environment-specific credentials files by passing
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