Simon Szustkowski

Ein Blog über alles, was mir gerade so durch den Kopf geht

Feb 20, 2015

Ansible SSH Bastion

Da mir die Administration aller Hosts, die von mir in irgeneiner Form immer zeitraubender wurde, habe ich mich entschieden, Ansible auch mal eine Chance zu geben. Damit das rund läuft, benötigt Ansible am besten key-basierte Authentifizierung und SSH-Zugriff auf die zu administrierenden Hosts. Dies war im großen und ganzen kein Problem für mich, bis auf die Hosts, die in meinem Heimnetz zu Hause beheimatet sind. Da dieses Netz noch nativ IPv4 basiert ist, und daher mit NAT arbeitet, hat es genau einen nach außen öffentlichen Host, nämlich meinen Router. Dieser Router hat in meinem Setup ein Portforwarding auf ein Jail in meinem Homeserver, auf das ich mich im Regelfall von außen einwähle, und von dort aus dann weiter in mein Netz vordringen kann.

In der Regel brauche ich dafür zwei SSH-Commands. Einmal um die Verbindung zum Jail aufzubauen, und noch einmal, um von dort aus fortzufahren. Ansible kommt aber mit dieser Konstellation nicht zurecht, und möchte sich direkt auf den Zielhost verbinden. Nur wie?

Eine Möglichkeit wäre, für jeden Host ein eigenes Portforwarding einzurichten. Würde funktionieren, wäre aber sehr blöd, weil meine Firewall dann löchrig wie ein Schweizer Käse wird, und die zusätzliche Sicherheit eines zweiten Logins bei manueller Einwahl wegfällt.

Eine andere Möglichkeit wäre, jeden Host über seine IPv6 öffentlich erreichbar zu machen. Allerdings fällt dann auch die Sicherheit eines zweiten Logins weg, und ich könnte Ansible nur von Steuerrechnern ausführen, die selbst IPv6 haben, was immer noch nicht wirklich alle möglichen Szenarien abdeckt.

Glücklicherweise gibt es in der OpenSSH-Config die Möglichkeit, SSH-Proxys zu konfigurieren, d.h. man baut die Verbindung auf den Proxy auf, und wird automatisch an den Zielhost weitergereicht. Das Stichwort, was ich hierzu fand, war SSH-Bastion. Es gibt hierzu eine Anleitung, wie bereits jemand anders dieses Problem gelöst hat. Dies erschien mir aber relativ komplex, weil es in meinem momentanen Setup erfordert, manche Hosts doppelt in der Config aufzuführen, sodass man je nach Namen der Verbindung andere Konfigurationen nutzen konnte, und alles. Weiterhin klappte das alles irgendwie überhaupt nicht. Die erforderlichen mux-Files wurden nicht angelegt, und Ansible produzierte lustigen roten Text, dass alles doof sei, und überhaupt mimimi.

Aber es geht auch einfacher. Viel einfacher. Ohne den ganzen ControlMaster-Kram. Es reicht, den Bastion-Host als Proxy in den Verbindungen der dahinterliegenden Hosts zu definieren. Sprich, meine SSH-Config sieht jetzt so aus:

Host bastion
HostName bastion.example.com
User mybastionuser
ServerAliveInterval 15

Host ansiblehost
User ansibleuser
HostName ansiblehost.inside.example.com
ProxyCommand ssh -W %h:%p bastion

Wichtig: Der HostName muss in einem Format angegeben sein, den der Bastion-Host auflösen kann. Wenn man keinen internen DNS hat, muss man dort also eine IP angeben.

Die in der oben verlinkten Anleitung erwähnten Änderungen in der ansible.cfg sind nicht nootwendig. Was allerdings notwendig ist: Der Public-SSH-Key des Steuerrechners muss sich sowohl am Bastion-Host als auch am Zielrechner authentifizieren dürfen.

Nun reicht es völlig aus, den Ansible-Host in die .ansible/hosts einzutragen, aber exakt so, wie man ihn in die Host-Direktive in der SSH-Config eingetragen hat.

Ein netter Seiteneffekt ist ebenfalls: Die in oben verlinkter Anleitung erwähnte extreme Verbosität von Ansible fällt weg. Es ist verbosig verbost mitteilungsfreudig wie gewohnt, und lässt sich mit -v gerne zur erhöhten Verbosität überreden.