We have been using multiple different secrets.yml
with Capistrano on multiple production servers. Since Rails 7.1 has deprecated secrets.yml we’re switching to Rails credentials.
If I understand it correctly the preferred way is to commit the credentials.yml.enc file and distribute the master key through environment variables. This will also be useful when we switch to Kamal for deployment. However, how would we handle this when the contents need to differ per production server? It is not an option to use environment names different from production because some gems we use break or get disabled in non-production. Maybe something using config.credentials.content_path
?
An easy way is to have a credential file like this:
production1:
secret: abc
production2:
secret: def
Then in the app, call: Rails.application.credentials.dig(ENV["server_name"], "secret")
With the env var server_name being either production1 or production2.
Great suggestion, thanks! My main problem however is the secret_key_base as it is used in ActiveStorage urls and these will break when all production servers switch to one same secret_key_base. Any solution for that?
You can override the secret key base with the env var ENV["SECRET_KEY_BASE"]
.
@frenkel I find working with rails’ encrypted credential cumbersome and prone to errors. E.g., it is way to easy to accidentally commit your encryption key to git. There is a good comment by GreenCalligrapher571
on reddit that I think it is worth reading. It makes a few good arguments for storing your secrets in S3 and decrypting them as needed. It should be fairly easy to achieve this with ActiveSupport::EncryptedFile
. The master key
will still be distributed via env variables.
Here’s the reddit thread Rails Credentials instead of .env — how and why?
@n-studio thanks! I hadn’t thought about that.
@dan-corneanu yes, that’s why I hadn’t switch to credentials yet. Keeping a local copy of the secrets.yml only on production servers didn’t have the risk of committing/exposing the actual secrets.