Ansible
Theorie (Folien)
Einstiegsfragen
Wie viele Server verwaltet Ihr Lehrbetrieb?
Wie kontrollieren Sie…
- …welche Software auf welchen Servern installiert ist?
- …welche Dienste auf welchen Servern laufen?
- …welche Benutzer auf welchen Servern welche Berechtigungen haben?
Was ist Konfigurationsmanagement?
Die Konfiguration von Systemen wird…
- …zentral verwaltet (i.d.R. in einem Git-Repository),
- Infrastructure as Code (IaC)
- …automatisch angewendet (zeitlich oder manuell getriggert),
- …durch Änderungen mitdokumentiert.
Dank einem Konfigurationsmanagementsystem kann man…
- …lokal eine realitätsnahe Testumgebung betreiben,
- …Systeme bei Bedarf schnell neu aufsetzen.
Die Systemkonfiguration sollte aber nicht mehr manuell angepasst werden!
Was ist Ansible?
Ansible…
- …ist ein Konfigurationsmanagementsystem (Configuration Management, CM),
- …wird von Red Hat betreut,
- …ist unter der GPLv3 lizenziert,
- …ist modular aufgebaut,
- …arbeitet agentless (erfordert SSH und Python 3 auf dem verwalteten System).
Begriffe
- Control Node: Unix-System, welches andere Systeme steuert.
- Managed Host: System, welches gesteuert wird.
- Inventory: Datei mit (gruppierter) Auflistung von Managed Hosts.
- Task: Auszuführender Konfigurationsschritt.
- z.B. Software installieren
- Role: Gruppierung von Tasks für eine bestimmte Art von System.
- z.B. Datenbankserver, Web-Server, FTP-Server
- Playbook: Sammlung sortierter Tasks/Roles zur Konfiguration eines Hosts.
Control Nodes und Managed Hosts
Idempotenz
Interessiert mich die Handlung oder der Zustand?
- imperativ: «Schliessen Sie das Fenster!»
- deklarativ: «Das Fenster soll geschlossen sein!»
if window.is_open():
window.close()
Nur nötige Änderungen sollen vorgenommen werden:
- idempotent: Gleiches Ergebnis nach mehreren Ausführungen
- Mathematik: $x + 0$, $x \times 1$, $x^1$
Ansible-Tasks sind idempotent; Ansible arbeitet deklarativ.
Setup & Tools
Installation (unter Debian):
sudo apt install -y ansible
Werkzeuge:
ansible
: Ausführung einzelner Taskansible-playbook
: Ausführung ganzer Playbooksansible-vault
: Verwaltung von Secretsansible-galaxy
: Rollen verwalten
Einstiegsbeispiel (I): Playbook
Playbook (apache.yaml
):
- name: Setup Apache Web Server
hosts: webservers
become: yes
become_method: sudo
remote_user: user
tasks:
- name: Install Apache 2
package:
name: apache2
state: present
Einstiegsbeispiel (II): Inventory & Ausführung
Inventory (hosts.ini
):
[webservers]
localhost
Ausführung (Apache installieren):
ansible-playbook -i hosts.ini -c local apache.yaml
Einmalige Tasks (Service neu starten):
ansible -i hosts.ini \
-m service -a "name=apache2 state=restarted" \
-b -c local webservers
Literatur
Links
- Ansible.com: Offizielle Webseite
- Get Started: Einstieg in Ansible
- Ansible Galaxy: Playbooks der Community
- Documentation: Offizielle Dokumentation
- Module Index: Modulübersicht
- YAML Syntax: Einführung in die YAML-Syntax
- Using Variables: Arbeiten mit Variablen
- Vault Guide: Schützenswerte Daten mit Ansible Vault verschlüsseln
Praxis (Übungen)
Aufgabe 0: Vorbereitung und Test
Installieren Sie Ansible:
sudo apt install -y ansible
Laden Sie sich die folgenden Dateien mit wget
auf Ihre VM herunter:
Führen Sie nun das Playbook zur Installation des Apache-Webservers aus:
ansible-playbook -i hosts.ini -c local apache.yaml
Aufgabe 1: Eine Apache-Testseite erstellen
Erweitern Sie das Playbook apache.yaml
, sodass unter
http://IP-ADRESSE eine PHP-Infoseite angezeigt wird. Hierzu
sind folgende Schritte nötig, für welche Sie den Abschnitt tasks
im Playbook
erweitern:
- Installieren Sie das PHP-Paket
php8.2
. - Erstellen Sie das Verzeichnis
/var/www/phpinfo
, das dem Benutzer und der Gruppewww-data
gehört. - Erstellen Sie eine Apache-Konfiguration
/etc/apache2/sites-available/phpinfo.conf
. - Erstellen Sie eine PHP-Seite
/var/www/phpinfo/index.php
. - Aktivieren Sie die PHP-Infoseite, indem Sie einen symbolischen Link von
/etc/apache2/sites-enabled/phpinfo.conf
auf/etc/apache2/sites-available/phpinfo.conf
erstellen. - Deaktivieren Sie die Debian-Infoseite, indem Sie den symbolischen Link
/etc/apache2/sites-enabled/000-default.conf
entfernen. - Laden Sie die Apache-Konfiguration neu.
Verwenden Sie hierzu die folgenden Ansible-Module:
package
zur Installation von PHP (analog zu Apache).file
zum Erstellen von Verzeichnissen und symbolischer Links.- Beachten Sie die Parameter
state
undsrc
(für symbolische Links).
- Beachten Sie die Parameter
copy
zum Kopieren vorgegebener Dateien auf das Zielsystem.service
zum Verwalten von Diensten.- Der Zielzustand soll
reloaded
lautet.
- Der Zielzustand soll
Tipp: Gehen Sie in einzelnen Schritten vor, d.h. erweitern Sie das Playbook nur um jeweils einen Tasks und führen Sie es anschliessend aus:
ansible-playbook -i hosts.ini -c local apache.yaml
Verwenden Sie sprechende Bezeichnungen für den name
der einzelnen tasks
.
Da Ansible idempotent arbeitet, werden nur jeweils die noch ausstehenden Schritte durchgeführt.
Überprüfen Sie anschliessend, ob die PHP-Infoseite im Browser erscheint.
Nehmen Sie anschliessend das erweiterte Playbook apache.yaml
in dieses
Repository auf.
Aufgabe 2: PHP-FPM konfigurieren
Erstellen Sie ein neues Playbook namens php-fpm.yaml
, wobei Sie (bis
auf name
, welchen Sie anpassen) die ersten Zeilen vom Playbook apache.yaml
verwenden können (bis zu den Tasks). Erweitern Sie das Playbook um folgende
Tasks:
- Installieren Sie die Pakete
php8.2-fpm
undlibapache2-mod-fcgid
. - Deaktivieren Sie das Apache-Modul
php8.2
. - Aktivieren Sie das Apache-Modul
proxy_fcgi
. - Aktivieren Sie die Apache-Konfiguration
php-fpm
. - Laden Sie die Apache-Konfiguration neu, damit die Änderungen aktiv werden.
- Erhöhen Sie das
memory_limit
in der PHP-FPM-Konfiguration/etc/php/8.2/fpm/php.ini
von 128 auf 256 Megabyte. - Starten sie den PHP-FPM-Service neu, damit die Änderungen aktiv werden.
Verwenden Sie hierzu die folgenden Ansible-Module:
package
zur Installation von PHP-FPM.command
zum Deaktivieren/Aktivieren von Apache-Modulen bzw. -Konfigurationen mita2dismod
,a2enconf
usw.- Der
cmd
-Parameter definiert den auszuführenden Befehl. - Achtung: Durch die Verwendung von
command
wird das Playbook imperativ («tue das!») und ist nicht mehr deklarativ («sorge für diesen Zustand»)! Damit das Playbook trotzdem idempotent bleibt, kann die Ausführung des Befehls mit den Parameterncreates
bzw.removes
auf bestimmte Situationen beschränkt werden.- Aktivieren Sie ein Modul nur, wenn die entsprechende
*.load
-Datei noch nicht im Verzeichnis/etc/apache2/mods-enabled
besteht. - Deaktivieren Sie ein Modul nur, wenn die entsprechende
*.load
-Datei noch im Verzeichnis/etc/apache2/mods-enabled
besteht.
- Aktivieren Sie ein Modul nur, wenn die entsprechende
- Der
lineinfile
zum Ersetzen einer einzelnen Zeile in der PHP-Konfiguration.- Der
path
-Parameter gibt die zu verändernde Datei an. - Der
line
-Parameter definiert die neue Zeile. - Der
regexp
-Parameter definiert ein Muster (regulärer Ausdruck) für die zu ersetzende Zeile.
- Der
service
zum Neustarten bzw. Neuladen von einem systemd-Service.
Tipp: Der name
-Parameter unterstützt nicht nur einen einzelnen Wert,
sondern Listen von Werten:
name:
- foo
- bar
Kontrollieren Sie auf PHP-Infoseite zwei Sachen:
- Die
Server API
heisstFPM/FastCGI
und nicht mehrApache 2.0 Handler
. - Das
memory_limit
beträgt256M
und nicht mehr128M
.
Nehmen Sie anschliessend das neue Playbook php-fpm.yaml
in dieses Repository
auf.
Aufgabe 3: Minio in Betrieb nehmen
Erstellen Sie ein neues Playbook namens minio.yaml
analog zu den beiden
vorherigen. Vor dem Abschnitt tasks
soll ein neuer Abschnitt namens vars
eingefügt werden, in welchem die folgenden wiederverwendbaren Variablen
definiert werden:
vars:
minio_bin: /usr/local/bin/minio
minio_data_dir: TODO
minio_user: TODO
minio_group: TODO
minio_password: TODO
environment_file: TODO
tasks:
…
Ersetzen Sie dabei den Platzhalter TODO
durch die Werte, die gleich in der
Aufgabenstellung folgen. Die oben definierten Variablen können folgendermassen
verwendet werden:
# old
dest: /usr/local/bin/minio
# new
dest: '{{ minio_bin }}'
Dank Variablen können die gleichen Werte sowohl im Playbook als auch in Templates verwendet werden. Dadurch können Änderungen nun zentral vorgenommen ‒ und die hartkodierten Passwörter ausgelagert werden.
Ergänzen Sie das Playbook um folgende tasks
, um Minio in Betrieb zu nehmen:
- Laden Sie den Minio-Server
minio
von der Minio-Downloadseite herunter ins lokale Verzeichnis/usr/local/bin/
und machen Sie die Datei ausführbar. - Erstellen Sie einen Benutzergruppe namens
minio
und einen Benutzer gleichen Namens mit dem Home-Verzeichnis/home/minio
. - Erstellen Sie das Minio-Datenverzeichnis
/home/minio/minio-data
, welches dem Benutzerminio
gehört. - Erstellen Sie eine Datei
/home/minio/environment
mit den beiden UmgebungsvariablenMINIO_ROOT_USER=minio
undMINIO_ROOT_PASSWORD=topsecret
. - Erstellen Sie ein systemd-Unitfile unter
/etc/systemd/system/minio.service
auf Basis des Templatesminio.service.jinja2
.
Verwenden Sie hierzu die folgenden Ansible-Module:
get_url
zum Herunterladen von Dateien von einer bestimmten Quelle (url
) an einen bestimmten Ort (dest
). Damitminio
ausführbar ist, sollte dermode
-Parameter auf755
gesetzt werden. Optional kann auch auf eine bestimmtechecksum
geprüft werden.group
zum Erstellen einer Benutzergruppe.user
zum Erstellen eines Benutzers. Verwenden Sie die Parametercreate_home
,home
,group
, undshell
.template
zum Erstellen von Konfigurationsdateien aus Vorlagen. Geben Sie das Template alssrc
und die Zieldatei mitdest
an.systemd_service
zum Verwalten von systemd-Services. Setzen Siedaemon_reload: true
, damit das neu erstellte Service-Unit-File nachgeladen wird. Verwenden Sie weiter die Parameterenabled
undstate
, um den Service (automatisch) zu starten.
Wenn Sie alles richtig gemacht haben, steht Minio unter http://IP-ADRESSE:9090 zur Verfügung.
Tipp: Schauen Sie bei Unklarheiten im systemd-Repository nach, wie wir Minio manuell in Betrieb genommen haben.
Aufgabe 4: Passwörter mit Ansible Vault verschlüsseln
Passwörter im Klartext zu speichern ist ein Sicherheitsrisiko, zumal Playbooks und Template-Dateien oftmals in einem (öffentlichen) Git-Repository zu liegen kommen. Aus diesem Grund sollten Passwörter und andere Secrets (wie z.B. Token) nur verschlüsselt abgelegt werden.
In dieser Übung soll das Minio-Passwort aus dem Playbook entfernt, durch ein stärkeres ersetzt und verschlüsselt in eine separate Datei ausgelagert werden.
Zunächst soll die Variable minio_password
aus dem Playbook minio.yaml
entfernt werden. Unmittelbar nach vars
soll ein Abschnitt namens vars_files
hinzugefügt werden:
vars:
…
vars_files:
- minio-secrets.yaml
tasks:
…
Das Werkzeug pwgen
soll installiert werden, womit sich sichere zufällige
Passwörter generieren lassen:
sudo apt install -y pwgen
Ein zufälliges Passwort der Länge 36 lässt sich folgendermassen generieren:
pwgen 36 1
Mögliche Ausgabe:
Hie6sheim2FiefahWoo4vu7shisoozeeboka
Das Newline-Zeichen \n
am Ende soll jedoch entfernt werden, da dieses nicht
mitverschlüsselt werden soll:
pwgen 36 1 | tr -d '\n'
Als nächstes wird die Datei minio-secrets.yaml
mit der verschlüsselten
Variablen minio_password
mithilfe von ansible-vault
erstellt:
pwgen 36 1 | tr -d '\n' | ansible-vault encrypt_string --stdin-name minio_password > minio-secrets.yaml
Es wird ein Vault-Passwort interaktiv abgefragt, das man sich merken muss. (Mit diesem Passwort werden die Secrets bei der neuerlichen Ausführung des Playbooks entschlüsselt.)
Mit --stdin-name
wird angegeben, wie die Variable heissen soll, deren Wert per
stdin
mitgegeben werden soll. Die Datei minio-secrets.yaml
wurde nun erstellt
und enthält ein zufälliges, verschlüsseltes Secret.
Nun soll das angepasste Playbook mit dem angepassten und ausgelagerten Passwort
ausgeführt werden, wozu zusätzlich der Parameter --ask-vault-pass
angegeben
wird, damit das Passwort zum Entschlüsseln der verwendeten Secrets interaktiv
eingegeben werden kann:
ansible-playbook -i hosts.ini -c local --ask-vault-pass minio.yaml
Das neue Passwort sollte jetzt in /home/minio/environment
gesetzt sein und
unter http://IP-ADRESSE:9090 verwendet werden können.
Die Datei minio-secrets.yaml
kann nun ins Repository aufgenommen werden.