Rails Deployment with Git, Vlad and SSH Agent Forwarding

I'm switching my code repositories over to Git from Subversion. For the most part it's going well. I'm having some issues with line endings, but that's for another post. I'm still getting to grips with day to day usage, but can already see that it's going to be a great improvement on Subversion.

This is how I've setup Vlad, Git, and SSH to work together.

Vlad Configuration

I use Vlad to deploy my projects to the staging/live server, so I needed to re-configure Vlad to support Git. This was very simple to do. In my Rakefile, I included the Git class instead of the Subversion class. This removes the Subversion specific commands and includes the Git specific commands instead.

-require 'vlad/subversion'
+require 'vlad/git'

I also changed the repository address in my config/deploy.rb file.

-set :repository, 'https://sub.version.server/repo'
+set :repository, 'git@github.com:username/repo.git'

These are the only changes I needed to make.

SSH and Git setup

Git uses SSH keys to control access to repositories. As I'm using GitHub as my deployment Git repository, I needed to identify myself with them. To do this, I supplied them with my SSH public key. GitHub have good instructions on how to do this.

As the code is cloned from GitHub directly to the deployment server (not my machine), my private SSH key would also need to be installed on the deployment server.

Vlad deployment now works! This will checkout the latest HEAD and deploy it to the server. You can set the specific revision that you want in your config/deploy.rb as well if required. I'm not doing that at the moment.

So, what's the problem?

The problem is that you need to install your private SSH key on the deployment server. I didn't want to do this in case the server was ever compromised. If it was compromised, the attacker could also theoretically get into other systems using that key if it didn't have a passphrase. This would be bad. My key does have a passphrase, but why install it when you don't really need to?

Making it more secure

Fortunately, there's a rather nifty solution to this problem — SSH agent forwarding. In order to do so, you must first be using SSH Agent. SSH Agent allows you to authenticate yourself once per session, so you don't have to enter your password every time you connect to the server. If you're already using SSH keys and have SSH Agent running on your system (which is the default in Ubuntu), you just need to do:

ssh-add ~/.ssh/<keyname>

You'll be prompted for the passphrase to the key. Once you enter it, you should be able to connect to any servers using that key without entering it again. This is very handy anyway regardless of whether you're going to be using forwarding or not.

See this wikipedia page for more information.

How to setup the forwarding

This is where the forwarding comes in. SSH can forward requests for authentication back to the original SSH Agent process running on your machine. So, you can connect to your deployment server and then connect to another server without re-entering your passphrase or having to install any keys on the deployment machine itself. Much coolness. This negates the need to install any other keys on the deployment server itself.

There is a very well explained article called An Illustrated Guide to SSH Agent Forwarding over at Unixwiz.net that goes into a lot of detail about how this all works. It's well worth a read.

This is how to set it up.

Edit your ~/.ssh/config file and add something like this:

Host <name>
  HostName <ip or host>
  User <username>
  IdentityFile ~/.ssh/<filename>
  ForwardAgent yes

This is all you need. If you've got SSH Agent running, you're sorted.

Incidentally, you can add these sections for as many hosts as required. It saves you having to type out lots of command line switches all the time. Just leave out the ForwardAgent yes line.