secrets.yml Best Practices

This article will go over a few best practices for the Rails secrets.yml file.


Published on:May 27, 2016

Introduction

In The Rails 4.1 secrets.yml File, we covered the basics of using secrets.yml, a new secure settings mechanism built into Rails 4.1 and up. In this article, we will cover a few best practices that will help keep you implement and utilize secrets.yml. Let's get started.

Securing secrets.yml:

As mentioned in our previous article, you should make sure to add secrets.yml to your .gitignore file. However, this presents a bit of an issue because you would have to manually pass around (via email or some other means) the file to other developers, right? Not so fast. The solution to this is to create a template file called secrets.yml.example and add that file to source control. An example of what this template file would look like is listed below.

secrets.yml.example:

development:
  secret_key_base: <%= ENV['secret_key_base'] %>
  github_client_id: Your github client id here
  github_client_secret: Your github secret here
  stripe_publishable_key: Your stripe publishable key here
  stripe_secret_key: Your stripe secret key here
  aws_access_key_id: Your aws access key id here
  aws_secret_access_key: Your aws secret access key here

test:
  secret_key_base: <%= ENV['secret_key_base'] %>
  github_client_id: Your github client id here
  github_client_secret: Your github secret here
  stripe_publishable_key: Your stripe publishable key here
  stripe_secret_key: Your stripe secret key here
  aws_access_key_id: Your aws access key id here
  aws_secret_access_key: Your aws secret access key here

production:
  secret_key_base: <%= ENV['secret_key_base'] %>
  github_client_id: Your github client id here
  github_client_secret: Your github secret here
  stripe_publishable_key: Your stripe publishable key here
  stripe_secret_key: Your stripe secret key here
  aws_access_key_id: Your aws access key id here
  aws_secret_access_key: Your aws secret access key here

In the code listed above, you'll notice that all of the sensitive values have been removed, and placeholders have been added in. You would then add this file to git. Developers would pull down the file, rename it to secrets.yml, and change the values as needed. Your .gitignore would have secrets.yml listed in it, which would prevent them from accidently checking it in. If storing common settings, the use of a placeholder isn't necessary, you can still put these values (example: password_expiry_days: 30) in the file. Note that you could shorten the listing above by using YAML labels for the repeated nodes, but I include the verbose version for demonstration sake.

Keep ALL Your Settings in secrets.yml

While this may seem obvious, keep ALL your settings in secrets.yml. This includes mundane things like password expiry times, etc. Doing this ensures that you always know where to change those settings. Instead of hunting down a password_expiry_days setting in your User model, you simply go change it in secrets.yml. This also makes it easier for your QA department (if you have one) to test things: instead of digging around in code they don't understand, they can change a setting in the file.

Reloading secrets.yml

On the off chance you need to reload secrets.yml at any point, the code below will let you do just that. You can attach this code to a reload button that will reload the settings without restarting the application.


all_secrets = YAML.load(ERB.new(IO.read(Rails.root.join('config','secrets.yml'))).result)[Rails.env].symbolize_keys
Rails.application.secrets.merge!(all_secrets)

Note that the code listed above won't change any secret keys declared in your initializers. You would have to write code to update those separately, or you could simply avoid using initializers. Most libraries should have a way to update the settings at runtime.

Testing for Missing Settings

It's a good idea to test secrets.yml to make sure it includes any settings that are required for your application. At the very minimum this includes ensuring the keys are present. The Rails.application.secrets.keys method returns an array of keys that were loaded from the secrets.yml file. To check for differences you can simple do array subtraction. For example, let's say I was looking for settings called airbrake_project_id and airbrake_secret_key:


[:airbrake_project_id, :airbrake_secret_key, :secret_key_base] - Rails.application.secrets.keys #=> [:airbrake_project_id, :airbrake_secret_key]

In the example above, I have 3 required settings, I simply place them into an array and do array subtraction. This returns the keys that are missing (in this case airbrake_project_id and airbrake_secret_key) as an array. If all of the keys are present, the returned array would be empty. It is recommended that you add this test to both your test suite as well as in an initializer.

Please feel free to leave feedback in the comments below. That's it! Thanks for reading!