rails-template icon indicating copy to clipboard operation
rails-template copied to clipboard

Should we still be generating config/secrets.yml

Open eoinkelly opened this issue 2 years ago • 7 comments

Rails encrypted credentials is the Rails default now. Are we comfortable making that our default too?

eoinkelly avatar Aug 12 '22 00:08 eoinkelly

Rails custom config docs: https://guides.rubyonrails.org/configuring.html#custom-configuration

eoinkelly avatar Aug 18 '22 22:08 eoinkelly

We noted in our discussion that it is a bit unfortunate that the file is called "secrets". It's really a single place to load configuration for the app. Some of that configuration can be hard-coded into the YML and the secret stuff is loaded from ENV via ERB at runtime.

eoinkelly avatar Aug 18 '22 22:08 eoinkelly

This is a write-up of the tradeoffs I see with using encrypted credentials:

A deployment is required whenever we need to update env values

Some clients require deployments to go through a CAB process which often only meets once a week at least, or have code freezes during which code changes need to be submitted and approved by an external department, whereas this generally doesn't apply to changes to environment variables.

Since using encrypted credentials would require us to do a deployment, it can greatly impact our ability to respond to certain issues, including with third-party services which we typically configure with env variables (I had this happen the other week with the email service for an app failing - I was able to fix it within minutes by updating the env variables with creds for another service).

This also means if anything in the infrastructure changes such as the database endpoint, those variables need to be updated at the application level making it more complex to manage.

Secrets are kept in version control, forever (even if we no longer own the repo)

While having secrets versioned has some wins, it also means that every version can be retrieved by anyone that has the encryption key - so long as the codebase remains with us that's not a big deal, but if we offboard an application to another vendor they would be able to access all of these past secrets unless we rotated the encryption keys before hand (which would effectively destroy the old versions of the secrets).

Generally we only use app-specific secrets whereas possible, but services don't manage keys equally so it's not always possible; and all it takes is one commit to accidently include something secret, and it's not even easily auditable because you need the encryption key to even see what is in the creds in the first place.

The encryption key is needed to do anything (which sort of defeats the point)

In order to do anything with the encrypted credentials, you still need the encryption key and generally you need that key on disk or you've having to copy and paste the key around the place. This is required by multiple people anytime the credentials are modified since you need the encryption key to actually do the modification and then reviewers need the key in order to be able to check the changes.

While we expect developers to be aware of and apply strong security practices when handling any sensitive material (keys or otherwise), and to also not need to edit the credentials as frequently as most other parts of a codebase, this is greatly increasing the amount of "human" factor compared to our current ways of handling secrets (Heroku Config and AWS Secrets Manager - both of which make it very easy to edit credentials entirely in their UI).


In addition to all this, we still need to get the encryption key secret to the application which means we'd still need to keep around our current secrets setup.

G-Rath avatar Aug 29 '22 00:08 G-Rath

Just noting here that Rails 7+ encrypted attributes API (which we are planning to use for the 2FA feature) will require the use of Rails encrypted credentials so we will have both enabled on apps.

eoinkelly avatar Oct 07 '22 02:10 eoinkelly

@eoinkelly I'm not sure that it does? it might recommend it but it looks like we can still provide our own config source

G-Rath avatar Oct 07 '22 02:10 G-Rath

We discussed:

  • We still want to load all our config and secret values in the environment
  • There is no meaningful difference in how "secret" and "non-secret" values from the environment are handled in the app

Conclusion

We should stop loading things into Rails.application.secret and put everything in Rails.application.config by loading a YAML file.

eoinkelly avatar Oct 20 '22 21:10 eoinkelly

The Rails docs for Rails.application.secret_key_base detail the order of priority that these secrets are considered:

The secret_key_base is used as the input secret to the application's key generator, which in turn is used to create all ActiveSupport::MessageVerifier and ActiveSupport::MessageEncryptor instances, including the ones that sign and encrypt cookies.

In development and test, this is randomly generated and stored in a temporary file in tmp/development_secret.txt.

In all other environments, we look for it first in ENV["SECRET_KEY_BASE"], then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications, the correct place to store it is in the encrypted credentials file.

When you generate an app with this template you will have both Rails.application.secrets.secret_key_base and Rails.application.credentials.secret_key_base (because Rails generator automatically creates config/master.key). config/master.key is not in git so Rails.application.credentials.secret_key_base will not exist on other machines but this could still be a source of confusion.

I think we should remove config/master.key and config/credentials.yml.enc if we are not using them.

This also shows that the "secrets" namespace is still special in Rails. If we stop using both the encrypted credentials and config/secrets.yml then we will have to rely on the existence of the SECRET_KEY_BASE env var to set that particular (very important) secret. That feels like something which could trip up a future dev.

eoinkelly avatar Oct 22 '22 01:10 eoinkelly

Noting a few things I have learned while reading up on this:

Rails can load the master key from ENV

If RAILS_MASTER_KEY exists in the env then it is used instead of config/master.key (or config/<ENV_NAME>.key if you are using environment credential files).

Rails 6+ supports per environment encrypted credential files

Source: https://blog.saeloun.com/2019/10/10/rails-6-adds-support-for-multi-environment-credentials.html

The PR adding this feature helps understand it a bit.

The intent seems to be that Rails will load only one credentials file in each env i.e. config/credentials.yml.enc is only loaded if an environment credentials file is not found.

# loaded only if an environment credentials file does not exist for the current Rails env
# edit with: rails credentials:edit 
config/credentials.yml.enc
config/master.key # or ENV["RAILS_MASTER_KEY"]

# loaded only in production env
# edit with: rails credentials:edit --environment production
config/production.yml.enc
config/production.key # or ENV["RAILS_MASTER_KEY"]

eoinkelly avatar Oct 22 '22 19:10 eoinkelly