Life in DevOps land has been pretty exciting for me. I've learned to create a tiered service (an app server + worker server), deal with RVM + upstart, finagle monit into submission, and most recently work with multiple SSH keys on one server.

Scenario

You've got a server with 2-3 apps on it, and you'd like to use deploy keys for each app, but how do we keep them separate and how will the system know which to use? There's a thing called a config file that can be used for our SSH keys. It's kind of awesome.

I'll step through how to set it up and the like in this post.

Repo examples

Let's pretend we have 2 repos, and both are hosted on Github:

  • App 1 = Surprise
  • App 2 = Badger

Server

The pretend server is going to be Ubuntu 14.04+. I'll assume you've created a ~/.ssh directory and chmod'd it appropriately. On DigitalOcean, the directions for doing that can be found here about midway down. We'll skip their directions about creating keys.

Creating SSH Keys

Github's SSH key article is probably the best thing that's happened on the internet for people like me since sliced bread. (But not since buttered and toasted sliced bread...)

Here's the abbreviated version of that article for our purposes, using our examples. Because examples are great! I'll use Surprise (app 1) as the example since the steps are repeated for Badger (app 2).

ssh-keygen -t rsa -b 4096 -C "devops@surprise"
# really, we don't need to put an email. this just lets us know
# that it's the surprise repo we're dealing with.
Enter file in which to save the key (/Users/you/.ssh/id_rsa): surprise_rsa
# here put in something like surprise_rsa then hit enter
Enter passphrase (empty for no passphrase): # optional
Enter same passphrase again: # optional
# these are optional but highly recommended

You should get some funky design/image after this. Repeat these for badger.

Once both are set up, we can proceed to the next step, adding the keys to the ssh-agent. You want to run the eval statement once. This tripped me up a couple of times.

eval "$(ssh-agent -s)"
# this gets you a pid. Agent pid ####
ssh-add ~/.ssh/surprise_rsa
ssh-add ~/.ssh/badger_rsa
# you will probably have to add your passphrases in here. do it.

Sanity check yourself by confirming that both SSH keys have been added.

ssh-add -l
# this should display both apps

Add Keys to Repo

Deploy keys. The only way I could really understand their functionality was that they are the server's ssh keys that get put into a particular repo, so that particular key is the only one that's allowed to read/write to that repo only. This prevents the key from accessing other repos. Usually we create ssh keys and attach them to our account, so we can then grab ANY repo we're associated with. This can be dangerous, and it can cause problems if the associated member leaves the organization. (i.e., if I leave the company, the keys on the servers that I had attached to my account will no longer work)

First, we'll need to cat the public keys. Let's start with Surprise.

cat ~/.ssh/surprise_rsa.pub

Copy the surprise_rsa.pub key, from ssh-rsa all the way to devops@surprise.

Now, go to Surprise's repo in Github > Settings (right panel) > Deploy keys. The path will look like:
https://github.com/your_github/Surprise/settings/keys

Click on Add Deploy Key, name the key something you'd understand. "My awesome server's deploy key" is totally OK. You're the captain of this ship, after all. Paste in your key. Save.

Repeat steps for Badger.

Create SSH Config

Now that we've got our 2 deploy keys set up, we need to make sure git knows which key to use and when, when we do our git clones and git pulls and pushes.

Create a config file in ~/.ssh/ called config.

nano ~/.ssh/config

The file will be in this format:

# surprise github
Host surprise
  Hostname github.com
  User git
  IdentityFile ~/.ssh/surprise_rsa

# badger github
Host badger
  Hostname github.com
  User git
  IdentityFile ~/.ssh/badger_rsa

Let's break this down.

  • Host can be whatever you want. It can be asdfjkl; for all we care.
  • Hostname is github.com as that's where our repo is at.
  • User is git, because we are SSH'ing to github. (You know, git@github.com...)
  • IdentityFile is the private key for that repo. Remember, we associated it's public key to the repo, so we need the matching private key for the connection to work.

Save and exit!

Setting up the repos

Assuming we haven't pulled down the repos to the server, we'll do that now. I know you're inclined to copy paste the SSH URL from Github: git@github.com:your_github/surprise.git BUT DON'T DO IT.

DON'T YOU DARE!

Instead, you will do this:

git clone git@surprise:your_github/surprise.git

Do you see it? github.com was replaced with surprise. It forces git to look at the SSH config file and be like "What is this host called surprise? Oh, we're going to use this identity file and connect to this repo on github! Ok got it!"

At that point, your origin will be pointing to surprise and you'll be able to do git pull origin master or git push origin master and life will be deliciously fabulous.

Repeat this for badger, of course.

NOTE: If you've already cloned, you can change your origin to point to the above URL instead and that'll solve your issues.

Serious thanks to this StackOverflow answer that cleared things up for me.

Level up +10


Questions? Comments? Hit me up at risaonrails !