Development icon

Sometimes a Vagrant-based project that you’re working on may require you to have an SSH agent running with your key in it.

Steven Merrill, Director of Devops
#Development | Posted

Sometimes a Vagrant-based project that you’re working on may require you to have an SSH agent running with your key in it. The reason it needs the SSH agent running is so that it can SSH to your virtual development environment and checkout a given project from BitBucket or GitHub as your user. Throughout this post, I will refer to the host machine and the guest machine. The host machine is your Linux, Mac, or Windows workstation on which you are running Vagrant and VirtualBox or VMware. The guest machine is the virtual machine that emulates the client’s build environment.

SSH Basics

It is a best practice to use public/private keypairs to authenticate with SSH servers. Normally you put your SSH public key on a remote server and when you SSH to it from your workstation, it authenticates you based on your private key. This private key is usually located at ~/.ssh/id_rsa on your host machine.

It is a best practice to put a passphrase on your private key so that if someone gets ahold of it, they do not get carte blanche access to all the machines that you have access to. Normally you would have to type this passphrase in every time you connected to a server over SSH, but there is a program called an SSH agent that can remember your unlocked private key so that you don’t have to type a passphrase every time you SSH to a server or check out a git repository.

Running an SSH Agent

You can check to see what identities have been loaded into a running SSH agent by running the following command. It will show output similar to the following if there is an SSH agent running with a private key unlocked in memory.

$ ssh-add -l

2048 12:34:56:79:90:12:34:56:78:90:12:34:56:78:90:12 /Users/smerrill/.ssh/id_rsa (RSA)

If there is no SSH agent running, you will get the following message.

$ ssh-add -l

Could not open a connection to your authentication agent.

If there is an agent running but it has no keys, you will get the following message.

$ ssh-add -l

The agent has no identities.

Here is what you need to do to start up an SSH agent on the major platforms.

Running an SSH Agent on a Mac

Great news! OS X will automatically start an SSH agent for you if your key has a passphrase.

If your key does not have a passphrase, you can add a new passphrase to it using ssh-keygen.

$ ssh-keygen -p -f /Users/smerrill/.ssh/id_rsa

Key has comment '/Users/smerrill/.ssh/id_rsa'

Enter new passphrase (empty for no passphrase): ••••••••••••••••••

Enter same passphrase again: ••••••••••••••••••

Your identification has been saved with the new passphrase.

After doing that, you will get a dialog box prompting you for the key’s passphrase the next time you SSH to a server or do a git or hg clone as described at https://help.github.com/articles/working-with-ssh-key-passphrases#os-x-keychain . If you check “Remember password in my keychain” at this dialog box, OS X will manage an SSH agent for you from now on.

Manually Running an SSH Agent on Windows or Linux

If you need to start an SSH agent once for a single terminal session, you can do the following from a bash shell. (This should work from a Git Bash or Cygwin bash shell on Windows.)

$ eval $(ssh-agent)  # Start the agent.

Agent pid 7882

$ ssh-add            # Add your key. This will default to adding ~/.ssh/id_rsa and ~/.ssh/id_dsa.

Enter passphrase for /home/smerrill/.ssh/id_rsa: ••••••••••••••••••

Identity added: /home/smerrill/.ssh/id_rsa (/home/smerrill/.ssh/id_rsa)

$ ssh-add -l         # (Optional:) Test that your key is unlocked in the agent.

2048 12:34:56:79:90:12:34:56:78:90:12:34:56:78:90:12 /home/smerrill/.ssh/id_rsa (RSA)

Automatically Running an SSH Agent on Windows or Linux

If you would like to automatically start an SSH agent when you log into a machine, you can add the following two lines to your ~/.bash_profile and the agent will be started when you start any new bash session.

eval $(ssh-agent)

ssh-add

Alternately, on Linux and Cygwin, there is a project called keychain that can handle doing all this for you with a single command. If you would like to use keychain, install it using your package manager and put the following in your ~/.bash_profile.

eval `keychain --eval --agents ssh id_rsa id_dsa`

When keychain runs, it will prompt you for any keys not yet added and then show which are in the SSH agent, like so.

KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/

Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL

* Initializing /home/smerrill/.keychain/knox-box-sh file...

* Initializing /home/smerrill/.keychain/knox-box-csh file...

* Initializing /home/smerrill/.keychain/knox-box-fish file...

* Starting ssh-agent

* Warning: can't find id_dsa; skipping

* Adding 1 ssh key(s)...

Enter passphrase for /home/smerrill/.ssh/id_rsa: ••••••••••••••••••

Identity added: /home/smerrill/.ssh/id_rsa (/home/smerrill/.ssh/id_rsa)

SSH Agent Forwarding and Vagrant

When you use a Vagrant virtual machine, however, that same ~/.ssh/id_rsa file is not present in the guest machine, and so if you want to check out repositories as your normal GitHub or BitBucket user, you need some way to get your private SSH key onto the guest from the host. One way to solve this would be to copy your key from the host to the guest, but now that you are running an SSH agent, there is a standard way to pass the unlocked private key to the guest, using SSH agent Forwarding.

In brief, SSH agent forwarding will pass the unlocked private key to the guest machine when you use vagrant upvagrant provision, or vagrant ssh to interact with your Vagrant virtual machine. So long as you have an SSH agent running on your host, there is no need to do anything special.

Vagrantfile Configuration

This section is intended only for people authoring Vagrant environments. If you are just an end-user, the instructions above should get you up and running.

To enable SSH agent forwarding for your provisioners, you need to set the config.ssh.forward_agent option to true in the Vagrantfile. Note also that the default sudoers configuration on all major distros will cause any provisioner that runs as root to lose the forwarded SSH key, so you will generally need to clone repositories in a non-privileged shell provisioner (or run Puppet/Chef as the vagrant user.)

 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

 # Set up SSH agent forwarding.

  config.ssh.forward_agent = true

  # This script will probably not be able to use SSH agent forwarding since it will run as root.

  config.vm.provision "shell", path: "myprovisioning1.sh"

  # This script will probably be able to use SSH agent forwarding since it will run as the vagrant user.

  config.vm.provision "shell", path: "myprovisioning2.sh", privileged: false

end

Finally, one great trick that I enjoy taking advantage of is the fact that when a Vagrantfile is run, you have access to Vagrant’s full Ruby 2.0 environment and so you can do anything you want using Ruby code. If you want to provide better help to your users, you can check to see if they have an SSH agent running for them, and error out if that is not the case. Below is an example of checking for several possible error conditions, including an SSH agent that has not started or contains no keys.

# Check to see if there's an SSH agent running with keys.

`ssh-add -l`

 

if not $?.success?

  puts 'Your SSH does not currently contain any keys (or is stopped.)'

  puts 'Please start it and add your BitBucket SSH key to continue.'

  exit 1

end

 

if Vagrant::VERSION < "1.5.1"

  puts 'This Vagrant environment requires Vagrant 1.5.1 or higher.'

  exit 1

end

 

unless Vagrant.has_plugin?("vagrant-host-shell")

  puts "This Vagrant environment requires the 'vagrant-host-shell' plugin."

  puts "Please run `vagrant plugin install vagrant-host-shell` and then run this command again."

  exit 1

end

 

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

# The rest of your normal Vagrant configuration goes here.

end

Want to learn more about Vagrant? Check out more of our thoughts on Vagrant!

Steven Merrill

Director of Devops