Ansible mit Rocky: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
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.
  
= Wir arbeiten als kit User=
+
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''.
  
= Installation =
+
== Voraussetzungen ==
;Ansible wird nur auf dem Control Node installiert – also auf client.it2XX.int
+
;Auf jedem Zielsystem muss ein kit-User mit passwortlosem sudo existieren
 +
* sudo visudo
 +
<pre>
 +
kit ALL=(ALL) NOPASSWD: ALL
 +
</pre>
 +
 
 +
= Installation des Control Node =
 +
;Ansible wird nur auf client.it2XX.int installiert
 
* sudo dnf install -y ansible
 
* 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 Schlüssel, der auf allen Zielsystemen beim kit-User hinterlegt wird
* ssh-keygen -t ed25519 -C "ansible@it2XX.int"
+
* ssh-keygen -t ed25519 -C "kit@it2XX.int"
;Schlüssel auf alle DMZ-Server verteilen
+
 
 +
;Schlüssel als kit auf alle DMZ-Server verteilen – NICHT als root, da PermitRootLogin deaktiviert ist
 
* 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@container.it2XX.int
+
* ssh-copy-id kit@ldap.it2XX.int
  
= Inventory =
+
= Projektverzeichnis und Inventory =
;Das Inventory listet alle verwalteten Maschinen hier gruppiert nach ihrer Rolle
+
;kit hat keine Schreibrechte auf /etc/ansible deshalb arbeiten wir im Home-Verzeichnis statt mit sudo im systemweiten Pfad
*mkdir -p ~/ansible
+
* mkdir -p ~/ansible
*vim ~/ansible/hosts
+
* cd ~/ansible
 +
 
 +
;ansible.cfg legt fest, wo das Inventory liegt – dann ist kein -i-Parameter mehr nötig
 +
* vi ~/ansible/ansible.cfg
 +
<pre>
 +
[defaults]
 +
inventory = ./hosts
 +
</pre>
  
 +
;Inventory anlegen – Maschinen nach Rolle gruppiert, kit als Verbindungsuser, sudo für privilegierte Tasks
 +
* vi ~/ansible/hosts
 
<pre>
 
<pre>
 
[dmz]
 
[dmz]
Zeile 28: Zeile 45:
 
ns.it2XX.int
 
ns.it2XX.int
 
www.it2XX.int
 
www.it2XX.int
 
+
ldap.it2XX.int
  
 
[dmz:vars]
 
[dmz:vars]
 
ansible_user=kit
 
ansible_user=kit
 +
ansible_become=true
 +
ansible_become_method=sudo
 
</pre>
 
</pre>
  
Zeile 41: Zeile 60:
 
     "ping": "pong"
 
     "ping": "pong"
 
  }
 
  }
 +
 +
;Verbindungsuser prüfen – muss kit sein, nicht root
 +
* ansible dmz -m command -a "whoami"
 +
 +
;sudo-Rechte prüfen – mit -b (become) sollte root erscheinen
 +
* ansible dmz -b -m command -a "whoami"
  
 
;Ad-hoc Befehl auf allen Maschinen ausführen
 
;Ad-hoc Befehl auf allen Maschinen ausführen
Zeile 50: Zeile 75:
 
= 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
;Einfaches Beispiel – Paket installieren und Dienst starten
+
;Einfaches Beispiel – Paket installieren, läuft dank ansible_become automatisch mit sudo
* vi /root/test.yml
+
* vi ~/ansible/test.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: Testplaybook
 
- name: Testplaybook
Zeile 62: Zeile 87:
 
         name: tree
 
         name: tree
 
         state: present
 
         state: present
</pre>
+
</syntaxhighlight>
* ansible-playbook /root/test.yml
+
* ansible-playbook ~/ansible/test.yml
  
 
= 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
;Eine Rolle hat immer dieselbe Verzeichnisstruktur:
 
 
  roles/
 
  roles/
 
  └── rollenname/
 
  └── rollenname/
Zeile 80: Zeile 104:
  
 
;Rollengerüst automatisch erstellen
 
;Rollengerüst automatisch erstellen
* mkdir -p /etc/ansible/roles
+
* mkdir -p ~/ansible/roles
* cd /etc/ansible/roles
+
* cd ~/ansible/roles
 
* ansible-galaxy init sssd
 
* ansible-galaxy init sssd
 
* ansible-galaxy init ssh-hardening
 
