February 1st 2011

OSS; my Code, Yes but Not My Secret Stuff

Using Ruby, GitHub and Heroku is absolutely a great combination to work with, the easy way to ‘push’ something into staging or production is just wonderful. GitHub is also a great place to share code and get feedback on it. For this reason I rather OSS something then keep it in a private repository at GitHub.

But I don’t want the whole world to be able to see my database credentials or the different API keys that I am using for my projects.

And for this I found a dead simple solution which I’ll share with you here, and of-course hope to get your feedback on!

Currently

Lets just take a look at a Rails project; there are many different ways to define your credentials and other configurable information. We can for example use YAML::load to load configuration from a .yml file, many gems are familiar with this way of working some even search for a .yml file themselves.

An other way is to assign Environment Variables in the different environment configuration files from Rails, like assigning ENV[‘mongodb_password’] in /config/environments/production.rb. These environment variables are then used in the different places in the code, like my MongoDB initializer does:

And finally you can hardcode them, but I am not going to put any energy into explaining why you might not want to do that.

The Problem

Well simply put if you use either one of these approaches then you cannot OSS your code because well then everybody can look at your code get the credentials and well lets just say that if you do this you would be better of not having any security at all. Saves you a lot of worries.

So you want to keep that type of information outside of your repository if you plan on releasing it as OSS and at the same time use the actual code in production.

But when using Heroku you get yourself a problem, because Heroku receives a push request from your git repository, gets all changes and uses that and only that to build a new instance of your application. Which would then fail to start because it misses the credentials that you placed outside the repository.

The Solution, or well a Solution

First step is to make sure all this secret data is placed in Environment Variables like; ENV[‘mongodb_password’]. Take for example again a look at my MongoDB Rails initializer:

As you can see there are no actual sensitive credentials or other identifiable information stored in the code anymore. Now we only need a way to set these environment variables and for that I use Rake tasks. Lets first look at how I start my development server or run my test, below are my rake tasks:

What happens here is that when I execute “rake run” that before running the actual task it will first run the “set_development_environment” task which as you can see sets the right environment variables. Now I could do this differently by defining these in the different environment config files, but I’ll explain later why I don’t do that.

The Trick

I know, I know, now the secret stuff is still in the same repository. And the dead simple easy trick is to just split this file into two files, one that is outside the repository containing all the secret stuff, like the one here:

And just require this secret rake file inside the public rake file, like this:

Wow that was simple right?

The reason for checking if it exists is that if you want to use Rake and this file is not present then Rake will throw an exception. Now only those tasks that require functionality from the secret rake file will fail. Hint: Heroku uses Rake.

Heeroookuuuu

Yeah yeah, you are right, this won’t work in Heroku because, well Heroku doesn’t have access to this secret repository. But thankfully Heroku has an easy way to set these environment variables using the Heroku gem. Take a look at this additional task which is also located in the secret rake file:

This will set all the needed configuration in the environment variables at Heroku, and is persisted through restarts of the application. So you don’t have to do this after each push to Heroku. The last command just lists all environment variables currently configured. And because I have included this in the project rake file I can within my project structure just type “rake set_heroku_production_environment” without having to navigate somewhere else.

Oh I almost forgot; the reason I don’t use the environment configuration from Rails to setup my test and development environment is that I want to keep all these things in one location. By having them in the same file it is easy to see if I am missing something. Also if I am not using Rails but for example Sinatra then I can keep the same convention.

So there is no reason why you shouldn’t share your code! So share it!






About me

Hi, my name is Mark Nijhof and I am using this space to express my own "creative" thoughts about software development and other things that interest me. If you have any questions then please don't hesitate to contact me:

E-mail: Mark.Nijhof (@) Cre8iveThought.com
Phone: 0031 6 2383 0739
Twitter: @MarkNijhof