Zero-downtime with Rails credentials part III

This post is part of the Zero-downtime with Rails credentials series.

In the first post we talked about the reasons that moved us towards making a codewide change and adopt Rails credentials rather than using environment variables to manage our secrets.

In the second post we saw what that means to us in our codebase in practice, and how to structure the files necessary to use Rails credentials in each environment within our application.

We left you hanging with a big question, whether we still need an .env file after all. Here’s the answer…

Credentials don’t fully replace .env

In an ideal world we would not need to have a .env file at all.

When we originally started this task, we thought credentials would replace environment variables in their entirety.

However, as you may have already guessed, at the very least we need 2 environment variables even when using credentials:

  • RAILS_ENV
  • RAILS_MASTER_KEY

RAILS_ENV tells the application which environment it is when it loads and guides the application towards the correct credentials file for that environment.

RAILS_MASTER_KEY allows Rails to decrypt the credentials.

Without these 2 environment variables, Rails would not be able to infer which credential file to use and how to encrypt it.

Load Differences

We may also have other environment variables that still need to be defined apart from RAILS_ENV and RAILS_MASTER_KEY.

This is because environment variables are available when the app loads at an earlier stage than Rails Credentials.

This is one of the drawbacks of Rails Credentials, unlike environment variables, they live within the application, so they require the application to load before they are available to use.

Therefore, some environment variables that we use during the loading of the application may need to remain as environment variables.

These are mainly in files that live in config/ or initializers/.

OK, well, surely if we still have .env files then we can’t use hot reloading and achieve zero-downtime?

Don’t worry, we can, and we will!

The only issue with using hot reloading with environment variables is that hot reloading does not pick up any changes to those environment variables.

However, we have now distilled our .env files to only house minimal environment variables that we do not expect to change and should not change.

The vast majority of key value pairs have moved to credentials and changes to them will be reflected with hot reloading puma.

However, if for some reason, we did make a change to an environment variable then we would need to restart the puma server for this change to be picked up.

Where do I put things going forward in .env or credentials?

It’s a great question!

We think that by default we should always endeavour to use Rails Credentials. This protects us from being able to change the values without having downtime and also has the added benefit of storing things inside the application which will be easier to manage.

However, if you are adding something that needs to read before the credentials have loaded than you can add it to the .env file.

Now that we have Rails credentials in our application, we want to explore how to use them in our test suite. Stay tuned for the next article, about stubbing Rails credentials in specs and other caveats.