* ansible-galaxy init ssh-hardening
Zeile 87: Zeile 111:
 
= 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
  
 
== 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 111: Zeile 135:
 
   notify: sssd neu starten
 
   notify: sssd neu starten
  
- name: authselect konfigurieren
+
- name: sudoers-Eintrag in nsswitch.conf setzen
  command: authselect select sssd with-mkhomedir --force
 
  changed_when: false
 
 
 
- name: oddjobd starten
 
  systemd:
 
    name: oddjobd
 
    enabled: true
 
    state: started
 
</pre>
 
 
 
== templates/sssd.conf.j2 ==
 
;Das Template nutzt Ansible-Variablen – so funktioniert dieselbe Rolle für jeden Studenten
 
* vi /etc/ansible/roles/sssd/templates/sssd.conf.j2
 
<pre>
 
[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
 
</pre>
 
 
 
== handlers/main.yml ==
 
* vi /etc/ansible/roles/sssd/handlers/main.yml
 
<pre>
 
---
 
- name: sssd neu starten
 
  systemd:
 
    name: sssd
 
    state: restarted
 
</pre>
 
 
 
== defaults/main.yml ==
 
;Standardwerte – werden durch group_vars oder host_vars überschrieben
 
* vi /etc/ansible/roles/sssd/defaults/main.yml
 
<pre>
 
---
 
domain: "it2XX.int"
 
dc1: "it2XX"
 
dc2: "int"
 
ldap_password: "123Start$"
 
</pre>
 
 
 
= 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:
 
   lineinfile:
     path: /etc/ssh/sshd_config
+
     path: /etc/nsswitch.conf
     regexp: '^#?PasswordAuthentication'
+
     regexp: '^sudoers:'
     line: 'PasswordAuthentication no'
+
     line: 'sudoers:   files sss'
    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 ==
 
* vi /etc/ansible/roles/ssh-hardening/handlers/main.yml
 
<pre>
 
---
 
- name: sshd neu starten
 
  systemd:
 
    name: sshd
 
    state: restarted
 
</pre>
 
 
 
= Playbook: DMZ ausrollen =
 
 
 
;Ein Playbook das beide Rollen nacheinander ausführt
 
* vi /etc/ansible/dmz.yml
 
<pre>
 
---
 
- name: DMZ-Server konfigurieren
 
  hosts: dmz
 
  roles:
 
    - sssd
 
    - ssh-hardening
 
</pre>
 
 
 
;Zuerst nur SSSD ausrollen und testen
 
* ansible-playbook /etc/ansible/dmz.yml --tags sssd
 
 
 
;Danach SSH-Härtung
 
* ansible-playbook /etc/ansible/dmz.yml
 
 
 
;Dry-run – zeigt was sich ändern würde ohne es anzuwenden
 
* ansible-playbook /etc/ansible/dmz.yml --check
 
 
 
= Kontrolle =
 
 
 
;SSSD auf einem Server prüfen
 
* ansible ns.it2XX.int -m command -a "getent passwd thomas"
 
 
 
;SSH-Konfiguration prüfen
 
* ansible dmz -m command -a "grep PasswordAuthentication /etc/ssh/sshd_config"
 
 
 
;Alle Fakten eines Servers anzeigen – nützlich zur Fehlersuche
 
* ansible ns.it2XX.int -m setup
 
 
 
= Logs =
 
* journalctl -fu sshd
 
* ansible-playbook /etc/ansible/dmz.yml -v
 
* ansible-playbook /etc/ansible/dmz.yml -vvv
 
el auf alle DMZ-Server verteilen
 
* ssh-copy-id root@ns.it2XX.int
 
* ssh-copy-id root@www.it2XX.int
 
* ssh-copy-id root@ldap.it2XX.int
 
 
 
= Inventory =
 
;Das Inventory listet alle verwalteten Maschinen – hier gruppiert nach ihrer Rolle
 
* mkdir -p /etc/ansible
 
* vi /etc/ansible/hosts
 
<pre>
 
[dmz]
 
ns.it2XX.int
 
www.it2XX.int
 
ldap.it2XX.int
 
container.it2XX.int
 
 
 
[dmz:vars]
 
ansible_user=root
 
</pre>
 
 
 
= Erster Test =
 
;Alle Maschinen anpingen – Ansible nutzt dafür das ping-Modul, nicht ICMP
 
* ansible all -m ping
 
ns.it2XX.int | SUCCESS => {
 
    "changed": false,
 
    "ping": "pong"
 
}
 
 
 
;Ad-hoc Befehl auf allen Maschinen ausführen
 
* ansible all -m command -a "hostname"
 
 
 
;Nur die DMZ-Gruppe ansprechen
 
* ansible dmz -m command -a "uptime"
 
 
 
= Playbooks =
 
 
 
;Ein Playbook ist eine YAML-Datei die Tasks in einer bestimmten Reihenfolge ausführt
 
;Einfaches Beispiel – Paket installieren und Dienst starten
 
* vi /root/test.yml
 
<pre>
 
---
 
- name: Testplaybook
 
  hosts: dmz
 
  tasks:
 
    - name: tree installieren
 
      dnf:
 
        name: tree
 
        state: present
 
</pre>
 
* ansible-playbook /root/test.yml
 
 
 
= Rollen =
 
 
 
;Rollen sind wiederverwendbare Ansible-Strukturen – Playbook, Templates und Handler in einem Verzeichnis
 
;Eine Rolle hat immer dieselbe Verzeichnisstruktur:
 
roles/
 
└── rollenname/
 
    ├── tasks/
 
    │  └── main.yml
 
    ├── templates/
 
    ├── handlers/
 
    │  └── main.yml
 
    └── defaults/
 
        └── main.yml
 
 
 
;Rollengerüst automatisch erstellen
 
* mkdir -p /etc/ansible/roles
 
* cd /etc/ansible/roles
 
* ansible-galaxy init sssd
 
* ansible-galaxy init ssh-hardening
 
 
 
= Rolle: SSSD =
 
 
 
;Diese Rolle installiert SSSD auf allen DMZ-Servern und verbindet sie gegen den LDAP-Server
 
 
 
== tasks/main.yml ==
 
* vi /etc/ansible/roles/sssd/tasks/main.yml
 
<pre>
 
---
 
- name: Pakete installieren
 
  dnf:
 
    name:
 
      - sssd
 
      - sssd-ldap
 
      - oddjob
 
      - oddjob-mkhomedir
 
 
     state: present
 
     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
 
- name: authselect konfigurieren
Zeile 353: Zeile 151:
 
     enabled: true
 
     enabled: true
 
     state: started
 
     state: started
</pre>
+
</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.
  
 
== 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
* vi /etc/ansible/roles/sssd/templates/sssd.conf.j2
+
* vi ~/ansible/roles/sssd/templates/sssd.conf.j2
 
<pre>
 
<pre>
 
[sssd]
 
[sssd]
Zeile 387: Zeile 187:
  
 
== handlers/main.yml ==
 
== handlers/main.yml ==
* vi /etc/ansible/roles/sssd/handlers/main.yml
+
* vi ~/ansible/roles/sssd/handlers/main.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: sssd neu starten
 
- name: sssd neu starten
Zeile 394: Zeile 194:
 
     name: sssd
 
     name: sssd
 
     state: restarted
 
     state: restarted
</pre>
+
</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
* 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 405: Zeile 205:
 
dc2: "int"
 
dc2: "int"
 
ldap_password: "123Start$"
 
ldap_password: "123Start$"
</pre>
+
</syntaxhighlight>
 +
 
 +
;Für den produktiven Einsatz: Passwort niemals im Klartext in defaults/main.yml – stattdessen mit ansible-vault verschlüsseln
 +
* ansible-vault encrypt_string '123Start$' --name 'ldap_password'
  
 
= Rolle: SSH-Härtung =
 
= Rolle: SSH-Härtung =
  
;Diese Rolle schaltet Passwort-Authentifizierung ab – erst nachdem die SSH-Keys verteilt wurden
+
;Diese Rolle schaltet Passwort-Authentifizierung ab – ERST nachdem die SSH-Keys für kit auf allen Zielsystemen verteilt wurden. Reihenfolge unbedingt einhalten, sonst sperrt man sich aus.
;Wichtig: Reihenfolge beachten – erst Keys verteilen, dann diese Rolle ausführen
 
  
 
== tasks/main.yml ==
 
== tasks/main.yml ==
* vi /etc/ansible/roles/ssh-hardening/tasks/main.yml
+
* vi ~/ansible/roles/ssh-hardening/tasks/main.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: Passwort-Login deaktivieren
 
- name: Passwort-Login deaktivieren
Zeile 431: Zeile 233:
 
     state: present
 
     state: present
 
   notify: sshd neu starten
 
   notify: sshd neu starten
</pre>
+
</syntaxhighlight>
  
 
== handlers/main.yml ==
 
== handlers/main.yml ==
* vi /etc/ansible/roles/ssh-hardening/handlers/main.yml
+
* vi ~/ansible/roles/ssh-hardening/handlers/main.yml
<pre>
+
<syntaxhighlight lang="yaml">
 
---
 
---
 
- name: sshd neu starten
 
- name: sshd neu starten
Zeile 441: Zeile 243:
 
     name: sshd
 
     name: sshd
 
     state: restarted
 
     state: restarted
</pre>
+
</syntaxhighlight>
  
 
= Playbook: DMZ ausrollen =
 
= Playbook: DMZ ausrollen =
  
;Ein Playbook das beide Rollen nacheinander ausführt
+
;Ein Playbook, das beide Rollen nacheinander ausführt – Tags erlauben es, sie einzeln zu testen
* 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
+
     - { role: ssh-hardening, tags: ['ssh-hardening'] }
</pre>
+
</syntaxhighlight>
  
 
;Zuerst nur SSSD ausrollen und testen
 
;Zuerst nur SSSD ausrollen und testen
* ansible-playbook /etc/ansible/dmz.yml --tags sssd
+
* ansible-playbook ~/ansible/dmz.yml --tags sssd
  
;Danach SSH-Härtung
+
;Danach SSH-Härtung – erst wenn SSSD und Keys sicher funktionieren
* ansible-playbook /etc/ansible/dmz.yml
+
* ansible-playbook ~/ansible/dmz.yml --tags ssh-hardening
  
;Dry-run – zeigt was sich ändern würde ohne es anzuwenden
+
;Beide Rollen zusammen
* ansible-playbook /etc/ansible/dmz.yml --check
+
* ansible-playbook ~/ansible/dmz.yml
 +
 
 +
;Dry-run – zeigt was sich ändern würde, ohne es anzuwenden
 +
* ansible-playbook ~/ansible/dmz.yml --check
  
 
= Kontrolle =
 
= Kontrolle =
Zeile 472: Zeile 277:
 
;SSH-Konfiguration prüfen
 
;SSH-Konfiguration prüfen
 
* ansible dmz -m command -a "grep PasswordAuthentication /etc/ssh/sshd_config"
 
* 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"
  
 
;Alle Fakten eines Servers anzeigen – nützlich zur Fehlersuche
 
;Alle Fakten eines Servers anzeigen – nützlich zur Fehlersuche
 
* ansible ns.it2XX.int -m setup
 
* ansible ns.it2XX.int -m setup
  
= Logs =
+
= Logs und Debugging =
 
* journalctl -fu sshd
 
* journalctl -fu sshd
* 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

Version vom 5. Juli 2026, 09:34 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.

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.

Voraussetzungen

Auf jedem Zielsystem muss ein kit-User mit passwortlosem sudo existieren
  • sudo visudo
kit ALL=(ALL) NOPASSWD: ALL

Installation des Control Node

Ansible wird nur auf client.it2XX.int installiert
  • sudo dnf install -y ansible

SSH-Schlüssel vorbereiten

kit braucht auf dem Control Node einen eigenen Schlüssel, der auf allen Zielsystemen beim kit-User hinterlegt wird
  • ssh-keygen -t ed25519 -C "kit@it2XX.int"
Schlüssel als kit auf alle DMZ-Server verteilen – NICHT als root, da PermitRootLogin deaktiviert ist
  • ssh-copy-id kit@fw.it2XX.int
  • ssh-copy-id kit@ns.it2XX.int
  • ssh-copy-id kit@www.it2XX.int
  • ssh-copy-id kit@ldap.it2XX.int

Projektverzeichnis und Inventory

kit hat keine Schreibrechte auf /etc/ansible – deshalb arbeiten wir im Home-Verzeichnis statt mit sudo im systemweiten Pfad
  • mkdir -p ~/ansible
  • cd ~/ansible
ansible.cfg legt fest, wo das Inventory liegt – dann ist kein -i-Parameter mehr nötig
  • vi ~/ansible/ansible.cfg
[defaults]
inventory = ./hosts
Inventory anlegen – Maschinen nach Rolle gruppiert, kit als Verbindungsuser, sudo für privilegierte Tasks
  • vi ~/ansible/hosts
[dmz]
fw.it2XX.int
ns.it2XX.int
www.it2XX.int
ldap.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
  • ansible all -m ping
ns.it2XX.int | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
Verbindungsuser prüfen – muss kit sein, nicht root
  • ansible dmz -m command -a "whoami"
sudo-Rechte prüfen – mit -b (become) sollte root erscheinen
  • ansible dmz -b -m command -a "whoami"
Ad-hoc Befehl auf allen Maschinen ausführen
  • ansible all -m command -a "hostname"
Nur die DMZ-Gruppe ansprechen
  • ansible dmz -m command -a "uptime"

Playbooks

Ein Playbook ist eine YAML-Datei, die Tasks in fester Reihenfolge auf einer Zielgruppe ausführt
Einfaches Beispiel – Paket installieren, läuft dank ansible_become automatisch mit sudo
  • vi ~/ansible/test.yml
---
- name: Testplaybook
  hosts: dmz
  tasks:
    - name: tree installieren
      dnf:
        name: tree
        state: present
  • ansible-playbook ~/ansible/test.yml

Rollen

Rollen sind wiederverwendbare Ansible-Strukturen – Tasks, Templates und Handler in einem festen Verzeichnisschema
roles/
└── rollenname/
    ├── tasks/
    │   └── main.yml
    ├── templates/
    ├── handlers/
    │   └── main.yml
    └── defaults/
        └── main.yml
Rollengerüst automatisch erstellen
  • mkdir -p ~/ansible/roles
  • cd ~/ansible/roles
  • ansible-galaxy init sssd
  • ansible-galaxy init ssh-hardening

Rolle: SSSD

Diese Rolle installiert SSSD auf allen DMZ-Servern und bindet sie gegen den LDAP-Server an

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: sudoers-Eintrag in nsswitch.conf setzen
  lineinfile:
    path: /etc/nsswitch.conf
    regexp: '^sudoers:'
    line: 'sudoers:    files sss'
    state: present

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

- name: oddjobd starten
  systemd:
    name: oddjobd
    enabled: true
    state: started
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.

templates/sssd.conf.j2

Das Template nutzt Ansible-Variablen – so funktioniert dieselbe Rolle für jeden Studenten
  • 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

  • vi ~/ansible/roles/sssd/handlers/main.yml
---
- name: sssd neu starten
  systemd:
    name: sssd
    state: restarted

defaults/main.yml

Standardwerte – werden durch group_vars oder host_vars überschrieben
  • 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
  • ansible-vault encrypt_string '123Start$' --name 'ldap_password'

Rolle: SSH-Härtung

Diese Rolle schaltet Passwort-Authentifizierung ab – ERST nachdem die SSH-Keys für kit auf allen Zielsystemen verteilt wurden. Reihenfolge unbedingt einhalten, sonst sperrt man sich aus.

tasks/main.yml

  • vi ~/ansible/roles/ssh-hardening/tasks/main.yml
---
- 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

handlers/main.yml

  • vi ~/ansible/roles/ssh-hardening/handlers/main.yml
---
- name: sshd neu starten
  systemd:
    name: sshd
    state: restarted

Playbook: DMZ ausrollen

Ein Playbook, das beide Rollen nacheinander ausführt – Tags erlauben es, sie einzeln zu testen
  • vi ~/ansible/dmz.yml
---
- name: DMZ-Server konfigurieren
  hosts: dmz
  roles:
    - { role: sssd, tags: ['sssd'] }
    - { role: ssh-hardening, tags: ['ssh-hardening'] }
Zuerst nur SSSD ausrollen und testen
  • ansible-playbook ~/ansible/dmz.yml --tags sssd
Danach SSH-Härtung – erst wenn SSSD und Keys sicher funktionieren
  • ansible-playbook ~/ansible/dmz.yml --tags ssh-hardening
Beide Rollen zusammen
  • ansible-playbook ~/ansible/dmz.yml
Dry-run – zeigt was sich ändern würde, ohne es anzuwenden
  • ansible-playbook ~/ansible/dmz.yml --check

Kontrolle

SSSD auf einem Server prüfen
  • ansible ns.it2XX.int -m command -a "getent passwd thomas"
SSH-Konfiguration prüfen
  • 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"
Alle Fakten eines Servers anzeigen – nützlich zur Fehlersuche
  • ansible ns.it2XX.int -m setup

Logs und Debugging

  • journalctl -fu sshd
  • ansible-playbook ~/ansible/dmz.yml -v
  • ansible-playbook ~/ansible/dmz.yml -vvv