Ansible mit Rocky: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
(Die Seite wurde neu angelegt: „= Ansible auf Rocky Linux = Ansible ist ein agentenloser Automatisierungsdienst – es wird nur auf dem Control Node installiert, die verwalteten Maschinen br…“)
 
 
(20 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 brauchen nichts außer SSH und Python. Im Labor übernimmt der Client im LAN die Rolle des Control Node und verwaltet alle DMZ-Server.
+
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.
  
= Installation =
+
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''.
;Ansible wird nur auf dem Control Node installiert – also auf client.it2XX.int
+
 
* dnf install -y ansible
+
== 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
 +
<pre>
 +
kit ALL=(ALL) NOPASSWD: ALL
 +
</pre>
 +
 
 +
= 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 =
 
= SSH-Schlüssel vorbereiten =
;Ansible kommuniziert über SSH – der Control Node braucht einen Schlüssel der auf allen Zielsystemen hinterlegt ist
+
;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 "ansible@it2XX.int"
+
* ssh-keygen -t ed25519 -C "kit@it2XX.int"
;Schlüssel auf alle DMZ-Server verteilen
+
 
* ssh-copy-id root@ns.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 root@www.it2XX.int
+
* ssh-copy-id kit@fw.it2XX.int
* ssh-copy-id root@ldap.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
 +
<pre>
 +
[defaults]
 +
inventory = ./hosts
 +
</pre>
  
= Inventory =
+
;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.
;Das Inventory listet alle verwalteten Maschinen – hier gruppiert nach ihrer Rolle
+
* vi ~/ansible/hosts
* mkdir -p /etc/ansible
 
* vi /etc/ansible/hosts
 
 
<pre>
 
<pre>
 
[dmz]
 
[dmz]
 +
fw.it2XX.int
 
ns.it2XX.int
 
ns.it2XX.int
 
www.it2XX.int
 
www.it2XX.int
ldap.it2XX.int
 
  
 
[dmz:vars]
 
[dmz:vars]
ansible_user=root
+
ansible_user=kit
 +
ansible_become=true
 +
ansible_become_method=sudo
 
</pre>
 
</pre>
  
 
= 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 37: Zeile 59:
 
  }
 
  }
  
;Ad-hoc Befehl auf allen Maschinen ausführen
+
 
 +
;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"
 
* 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 einer bestimmten Reihenfolge 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 Dienst starten
+
;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 /root/test.yml
+
* vi ~/ansible/test.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: Testplaybook
 
- name: Testplaybook
 
   hosts: dmz
 
   hosts: dmz
 
   tasks:
 
   tasks:
     - name: tree installieren
+
     - name: htop installieren
 
       dnf:
 
       dnf:
         name: tree
+
         name: htop
 
         state: present
 
         state: present
</pre>
+
 
* ansible-playbook /root/test.yml
+
    - name: Testdatei mit Zeitstempel anlegen
 +
      copy:
 +
        content: "Ansible-Testlauf: {{ ansible_date_time.iso8601 }}\n"
 +
        dest: /tmp/ansible-test.txt
 +
        mode: '0644'
 +
</syntaxhighlight>
 +
* 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 =
  
;Rollen sind wiederverwendbare Ansible-Strukturen – Playbook, Templates und Handler in einem Verzeichnis
+
;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.
;Eine Rolle hat immer dieselbe Verzeichnisstruktur:
 
 
  roles/
 
  roles/
 
  └── rollenname/
 
  └── rollenname/
Zeile 74: 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.
* mkdir -p /etc/ansible/roles
+
;Rollengerüst automatisch erstellen – legt tasks/, handlers/, defaults/, templates/ mit leeren main.yml-Dateien an, die anschließend gefüllt werden.
* cd /etc/ansible/roles
+
* mkdir -p ~/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 verbindet sie gegen den LDAP-Server
+
;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 /etc/ansible/roles/sssd/tasks/main.yml
+
* vi ~/ansible/roles/sssd/tasks/main.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: Pakete installieren
 
- name: Pakete installieren
Zeile 109: Zeile 146:
 
   command: authselect select sssd with-mkhomedir --force
 
   command: authselect select sssd with-mkhomedir --force
 
   changed_when: false
 
   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
 
