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:
- The Rails app loads on the given environment
- Rails checks the value of
RAILS_ENV
so it knows theRails Environment
it is operating in - Rails uses the correct
config/environment
file for that environment - 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.