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
ubuntu/xenial64– Ubuntu 16.04.3
- Ansible 18.104.22.168
- 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.
To test that it’s working, run
git clone and make sure it succeeds:
git clone firstname.lastname@example.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:
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'
vagrant provision. Then connect to your VM with
vagrant ssh. The clone command should then succeed:
[vagrant@localhost ~]$ git clone email@example.com: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 # ... end
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 file: 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 git: repo: 'firstname.lastname@example.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:
config.ssh.private_key_path = "~/.ssh/id_rsa"
ansible.sudo = true(it’s deprecated anyway)
ansible.host_key_checking = false
- Set any
ansible.raw_ssh_args = ['-o UserKnownHostsFile=/dev/null']
- Create an
Resources that helped me get this working: