📜 ⬆️ ⬇️

Storing the ssh config in an ansible project and solving the tunnel problem when using the relative path

Ansible is an excellent server management tool. Together with git, it allows you to go into the paradigm of deploy as code with all the resulting charms, such as review of the code, merge (pull), change requests, and the like. This is especially true if the team is working on this, and not the only person.


In this light, it becomes obviously convenient to store the connection settings to the managed hosts directly in the same repository, in addition to the inventory / hosts file (it is generally better to bring it to some service like CMDBuild or similar ones). That is, if, say, the connection port or IP address on the host has changed, the rest of the team members should receive it when they next pull up the changes from the repository, and did not make every change in their ~ / .ssh / config file.


And most of the parameters will work properly without any effort, but not so simple if you want to use ssh-tunnels.
So, suppose we saved the config file in the inventory / ssh.config file.
It was prescribed basic connections and basic settings:


Host * IdentityFile /secret/id_rsa User wheel Host host.one HostName 1.2.3.4 User ant Host host.two HostName 2.3.4.5 Port 2022 

Well, and so on, everything is standard, as we usually write it in the user level config.


In ansible.cfg, it is proposed to specify its relative path using the -F option:


 ssh_args = -o ControlMaster=auto -o ControlPersist=60s -F inventory/ssh.config 

This will allow everyone to simply clone the repository and immediately start working without setting up their machine and access (of course, it’s worth taking private access keys somewhere, it’s not generally recommended to keep them here, although if you have private repositories, you can also consider) .


Most options will then work, however, if you try to use tunnels, something like this:


 Host organization.gateway HostName 1.2.3.4 Host inner.host HostName 2.3.4.5 ProxyCommand ssh organization.gateway -W %h:%p 

You will immediately receive an error that you can not connect to the host inner.host!


How so?
In fact, everything is simple. Ansible when connecting simply calls the ssh binary file, passes it the specified options. Next, here is a tunnel, for ssh it will fork and call the specified command as is. This can be nc by the word or port forwarding using iptables (firewalld). That is, no interpretation is made. And this means that the command will be called:


 ssh organization.gateway -W %h:%p 

And in general, ssh cannot establish a connection because it does not know what an organization.gateway is.


Of course, we could correct this situation by specifying the path to the file here:


 Host inner.host HostName 2.3.4.5 ProxyCommand ssh -F /path/to/same/ssh.config organization.gateway -W %h:%p 

This will work, but we did not want to be attached to the path on a specific machine, but rather to keep a file that is universal for all!
A partial solution to the problem will be an indication of the relative path, but only partially decides if you want to call ansible by an absolute path from another directory.


Since ssh does not provide any inheritance of configs, for bash (it should work in sh too, for others it is possible to slightly modify) we can simply emulate it:


 Host inner.host HostName 2.3.4.5 ProxyCommand ssh $( egrep -z -A1 '^-F$' /proc/$PPID/cmdline ) organization.gateway -W %h:%p 

All that we changed, put " $ (egrep -z -A1 '^ -F $' / proc / $ PPID / cmdline) " and all the magic will happen here. So this is just "the same config with which the main ssh process is called."


It works simply: for the spawned process, the value of the -F option is substituted, which is derived from the caller's options.


')

Source: https://habr.com/ru/post/307316/


All Articles