When it comes to secure storage of API keys or tokens in the application development, we got used to environment variables for a long time. Of course, I was comfortable too with env vars until I found about the security lapse of using those. This article shows the drawbacks of using environment variables and it’s alternative in Rails to mitigate these issues.
To use the environment variables config, we have options like creating a
.env files to store the sensitive key information. The variables are stored as key-value pairs in the plain text as mentioned below.
SOME_API_TOKEN = 'vfsdjkgb4irhgoreidfnvldaknvd9wej09qwfnsl' SCERET_KEY = 'fe8934ygt983qhv8934hf934q8gf343qhjrajvlksdvklvdsnl'</span>
and the value can be accessed thru
ENV['SOME_API_TOKEN']. Look at the below example.
Even though we are not committing
.env file to version control, there is a security risk involved with environment variables. The major risks are:
- Exposure of sensitive information like keys and API tokens through log reports during debugging and error logging.
- This stolen keys can be misused by other people which may increase your server costs to sky-high.
Some other disadvantages:
- deployment is challenging due to dealing with many environment variables
- chances of accidental pushing to version control
Now the question comes what we need to use instead of environment variables.
The answer is Rails credentials.
In the previous versions, its called Rails secrets. Since version 5.2, it got more stable and it’s much better now with the feature of generating separate credential files for each environment in Rails 6.0.
Features of Rails credentials:
- Rails credentials are encrypted. They can’t be decrypted without a master key. So you can push the credentials file to version control and track changes.
- No hustle of managing the different environment variables in deployment. The only environment variable required in production is the master key (i.e.
- Rails scaffolding will add the
.gitignore. So, there is no scope of accidental moving to version control.
- Easy to deal with environments for different environment variables. Separate files will be created for each environment from the Rails version 6.0 onwards.
1. The Rails new application scaffold will create a
master.key files in the config folder. The file
credentials.yml.enc is encrypted and the contents of this encrypted file will look like as below.
2. The above file is an encrypted version of our secret keys and passwords. The data can be opened only with the master key. Rails will add this
3. Since it is encrypted, we cant edit the file directly. We need the following command to add or modify the keys in the
EDITOR="code --wait" bin/rails credentials:edit</span>
- Here we need to mention the type of editor you want to use. Since I’m using VScode editor, using the term code.
- For example, If you want to open in atom editor, you should mention
EDITOR = "atom --wait"and the rest of the command follows.
- It’s important to pass a wait flag. Otherwise, the credentials will be saved immediately with no chance to edit.
4. After running the above command, the decrypted credentials file will open in the editor. The credentials are stored in the YAML format as shown below.
This is the default
credentials.yml.enc file, with only one key active.
# aws: # access_key_id: 123 # secret_access_key: 345</span> <span id="c3d4" class="dz kk iy fq kb b dj lb lc ld le lf km s kn"># Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.</span> <span id="ec37" class="dz kk iy fq kb b dj lb lc ld le lf km s kn">secret_key_base:68ef73fa111800521c3a62237a7398a5e49c684bc6f50092ab98b742d151f6f8ef45cc337e5a7dedd6145624ddf5345cdf262653ef403a8018852a411ce04cf</span>
5. Now we can add or edit the keys as per our requirement. Let us say, we want to add some credentials of AWS. See the below example.
aws: api_token: 'vfsdjkgb4irhgoreidfnvldaknvd9wej09qwfnsl' access_key: 'fe8934ygt983qhv8934hf934q8gf343qhjrajvlksdvklvdsnl'</span> <span id="3648" class="dz kk iy fq kb b dj lb lc ld le lf km s kn"># Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.</span> <span id="74bf" class="dz kk iy fq kb b dj lb lc ld le lf km s kn">secret_key_base:068ef73fa111800521c3a62237a7398a5e49c684bc6f50092ab98b742d151f6f8ef45cc337e5a7dedd6145624ddf5345cdf262653ef403a8018852a411ce04cf</span>
That’s it. After save and exiting the editor, you can see the message
**File encrypted and saved** in the terminal.
6. To access these credentials, you need the following code.
Rails.application.credentials.aws[:api_token] => "vfsdjkgb4irhgoreidfnvldaknvd9wej09qwfnsl"</span>
7. Coming to production, we need to create only one environment variable in production. i.e.
RAILS_MASTER_KEY = <your-master-key> Rails will use this environment variable as
master.key for encryption and decryption. Thus, it enables accessing the rails credentials in the production environment.
8. You can also set the separate keys for each environment with the following command.
EDITOR="code --wait" bin/rails credentials:edit --environment development</span>
This command will create the file
development.yml.enc and the new encryption key
development.key in the folder
config/credentials. The remaining process of accessing and modifying the credentials are the same as above.
The security of sensitive keys in application development is an important aspect. The use of environment variables is getting deprecated due to security lapses. Hope this article gave enough information to start working with the Rails credentials. There are also third-party gems which are addressing these issues. If you are using any other way to handle this sensitive data, please let me know by commenting below.