Streamlining Secret Management with Rails Credentials and AWS Secrets

Secret Management Made Easy

Muralish Clinton
Level Up Coding

--

I remember beginning my Ruby on Rails development journey by using encrypted secrets, which are packaged as part of the application. I then moved on to using environment variables and eventually to using a file with all the secrets, which is packaged during compile time in the build pipeline.

Though these strategies seem straightforward, they also come with several vulnerabilities. I’d like to discuss a strategy through which we can store and consume secrets better in Ruby on Rails 7.

Photo by Jason Dent on Unsplash

Credentials were introduced to Ruby on Rails in version 5.2, and in subsequent major versions, we have witnessed significant improvements to credential management within the framework. I’m excited to see how it will evolve in the upcoming versions.

How to get started with Credentials?

Rails stores secrets in config/credentials.yml.enc, which is encrypted and hence cannot be edited directly. Rails uses config/master.key or alternatively looks for the environment variable ENV["RAILS_MASTER_KEY"] to encrypt the credentials file. Because the credentials file is encrypted, it can be stored in version control, as long as the master key is kept safe.

By default, the credentials file contains the application’s secret_key_base. It can also be used to store other secrets such as access keys for external APIs.

The following command will create the credentials file (e.g: config/credentials.yml.enc) if it does not exist. Additionally, this command will create config/master.key if no master key is defined.

rails credentials:edit

credentials.yml.enc file will contain a string which when decrypted will revert back to the actual configs. The configs before encrypting will look as follows:

secret_key_base: 3b7cd72...
some_api_key: SOMEKEY
system:
access_key_id: 1234AB

How is the credential stored?

Rails uses AES with GCM for encrypting the credentials

AES cipher is still the most current symmetric cipher widely used today. In encryption there are several modes for symmetric block encryption and most of them are good until used properly. Very often neglected property of encryption is using authenticated encryption. It means making sure, that the ciphertext was not changed.

AES-GCM has the cipher authentication built-in in the specification. AES-GCM is in top shelf if you need symmetric block encryption.

Also, a separate file will be maintained within the config folder for each environment that will be spun up.

How does the application access the encrypted credentials?

Rails.application.credentials.some_api_key returns "SOMEKEY". Rails.application.credentials.system.access_key_id returns "1234AB".

If you want an exception to be raised when some key is blank, you can use the bang version:

# When some_api_key is blank...
Rails.application.credentials.some_api_key! # => KeyError: :some_api_key is blank

How to securely store the master key?

A suggested way of storing the master key is in environment variables but this defeats the purpose of moving away from using environment variables to more secure ways. Therefore, we could make use of AWS Secret Manager and define an IAM role to the application instance to read from the secret manager and retrieve the master key which will later be used to decrypt the credentials file and make use of the secrets.

Allowing the EC2 instance to read from Secret Manager via IAM

A commonly asked questions is:

“If we are making use of IAM roles, why do we need to go through the pain of maintaining the secrets within the application? Why don’t we store all the secrets in the secret manager?

Yes indeed! This is possible but my personal preference is to make use of the credentials feature provided by the framework and not bloat the secret manager hence reducing the maintenance overhead in the long run.

Conclusion

There are several advantages of using the Rails Credentials and AWS Secret manager together and some of my personal favorite reasons are:

  1. All the credentials are encrypted: No one will be able to decrypt your credentials without the key.
  2. The encrypted credentials are saved in the repository, and we’ll be able to track changes easily.
  3. Since we deploy new credentials together with the code, the overhead of change management is reduced as everything is in one central place.

Though this method is interesting, the topic of secret management is rapidly evolving, and there will definitely be better ways existing or emerging. Stay tuned to learn more about this.

--

--