How do I configure Ansible to jump through two bastion hosts?

Viewed 4146

I want to write an Ansible playbook (using Ansible 2.7.5) that will jump through two hosts before reaching the intended server to do things such as install docker and python, etc.

I'm able to get Ansible to jump through one host into server1 by adding this to my hosts file:

[server1:vars]
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q bastion"'

I have also updated my ~/.ssh/config file:

Host bastion
  Hostname YY.YY.YY.YY
  User user
  IdentityFile ~/.ssh/bastion_private_key

Host server1
  Hostname XX.XX.XX.XX
  User user
  IdentityFile ~/.ssh/private_key
  ProxyJump bastion

However, I now also need to do this through two hosts. I've added the following to ~/.ssh/config:

Host server2
  Hostname ZZ.ZZ.ZZ.ZZ
  User user
  IdentityFile ~/.ssh/private_key_3
  ProxyJump server1

This allows me to type ssh server2 and open a shell inside server2. So that seems to be working.

But, I do not know how to change the hosts file to jump through both of these hosts. I've tried:

ansible_ssh_common_args='-o ProxyCommand="ssh -J bastion,server1"'

and

ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q bastion ssh -W %h:%p -q server1"'

Neither work, and both result in a timeout. What should I do to make Ansible jump through bastion and then server1 so that it can reach server2?

This is the result when I run -vvvv (with some path and names obfuscated):

ansible-playbook 2.7.5
  config file = /path/to/dir/ansible.cfg
  configured module search path = [u'/home/user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 2.7.15rc1 (default, Nov 12 2018, 14:31:15) [GCC 7.3.0]
Using /path/to/dir/ansible.cfg as config file
setting up inventory plugins
/path/to/dir/hosts did not meet host_list requirements, check plugin documentation if this is unexpected
/path/to/dir/hosts did not meet script requirements, check plugin documentation if this is unexpected
/path/to/dir/hosts inventory source with ini plugin
 [WARNING]: Found both group and host with same name: server2

statically imported: /path/to/dir/tasks/ansible.yml
Loading callback plugin default of type stdout, v2.0 from /usr/lib/python2.7/dist-packages/ansible/plugins/callback/default.pyc

PLAYBOOK: enable-ansible.yml *********************************************************************************************************************************
1 plays in enable-ansible.yml

PLAY [server2] ****************************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************************
task path: /path/to/dir/enable-ansible.yml:2
<server2> ESTABLISH SSH CONNECTION FOR USER: ubuntu
<server2> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o 'ProxyCommand=ssh -W %h:%p -q bastion ssh -W %h:%p -q server1' -o ControlPath=/home/user/.ansible/cp/460e3f86d3 server2 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /tmp/ansible-tmp-1546192323.33-48994637286535 `" && echo ansible-tmp-1546192323.33-48994637286535="` echo /tmp/ansible-tmp-1546192323.33-48994637286535 `" ) && sleep 0'"'"''
<server2> (255, '', 'OpenSSH_7.6p1 Ubuntu-4ubuntu0.1, OpenSSL 1.0.2n  7 Dec 2017\r\ndebug1: Reading configuration data /home/user/.ssh/config\r\ndebug1: /home/user/.ssh/config line 70: Applying options for server2\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: /etc/ssh/ssh_config line 19: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug1: Control socket "/home/user/.ansible/cp/460e3f86d3" does not exist\r\ndebug1: Executing proxy command: exec ssh -W SERVER2_IP_ADDRESS:22 -q bastion ssh -W SERVER2_IP_ADDRESS:22 -q server1\r\ndebug3: timeout: 10000 ms remain after connect\r\ndebug1: key_load_public: No such file or directory\r\ndebug1: identity file /home/user/.ssh/bastion type -1\r\ndebug1: key_load_public: No such file or directory\r\ndebug1: identity file /home/user/.ssh/bastion-cert type -1\r\ndebug1: Local version string SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.1\r\ndebug1: permanently_drop_suid: 1000\r\nConnection timed out during banner exchange\r\n')
fatal: [server2]: UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: OpenSSH_7.6p1 Ubuntu-4ubuntu0.1, OpenSSL 1.0.2n  7 Dec 2017\r\ndebug1: Reading configuration data /home/user/.ssh/config\r\ndebug1: /home/user/.ssh/config line 70: Applying options for server2\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: /etc/ssh/ssh_config line 19: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug1: Control socket \"/home/user/.ansible/cp/460e3f86d3\" does not exist\r\ndebug1: Executing proxy command: exec ssh -W SERVER2_IP_ADDRESS:22 -q bastion ssh -W SERVER2_IP_ADDRESS:22 -q server1\r\ndebug3: timeout: 10000 ms remain after connect\r\ndebug1: key_load_public: No such file or directory\r\ndebug1: identity file /home/user/.ssh/bastion type -1\r\ndebug1: key_load_public: No such file or directory\r\ndebug1: identity file /home/user/.ssh/bastion-cert type -1\r\ndebug1: Local version string SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.1\r\ndebug1: permanently_drop_suid: 1000\r\nConnection timed out during banner exchange\r\n", 
    "unreachable": true
}
    to retry, use: --limit @/home/user/Documents/repos/cloud-devops/enable-ansible.retry

PLAY RECAP ***************************************************************************************************************************************************
server2                  : ok=0    changed=0    unreachable=1    failed=0 

For some added context, this playbook is logging into the remote server as a non-root account and creating the ansible user in it. And to reiterate, this playbook works when I am only jumping through one host.

1 Answers

Just use

ansible_ssh_common_args='-J bastion,server1'
Related