Ansible mit Rocky: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
 
(5 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
 
= Ansible auf Rocky Linux =
 
= Ansible auf Rocky Linux =
  
Ansible ist ein agentenloser Automatisierungsdienst: Es wird nur auf dem '''Control Node''' installiert, die verwalteten Maschinen ("Managed Nodes") brauchen lediglich SSH-Zugang und Python – kein Agent, kein zusätzlicher Dienst.
+
Ansible ist ein agentenloser Automatisierungsdienst: Es wird nur auf dem '''Control Node''' installiert, die verwalteten Maschinen ("Managed Nodes") brauchen lediglich SSH-Zugang und Python – kein Agent, kein zusätzlicher Dienst. Das unterscheidet Ansible von Werkzeugen wie Puppet oder Chef, die einen dauerhaft laufenden Agenten auf jedem Zielsystem voraussetzen.
  
Im Labor übernimmt '''client.it2XX.int''' die Rolle des Control Node und verwaltet von dort aus alle DMZ-Server (''fw'', ''ns'', ''www'', ''ldap''). Gearbeitet wird durchgehend als unprivilegierter User '''kit''' – root-Login ist auf allen Systemen deaktiviert, privilegierte Aktionen laufen über ''sudo''.
+
Im Labor übernimmt '''desktop.it2XX.int''' die Rolle des Control Node und verwaltet von dort aus die DMZ-Server (''fw'', ''ns'', ''www''; ''ldap'' und der Container folgen später als eigene Gruppe). Gearbeitet wird durchgehend als unprivilegierter User '''kit''' – root-Login ist auf allen Systemen deaktiviert, privilegierte Aktionen laufen über ''sudo''.
  
 
== Voraussetzungen ==
 
== Voraussetzungen ==
;Auf jedem Zielsystem muss ein kit-User mit passwortlosem sudo existieren
+
;Auf jedem Zielsystem muss ein kit-User mit passwortlosem sudo existieren. Ohne NOPASSWD würde Ansible bei jedem privilegierten Task nach einem sudo-Passwort fragen und den automatisierten Ablauf unterbrechen.
 
* sudo visudo
 
* sudo visudo
 
<pre>
 
<pre>
Zeile 13: Zeile 13:
  
 
= Installation des Control Node =
 
= Installation des Control Node =
;Ansible wird nur auf client.it2XX.int installiert
+
;Ansible wird ausschließlich auf desktop.it2XX.int installiert. Die Managed Nodes brauchen keine Ansible-Installation, nur SSH und Python – das ist der Kern des agentenlosen Modells.
 
* sudo dnf install -y ansible
 
* sudo dnf install -y ansible
  
 
= SSH-Schlüssel vorbereiten =
 
= SSH-Schlüssel vorbereiten =
;kit braucht auf dem Control Node einen eigenen Schlüssel, der auf allen Zielsystemen beim kit-User hinterlegt wird
+
;kit braucht auf dem Control Node einen eigenen SSH-Schlüssel, der auf allen Zielsystemen beim kit-User hinterlegt wird. Ansible nutzt diesen Schlüssel für jede Verbindung – ohne ihn müsste bei jedem Task ein Passwort eingegeben werden.
 
* ssh-keygen -t ed25519 -C "kit@it2XX.int"
 
* ssh-keygen -t ed25519 -C "kit@it2XX.int"
  
;Schlüssel als kit auf alle DMZ-Server verteilen – NICHT als root, da PermitRootLogin deaktiviert ist
+
;Schlüssel als kit auf die DMZ-Server verteilen – NICHT als root, da PermitRootLogin auf den Zielsystemen bereits deaktiviert ist. Ein Versuch mit root@... schlägt deshalb fehl, ssh-copy-id muss den tatsächlichen Verbindungsuser kit verwenden.
 
* ssh-copy-id kit@fw.it2XX.int
 
* ssh-copy-id kit@fw.it2XX.int
 
* ssh-copy-id kit@ns.it2XX.int
 
* ssh-copy-id kit@ns.it2XX.int
 
* ssh-copy-id kit@www.it2XX.int
 
* ssh-copy-id kit@www.it2XX.int
* ssh-copy-id kit@ldap.it2XX.int
 
  
 
= Projektverzeichnis und Inventory =
 
= Projektverzeichnis und Inventory =
;kit hat keine Schreibrechte auf /etc/ansible – deshalb arbeiten wir im Home-Verzeichnis statt mit sudo im systemweiten Pfad
+
;kit hat keine Schreibrechte auf /etc/ansible – deshalb arbeiten wir im Home-Verzeichnis statt mit sudo im systemweiten Pfad. Das vermeidet unnötige root-Eingriffe für reine Konfigurationsdateien.
 
* mkdir -p ~/ansible
 
* mkdir -p ~/ansible
 
* cd ~/ansible
 
* cd ~/ansible
  
;ansible.cfg legt fest, wo das Inventory liegt – dann ist kein -i-Parameter mehr nötig
+
;ansible.cfg legt fest, wo das Inventory liegt – dann ist kein -i-Parameter mehr nötig. Wichtig: Der relative Pfad ./hosts wirkt nur, wenn Ansible aus genau diesem Verzeichnis heraus aufgerufen wird; aus Unterverzeichnissen (z.B. roles/) wird die Datei nicht gefunden.
 
* vi ~/ansible/ansible.cfg
 
* vi ~/ansible/ansible.cfg
 
<pre>
 
<pre>
Zeile 38: Zeile 37:
 
</pre>
 
</pre>
  
;Inventory anlegen – Maschinen nach Rolle gruppiert, kit als Verbindungsuser, sudo für privilegierte Tasks
+
;Inventory anlegen – Maschinen nach Rolle gruppiert, kit als Verbindungsuser, sudo für privilegierte Tasks. Die dmz:vars-Sektion gilt für alle Hosts der Gruppe gleichzeitig, statt sie einzeln pro Host wiederholen zu müssen.
 
* vi ~/ansible/hosts
 
* vi ~/ansible/hosts
 
<pre>
 
<pre>
Zeile 45: Zeile 44:
 
ns.it2XX.int
 
ns.it2XX.int
 
www.it2XX.int
 
www.it2XX.int
ldap.it2XX.int
 
  
 
[dmz:vars]
 
[dmz:vars]
Zeile 54: Zeile 52:
  
 
= Erster Test =
 
= Erster Test =
;Alle Maschinen anpingen – Ansible nutzt dafür das ping-Modul, nicht ICMP
+
;Alle Maschinen anpingen – Ansible nutzt dafür das ping-Modul, nicht ICMP. Das Modul prüft, ob eine SSH-Verbindung inklusive Python-Interpreter auf der Gegenseite funktioniert, nicht nur ob der Host im Netzwerk erreichbar ist.
 
* ansible all -m ping
 
* ansible all -m ping
 
  ns.it2XX.int | SUCCESS => {
 
  ns.it2XX.int | SUCCESS => {
Zeile 61: Zeile 59:
 
  }
 
  }
  
;Verbindungsuser prüfen – muss kit sein, nicht root
 
* ansible dmz -m command -a "whoami"
 
  
;sudo-Rechte prüfen – mit -b (become) sollte root erscheinen
+
;sudo-Rechte prüfen – mit -b (become) sollte root erscheinen. Das bestätigt, dass ansible_become und das passwortlose sudo auf den Zielsystemen korrekt zusammenspielen.
 
* ansible dmz -b -m command -a "whoami"
 
* ansible dmz -b -m command -a "whoami"
  
;Ad-hoc Befehl auf allen Maschinen ausführen
+
;Ad-hoc Befehl auf allen Maschinen ausführen. Ad-hoc-Kommandos eignen sich für schnelle Einzelaktionen und Debugging, nicht für wiederholbare Konfiguration – dafür sind Playbooks gedacht.
 
* ansible all -m command -a "hostname"
 
* ansible all -m command -a "hostname"
  
;Nur die DMZ-Gruppe ansprechen
+
;Nur die DMZ-Gruppe ansprechen. Gruppenfilter im Inventory erlauben es, gezielt Teilmengen der Infrastruktur anzusprechen, statt immer alle Hosts zu treffen.
 
* ansible dmz -m command -a "uptime"
 
* ansible dmz -m command -a "uptime"
  
 
= Playbooks =
 
= Playbooks =
  
;Ein Playbook ist eine YAML-Datei, die Tasks in fester Reihenfolge auf einer Zielgruppe ausführt
+
;Ein Playbook ist eine YAML-Datei, die Tasks in fester Reihenfolge auf einer Zielgruppe ausführt. Im Gegensatz zu Ad-hoc-Befehlen sind Playbooks wiederholbar, versionierbar und dokumentieren den gewünschten Zielzustand.
;Einfaches Beispiel – Paket installieren und eine harmlose Testdatei anlegen, läuft dank ansible_become automatisch mit sudo. Nichts hiervon verändert bestehende Konfiguration.
+
;Einfaches Beispiel – Paket installieren und eine harmlose Testdatei anlegen, läuft dank ansible_become automatisch mit sudo. Nichts hiervon verändert bestehende Konfiguration, das Beispiel dient nur zum Kennenlernen der Playbook-Syntax.
 
* vi ~/ansible/test.yml
 
* vi ~/ansible/test.yml
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
Zeile 96: Zeile 92:
 
* ansible-playbook ~/ansible/test.yml
 
* ansible-playbook ~/ansible/test.yml
  
;Idempotenz zeigen – zweiter Lauf meldet "changed=0", da nichts mehr zu tun ist
+
;Idempotenz zeigen – zweiter Lauf meldet "changed=0", da nichts mehr zu tun ist. Das ist ein zentrales Ansible-Prinzip: Ein Playbook kann beliebig oft ausgeführt werden, ohne den Zielzustand erneut zu verändern.
 
* ansible-playbook ~/ansible/test.yml
 
* ansible-playbook ~/ansible/test.yml
  
;Ergebnis prüfen
+
;Ergebnis prüfen. Zeigt, dass die Testdatei tatsächlich mit dem korrekten Zeitstempel auf den Zielsystemen angekommen ist.
 
* ansible dmz -m command -a "cat /tmp/ansible-test.txt"
 
* ansible dmz -m command -a "cat /tmp/ansible-test.txt"
  
 
= Rollen =
 
= Rollen =
  
;Rollen sind wiederverwendbare Ansible-Strukturen – Tasks, Templates und Handler in einem festen Verzeichnisschema
+
;Rollen sind wiederverwendbare Ansible-Strukturen – Tasks, Templates und Handler in einem festen Verzeichnisschema. Das feste Schema erlaubt es Ansible, Dateien wie templates/sssd.conf.j2 automatisch zu finden, ohne dass der Pfad in jedem Task ausgeschrieben werden muss.
 
  roles/
 
  roles/
 
  └── rollenname/
 
  └── rollenname/
Zeile 115: Zeile 111:
 
         └── main.yml
 
         └── main.yml
  
;Rollengerüst automatisch erstellen
+
;ansible-galaxy ist das mit Ansible mitgelieferte CLI-Tool zum Verwalten von Rollen. Zwei Funktionen: (1) Skelett einer neuen Rolle generieren – das nutzen wir hier, (2) fertige Rollen von galaxy.ansible.com herunterladen – nicht Teil dieses Kurses, da die Rollen hier bewusst selbst geschrieben werden.
 +
;Rollengerüst automatisch erstellen – legt tasks/, handlers/, defaults/, templates/ mit leeren main.yml-Dateien an, die anschließend gefüllt werden.
 
* mkdir -p ~/ansible/roles
 
* mkdir -p ~/ansible/roles
 
* cd ~/ansible/roles
 
* cd ~/ansible/roles
 
* ansible-galaxy init sssd
 
* ansible-galaxy init sssd
* ansible-galaxy init ssh-hardening
 
  
 
= Rolle: SSSD =
 
= Rolle: SSSD =
  
;Diese Rolle installiert SSSD auf allen DMZ-Servern und bindet sie gegen den LDAP-Server an
+
;Diese Rolle installiert SSSD auf allen DMZ-Servern und bindet sie gegen den LDAP-Server an. Damit können sich Benutzer aus dem zentralen Verzeichnis auf jedem DMZ-Server anmelden, statt lokale Konten pro Host pflegen zu müssen.
  
 
== tasks/main.yml ==
 
== tasks/main.yml ==
 
* vi ~/ansible/roles/sssd/tasks/main.yml
 
* vi ~/ansible/roles/sssd/tasks/main.yml
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
 +
---
 
- name: Pakete installieren
 
- name: Pakete installieren
 
   dnf:
 
   dnf:
Zeile 165: Zeile 162:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
;Merksatz: sssd.conf definiert die Quelle (sudo_provider = ldap), nsswitch.conf entscheidet ob das System sie überhaupt befragt. Ohne den Eintrag in nsswitch.conf bleibt der sudo_provider wirkungslos.
+
;Merksatz: authselect generiert /etc/nsswitch.conf komplett neu aus dem gewählten Profil und aus /etc/authselect/user-nsswitch.conf – direkte Einträge in /etc/nsswitch.conf werden dabei überschrieben. Änderungen gehören deshalb in user-nsswitch.conf und werden über authselect apply-changes aktiv geschaltet. Reihenfolge zwingend: erst authselect select, danach den sudoers-Eintrag setzen – sonst wird er beim nächsten select wieder verworfen.
  
 
== templates/sssd.conf.j2 ==
 
== templates/sssd.conf.j2 ==
;Das Template nutzt Ansible-Variablen – so funktioniert dieselbe Rolle für jeden Studenten
+
;Das Template nutzt Ansible-Variablen – so funktioniert dieselbe Rolle für jeden Studenten, ohne den Code anzufassen. Nur defaults/main.yml oder group_vars müssen pro Umgebung angepasst werden.
 
* vi ~/ansible/roles/sssd/templates/sssd.conf.j2
 
* vi ~/ansible/roles/sssd/templates/sssd.conf.j2
 
<pre>
 
<pre>
Zeile 199: Zeile 196:
  
 
== handlers/main.yml ==
 
== handlers/main.yml ==
 +
;Handler laufen nur, wenn ein Task mit notify sie tatsächlich auslöst, und erst am Ende des Playbook-Durchlaufs. Das verhindert unnötige Neustarts von Diensten, wenn sich an der Konfiguration nichts geändert hat.
 
* vi ~/ansible/roles/sssd/handlers/main.yml
 
* vi ~/ansible/roles/sssd/handlers/main.yml
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
Zeile 206: Zeile 204:
 
     name: sssd
 
     name: sssd
 
     state: restarted
 
     state: restarted
 +
 +
- name: authselect anwenden
 +
  command: authselect apply-changes
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
== defaults/main.yml ==
 
== defaults/main.yml ==
;Standardwerte – werden durch group_vars oder host_vars überschrieben
+
;Standardwerte – werden durch group_vars oder host_vars überschrieben, ohne dass die Rolle selbst verändert werden muss. Das ist der Mechanismus, der dieselbe Rolle für unterschiedliche Studenten-Domains (it201, it202, ...) wiederverwendbar macht.
 
* vi ~/ansible/roles/sssd/defaults/main.yml
 
* vi ~/ansible/roles/sssd/defaults/main.yml
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
Zeile 219: Zeile 220:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
;Für den produktiven Einsatz: Passwort niemals im Klartext in defaults/main.yml – stattdessen mit ansible-vault verschlüsseln
+
;Für den produktiven Einsatz: Passwort niemals im Klartext in defaults/main.yml – stattdessen mit ansible-vault verschlüsseln. Im Kursumfeld mit Wegwerf-Passwörtern ist das Klartext-Passwort didaktisch vertretbar, in Produktion nicht.
 
* ansible-vault encrypt_string '123Start$' --name 'ldap_password'
 
* ansible-vault encrypt_string '123Start$' --name 'ldap_password'
  
 
= Playbook: DMZ ausrollen =
 
= Playbook: DMZ ausrollen =
  
;Ein Playbook, das beide Rollen nacheinander ausführt Tags erlauben es, sie einzeln zu testen
+
;Ein Playbook, das die Rolle auf die dmz-Gruppe anwendet der Tag sssd erlaubt es, sie gezielt einzeln auszuführen, statt immer das komplette Playbook zu starten.
 
* vi ~/ansible/dmz.yml
 
* vi ~/ansible/dmz.yml
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
Zeile 232: Zeile 233:
 
   roles:
 
   roles:
 
     - { role: sssd, tags: ['sssd'] }
 
     - { role: sssd, tags: ['sssd'] }
  </syntaxhighlight>
+
</syntaxhighlight>
  
;Zuerst nur SSSD ausrollen und testen
+
;SSSD ausrollen und testen.
 
* ansible-playbook ~/ansible/dmz.yml --tags sssd
 
* ansible-playbook ~/ansible/dmz.yml --tags sssd
  
 
+
;Dry-run – zeigt was sich ändern würde, ohne es anzuwenden. Nützlich um vor einem echten Lauf zu prüfen, welche Tasks als changed markiert würden.
;Dry-run – zeigt was sich ändern würde, ohne es anzuwenden
 
 
* ansible-playbook ~/ansible/dmz.yml --check
 
* ansible-playbook ~/ansible/dmz.yml --check
  
 
= Kontrolle =
 
= Kontrolle =
  
;SSSD auf einem Server prüfen
+
;SSSD auf einem Server prüfen. getent fragt über nsswitch.conf alle konfigurierten Quellen ab (hier: files und sss) – erscheint der Benutzer, funktioniert die LDAP-Anbindung.
 
* ansible ns.it2XX.int -m command -a "getent passwd thomas"
 
* ansible ns.it2XX.int -m command -a "getent passwd thomas"
  
;SSH-Konfiguration prüfen
+
;nsswitch.conf prüfen – sudoers-Zeile muss sss enthalten. Fehlt sie, liest das System keine sudo-Regeln aus LDAP, selbst wenn sssd.conf korrekt konfiguriert ist.
* ansible dmz -m command -a "grep PasswordAuthentication /etc/ssh/sshd_config"
 
 
 
;nsswitch.conf prüfen – sudoers-Zeile muss sss enthalten
 
 
* ansible dmz -m command -a "grep sudoers /etc/nsswitch.conf"
 
* ansible dmz -m command -a "grep sudoers /etc/nsswitch.conf"
  
;Alle Fakten eines Servers anzeigen – nützlich zur Fehlersuche
+
;Alle Fakten eines Servers anzeigen – nützlich zur Fehlersuche. Das setup-Modul liefert Systeminformationen (IP, OS, Hardware), auf die auch in Templates über Variablen wie ansible_date_time zugegriffen werden kann.
 
* ansible ns.it2XX.int -m setup
 
* ansible ns.it2XX.int -m setup
  
 
= Logs und Debugging =
 
= Logs und Debugging =
* journalctl -fu sshd
+
;-v, -vv und -vvv erhöhen die Ausgabe-Ausführlichkeit von ansible-playbook schrittweise – von den Task-Ergebnissen bis hin zu den vollständigen Modul-Argumenten und Verbindungsdetails. Bei unklaren Fehlern liefert -vvv meist den entscheidenden Hinweis.
 
* ansible-playbook ~/ansible/dmz.yml -v
 
* ansible-playbook ~/ansible/dmz.yml -v
 
* ansible-playbook ~/ansible/dmz.yml -vvv
 
* ansible-playbook ~/ansible/dmz.yml -vvv

Aktuelle Version vom 9. Juli 2026, 13:36 Uhr

Ansible auf Rocky Linux

Ansible ist ein agentenloser Automatisierungsdienst: Es wird nur auf dem Control Node installiert, die verwalteten Maschinen ("Managed Nodes") brauchen lediglich SSH-Zugang und Python – kein Agent, kein zusätzlicher Dienst. Das unterscheidet Ansible von Werkzeugen wie Puppet oder Chef, die einen dauerhaft laufenden Agenten auf jedem Zielsystem voraussetzen.

Im Labor übernimmt desktop.it2XX.int die Rolle des Control Node und verwaltet von dort aus die DMZ-Server (fw, ns, www; ldap und der Container folgen später als eigene Gruppe). Gearbeitet wird durchgehend als unprivilegierter User kit – root-Login ist auf allen Systemen deaktiviert, privilegierte Aktionen laufen über sudo.

Voraussetzungen

Auf jedem Zielsystem muss ein kit-User mit passwortlosem sudo existieren. Ohne NOPASSWD würde Ansible bei jedem privilegierten Task nach einem sudo-Passwort fragen und den automatisierten Ablauf unterbrechen.
  • sudo visudo
kit ALL=(ALL) NOPASSWD: ALL

Installation des Control Node

Ansible wird ausschließlich auf desktop.it2XX.int installiert. Die Managed Nodes brauchen keine Ansible-Installation, nur SSH und Python – das ist der Kern des agentenlosen Modells.
  • sudo dnf install -y ansible

SSH-Schlüssel vorbereiten

kit braucht auf dem Control Node einen eigenen SSH-Schlüssel, der auf allen Zielsystemen beim kit-User hinterlegt wird. Ansible nutzt diesen Schlüssel für jede Verbindung – ohne ihn müsste bei jedem Task ein Passwort eingegeben werden.
  • ssh-keygen -t ed25519 -C "kit@it2XX.int"
Schlüssel als kit auf die DMZ-Server verteilen – NICHT als root, da PermitRootLogin auf den Zielsystemen bereits deaktiviert ist. Ein Versuch mit root@... schlägt deshalb fehl, ssh-copy-id muss den tatsächlichen Verbindungsuser kit verwenden.
  • ssh-copy-id kit@fw.it2XX.int
  • ssh-copy-id kit@ns.it2XX.int
  • ssh-copy-id kit@www.it2XX.int

Projektverzeichnis und Inventory

kit hat keine Schreibrechte auf /etc/ansible – deshalb arbeiten wir im Home-Verzeichnis statt mit sudo im systemweiten Pfad. Das vermeidet unnötige root-Eingriffe für reine Konfigurationsdateien.
  • mkdir -p ~/ansible
  • cd ~/ansible
ansible.cfg legt fest, wo das Inventory liegt – dann ist kein -i-Parameter mehr nötig. Wichtig
Der relative Pfad ./hosts wirkt nur, wenn Ansible aus genau diesem Verzeichnis heraus aufgerufen wird; aus Unterverzeichnissen (z.B. roles/) wird die Datei nicht gefunden.
  • vi ~/ansible/ansible.cfg
[defaults]
inventory = ./hosts
Inventory anlegen – Maschinen nach Rolle gruppiert, kit als Verbindungsuser, sudo für privilegierte Tasks. Die dmz
vars-Sektion gilt für alle Hosts der Gruppe gleichzeitig, statt sie einzeln pro Host wiederholen zu müssen.
  • vi ~/ansible/hosts
[dmz]
fw.it2XX.int
ns.it2XX.int
www.it2XX.int

[dmz:vars]
ansible_user=kit
ansible_become=true
ansible_become_method=sudo

Erster Test

Alle Maschinen anpingen – Ansible nutzt dafür das ping-Modul, nicht ICMP. Das Modul prüft, ob eine SSH-Verbindung inklusive Python-Interpreter auf der Gegenseite funktioniert, nicht nur ob der Host im Netzwerk erreichbar ist.
  • ansible all -m ping
ns.it2XX.int | SUCCESS => {
    "changed": false,
    "ping": "pong"
}


sudo-Rechte prüfen – mit -b (become) sollte root erscheinen. Das bestätigt, dass ansible_become und das passwortlose sudo auf den Zielsystemen korrekt zusammenspielen.
  • ansible dmz -b -m command -a "whoami"
Ad-hoc Befehl auf allen Maschinen ausführen. Ad-hoc-Kommandos eignen sich für schnelle Einzelaktionen und Debugging, nicht für wiederholbare Konfiguration – dafür sind Playbooks gedacht.
  • ansible all -m command -a "hostname"
Nur die DMZ-Gruppe ansprechen. Gruppenfilter im Inventory erlauben es, gezielt Teilmengen der Infrastruktur anzusprechen, statt immer alle Hosts zu treffen.
  • ansible dmz -m command -a "uptime"

Playbooks

Ein Playbook ist eine YAML-Datei, die Tasks in fester Reihenfolge auf einer Zielgruppe ausführt. Im Gegensatz zu Ad-hoc-Befehlen sind Playbooks wiederholbar, versionierbar und dokumentieren den gewünschten Zielzustand.
Einfaches Beispiel – Paket installieren und eine harmlose Testdatei anlegen, läuft dank ansible_become automatisch mit sudo. Nichts hiervon verändert bestehende Konfiguration, das Beispiel dient nur zum Kennenlernen der Playbook-Syntax.
  • vi ~/ansible/test.yml
---
- name: Testplaybook
  hosts: dmz
  tasks:
    - name: htop installieren
      dnf:
        name: htop
        state: present

    - name: Testdatei mit Zeitstempel anlegen
      copy:
        content: "Ansible-Testlauf: {{ ansible_date_time.iso8601 }}\n"
        dest: /tmp/ansible-test.txt
        mode: '0644'
  • ansible-playbook ~/ansible/test.yml
Idempotenz zeigen – zweiter Lauf meldet "changed=0", da nichts mehr zu tun ist. Das ist ein zentrales Ansible-Prinzip
Ein Playbook kann beliebig oft ausgeführt werden, ohne den Zielzustand erneut zu verändern.
  • ansible-playbook ~/ansible/test.yml
Ergebnis prüfen. Zeigt, dass die Testdatei tatsächlich mit dem korrekten Zeitstempel auf den Zielsystemen angekommen ist.
  • ansible dmz -m command -a "cat /tmp/ansible-test.txt"

Rollen

Rollen sind wiederverwendbare Ansible-Strukturen – Tasks, Templates und Handler in einem festen Verzeichnisschema. Das feste Schema erlaubt es Ansible, Dateien wie templates/sssd.conf.j2 automatisch zu finden, ohne dass der Pfad in jedem Task ausgeschrieben werden muss.
roles/
└── rollenname/
    ├── tasks/
    │   └── main.yml
    ├── templates/
    ├── handlers/
    │   └── main.yml
    └── defaults/
        └── main.yml
ansible-galaxy ist das mit Ansible mitgelieferte CLI-Tool zum Verwalten von Rollen. Zwei Funktionen
(1) Skelett einer neuen Rolle generieren – das nutzen wir hier, (2) fertige Rollen von galaxy.ansible.com herunterladen – nicht Teil dieses Kurses, da die Rollen hier bewusst selbst geschrieben werden.
Rollengerüst automatisch erstellen – legt tasks/, handlers/, defaults/, templates/ mit leeren main.yml-Dateien an, die anschließend gefüllt werden.
  • mkdir -p ~/ansible/roles
  • cd ~/ansible/roles
  • ansible-galaxy init sssd

Rolle: SSSD

Diese Rolle installiert SSSD auf allen DMZ-Servern und bindet sie gegen den LDAP-Server an. Damit können sich Benutzer aus dem zentralen Verzeichnis auf jedem DMZ-Server anmelden, statt lokale Konten pro Host pflegen zu müssen.

tasks/main.yml

  • vi ~/ansible/roles/sssd/tasks/main.yml
---
- name: Pakete installieren
  dnf:
    name:
      - sssd
      - sssd-ldap
      - oddjob
      - oddjob-mkhomedir
    state: present

- name: sssd.conf schreiben
  template:
    src: sssd.conf.j2
    dest: /etc/sssd/sssd.conf
    owner: root
    group: root
    mode: '0600'
  notify: sssd neu starten

- name: authselect konfigurieren
  command: authselect select sssd with-mkhomedir --force
  changed_when: false

- name: sudoers-Eintrag in user-nsswitch.conf setzen
  lineinfile:
    path: /etc/authselect/user-nsswitch.conf
    regexp: '^sudoers:'
    line: 'sudoers:    files sss'
    state: present
  notify: authselect anwenden

- name: oddjobd starten
  systemd:
    name: oddjobd
    enabled: true
    state: started
Merksatz
authselect generiert /etc/nsswitch.conf komplett neu aus dem gewählten Profil und aus /etc/authselect/user-nsswitch.conf – direkte Einträge in /etc/nsswitch.conf werden dabei überschrieben. Änderungen gehören deshalb in user-nsswitch.conf und werden über authselect apply-changes aktiv geschaltet. Reihenfolge zwingend: erst authselect select, danach den sudoers-Eintrag setzen – sonst wird er beim nächsten select wieder verworfen.

templates/sssd.conf.j2

Das Template nutzt Ansible-Variablen – so funktioniert dieselbe Rolle für jeden Studenten, ohne den Code anzufassen. Nur defaults/main.yml oder group_vars müssen pro Umgebung angepasst werden.
  • vi ~/ansible/roles/sssd/templates/sssd.conf.j2
[sssd]
config_file_version = 2
services = nss, pam, sudo
domains = {{ domain }}

[domain/{{ domain }}]
id_provider = ldap
auth_provider = ldap
chpass_provider = ldap
access_provider = permit
sudo_provider = ldap
ldap_uri = ldaps://ldap.{{ domain }}
ldap_search_base = dc={{ dc1 }},dc={{ dc2 }}
ldap_sudo_search_base = ou=sudo,dc={{ dc1 }},dc={{ dc2 }}
ldap_default_bind_dn = cn=admin,dc={{ dc1 }},dc={{ dc2 }}
ldap_default_authtok = {{ ldap_password }}
ldap_tls_cacert = /etc/pki/tls/certs/ca-bundle.crt
ldap_tls_reqcert = hard
cache_credentials = True

[nss]
filter_users = root,daemon,bin,sys,sync,games,man,lp,mail,news,uucp,proxy,nobody,systemd-network,systemd-resolve,dbus,polkitd,unbound,tss,sssd,chrony,sshd,rngd

[pam]
offline_credentials_expiration = 2

handlers/main.yml

Handler laufen nur, wenn ein Task mit notify sie tatsächlich auslöst, und erst am Ende des Playbook-Durchlaufs. Das verhindert unnötige Neustarts von Diensten, wenn sich an der Konfiguration nichts geändert hat.
  • vi ~/ansible/roles/sssd/handlers/main.yml
---
- name: sssd neu starten
  systemd:
    name: sssd
    state: restarted

- name: authselect anwenden
  command: authselect apply-changes

defaults/main.yml

Standardwerte – werden durch group_vars oder host_vars überschrieben, ohne dass die Rolle selbst verändert werden muss. Das ist der Mechanismus, der dieselbe Rolle für unterschiedliche Studenten-Domains (it201, it202, ...) wiederverwendbar macht.
  • vi ~/ansible/roles/sssd/defaults/main.yml
---
domain: "it2XX.int"
dc1: "it2XX"
dc2: "int"
ldap_password: "123Start$"
Für den produktiven Einsatz
Passwort niemals im Klartext in defaults/main.yml – stattdessen mit ansible-vault verschlüsseln. Im Kursumfeld mit Wegwerf-Passwörtern ist das Klartext-Passwort didaktisch vertretbar, in Produktion nicht.
  • ansible-vault encrypt_string '123Start$' --name 'ldap_password'

Playbook: DMZ ausrollen

Ein Playbook, das die Rolle auf die dmz-Gruppe anwendet – der Tag sssd erlaubt es, sie gezielt einzeln auszuführen, statt immer das komplette Playbook zu starten.
  • vi ~/ansible/dmz.yml
---
- name: DMZ-Server konfigurieren
  hosts: dmz
  roles:
    - { role: sssd, tags: ['sssd'] }
SSSD ausrollen und testen.
  • ansible-playbook ~/ansible/dmz.yml --tags sssd
Dry-run – zeigt was sich ändern würde, ohne es anzuwenden. Nützlich um vor einem echten Lauf zu prüfen, welche Tasks als changed markiert würden.
  • ansible-playbook ~/ansible/dmz.yml --check

Kontrolle

SSSD auf einem Server prüfen. getent fragt über nsswitch.conf alle konfigurierten Quellen ab (hier
files und sss) – erscheint der Benutzer, funktioniert die LDAP-Anbindung.
  • ansible ns.it2XX.int -m command -a "getent passwd thomas"
nsswitch.conf prüfen – sudoers-Zeile muss sss enthalten. Fehlt sie, liest das System keine sudo-Regeln aus LDAP, selbst wenn sssd.conf korrekt konfiguriert ist.
  • ansible dmz -m command -a "grep sudoers /etc/nsswitch.conf"
Alle Fakten eines Servers anzeigen – nützlich zur Fehlersuche. Das setup-Modul liefert Systeminformationen (IP, OS, Hardware), auf die auch in Templates über Variablen wie ansible_date_time zugegriffen werden kann.
  • ansible ns.it2XX.int -m setup

Logs und Debugging

-v, -vv und -vvv erhöhen die Ausgabe-Ausführlichkeit von ansible-playbook schrittweise – von den Task-Ergebnissen bis hin zu den vollständigen Modul-Argumenten und Verbindungsdetails. Bei unklaren Fehlern liefert -vvv meist den entscheidenden Hinweis.
  • ansible-playbook ~/ansible/dmz.yml -v
  • ansible-playbook ~/ansible/dmz.yml -vvv