Securing your api keys

A Rails app often has to connect to other services via an api key. For example, if you want users to be able to log in via their google credentials. One problem this raises is how to secure these api keys.

The solution I’ve used in my latest app, was to encrypt the key in the database. With this solution, the key is:

  • instance specific;
  • can be made easy to access through the app, but difficult out side the app;
  • is not stored in the app code;
  • doesn’t rely on having to load extra files to production environments.

I decided to base my solution on a Setting model I had used in another app. This would give me a way of storing the setting data, and retrieving it.

However, each setting value is stored in plain text in the database, so the setting would not only be accessible via the app, but also directly from the database. The value needed to be encrypted. I decided that I would not want to encrypt all settings, so I wanted encryption to be an optional setting.

The end result was mournful settings.

With this in place I was able to store my api keys and secrets encrypted in the database and retrieve them like this (example from devise initializer):

config.omniauth(
  :google_oauth2,
  Setting.for(:google_client_id),
  Setting.for(:google_client_secret)  
)

I used seeding to set up the setting objects with invalid values, and exposed the setting model via active_admin with this register:

ActiveAdmin.register Setting do
 
  actions :all, :except => [:destroy]
 
  index do
    selectable_column
    column :name
    column :description
    column :value
    column :encrypted
    default_actions
  end
 
  form do |f|
    f.inputs "Details" do
      f.input :name
      f.input :description
      f.input :value, :input_html => {:value => setting.value}
      f.input :encrypted
    end
    f.buttons
  end
 
end

In this way api keys can be accessed via administrators and modified as needed.

Of course, this is only as secure as the active admin interface, but that’s fine for this project. If I was being paranoid, I’d not expose the setting model via a web interface, and instead create and edit settings via the console.

An update
Recently I needed to secure some api keys without putting them into the database, and I used figaro. Definitely worth a look at if you need to secure api keys without having to exposed them via an admin interface.

This entry was posted in Ruby. Bookmark the permalink.