How to keep your credentials a secret when working with Rails.

Jason Arnold
6 min readJan 12, 2017

--

When working with public facing code, hiding things like API keys or other credentials is serious stuff. When you push your code to places like GitHub, that code may be visible and accessible for all to see. That would include any credentials that you need for your app to work.

This seems to be an issue that has only gotten worse since GitHub implemented their search function. While this does make code you want to work on easier to find, it also makes any sensitive code easier to find. There are many examples of developers unknowingly pushing code up to GitHub that contains this information. There are also plenty of people out there that know about this and are willing to exploit it.

I recently ran into this problem when trying to add functionality to my Flatiron School final project. The back end is built in Rails and connects to several APIs which all require their own credentials. I got everything working in my local environment but then wasn’t sure how to handle the problem of keeping those credentials a secret.

After a bit of Googling, leveraging some built-in Rails functionality, and some Git-fu, I had my solution. It involves adding credentials to the ‘secrets.yml’ file in the Rails build and then turning those credentials into environment variables that then become available to the rest of the app.

Sounds a bit involved but it really isn’t too bad, I promise. I’ll walk you through creating a Rails app, adding secret key data to it and confirming that it is available to the rest of the application.

First step is to create your Rails app. This is done with the rails new command followed by the name of your app. I’m calling mine ‘hide_keys’.

rails new hide_keys

This will give you all of the boilerplate rails directories and files.

Boilerplate folders from a Rails build.

From there, open your text editor and open the ‘config/secrets.yml’ file. The file will already include your secret_key_base number as well as the ERB (Embedded Ruby, not epic rap battles, sadly) syntax for creating the environment variable.

Include your super secret credentials under the ‘development’ and ‘test’ sections of the file. Also add the environment variable to the ‘production’ section of the file.

Adding custom variables to the secrets.yaml file.

At this point, you need to take a bit of a side step and think about this file in terms of Git and GitHub. This file now contains some secret information that you don’t want anyone to get a hold of, so you probably shouldn’t include it in your Git or GitHub repos since those may be public facing.

How do you tell Git to ignore a file? With the .gitignore file of course!

“I Don’t have a .gitignore file!” you say? Oh but you do! Your Rails build comes with one (or you can just create your own in your Git repo). You can read more about this here, but the quick version is to just create a .gitignore file and add ‘secrets.yml’ to it.

Add these lines to your .gitignore file

With this line added, my git status results go from this:

Before adding secrets.yml to ‘.gitignore, Git wants to back up the .yml file.

To just this:

After adding secrets.yml to .gitignore, Git ignores the .yml file.

There is now one more step to start creating your environment variables and this is where a bit of Googling and asking around helped me. When researching this issue, I was directed to this Stack Overflow (SO) post which contained this code block

config_files = ['secrets.yml']

config_files.each do |file_name|
file_path = File.join(Rails.root, 'config', file_name)
config_keys = HashWithIndifferentAccess.new(YAML::load(IO.read(file_path)))[Rails.env]
config_keys.each do |k,v|
ENV[k.upcase] ||= v
end
end

Let’s break this down a bit to see what exactly is going on.

config_files is a variable that contains an array of file names. In this case, it is just one name but the each loop that follows could be run against a list of files in this array.

The next line is initializing an ‘each’ loop to run against the config_files variable.

file_path is another variable that is set to a string. This string is a joining of three separate strings of the Rails root path, the string ‘config’ and then the file_name which is the name of the file that the each loop is being run against. So after all of this, the file_path variable is now set to

/Users/jason/Development/scratch/rails_env_variable/hide_keys/config/secrets.yml

Whew. Okay, carrying on…

There is a lot going on in the next line. In starting to research it, I realized it was quickly getting to be out-of-scope for this particular post. Since I don’t want to stray too far off topic here, let’s just say it performs some Ruby magic that turns the keys and values contained in the ‘secrets.yml’ file into a hash.

(I can dive deeper into this in another post and will link to it once it’s up.)

At this point, the config_keys variable contains this hash {“super_secret_key”=>”123456ABCDEF”}

The next line is another each loop which iterates through the config_keys hash assigning each key/value pair as an environment variable. This essentially adds each key/value to the ENV hash which is the hash of environment variables Rails uses.

So, now that you understand how this script does what it does, what do you do with it? Copy and paste it into your ‘config/application.rb’ file. The code in this file is run whenever the Rails server is started up.

So, finally, when you start your rails server you can test to make sure this worked by going into the Rails console,rails c , and looking for the environment variables in the ENV hash.

As another test that Rails has access to this information, I pushed this key out to a web page.

An .erb file referencing the custom ENV variable.
The super secret key is revealed!

Now you can add whatever credential information you want to the secrets.yml file and it will be available to your Rails application but stay hidden from prying eyes.

This is just one example of how this can be done. And you need to know about it before the information becomes compromised. What if you realize too late that you’ve pushed up information that others shouldn’t see? Luckily GitHub provides a guide on what to do in that situation.

Most importantly:

Once you have pushed a commit to GitHub, you should consider any data it contains to be compromised.” — GitHub

--

--