Using Ansible through a bastion host

Are you trying to use Ansible through a bastion host? Me too.

We use bastion hosts to access servers which are part of controlled network segments, seperated from our corporate network to meet a particular compliance regime.

Alex Bilbie wrote a good piece about how to get Ansible working with a bastion host. The only problem with his piece is that it mandates that all hosts in your inventory file have to use the same bastion host.

We have a mix of hosts under our support. Some that need to go through the bastion host, some that definitely don’t. I needed a solution that let me specify which servers I wanted to route through our bastion host and which ones I didn’t. So, here’s one way to do it.


  1. First up, make sure you have nc (netcat) on your bastion host.
  2. Create an ssh configuration file which contains:
Host bastion+*
 Port 22
 ProxyCommand ssh jump "nc $(echo %h | sed 's/^bastion+//g') %p"

This assumes that your bastion host’s name is jump.

Save this configuration as /etc/ansible/ssh.config, or something.

This configuration file kicks into action when ssh is fed a hostname which starts with bastion+. For those particular hostnames, we connect first to the bastion host and then pass straight through to the hostname represented by *.

3. Add the following directive under the [ssh_connection] configuration area in /etc/ansible/ansible.cfg:

ssh_args = -F /etc/ansible/ssh.config

Here, we tell Ansible that we always want to use a special ssh configuration file when we connect to hosts. The important thing is that the configuration file is benign enough to allow “normal” connections to pass through!

4. Populate your /etc/ansible/hosts file appropriately:

# cat /etc/ansible/hosts
[no_bastion_host]
host1
host2

[via_bastion_host]
host3               ansible_ssh_host="bastion+host3"
host4               ansible_ssh_host="bastion+host4"

Update — I’ve since been informed that the ansible_ssh_host directive also works on a per-hostgroup basis, too! So don’t worry if you have hundreds of hosts!

5. Test it out! I set up authentication with ssh-agent first.

My playbook connects to each server in turn and returns its hostname. The very fact that I can connect successfully to host3 and host4 means that I’ve succeeded. On my network, these hosts live in a separate network, firewalled off from everything else.

Anyways, I hope that this helps somebody out.