- name: oddjobd starten
Zeile 115: Zeile 160:
 
     enabled: true
 
     enabled: true
 
     state: started
 
     state: started
</pre>
+
</syntaxhighlight>
 +
 
 +
;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 /etc/ansible/roles/sssd/templates/sssd.conf.j2
+
* vi ~/ansible/roles/sssd/templates/sssd.conf.j2
 
<pre>
 
<pre>
 
[sssd]
 
[sssd]
Zeile 149: Zeile 196:
  
 
== handlers/main.yml ==
 
== handlers/main.yml ==
* vi /etc/ansible/roles/sssd/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.
<pre>
+
* vi ~/ansible/roles/sssd/handlers/main.yml
 +
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: sssd neu starten
 
- name: sssd neu starten
Zeile 156: Zeile 204:
 
     name: sssd
 
     name: sssd
 
     state: restarted
 
     state: restarted
</pre>
+
 
 +
- name: authselect anwenden
 +
  command: authselect apply-changes
 +
</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 /etc/ansible/roles/sssd/defaults/main.yml
+
* vi ~/ansible/roles/sssd/defaults/main.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
domain: "it2XX.int"
 
domain: "it2XX.int"
Zeile 167: Zeile 218:
 
dc2: "int"
 
dc2: "int"
 
ldap_password: "123Start$"
 
ldap_password: "123Start$"
</pre>
+
</syntaxhighlight>
 
 
= Rolle: SSH-Härtung =
 
 
 
;Diese Rolle schaltet Passwort-Authentifizierung ab – erst nachdem die SSH-Keys verteilt wurden
 
;Wichtig: Reihenfolge beachten – erst Keys verteilen, dann diese Rolle ausführen
 
 
 
== tasks/main.yml ==
 
* vi /etc/ansible/roles/ssh-hardening/tasks/main.yml
 
<pre>
 
---
 
- name: Passwort-Login deaktivieren
 
  lineinfile:
 
    path: /etc/ssh/sshd_config
 
    regexp: '^#?PasswordAuthentication'
 
    line: 'PasswordAuthentication no'
 
    state: present
 
  notify: sshd neu starten
 
 
 
- name: Root-Login nur mit Key erlauben
 
  lineinfile:
 
    path: /etc/ssh/sshd_config
 
    regexp: '^#?PermitRootLogin'
 
    line: 'PermitRootLogin prohibit-password'
 
    state: present
 
  notify: sshd neu starten
 
</pre>
 
  
== handlers/main.yml ==
+
;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.
* vi /etc/ansible/roles/ssh-hardening/handlers/main.yml
+
* ansible-vault encrypt_string '123Start$' --name 'ldap_password'
<pre>
 
---
 
- name: sshd neu starten
 
  systemd:
 
    name: sshd
 
    state: restarted
 
</pre>
 
  
 
= Playbook: DMZ ausrollen =
 
= Playbook: DMZ ausrollen =
  
;Ein Playbook das beide Rollen nacheinander ausführt
+
;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 /etc/ansible/dmz.yml
+
* vi ~/ansible/dmz.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: DMZ-Server konfigurieren
 
- name: DMZ-Server konfigurieren
 
   hosts: dmz
 
   hosts: dmz
 
   roles:
 
   roles:
     - sssd
+
     - { role: sssd, tags: ['sssd'] }
    - ssh-hardening
+
</syntaxhighlight>
</pre>
 
 
 
;Zuerst nur SSSD ausrollen und testen
 
* ansible-playbook /etc/ansible/dmz.yml --tags sssd
 
  
;Danach SSH-Härtung
+
;SSSD ausrollen und testen.
* ansible-playbook /etc/ansible/dmz.yml
+
* ansible-playbook ~/ansible/dmz.yml --tags sssd
  
;Dry-run – zeigt was sich ändern würde ohne es anzuwenden
+
;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 /etc/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"
+
* 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 =
+
= 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 /etc/ansible/dmz.yml -v
+
* ansible-playbook ~/ansible/dmz.yml -v
* ansible-playbook /etc/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