Dies ist eine alte Version des Dokuments!
Ansible - erweiterte Konfigurationsbeispiele: Ansible-Controll-Node und SSH-Jumphosts
Ausgangssituation
In verteilten und getrennten Netz(werk)umgebungen ist es sehr oft nicht ohne Aufwand möglich zu Administrations- und Orchestrierungsaufgaben alle Hosts zu erreichen.
Schauen wir uns hierzu einfach mal nachstehende exemplarische Skizze an.
Von der Admin-Workstation bzw. dem Ansible-Controll-Node aus, wollen wir nun nicht nur zum nächstgelegenen Host erreichen, sondern auch zum übernächsten oder gar zu einem Host im Internet, den wir aber aus Sicherheitsgründen nicht direkt erreichen dürfen und auch können.
Die Komfortabelste Variante ist nun die Nutzung der Option ProxyCommand. Bei „nur“ einem Jump-Host kann man dies im Inventory noch recht bequem und einfach abbilden. Weitaus schwieriger wird die Sache, bei Umgebungen, bei denen mehrere Jumphost beteiligt sind. Hier bietet es sich an, die SSH-Client Konfiguration des Ansible Control- bzw Admin-Users zu verwenden!
Weitaus einfacher gestaltet sich o.g. Szenario in dem man auf die SSH-Clientkonfigurationsdatei ~/.ssh/config
zurückgreift. Nachfolgendes Beispiel zeigt exemplarisch solch eine Clientspezifische Konfigurationsdatei:
$ vim ~/.ssh/config
- ~/.ssh/config
# Default Werte Host * Port 22 Protocol 2 user admin # Django : 2012-06-13 # ssh-jumps über mehrere Sprunghosts # Erster Sprunghost (fwc) - direkt erreichbar # Host --> fwc Host fwc Hostname firewall-c.idmz.nausch.org IdentityFile ~/.ssh/id_ed25519_idmz # Zweiter Sprunghost (fwb) - nur über fwc erreichbar # Host --> fwc --> fwb Host fwb Hostname firewall-b.edmz.nausch.org IdentityFile ~/.ssh/id_ed25519_edmz ProxyCommand ssh -A -q -W %h:%p fwc # Dritter Sprunghost (fwa) - nur über fwb erreichbar # Host --> fwc --> fwb --> fwa Host fwa Hostname firewall-a.nausch.org Port 22222 user sysadmin IdentityFile ~/.ssh/id_ed25519_edmz ProxyCommand ssh -A -q -W %h:%p fwc # externer Server im Internet nur über externe Firewall "A" erreichbar # also: Host --> fwc --> fwb --> fwa --> daxie Host s1u7 Hostname <was-das-auch-immer-für-ein geiler-FQDN-sein-mag> Port 42422 user n3rd IdentityFile ~/.ssh/id_ed25519_n3rd ProxyCommand ssh -A -q -W %h:%p fwa
Nun können wir ganz einfach direkt einen Tunnel zu unserem Zielhost aufspannen, genauso also würden wir den Zielhost direkt „sehen“.
$ ssh fwa
Auch können wir nun ohne grossen Aufwand Dateien von einem Ende zum anderen Ende kopieren bzw. Ansible dies ermöglichen.
$ scp ~/Downloads/enigmail-1.4-sm+tb.xpi 51u7:/tmp/
$ scp 51u7:/home/8483/51lv14/04x.png .
Somit ist natürlich auch Ansible in der Lage die definierten Zielhost aus dem Inventory ohne Probleme zu erreichen, da hier die SSH-Client-Konfiguration unseres Admin-Accounts auf unserem Ansible-Controll-Node verwendet wird.
Die Pflege der Konfigurationsdatei ~/.ssh/config
überlassen wir nun natürlich nicht jedem Admin einzeln, da dies viel zu fehleranfällig bzw. zeitaufwändig wäre.
Die aktuelle SSH-Clientconfigurationsdatei auf Djangos-Ansible-Controll-Node hat immerhin eine stattliche Anzahl an Konfigurationszeilen, Bsp.:
$ cat ~/.ssh/config | wc -l
1860
Das will sicherlich niemand, auch wenn er noch so fleissig und gewissenhaft ist, per Hand erledigen!
Wir werden dies mit den Informationen aus dem zentral gepflegten Inventory und einem Ansible-Playbook bewerkstelligen. Somit ist sichergestellt, dass auf jedem Ansible-Controll-Node und jedem Admin die betreffende Datei zur Verfügung steht und somit die Ansible- Playbooks auch überall unter den gleichen (Labor-)Bedingungen laufen können!
Lösungsmöglichkeit
Grundsätzlich alle möglichen Konfigurationsoptionen zur SSH-Clientkonfiguration finden wir in der zugehörigen man-page.
$ man ssh_config
Sehen wir uns unsere bisher manuell gepflegte SSH-Clientkonfigurationsdatei mal etwas genauer an und blenden mal ggf. besondere Fälle mal aus, so stellen wir zwei Dinge fest.
Direkt erreichbare Hosts
Wenn wir uns einmal folgendes Beispiel betrachten, dann sehen wir folgende Dinge.
- ~/.ssh/config
... Host pml010003 Hostname 10.10.10.3 User django Port 22 Protocol 2 IdentityFile ~/.ssh/id_intranet ...
Wir haben demnach in Summe sechs gesetzte Parameter:
Host
: Kurzname (alias) über den das Ziel erreichbar ist,Hostname
: FQDN oder IP-Adresse des Ziels,User
: User der zum Verbinden benötigt wird,Port
: SSH-Port des Zielsystems,Protocol
: verwendetes SSH-Protokoll sowieIdentityFile
: Datei des SSH-Keys, der bei der Verbindung verwendet werden muss.
Hosts erreichbar nur via Jump-Host
Bei einem Host, den wir nicht direkt erreichen können, sondern lediglich über einen Jump-Host stellen wir fest dass wir hier einen Parameter mehr haben.
- ~/.ssh/config
... Host fwi Hostname 10.30.30.20 User django Port 22 Protocol 2 IdentityFile ~/.ssh/id_idmz ProxyCommand ssh -q -W %h:%p vml030020 Host fw3 Hostname 10.50.50.250 User django Port 10022 Protocol 2 IdentityFile ~/.ssh/id_edmz ProxyCommand ssh -q -W %h:%p fwi ...
Bei diesem Beispiel haben wir zwei Jumphost. Der erste Host fwi
kann nicht direkt, sondern nur über den Jump-Host vml030020
erreicht werden. Der zweite Jump-Host fw3
wiederum ist nur über den ersten Jump-Host fwi
erreichbar. Die entscheidende Konfigzeile ist dabei jeweils:
ProxyCommand ssh -q -W %h:%p <-Sprung-Host->
Der Wert <-Sprung-Host->
kennzeichnet nun, über welchen Jump-Host das Ziel erreichbar sein wird.
Zusätzlich zu den Parametern eines Standardhosts haben wir hier eine weitere Option ProxyCommand
, der Definition wie und über welchen Jump-Host das Ziel erreicht werden kann
lorem ipsum dolor sit amet