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.
Just use
ansible_ssh_common_args='-J bastion,server1'
Related
I have two different machines I can connect to in SSH, using a corporate VPN and proxy.
For that, my ~/.ssh/config has two hosts defined like this:
Host foobar
User alice
HostName XXX.XXX.XXX.XXX
ProxyCommand nc -x proxy-socks.foobar.com:4242 %h %p
The ProxyCommand is identical for both hosts, only the HostName and User are different. Each host has my public key, I can connect to each one simply by typing ssh foobar, no password is asked.
Now, I tried to use ansible to act on these machines. I have an inventory.cfg like that listing the name of both machines as defined in my ~/.ssh/config:
[vpn]
foobar
barfoo
I tried this simple command:
ansible -i inventory.cfg vpn -m ping
This worked for one of the machines, but not the other. Here is the redacted output:
foobar | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
barfoo | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Welcome on barfoo [...] Permission denied (keyboard-interactive).",
"unreachable": true
}
Since I got the "welcome" message from the host in the output, it means that I did reach the host (so the proxy configuration should be ok).
But I cannot understand the error "Permission denied (keyboard-interactive).". I can connect to this machine by SSH without password (in fact, the admins even disabled password authentication, I had to send them my public key by e-mail).
I tried to explicitely specify my SSH key by adding --private-key $HOME/.ssh/id_rsa, but the error message was exactly the same.
By curiosity, I tried with Python's package fabric, but this worked fine for both machines:
import fabric
fabric.Connection('barfoo').run('hostname')
So it seems there is something weird going on between ansible and this machine configuration. Any clue?
EDIT
Using the advice from #GeralexGR, I added -vvvv in my ansible command to have more output.
In the output, I could see that ansible is making this call to SSH :
ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/home/alice/.ansible/cp/dbd7338475"' barfoo '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''
By trial and error, I could reduce this command to this one :
ssh -vvv -o PreferredAuthentications=publickey barfoo 'hostname'
This command fails on one machine but not the other. However, if I remove the PreferredAuthentications option, it works fine with both machines.
When it fails, it outputs something like that:
debug1: Next authentication method: publickey
debug1: Offering public key: [...]
[...]
debug1: Server accepts key: [...]
[...]
Authenticated with partial success.
debug1: Authentications that can continue: keyboard-interactive
debug3: start over, passed a different list keyboard-interactive
debug3: preferred publickey
debug1: No more authentication methods to try.
If I remove this option and do a simple ssh -vvvv, I get this in the output:
debug1: Next authentication method: publickey
debug1: Offering public key: [...]
[...]
debug1: Server accepts key: [...]
[...]
Authenticated with partial success.
debug1: Authentications that can continue: keyboard-interactive
[...]
debug1: Next authentication method: keyboard-interactive
debug2: userauth_kbdint
[...]
debug1: Authentication succeeded (keyboard-interactive).
So, my guess is that keyboard-interactive is required for this machine. And indeed, if I put both publickey and keyboard-interactive in the option, this works:
ssh -vvv -o preferredauthentications=publickey,keyboard-interactive barfoo 'hostname'
So, back to ansible, I tried this:
ansible -vvvv --ssh-extra-args='-o preferredauthentications=publickey,keyboard-interactive' -i inventory.cfg -m ping vpn
But it still failed, I guess that this authentication mecanism is not possible with ansible? I am not sure why/how keyboard-interactive is needed here, since I am never prompted for a password. I will ask the admins of the machine.
The solution was kindly given by #Zeitounator in comments.
I added these two lines in my inventory.cfg file (with a dummy password):
[vpn:vars]
ansible_ssh_pass=foo
Now the initial ansible command works well.
Alternatively, using the --ask-pass option on the command line works as well:
ansible --ask-pass -i inventory.cfg -m ping vpn
For the context I asked a bit more information to the admins of the machine. This machine does not ask me for a password or anything, however, it asks to some external users (not me) to accept some terms and conditions. This is why the keyboard-interactive mechanism is needed.
Duo requires keyboard-interactive authentication, but ansible turned it off by -o KbdInteractiveAuthentication=no as seen from the ansible -vvv output as shown in the original post. I added ssh_args -o KbdInteractiveAuthentication=yes in ansible.cfg:
ssh_args = -o PreferredAuthentications=publickey,keyboard-interactive -o ControlMaster=auto -o ControlPersist=300s -o KbdInteractiveAuthentication=yes
and now it works fine.
I have a machine that is accessible through a jump host.
What I need is this.
A is my local machine
B is the jump host
C is the destination machine
I need to connect to C using ansible via B but use a private key in B.
Current config is the inventory file is as shown below
[deployment_host:vars]
ansible_port = 22 # remote host port
ansible_user = <user_to_the_Target_machine> # remote user host
private_key_file = <key file to bastion in my laptop> # laptop key to login to bastion host
ansible_ssh_common_args='-o StrictHostKeyChecking=no -o ProxyCommand="ssh -o \'ForwardAgent yes\' <user>#<bastion> -p 2222 \'ssh-add /home/<user>/.ssh/id_rsa && nc %h 22\'"'
[deployment_host]
10.200.120.218 ansible_ssh_port=22 ansible_ssh_extra_args='-o StrictHostKeyChecking=no'
How can I do that
I have not made any changes to my ssh config and when i run ansible like below
ansible -vvv all -i inventory.ini -m shell -a 'hostname'
I get this error
ansible 2.9.0
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.9/dist-packages/ansible
executable location = /usr/local/bin/ansible
python version = 3.9.5 (default, May 11 2021, 08:20:37) [GCC 10.3.0]
No config file found; using defaults
host_list declined parsing /root/temp_ansible/inventory.ini as it did not pass its verify_file() method
script declined parsing /root/temp_ansible/inventory.ini as it did not pass its verify_file() method
auto declined parsing /root/temp_ansible/inventory.ini as it did not pass its verify_file() method
yaml declined parsing /root/temp_ansible/inventory.ini as it did not pass its verify_file() method
Parsed /root/temp_ansible/inventory.ini inventory source with ini plugin
META: ran handlers
<10.200.120.218> ESTABLISH SSH CONNECTION FOR USER: <user> # remote user host
<10.200.120.218> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="<user> # remote user host"' -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o 'ProxyCommand=ssh -o '"'"'ForwardAgent yes'"'"' <user>#35.223.214.105 -p 2222 '"'"'ssh-add /home/<user>/.ssh/id_rsa && nc %h 22'"'"'' -o StrictHostKeyChecking=no -o ControlPath=/root/.ansible/cp/ec0480070b 10.200.120.218 '/bin/sh -c '"'"'echo '"'"'"'"'"'"'"'"'~<user> # remote user host'"'"'"'"'"'"'"'"' && sleep 0'"'"''
<10.200.120.218> (255, b'', b'kex_exchange_identification: Connection closed by remote host\r\nConnection closed by UNKNOWN port 65535\r\n')
10.200.120.218 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: kex_exchange_identification: Connection closed by remote host\r\nConnection closed by UNKNOWN port 65535",
"unreachable": true
}
I figured out the solution.
For me this was
adding both entries of my server A and B into the ~/.ssh/config
Host bastion1
HostName <IP/FQDN>
StrictHostKeyChecking no
User <USER>
IdentityFile <File to log into the first bastion server> # should be present in your local machine.
Host bastion2
HostName <IP/FQDN>
StrictHostKeyChecking no
User <USER>
IdentityFile <File to log into the second bastion server> # should be present in your local machine.
ProxyJump bastion
Then editing the inventory file like shown below.
[deployment_host]
VM_IP ansible_user=<vm_user> ansible_ssh_extra_args='-o StrictHostKeyChecking=no' ansible_ssh_private_key_file=<file to login to VM>
[deployment_host:vars]
ansible_ssh_common_args='-J bastion1,bastion2'
Then any ansible command with this inventory should work without issue
❯ ansible all -i inventory.ini -m shell -a "hostname"
<VM_IP> | CHANGED | rc=0 >>
development-host-1
NOTE: All these ssh keys should be in your local system. You can get
the bastion2 private key from bastion1 using ansible and the same for
the VM from bastion2 using ansible ad-hoc fetch
Remote ssh connection not working with Solaris 11.4.29 with "-o PreferredAuthentications=password" argument, while the same works fine without it.
ssh -2 -vvv -l - works
ssh -2 -vvv -l -o PreferredAuthentications=password - doesn't work
From any Linux server when below command is executed to remote Solaris 11.4.29 :
ssh -2 -vvv -l -o PreferredAuthentications=password - doesn't work
Verbose messages -
debug1: PAM: setting PAM_TTY to "ssh"
debug1: PAM: password authentication failed for : Authentication failed
I have an ec2 amazon linux running which I can ssh in to using:
ssh -i "keypair.pem" ec2-user#some-ip.eu-west-1.compute.amazonaws.com
but when I try to ping the server using ansible I get:
testserver | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh.",
"unreachable": true
}
I'm using the following hosts file:
testserver ansible_ssh_host=some-ip.eu-west-1.compute.amazonaws.com ansible_ssh_user=ec2-user ansible_ssh_private_key_file=/Users/me/playbook/key-pair.pem
and running the following command to run ansible:
ansible testserver -i hosts -m ping -vvvvv
The output is:
<some-ip.eu-west-1.compute.amazonaws.com> ESTABLISH SSH CONNECTION FOR USER: ec2-user
<some-ip.eu-west-1.compute.amazonaws.com> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<some-ip.eu-west-1.compute.amazonaws.com> SSH: ANSIBLE_PRIVATE_KEY_FILE/private_key_file/ansible_ssh_private_key_file set: (-o)(IdentityFile="/Users/me/playbook/key-pair.pem")
<some-ip.eu-west-1.compute.amazonaws.com> SSH: ansible_password/ansible_ssh_pass not set: (-o)(KbdInteractiveAuthentication=no)(-o)(PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey)(-o)(PasswordAuthentication=no)
<some-ip.eu-west-1.compute.amazonaws.com> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=ec2-user)
<some-ip.eu-west-1.compute.amazonaws.com> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<some-ip.eu-west-1.compute.amazonaws.com> SSH: PlayContext set ssh_common_args: ()
<some-ip.eu-west-1.compute.amazonaws.com> SSH: PlayContext set ssh_extra_args: ()
<some-ip.eu-west-1.compute.amazonaws.com> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=/Users/me/.ansible/cp/ansible-ssh-%h-%p-%r)
<some-ip.eu-west-1.compute.amazonaws.com> SSH: EXEC ssh -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile="/Users/me/playbook/key-pair.pem"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ec2-user -o ConnectTimeout=10 -o ControlPath=/Users/me/.ansible/cp/ansible-ssh-%h-%p-%r ec2-52-18-106-35.eu-west-1.compute.amazonaws.com '/bin/sh -c '"'"'( umask 22 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1462096401.65-214839021792201 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1462096401.65-214839021792201 `" )'"'"''
testserver | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh.",
"unreachable": true
}
What am i doing wrong?
Try this Solution it worked fine for me
ansible ipaddress -m ping -i inventory -u ec2-user
where inventory is the host file name.
inventory :
[host]
xx.xx.xx.xx
[host:vars]
ansible_user=ec2-user
ansible_ssh_private_key_file=/location of your pem file/filename.pem
I was facing the problem as I didn't give the location of the host file I was referring to.
This is what my host file looks like.
[apache] is the group of hosts on which we are going to install apache server.
ansible_ssh_private_key_file should be the path of the dowloaded .pem file to access your instances. In my case both instances have same credentials.
[apache]
50.112.133.205 ansible_ssh_user=ubuntu
54.202.7.87 ansible_ssh_user=ubuntu
[apache:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=/home/hashimyousaf/Desktop/hashim_key_oregon.pem
I was having a similar problem, and reading throughTroubleshooting Connecting to Your Instance helped me. Specifically, I was pinging an Ubuntu instance from an Amazon-Linux instance but forgot to change the connection username from "ec2-user" to "ubuntu"!
You have to change the hosts file and make sure you have the correct username
test2 ansible_ssh_host=something.something.eu-west-1.compute.amazonaws.com ansible_ssh_user=theUser
'test2' - is the name I have give to the ssh machice on my local ansible hosts file
'ansible_ssh_host=something.something.eu-west-1.compute.amazonaws.com' - This is the connection to the ec2 instance
'ansible_ssh_user=theUser' - The user of the instance. (Important)
'ssh' into your instance
[theUser#Instance:] make sure you copy the 'theUser' into the hosts and place as the 'ansible_ssh_user' variable
then try to ping it.
If this does not work, check if you have rights to the ICMP packeting in the amazon aws enabled.
Worked for me ->
vi inventory
[hosts]
serveripaddress ansible_ssh_user=ec2-user
[hosts:vars]
ansible_user=ec2-user
ansible_ssh_private_key_file=/home/someuser/ansible1.pem
chmod 400 ansible1.pem
ansible -i inventory hosts -m ping -u ec2-user
I'm unsuccessfully trying to use SSH ProxyCommand to connect to a server via a jump box. My config is below, I'm running this command:
ssh 10.0.2.54 -F ssh.config -vv
Host x.x.x.x
User ec2-user
HostName x.x.x.x
ProxyCommand none
IdentityFile /Users/me/.ssh/keys.pem
BatchMode yes
PasswordAuthentication no
Host *
ServerAliveInterval 60
TCPKeepAlive yes
ProxyCommand ssh -W %h:%p -q ec2-user#x.x.x.x
ControlMaster auto
ControlPersist 8h
User ec2-user
IdentityFile /Users/me/.ssh/keys.pem
The result is:
OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011
debug1: Reading configuration data ssh.config
debug1: ssh.config line 9: Applying options for *
debug1: auto-mux: Trying existing master
debug1: Control socket "/Users/me/.ssh/mux-ec2-user#10.0.2.54:22" does not exist
debug2: ssh_connect: needpriv 0
debug1: Executing proxy command: exec ssh -W 10.0.2.54:22 -q ec2-user#x.x.x.x
debug1: identity file /Users/me/.ssh/keys.pem type -1
debug1: identity file /Users/me/.ssh/keys.pem-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.2
debug1: permanently_drop_suid: 501
How can I get this to work/troubleshoot the issue?
Thanks,
ControlPersist in combination with ProxyCommand is not effective and you miss ControlPath option. But it is not a problem here.
First of all, if you are using non-standard config file and you want it to be used even by the proxy command, you need to specify it even there. The -q option makes the connection quiet so you have no idea what is going on under the hood of the proxy command. LogLevel DEBUG3 option is quite useful.
This line:
ProxyCommand ssh -W %h:%p -q ec2-user#x.x.x.x
needs to be (and you don't need the username as it is already specified above):
ProxyCommand ssh -W %h:%p -F ssh.config x.x.x.x
You have also wrong order of parameters in your command:
ssh 10.0.2.54 -F ssh.config -vv
needs to be:
ssh -F ssh.config 10.0.2.54
as you can read from manual page. And -vv is not needed if you use LogLevel option.
Then it should work for you (at least it did for me, otherwise investigate the log).