I’ve been working on a Vagrant box configured with Ansible, and I need to clone a private Bitbucket git repo inside it. This turned out to be pretty tricky! A few years ago when some coworkers of mine set up a Vagrant/Ansible box, it copied our private SSH keys into the box to accomplish this. Today, a Vagrant feature called “SSH agent forwarding” seems to be preferred. And any time I can avoid copying my private keys somewhere seems safest. Besides, I plan on using this same Ansible script to configure a cloud server, and it would be nice if that server didn’t need to have my private key on it.

Here are the steps that ended up working for me. These steps should presumably work for private repos on GitHub or any other git host too. FYI, I’m using the following versions:

  • macOS 10.13
  • Vagrant 2.0.1
  • Box ubuntu/xenial64 – Ubuntu 16.04.3
  • Ansible
  • VirtualBox 5.1.30 which probably shouldn’t matter

Also, I’m using the default SSH key location ~/.ssh/id_rsa; if you’re using a different key location you may need additional steps.

Access on Your Host

First, as a sanity check, it’s a good idea to make sure you can connect to the repo on your host machine. This seems obvious, but in my case a macOS upgrade had just caused some issues with my SSH keys, and I was testing with a repo I don’t work in day-to-day.

Make sure your SSH key is set up on your host. Follow the instructions provided by your git host (GitHub instructions, Bitbucket instructions).

To test that it’s working, run git clone and make sure it succeeds:

git clone git@bitbucket.org:myuser/myrepo.git

Access in Vagrant

Next, let’s make sure we can access within Vagrant directly, before trying via Ansible.

There are a few steps to get this working on macOS. I’m not sure if they’re all necessary, because I don’t understand them well enough to be able to undo them to see if it still works! 😅 I’d recommend trying without these steps and then, if it doesn’t work, add them in one at a time to see if they’re needed.

Start the ssh-agent in the background:

eval "$(ssh-agent -s)"

Next, modify your ~/.ssh/config file to automatically load keys into the ssh-agent and store passphrases in your keychain. If there are already Host * entries in there, you can just add another one.

Host *
 AddKeysToAgent yes
 UseKeychain yes
 IdentityFile ~/.ssh/id_rsa

Add your SSH key which is tied to your git account to the host’s ssh-agent:

ssh-add ~/.ssh/id_rsa

Now, add your git server as to your known hosts. Even though we aren’t cloning via Ansible yet, it’s a good idea to go ahead and set up this known_hosts entry via Ansible, so you won’t forget to add it in there later:

# todo: add to the file instead of overwrite, but only if not already present
- name: set up bitbucket.org as a known host
  shell: 'ssh-keyscan -H bitbucket.org > /home/ubuntu/.ssh/known_hosts'

Now run vagrant provision. Then connect to your VM with vagrant ssh. The clone command should then succeed:

[vagrant@localhost ~]$ git clone git@bitbucket.org:myuser/myrepo.git

Cancel the operation and delete the cloned repo if it showed up. That way we can ensure Ansible itself can really clone it next.

Access in Ansible

Now that you’ve confirmed you can clone your private repo in your Vagrant box, let’s set up Ansible to be able to use the same connection.

First, in your Vagrantfile, configure your Ansible provisioner to use SSH agent forwarding:

Vagrant.configure('2') do |config|
  # ...
  config.ssh.forward_agent = true
  # ...

Next, we need an Ansible task to create the directory for the repo to be checked out into. Usually the git command can do that, but we need to run the git command not as root, and so it may not have permission to create the directory.

- name: create dir for repo as sudo
    path: /path/to/myrepo
    state: directory
    owner: ubuntu
    group: ubuntu

Finally, add the task to clone the repo. We need to specify that the task should not be run as root, so that SSH agent forwarding will work:

- name: clone repo
  become: no # to use ssh agent forwarding, must not be root
    repo: 'git@bitbucket.org:myuser/myrepo.git'
    dest: /path/to/myrepo

After this, run vagrant provision and your clone repo should succeed!

What Didn’t Work

In case you’ve been googling around and seen some other suggestions, I want to specifically call out the things I didn’t need to do. I got most of these from this SO question. No offense to those posters—I’m sure all these things helped at the time in their context!

I didn’t need to:

  • Set config.ssh.private_key_path = "~/.ssh/id_rsa"
  • Set ansible.sudo = true (it’s deprecated anyway)
  • Set ansible.host_key_checking = false
  • Set any ansible.extra_vars
  • Set ansible.raw_ssh_args = ['-o UserKnownHostsFile=/dev/null']
  • Create an ansible.cfg file

Resources that helped me get this working: