Ansible with jump host

Welcome

Long time no sea. It's not a typo last time when I saw the see was in September in Greece. Almost the same thing I can say about Ansible. The last time when I used this tool for resolving real problems was more-less 2years ago. To be honest, during this period Ansible becomes (in my mind at least) just another boring and old-fashioned tool. Who is using Ansible if we have containers, Kubernetes Engines and Serverless? Only boring people. However, do you know who does not use Ansible? People without personal life or interesting problem to solve. I'm boring...

Problem

As you can assume I'm not an Ansible uber-master, I know most of the bases, but still, sometimes I stuck with some small, hidden option or strange use case a bit too long. That will be one of this use-case. Run Ansible through jump server.

Scenario

I have a VM. Brand new and fresh machine with some awesome hardware - let's say GPU monster for machine learning processes. It's based in some office. No static IP. I can connect to this machine via SSH Tunneling through another machine. How to make the connection easier?

SSH config

If You wondering why Linux user don't use tools like MobaXterm, ~/.ssh/config is the answer. Basic config will looks like that:

1Host test-3sky-dev
2    # test, Suse
3    HostName 3.22.11.33
4    User kuba
5    Port 31
6    IdentityFile ~/.ssh/id_rsa_xy

With that I can only type ssh test-3sky-dev and buum I'm on my test VM. Cool.

Add jump host

For our case let's assume that I can access monster-3sky-dev only from test-3sky-dev. How to do that? Another simple example.

 1Host test-3sky-dev
 2    # test, Suse
 3    HostName 3.22.11.33
 4    User kuba
 5    Port 31
 6    IdentityFile ~/.ssh/id_rsa_xy
 7
 8Host monster-3sky-dev
 9    # prod, ubuntu
10   HostName 12.22.11.33
11   User kuba
12   Port 45
13   ProxyJump test-3sky-dev

Authentication

I like to avoid password authentication so, let's use ssh-copy-id

1# on test-3sky-dev machine
2ssh-keygen -t rsa -b 4096 -C "test-3sky-dev"
3ssh-copy-id -i ~/.ssh/id_rsa_yx.pub kuba@12.22.11.33 -p 45

And configure `~/.ssh/config` on my jump station

1Host monster-3sky-dev
2   HostName 12.22.11.33
3   User kuba
4   Port 45
5   IdentityFile ~/.ssh/id_rsa_yx

Finally

Just run from my workstation - sweet.

1ssh monster-3sky-dev

Implementation

As you can see I can connect to VM via SSH Tunneling, it was simple and rather fast. Now integration with Ansible. Let's write some super simple playbook, like:

 1---
 2- name: ADD NEW USER
 3  gather_facts: false
 4  user: kuba
 5  hosts: monster-3sky-dev
 6  become: yes
 7  vars:
 8    user: "adam"
 9
10  tasks:
11    - name: Ensure group "{{ user }}" exists
12      ansible.builtin.group:
13        name: "{{ user }}"
14        state: present
15
16    - name: Add the user "{{ user }}"
17      ansible.builtin.user:
18        name: "{{ user }}"
19        shell: /bin/bash
20        groups:
21          - "{{ user }}"
22          - docker
23        append: yes
24        home: /home/{{ user }}
25        password: "{{ 'password' | password_hash('sha512') }}"
26        update_password: on_create
27
28    - name: Creat home dirs
29      ansible.builtin.file:
30        path: "{{ item }}"
31        state: directory
32        mode: '0755'
33        owner: "{{ user }}"
34        group: "{{ user }}"
35      loop:
36        - /home/{{ user }}
37        - /home/{{ user }}/bin
38        - /home/{{ user }}/tools

Now I need to provide only differences between normal host, and host behind the firewall.

Look on my inventory file:

1[gpu]
2monster-3sky-dev ansible_python_interpreter=/usr/bin/python3

There is no IP. And that's the point. While executing the ansible-playbook command I need to specify one environment variable - ANSIBLE_SSH_ARGS. And that is how it looks:

1ANSIBLE_SSH_ARGS="-F /home/kuba/.ssh/config" ansible monster-3sky-dev -m ping -i host.ini
2monster-3sky-dev | SUCCESS => {
3    "changed": false,
4    "ping": "pong"
5}

One important thing. Hostname from inventory file needs to match with Host from `.ssh/config` file.

How to run a playbook? In the almost same way.

1ANSIBLE_SSH_ARGS="-F /home/kuba/.ssh/config" ansible-playbook add_users/add_user.yaml -i host.ini

Summary

OK, so that is it. Nothing very fancy, but It takes me a while to find the right solution for me. Also is one of these things which are worth working with. No more need to googling the solution I have it here. This article was written in org-mode, then converted into Hugo MD file. That was an interesting adventure, especially when Emacs become my main tool as I said. Ah and OpenSuse. Recently I had some issue with Fedora related to dns-resolver. Since the beginning of March, I'm a happy user of OpenSuse Tumbleweed and I need to say it's an awesome distro. Something between Archlinux(it's rolling release system) and Fedora(easy to use, and stable). Maybe some longe review? I'm not sure, but until now I'm super happy with SUSE.