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.
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!