A Practical Guide to Using Signed Ruby Gems - Part 1: Bundler

Updated 2013-03-08: Read Part 2 to learn how to use this feature with Heroku

Today's bundler release has a new flag: --trust-policy, which lets you enforce various kinds of signing policies on the gems your application users. Gem signing has received some recent attention due to the breach of rubygems.org in January of 2013. However, the concept of trust policies and signed gems is not a new one - rubygems itself has had the trust-policy flag for eight years now, while bundler has only had it for about four weeks.

We've open-sourced a simple tool to help you determine which of your dependencies are signed and which trust policies are available to your app. Before we get to that, let's look at the new functionality in bundler and see exactly what it does. Can we use this shiny new flag to make our Ruby or Rails app Double Plus Secure(tm)? Let's give it a try:

Great! You're good to go - Unit 61398 has nothing on you now. Thanks for reading this post!

What's actually going on here?

Or maybe you suspect that adding the trust-policy flag didn't actually do anything. Well, you'd be right. The value passed to trust-policy is only enforced on new gem installs - the signatures of existing installed gems are not validated. We can see this by forcing bundler to install to a local directory, instead of the system-wide gem path:

There's our security policy doing its work. The rake gem is unsigned, so it won't install with with a trust-policy of HighSecurity. Let's try MediumSecurity, that's almost as good, right?

MediumSecurity allows the use of unsigned gems, but if a gem is signed, it makes sure the signature is valid and also has a proper certificate chain. So rake and a few other gems install, but then we run in to our first signed gem, multi_json, and bundler bails on us. Erik seems like a pretty cool dude, so let's trust his signing certificate and proceed with the install:

So we're going to have to check and install certs for each signed gem we want to use. This probably isn't the best use of our time - we have to iterate over all our gems, check their certificates against some trusted public authority by hand, and then find a way to get that certificate list to our staging and production hosts as well. And this is all just to verify that the few gems that are signed haven't been tampered with - it tells us nothing about our legion of unsigned gems.

How close are we to "HighSecurity"?

Time for some automation. Let's see how much of our (admittedly large) Gemfile is ready for the brave new world of signature verification. I wrote a very simple Ruby gem to parse your Gemfile.lock and summarize the signing status of each of your gems:

The results are grim. Our Rails app depends on 183 gems. Of these, eight are fetched directly from git (where signatures are not checked, since there's no packaged gem), eight are signed (with six different keys), and the remaining 167 are unsigned. But at least we've established a baseline. In subsequent posts, I'll talk more about why gem signatures are useful, and about how the trust model works. I'll also show you how to sign your own gems and how to enforce a --trust-policy at deploy time. What else would you like to learn about gem signing? Join the discussion on Hacker News.