minute read
Jessica Dillon

Use GPG to hide Rails secrets

It has happened to us all. It’s late at night and you’re working on your side project. You’ve been trying to get that darned external API working for hours, and OH MY GOODNESS IT FINALLY WORKS! You push your changes up and abandon your computer for some well deserved rest. That is, however, until you wake up in the morning and your plain text API key you just threw into your app has been stolen by some jerk on the internet who was looking through GitHub search for unknowing victims. That causes your app to be hacked, your bank accounts to be emptied, and your inevitable arrest.

No? No one? Ok, maybe that’s just happened to me then.

“Ugh whatever I don’t care,” you may be thinking. “My repository is private.” Well, smartypants, you still need to be careful! If you ever want to open source that repository, your Git history will have these keys smattered throughout for the public to steal. Even if you keep the repository private, what if you want to give a contractor access temporarily?

Fellow Bugsnagger Conrad Irwin wrote dotgpg, a gem made for backing up and versioning your application secrets or shared passwords securely and easily. dotgpg makes the encryption process pretty simple, only interfacing with the basics of GPG that are needed for what we’re trying to accomplish.

Where should I store my secrets?

According to Twelve-Factor, an app is supposed to store its configuration options in environment variables. Like that API key you just lost. In your code, you should be referencing [CODE]ENV["SECRET_PASSWORD"][/CODE], grabbing the value associated with the “SECRET_PASSWORD” key.

Rails 4.1+

Rails 4.1 has this handy change that includes a [CODE]secrets.yml[/CODE] file. All we have to do is add our keys to the file and reference them with [CODE]Rails.application.secrets.secret_password[/CODE]. Easy enough!

Rails pre-4.1

How do these environment variables get set up? Well, in a Unix shell, you could always export them via command line.

-- CODE language-plaintext --
export SECRET_PASSWORD="omg-wow-this-is-a-super-secret-password"

However, this only lasts for that shell session and then disappears. One solution is to export the environment variable in one of our shell startup scripts ([CODE].bash_profile[/CODE], [CODE].zshrc[/CODE], etc.). Another is to make a file that stores all of these secrets and then read it in a Rails initializer so that it loads our variables on boot.

We recommend just using a gem like dotenv that has already solved this problem for us. Dotenv is just a shim to load environment variables from a file named [CODE].env[/CODE]. Either way, we’ll have to add the file containing our secrets to the [CODE].gitignore[/CODE] to make sure we don’t push it up.

How do I keep my secrets secure?

To get on the crypto-train, we first need to install GPG. We’re going to install it on the command line via homebrew, but if you want a nice GUI, I’d recommend trying out GPGTools.

-- CODE language-plaintext --
brew install gpg

Now that we have GPG installed, we need to generate a public and private key pair.

-- CODE language-plaintext --
gpg --gen-key

You’ll be walked through a bunch of prompts. You can use the defaults, but I recommend reading some articles on options to set up & configure your keys.

There’s only a few rules surrounding the key pair you’ve just made!

  • Never lose your keys or you’ll be sent to jail*
  • Never forget your key passcode or you’ll be sent to jail*

*There’s a small chance you won’t be sent to jail, but these are still very important.

Some people store their keys on a flash drive and put it in an actual physical safe, some keep them in cloud providers like Dropbox, and some write them on actual paper. The same goes for your key passcode (I store my key passcodes in 1Password).

For more information about GPG, see the Extra Notes & Resources section.

How do I set up dotgpg?

To get started, you need to either run [CODE]gem install dotgpg[/CODE] or add [CODE]gem "dotgpg"[/CODE] to your [CODE]Gemfile[/CODE] and run [CODE]bundle[/CODE]. Then, you need to run:

-- CODE language-plaintext --
dotgpg init

Ok awesome! This created a [CODE].gpg[/CODE] folder, which will later be used to hold each team member’s public key.

A new team member can run [CODE]dotgpg key[/CODE] to output her public key, which she must then send to an existing team member. If she hasn’t already created a key, this will walk her through the prompts to do so.

