Ich hatte schon erwähnt, dass ich gather_facts meistens abschalte, um Playbooks zu beschleunigen. Für diesen Tutorialteil schalte ich es ein, um zu zeigen, was es macht.
1 | Einführung |
---|---|
2 | Das Inventory |
3 | Über Rollen und Tasks |
4 | Die Module |
5 | Playbooks |
6 | Konfiguration |
7 | gather_facts |
8 | eigene Module |
gather_facts
Mit Hilfe der Variable gather_facts an einem Task sammelt Ansible so viel Informationen über den Managed Node wie möglich. Auf diese kann ein Task dann reagieren. Beispielsweise kann ein Task abhängig vom eingesetzten Betriebssystem auf dem Managed Node gestartet werden.
Task
Zunächst bauen wir uns einen Task roles/gather_facts/task/main.yml
, um die Facts des Managed Hosts zu sammeln und auszugeben. Für die Ausgabe benutzen wir das eingebaute Debug Modul ansible.builtin.debug
- name: Informationen sammeln
ansible.builtin.debug:
var: ansible_facts
Der Task ist sehr übersichtlich, er sammelt lediglich alle Informationen und gibt das Dictionary in der Shell aus. Das Dictionary ist ziemlich umfangreich, so dass ich nicht komplett hier aufliste. Im Repository habe ich die Files facts_brandine
und facts_quimby
abgelegt.
Playbook
Das Playbook gather_facts.yml
hat nur die Aufgabe, den oben stehenden Task abzuarbeiten.
- hosts: "{{ target }}"
gather_facts: true
remote_user: pi
roles:
- gather-facts
nützliche Informationen
In dem Dictionary gibt viele interessante Informationen , aber auch einige, deren Sinn mir nicht ganz erschließen.
lsb
lsb ist die Linux Standard Base, die verschiedene standardisierte Informationen zu einem Linux System fest schreibt. In dem Sub-Dictionary finde ich folgende Keys:
"lsb": {
"codename": "bookworm",
"description": "Raspbian GNU/Linux 12 (bookworm)",
"id": "Raspbian",
"major_release": "12",
"release": "12"
},
codename
ist der informelle Name des Betriebssystems hier bookworm für ein Debian 12 Systemdescription
enthält genauere Informationen zur Distribution. es ist ein Raspberry Pi OS (raspian
), dass ich auf Debian 12 geupgraded habe.- id ist einfach nur der Name der Distribution
major_release
enthält die Versionsnummer der Distribution (hier 12 für bookworm)release
ist hier mitmajor_release
identisch.
Diese Schlüssel kannst du in einem Play abfragen und so gezielt reagieren. Wie das geht, zeige ich die später. Bei meinem DietPi Raspi ist das lsb
Dictionary übrigens leer, da DietPi die Linux Standard Base nicht unterstützt.
iP-Adressen
Interessant finde ich diese Informationen:
"all_ipv4_addresses": [
"172.17.0.1",
"169.254.175.171",
"169.254.6.113",
"192.168.178.30",
"169.254.119.46",
"169.254.182.8",
"10.42.0.0",
"169.254.34.128",
"169.254.73.186",
"10.42.0.1"
],
Hier sind alle IP-Adressen aufgelistet, die der Raspi aktuell benutzt. Normalerweise würde hier nur eine IP stehen, da aber Docker virtuelle Netzwerke aufbaut, haben diese auch eigene Schnittstellen mit eigenen IP-Adressen.Die Namen der Netzwerk-Schnitstellen können wir auch abfragen:
"interfaces": [
"vethb296f487",
"veth2f4e591d",
"eth0",
"lo",
"veth752b092e",
"flannel.1",
"vethe0bacd3f",
"veth2d169caf",
"docker0",
"wlan0",
"cni0"
],
env
Ansible macht genau so das gleiche wie du, wenn du dich mit ssh einloggst und folglich wird dann auch eine Shell mit all ihren Umgebungsvariablen gestartet. Diese sind Sub-Dictionary env
vermerkt. Ich habe das ein wenig gekürzt, um es übersichtlich zu halten. Die meisten Variablen wirst du vermutlich eh schon kennen.
"env": {
"HOME": "/home/pi",
"LANG": "C",
"LC_ALL": "C",
"LC_NUMERIC": "C",
"LOGNAME": "pi",
"MOTD_SHOWN": "pam",
"PATH": "/usr/local/bin:/usr/bin:/bin:/usr/games",
"PWD": "/home/pi",
"SHELL": "/bin/bash",
"SSH_CLIENT": "192.168.178.104 33962 22",
"SSH_CONNECTION": "192.168.178.104 33962 192.168.178.30 22",
"SSH_TTY": "/dev/pts/0",
PWD
– das aktuelle Arbeitsverzeichnis, nach dem Login immer das Homeverzeichnis des Users.SSH_CLIENT
– IP von der aus sich eingeloggt wurde192.168.178.104
, den Port zum Control Node33962
und ssh-Port auf dem Managed Node22
.- SHELL – Der Pfad der aufgerufenen Shell
LOGNAME
– Username
globale Informationen
Viele Daten sind dem Hauptdictionary zugeordnet. Eine Auswahl davon kopiere ich hier mal zusammen.
"hostname": "brandine",
"kernel": "5.10.103-v8+",
"kernel_version": "#1529 SMP PREEMPT Tue Mar 8 12:26:46 GMT 2022",
"memtotal_mb": 7862,
"uptime_seconds": 1653888,
"architecture": "aarch64",
"bios_date": "",
"bios_vendor": "",
"bios_version": "",
hostname
– Der Hostname des Nodesarchitecure
– Die Architektur des Managed Hosts aarch64 ist ein 64bit ARM Systemkernel
– Die Versionsnummer des gestarteten Kernelskernel_version
– Die Build-Informationen des Kernels. Wieuname -a
memtoal_mb
– Der insgesamt verfügbare Hauptspeicher des Raspis. Hier 8GBuptime_seconds
– Die Zeit, die der Node läuft in Sekundenbios_*
– Informationen zum BIOS des Rechners , hier leer, da der Raspi kein BIOS besitzt.
Einige der gesammelten Fakten sind meiner Meinung nach sicherheitsrelevant. Mit Informationen über BIOS und Kernelversion kann ein Angreifer Schwachstellen gezielt ausnutzen.
Auf Variablen reagieren.
Die Informationen werden nicht zum Selbstzweck für das Ansiblesystem gesammelt, du kannst sie abfragen und damit konditionale Tasks schreiben.
Du erinnerst dich an die Zeile
var: ansible_facts
Damit werden weist gather_facts das Dictionary der Variable gather_facts
zu. Schauen wir mal, was mir damit anfangen können.
Ich erweitere die gather_facts Rolle um einen zusätzlichen Task, der mir nur auf brandine und kirk eine leere Datei namens testwhen
im Homeverzeichnis anlegen soll:
- name: leeres File anlegen
file:
path: /home/pi/testwhen
state: touch
when: (ansible_facts['hostname'] == 'brandine' or ansible_facts['hostname'] == 'kirk')
Mit dem Schlüsselwort whe
n bekommt der Task eine Bedingung, so dass er nur ausgelöst wird, wenn der darin enthaltene Ausdruck wahr ist. Mit ansible_facts['hostname']
greifen wir im Dictionary auf den Wert von hostname
zu und vergleichen ==
mit 'brandine'
oder or 'kirk'
. Nur, wenn hostname
einen der beiden Werte hat, wird der Task überhaupt ausgeführt ansonsten ignoriert. Wichtig ist, dass der zweite Task unter dem gather_facts in der main.yml steht, da das Dictionary natürlich erst gefüllt werden muss, bevor du es benutzen kannst.
Der Lauf des Playbooks liefert jetzt folgende Zusammenfassung:
Mit den Informationen, die dir gather_facts
liefert, bist du in der Lage, Tasks zu schreiben, die z.B. bei verschiedenen Betriebssystemen unterschiedlich reagieren.
Im nächsten Teil wollen wir ein eigenes Modul für Ansible schreiben.