---
title: Zero-downtime with Rails credentials part II
teaser: Transitioning the codebase from using environment variables to Rails Credentials
  for Zero-Downtime Deploys.
tags: ruby,rails,credentials,environment variables,devops,sre,infrastructure,zero
  downtime with rails credentials
author:
- Sami Birnbaum
- Valeria Graffeo
published_on: 2024-12-18
---

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 this article we are going to look at the consequences, and the impact that
these have on you as a developer, and your codebase.

## What impact does this change have on you?

### Credential files for each environment

It is important to conceptually consider all the environments
we run the application in. In our case, these are:

- development
- test
- staging
- production

Not all of these environments may deploy to a server, indeed both
`development` and `test` only exist on your local machine. `development`
when you run the development server and `test` when you run your
test suite.

Currently, when the application runs in any of these environments,
Rails looks for the `.env` file in order to pick up the environment
variables.

This is why we currently have a `.env` file for each of these environments.

With this change we will be moving away from a `.env` file to a credential file
for each environment. These will be located at `config/credentials/<environment_name>.yml.enc`.

The credential files we expect to have corresponding to each
environment:

- `config/credentials/devlopment.yml.enc`
- `config/credentials/test.yml.enc`
- `config/credentials/staging.yml.enc`
- `config/credentials/production.yml.enc`

These files are where you will now go to add, edit or remove
credentials, instead of doing so in the `.env` file.

### New `Rails Environments`

Another change that you will start to see is the creation of new
`Rails Environments` within the Rails app.

Have a look in `config/environments`. You will see that as things
currently stand the Rails application is only aware of 3 different
`Rails Environments`:

- development
- test
- production

When you run the server locally, Rails runs in the development `Rails Environment`.
When you run the test suite, Rails runs in the test `Rails Environment`.
You can check this with the command `Rails.env`.

However, for all of our other environments, namely `staging` and `production`,
Rails treats them all as production `Rails Environments`. The `Rails.env` command
returns "production" in all of these environments.

This has been set up this way intentionally, using the `RAILS_ENV` environment
variable in each `.env` file to set the `Rails Environment` to production,
like so: `RAILS_ENV=production`.

Up until now this didn't really matter. We are happy for Rails
to treat all of the deployable environments as "production".

But with Rails Credentials it does matter...
Rails uses the `Rails Environment` to determine
which Rails Credentials file to read from.

For example when Rails is running in the test `Rails Environment`
it will know to use the credentials from `config/credentials/test.yml.enc`.

But imagine when we have credential files for each of our environments:

- staging --> `config/credentials/staging.yml.enc`
- production --> `config/credentials/production.yml.enc`

The way Rails works is that it will first check what its `Rails Environment`
(`RAILS_ENV`) is set to and use that to infer which credential file to
read from.

As it stands, on all of these environments, the `Rails Environemnt`
is set to "production", in other words `RAILS_ENV=production`,
and therefore within each environment, Rails will always look for the
`config/credentials/production.yml.enc` file.

This is a problem as we want to have different credentials for each
environment, just like we have a different `.env` files for each
environment.

In order to do this we have to create a new `Rails Environment` for each environment,
by creating all the environments in `config/environments`.

So we expect to see the following files:

- `config/environments/development.rb`
- `config/environments/test.rb`
- `config/environments/staging.rb`
- `config/environments/production.rb`

We will also set `RAILS_ENV` on each environment to the actual
name of the environment and not just production.

- staging --> RAILS_ENV=staging
- production --> RAILS_ENV=production

This will allow Rails to check the `RAILS_ENV` on the environment
and use that to read from the correct credentials file.

So, to put it all together:

1. The Rails app loads on the given environment
2. Rails checks the value of `RAILS_ENV` so it knows the `Rails Environment` it is operating in
3. Rails uses the correct `config/environment` file for that environment
4. Rails uses the correct credentials file for that environment

### Use a Rails Master Key

As mentioned above, all the Rails Credential files will be
encrypted. This is why we can store them safely in version control.

However, when Rails attempts to read from these credential files,
it will need a key that it can use to decrypt the files and
retrieve the key value pairs in a decrypted state.

You will need to add the key to your `.env` file in order
to be able to work with the credential files and decrypt them.

*This key is highly sensitive and should not be stored in version
control.*

Rails uses a different master key for all the different environments.

## So, wait, why do we still need a `.env` file?

Well, yes. We will tell you more in our next article, promise.

[Zero-downtime with Rails credentials]: https://thoughtbot.com/blog/from-environment-variables-to-rails-credentials
[first post]: https://thoughtbot.com/blog/from-environment-variables-to-rails-credentials