When the key is sent over, the existing team member can run [CODE]dotgpg add[/CODE], which will prompt her to paste in the new team member’s public key. This will create a file named by the new team member’s GPG e-mail. The file will contain her public key, and will be automatically added into the [CODE].gpg[/CODE] folder.

Now all collaborators can create and edit files with:

-- CODE language-plaintext --
dotgpg edit <pgp-encrypted-filename></pgp-encrypted-filename>

This will open [CODE]<pgp-encrypted-filename>[/CODE] in your default editor (which you can </pgp-encrypted-filename>change by setting the [CODE]EDITOR[/CODE] environment variable). After entering your GPG passphrase, you’ll see the decrypted file!

You can also decrypt a PGP-encrypted file and pipe it to standard out (which will also ask for your GPG passphrase):

-- CODE language-plaintext --
dotgpg cat <pgp-encrypted-filename></pgp-encrypted-filename>

How do I share the secrets?

So now you’re putting all your environment variables in [CODE].bash_profile[/CODE], [CODE]secrets.yml[/CODE], or [CODE].env[/CODE], and your coworker is coming up to you because she is having a problem starting her local server. She doesn’t have ENV["SECRET_PASSWORD"! Teams have different ways of sharing keys, but now each person generally has to play fill-in-the-blank-scavenger-hunt, go-find-a-random-google-docs-password-file-that-feels-kinda-insecure, overhaul-the-companies-entire-setup-process-by-making-everyone-use-boxen, or the classic bug-my-coworker-until-she-IMs-me-the-key.

Let’s say your repository has a PGP-encrypted [CODE]config/secrets.yml.gpg[/CODE] file (or [CODE].env.gpg[/CODE] if you’re using Rails pre-4.1). Since [CODE]config/secrets.yml.gpg[/CODE] is encrypted, random users can’t read the application secrets and passwords contained within. However, since your public key has been added to the repository, you can run:

-- CODE language-plaintext --
dotgpg cat config/secrets.yml.gpg > config/secrets.yml

You now have a local copy of all the application secrets and passwords in [CODE]config/secrets.yml[/CODE]! Make sure this is in your [CODE].gitignore[/CODE], lest you defeat the whole purpose of all this extra security.

Now, even if you made this repository public, you’re still safe. Only existing team members can [CODE]dotgpg add[/CODE] new public keys, and only people whose public keys have been added can decrypt [CODE]config/secrets.yml.gpg[/CODE]. Removing a team member would entail deleting her public key and rolling the secrets. Unapproved viewers will be locked out, and will have to come up with their own set of application secrets and passwords!

Extra notes and resources

  • “GNU Privacy Guard”, or GPG, is data encryption and decryption software. You may be wondering why I’m spelling PGP wrong; GPG is a free alternative to “Pretty Good Privacy” or PGP. PGP was originally freeware written by Phillip Zimmerman, but was then purchased by Symantec who discontinued the freeware version. GPG is a rewrite of PGP created using the OpenGPG standards but different encryption algorithms. This makes it usable between people using other OpenGPG implementations and keeps it free. Check out this post for more detail on the differences between PGP and GPG.  
  • In this blog post, we only used GPG to create keypairs, but for any of your other GPG command needs, check out this cheat sheet.  
  • After creating your keys, you can upload them to a public key server. This makes your public key searchable by people who want to give you access to stuff. You can do this inside of GPGTools, or you can go to one of the many servers available to upload your key.  
  • keybase.io is an awesome in-beta app that is “a public directory of publicly auditable public keys”, where you also have an option to privately store your private key. However, a lot of people don’t recommend storing your private keys on their servers unless they’re encrypted, so I’d do some reading on this to find what best suites you.  
  • When discussing public key directories, you might think “Uploading your own public key feels pretty easy, couldn’t someone post a fraudulent key under my name?”, and you’d be right! That’s where key-signing comes in. It’s not important for using dotgpg, but definitely read about it and then throw a key signing party of your own! If anything else, it’s an excuse to order a bunch of pizza.  
Bugsnag helps you prioritize and fix software bugs while improving your application stability
Request a demo