Compare commits
9
Commits
master
..
f690c6cb3c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f690c6cb3c | ||
|
|
a9d09acbbc | ||
|
|
6ede4604e1 | ||
|
|
cef71dcd1b | ||
|
|
f8a5505047 | ||
|
|
0249f34ddf | ||
|
|
e3b60540b0 | ||
|
|
5febb427e6 | ||
|
|
45ccd6a25f |
+2
-4
@@ -1,7 +1,5 @@
|
|||||||
hosts
|
hosts
|
||||||
proxmox.*
|
proxmox.*
|
||||||
.vscode
|
.vscode
|
||||||
.vault_pass
|
inventory
|
||||||
logs
|
.vault_pass
|
||||||
.zabbix-psk
|
|
||||||
setenv.sh
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
# AGENTS.md
|
|
||||||
|
|
||||||
Richtlinien und Kontext für AI-Agenten (z. B. Mammouth Code, Claude, GPT),
|
|
||||||
die an diesem Ansible-Repository arbeiten. Diese Datei fasst Repository-spezifische
|
|
||||||
Konventionen zusammen, damit Änderungen konsistent und nachvollziehbar bleiben.
|
|
||||||
|
|
||||||
## Repository-Übersicht
|
|
||||||
|
|
||||||
Zentrale Ansible-Sammlung für die Bereitstellung, Härtung, Aktualisierung und
|
|
||||||
Überwachung von Debian-Hosts.
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── ansible.cfg # Globale Ansible-Konfiguration
|
|
||||||
├── bootstrap.yml # Top-Level-Playbook für die Ersteinrichtung
|
|
||||||
├── execute.sh # Startet die Docker-Ausführungsumgebung
|
|
||||||
├── setenv.sh # Umgebungsvariablen für Proxmox (git-ignored)
|
|
||||||
├── vault.yml # Ansible-Vault-verschlüsselte Secrets
|
|
||||||
├── .vault_pass # Vault-Passwort (git-ignored)
|
|
||||||
├── docker/ # Dockerfile & Requirements für die Laufzeit-Umgebung
|
|
||||||
├── inventory/ # Inventories mit group_vars
|
|
||||||
├── logs/ # Update-Logs (git-ignored)
|
|
||||||
├── playbooks/ # Playbooks, die die Rollen einbinden
|
|
||||||
└── roles/ # Wiederverwendbare Ansible-Rollen
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollen
|
|
||||||
|
|
||||||
| Rolle | Kurzbeschreibung |
|
|
||||||
|---------------------|-----------------------------------------------------------------------------|
|
|
||||||
| `bootstrap` | Ersteinrichtung: Pakete, Admin-User, SSH, MOTD, sysctl, Docker, Monitoring |
|
|
||||||
| `docker` | Installation der Docker Engine über das offizielle Repository |
|
|
||||||
| `hawser` | Aktualisierung des Hawser Docker-Compose-Stacks |
|
|
||||||
| `healthcheck` | Quality-Gate: prüft laufende Container nach Updates |
|
|
||||||
| `manage-ssh-keys` | Verwaltung erwünschter/unerwünschter SSH-Keys (Hardening) |
|
|
||||||
| `monitoring` | Zabbix Agent 2: Installation, TLS-PSK, Docker-Plugin, API-Registrierung |
|
|
||||||
| `os-updates` | Debian-Paketaktualisierung mit Spiegel-Wechsel, Reboot & Logging |
|
|
||||||
|
|
||||||
Jede Rolle besitzt eine eigene `README.md` unter `roles/<name>/README.md`,
|
|
||||||
die Anforderungen, Variablen, Templates, Handler, Tags und Nutzung
|
|
||||||
dokumentiert. Die globale `README.md` im Repo-Root verweist auf diese
|
|
||||||
Rollen-READMEs und beschreibt Inventories, Playbooks und die
|
|
||||||
Docker-Ausführungsumgebung.
|
|
||||||
|
|
||||||
## WICHTIG: Dokumentationspflicht bei Änderungen
|
|
||||||
|
|
||||||
> **Jede neue Funktion, jeder neue Parameter und jede neue Variable MUSS
|
|
||||||
> dokumentiert werden.** Keine undokumentierten Änderungen committen.
|
|
||||||
|
|
||||||
### Wann welche README aktualisiert werden muss
|
|
||||||
|
|
||||||
| Art der Änderung | Zu aktualisierende Datei(en) |
|
|
||||||
|-----------------------------------------------------------|-------------------------------------------------------|
|
|
||||||
| Neue Variable in `defaults/main.yml` einer Rolle | `roles/<rolle>/README.md` (Abschnitt "Variablen") |
|
|
||||||
| Neue Task-Datei / neuer Subtask in einer Rolle | `roles/<rolle>/README.md` (Abschnitte "Funktionsweise" / "Tasks") |
|
|
||||||
| Neues Template oder Handler | `roles/<rolle>/README.md` (Abschnitt "Templates" / "Handler") |
|
|
||||||
| Neuer Tag | `roles/<rolle>/README.md` (Abschnitt "Tags") |
|
|
||||||
| Neues Playbook oder wesentliche Änderung an bestehendem | Globale `README.md` (Tabelle "Playbooks") |
|
|
||||||
| Neue Rolle | Globale `README.md` (Tabellen "Inhalt" & "Rollen") + `roles/<neu>/README.md` erstellen |
|
|
||||||
| Neues Inventory oder group_vars | Globale `README.md` (Abschnitt "Inventories") |
|
|
||||||
| Änderung an `ansible.cfg`, `execute.sh` oder `docker/` | Globale `README.md` |
|
|
||||||
| Änderung an Secrets / Vault-Handhabung | Globale `README.md` (Abschnitt "Secrets & Vault") |
|
|
||||||
|
|
||||||
### Konventionen für Rollen-READMEs
|
|
||||||
|
|
||||||
Jede `roles/<name>/README.md` soll mindestens folgende Abschnitte enthalten:
|
|
||||||
|
|
||||||
1. **Titel & Kurzbeschreibung** – was macht die Rolle, Verweis auf Repo-README
|
|
||||||
2. **Voraussetzungen** – OS, Collections, Zugriff
|
|
||||||
3. **Einbindung** – Beispiel-Playbook oder Aufruf
|
|
||||||
4. **Funktionsweise** – Reihenfolge der Tasks, was passiert
|
|
||||||
5. **Variablen** – Tabelle mit Name, Typ, Default, Beschreibung
|
|
||||||
- Trennen zwischen Variablen mit Defaults (`defaults/main.yml`) und
|
|
||||||
Steuer-Variablen ohne Defaults
|
|
||||||
6. **Templates** – Template-Datei → Ziel-Pfad
|
|
||||||
7. **Handler** – Handler-Name → Auslöser
|
|
||||||
8. **Tags** – verfügbare Tags und Beispiel
|
|
||||||
9. **Abhängigkeiten** – andere Rollen oder Collections
|
|
||||||
10. **Hinweise** – Besonderheiten, Plattform-Einschränkungen
|
|
||||||
|
|
||||||
### Konventionen für die globale README
|
|
||||||
|
|
||||||
- Tabellen für Playbooks, Inventories und Rollen aktuell halten
|
|
||||||
- Neue Rollen-READMEs in der Rollen-Tabelle verlinken
|
|
||||||
- Aufrufbeispiele bei neuen Playbooks ergänzen
|
|
||||||
|
|
||||||
## Technische Konventionen
|
|
||||||
|
|
||||||
### Sprache & Stil
|
|
||||||
|
|
||||||
- **Dokumentation** (`README.md`, Kommentare in Templates): Deutsch
|
|
||||||
- **Code**: Englisch (Variablennamen, Task-Names, Module)
|
|
||||||
- **Keine** Kommentare in Task-Dateien, außer wenn der User es ausdrücklich
|
|
||||||
wünscht (siehe System-Regeln). Inline-Doku über die READMEs laufen.
|
|
||||||
|
|
||||||
### Ansible-Stil
|
|
||||||
|
|
||||||
- Module grundsätzlich mit FQCN verwenden (`ansible.builtin.apt`,
|
|
||||||
`ansible.builtin.template`, …), ausgenommen ältere Tasks, die
|
|
||||||
kurze Namen nutzen – bei neuen Tasks FQCN verwenden.
|
|
||||||
- Variablen-Defaults immer in `defaults/main.yml`, nie hart in Tasks.
|
|
||||||
- Variablen pro Inventory in `inventory/group_vars/<gruppe>.yml` überschreiben.
|
|
||||||
- Templates nutzen `# {{ ansible_managed }}` als Header.
|
|
||||||
- Tasks sind in Subtask-Dateien (`tasks/<name>.yml`) ausgelagert, wenn eine
|
|
||||||
Rolle mehr als eine logische Einheit hat. `tasks/main.yml` enthält nur
|
|
||||||
`import_tasks`/`include_tasks` und `import_role`.
|
|
||||||
|
|
||||||
### Secrets
|
|
||||||
|
|
||||||
- Sensible Werte (Passwörter, API-Keys) gehören in `vault.yml` (verschlüsselt).
|
|
||||||
- `.vault_pass`, `setenv.sh`, `logs/`, `.zabbix-psk` sind git-ignored und
|
|
||||||
dürfen **niemals** committet werden.
|
|
||||||
- Klartext-Secrets in `defaults/` oder `group_vars/` vermeiden; stattdessen
|
|
||||||
Vault-Referenz verwenden.
|
|
||||||
|
|
||||||
### OS-Unterstützung
|
|
||||||
|
|
||||||
- Alle Playbooks prüfen `ansible_facts['os_family'] == "Debian"` und brechen
|
|
||||||
bei Nicht-Debian ab. Neue Playbooks müssen diesen Check enthalten.
|
|
||||||
- LXC-Container: Tasks, die `sysctl` oder `reboot` betreffen, müssen
|
|
||||||
`virtualization_type != "lxc"` prüfen und übersprungen werden.
|
|
||||||
|
|
||||||
### Tags
|
|
||||||
|
|
||||||
- Verwendete Tags pro Rolle in der jeweiligen README dokumentieren.
|
|
||||||
- Gängige Tags: `ssh`, `motd`, `bashrc`, `sysctl`, `monitoring`.
|
|
||||||
|
|
||||||
### Collections
|
|
||||||
|
|
||||||
Benötigte Collections (in `docker/requirements.yml`):
|
|
||||||
|
|
||||||
- `ansible.posix`
|
|
||||||
- `community.general`
|
|
||||||
- `community.docker`
|
|
||||||
- `community.zabbix` (nur in der `monitoring`-Rolle verwendet – ggf. ergänzen)
|
|
||||||
|
|
||||||
### Docker-Ausführungsumgebung
|
|
||||||
|
|
||||||
- `docker/Dockerfile` baut ein `debian:trixie-slim`-Image mit `ansible-core`.
|
|
||||||
- `execute.sh` startet einen interaktiven Container, der das Repo nach
|
|
||||||
`/ansible` mountet und SSH-Keys unter `/root/.ssh` bereithält.
|
|
||||||
- Bei Änderung der Collections muss `docker/requirements.yml` aktualisiert und
|
|
||||||
ein Image-Rebuild durchgeführt werden.
|
|
||||||
|
|
||||||
## Testing & Verifikation
|
|
||||||
|
|
||||||
1. Änderungen im Docker-Container testen: `./execute.sh`
|
|
||||||
2. Lint prüfen, falls verfügbar: `ansible-lint` (nicht im Repo vorausgesetzt,
|
|
||||||
aber empfohlen).
|
|
||||||
3. Playbook Dry-Run: `--check` verwenden, wo sinnvoll.
|
|
||||||
4. Nach Änderungen an einer Rolle die zugehörige `README.md` aktualisieren.
|
|
||||||
|
|
||||||
## Häufige Fallstricke
|
|
||||||
|
|
||||||
- **`os_update_version_codename`** in `inventory/group_vars/debian.yml`:
|
|
||||||
Default `trixie`. Nicht blind ändern – wird für Template-Ausfüllung der
|
|
||||||
`sources.list` verwendet.
|
|
||||||
- **`ssh_service_name`**: Auf manchen Hosts heißt der Service `ssh`, nicht
|
|
||||||
`sshd` (siehe `inventory/dmc12.yml`: `gitea`, `ipam`). Beim Hinzufügen
|
|
||||||
neuer Hosts prüfen.
|
|
||||||
- **PSK-Store**: `monitoring` speichert pro Host eine PSK unter
|
|
||||||
`.zabbix-psk/<hostname>.psk` (git-ignored). Bei Host-Umbenennung PSK
|
|
||||||
migrieren oder neu generieren – sonst stimmt die Zabbix-Registrierung nicht.
|
|
||||||
- **Logs**: `os-updates` und `healthcheck` schreiben Logs nach
|
|
||||||
`logs/<inventory>/<hostname>/update.log` (auf dem Controller, delegiert).
|
|
||||||
Verzeichnis ist git-ignored.
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
# Ansible Playbooks
|
|
||||||
|
|
||||||
Zentrale Ansible-Sammlung für die Bereitstellung, Härtung, Aktualisierung und
|
|
||||||
Überwachung von Debian-Hosts. Das Repository enthält eigenständige Rollen,
|
|
||||||
zugehörige Playbooks, mehrere Inventories sowie eine Docker-basierte
|
|
||||||
Ausführungsumgebung, sodass Playbooks direkt aus einem Container heraus
|
|
||||||
gestartet werden können.
|
|
||||||
|
|
||||||
## Inhaltsübersicht
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── ansible.cfg # Globale Ansible-Konfiguration
|
|
||||||
├── bootstrap.yml # Top-Level-Playbook für die Ersteinrichtung
|
|
||||||
├── execute.sh # Startet die Docker-Ausführungsumgebung
|
|
||||||
├── setenv.sh # Umgebungsvariablen für Proxmox (nicht im Repo)
|
|
||||||
├── vault.yml # Ansible-Vault-verschlüsselte Secrets
|
|
||||||
├── docker/ # Dockerfile & Requirements für die Laufzeit-Umgebung
|
|
||||||
├── inventory/ # Inventories mit group_vars
|
|
||||||
├── logs/ # Update-Logs (git-ignored)
|
|
||||||
├── playbooks/ # Playbooks, die die Rollen einbinden
|
|
||||||
└── roles/ # Wiederverwendbare Ansible-Rollen
|
|
||||||
```
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- **Ansible** >= 2.20 (im Docker-Image bereits enthalten)
|
|
||||||
- **Ziel-Hosts**: Debian (alle Playbooks prüfen `os_family == "Debian"`)
|
|
||||||
- **Ansible-Collections**: `ansible.posix`, `community.general`,
|
|
||||||
`community.docker`, `community.zabbix` (siehe `docker/requirements.yml`)
|
|
||||||
- **Zugang**: SSH-Zugang als Benutzer `admin` mit hinterlegtem Public Key
|
|
||||||
|
|
||||||
### Docker-Ausführungsumgebung
|
|
||||||
|
|
||||||
Damit Playbooks nicht lokal installiert werden müssen, liefert das Repository
|
|
||||||
ein fertiges Docker-Image. `execute.sh` erstellt ein IPv6-fähiges Bridge-Netzwerk,
|
|
||||||
startet einen interaktiven Container und mountet das Repository nach `/ansible`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./execute.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Im Container stehen Aliase wie `ap` (ansible-playbook), `ag` (ansible-galaxy)
|
|
||||||
und `av` (ansible-vault) zur Verfügung. Das Image wird über
|
|
||||||
`docker/Dockerfile` gebaut, die benötigten Collections werden beim Build
|
|
||||||
automatisch installiert.
|
|
||||||
|
|
||||||
## Inventories
|
|
||||||
|
|
||||||
Alle Inventories liegen unter `inventory/`. Pro Inventory existiert eine
|
|
||||||
gleichnamige Datei sowie ein Eintrag in `group_vars/`:
|
|
||||||
|
|
||||||
| Inventory | Datei | group_vars | Beschreibung |
|
|
||||||
|------------------|--------------------|------------------------|-------------------------------------------------|
|
|
||||||
| DMC12 (Umgebung) | `dmc12.yml` | `debian.yml` | Debian-Hosts & Proxmox-Knoten |
|
|
||||||
| Home | `home.yml` | `home.yml` | Heimisches Netzwerk (10.13.37.0/24) |
|
|
||||||
| External | `external.yml` | `external.yml` | Externe Hosts (IPv6) |
|
|
||||||
|
|
||||||
Die `group_vars` definieren standortspezifische Werte wie Zabbix-Server,
|
|
||||||
Spiegelserver und autorisierte SSH-Keys.
|
|
||||||
|
|
||||||
## Playbooks
|
|
||||||
|
|
||||||
| Playbook | Rolle(n) | Zweck |
|
|
||||||
|---------------------------------------|-----------------------------------|--------------------------------------------------------|
|
|
||||||
| `bootstrap.yml` | bootstrap | Vollständige Ersteinrichtung eines Debian-Hosts |
|
|
||||||
| `playbooks/docker.yml` | docker | Docker Engine installieren |
|
|
||||||
| `playbooks/monitoring.yml` | monitoring | Zabbix Agent 2 installieren & registrieren |
|
|
||||||
| `playbooks/os-updates-deb.yml` | os-updates, healthcheck | Pakete aktualisieren + Healthcheck |
|
|
||||||
| `playbooks/upgrade-hawser.yml` | hawser | Hawser-Stack aktualisieren |
|
|
||||||
| `playbooks/hardening/manage-ssh-keys.yml` | manage-ssh-keys | SSH-Schlüssel hartieren |
|
|
||||||
|
|
||||||
### Aufrufbeispiele
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Ersteinrichtung aller Hosts im DMC12-Inventory
|
|
||||||
ansible-playbook -i inventory/dmc12.yml bootstrap.yml
|
|
||||||
|
|
||||||
# Nur Docker auf einem einzelnen Host installieren
|
|
||||||
ansible-playbook -i inventory/home.yml playbooks/docker.yml -l rp
|
|
||||||
|
|
||||||
# OS-Updates inkl. Healthcheck
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
|
|
||||||
|
|
||||||
# Hawser aktualisieren
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/upgrade-hawser.yml
|
|
||||||
|
|
||||||
# SSH-Keys härtene
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/hardening/manage-ssh-keys.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollen
|
|
||||||
|
|
||||||
| Rolle | Kurzbeschreibung | Dokumentation |
|
|
||||||
|---------------------|-----------------------------------------------------------------------------|-------------------------------------|
|
|
||||||
| `bootstrap` | Ersteinrichtung: Pakete, Admin-User, SSH, MOTD, sysctl, Docker, Monitoring | [roles/bootstrap/README.md](roles/bootstrap/README.md) |
|
|
||||||
| `docker` | Installation der Docker Engine über das offizielle Repository | [roles/docker/README.md](roles/docker/README.md) |
|
|
||||||
| `hawser` | Aktualisierung des Hawser Docker-Compose-Stacks | [roles/hawser/README.md](roles/hawser/README.md) |
|
|
||||||
| `healthcheck` | Quality-Gate: prüft laufende Container nach Updates | [roles/healthcheck/README.md](roles/healthcheck/README.md) |
|
|
||||||
| `manage-ssh-keys` | Verwaltung erwünschter/unerwünschter SSH-Keys (Hardening) | [roles/manage-ssh-keys/README.md](roles/manage-ssh-keys/README.md) |
|
|
||||||
| `monitoring` | Zabbix Agent 2: Installation, TLS-PSK, Docker-Plugin, API-Registrierung | [roles/monitoring/README.md](roles/monitoring/README.md) |
|
|
||||||
| `os-updates` | Debian-Paketaktualisierung mit Spiegel-Wechsel, Reboot & Logging | [roles/os-updates/README.md](roles/os-updates/README.md) |
|
|
||||||
|
|
||||||
## Secrets & Vault
|
|
||||||
|
|
||||||
Sensible Werte (z. B. `monitoring_zabbix_api_password`, `admin_password`)
|
|
||||||
liegen verschlüsselt in `vault.yml`. Zum Entschlüsseln wird eine Vault-Passwort
|
|
||||||
benötigt, die in `.vault_pass` hinterlegt ist (git-ignored). Beim Aufruf muss
|
|
||||||
Ansible die Vault-Passwort-Datei kennen:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml --vault-password-file .vault_pass bootstrap.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Hinweis:** Die Datei `setenv.sh` enthält Zugangsdaten für Proxmox und ist
|
|
||||||
> bewusst nicht für eine Veröffentlichung vorgesehen. `.vault_pass` und
|
|
||||||
> `setenv.sh` stehen in `.gitignore`.
|
|
||||||
|
|
||||||
## Logging
|
|
||||||
|
|
||||||
Die Rollen `os-updates` und `healthcheck` schreiben pro Host ein Update-Log
|
|
||||||
unter `logs/<inventory>/<hostname>/update.log`. Das Verzeichnis `logs/` ist
|
|
||||||
git-ignored und dient als lokales Audit-Trail.
|
|
||||||
|
|
||||||
## Konfiguration
|
|
||||||
|
|
||||||
`ansible.cfg` deaktiviert Host-Key-Checking und legt `./roles` als
|
|
||||||
Rollen-Pfad fest. SSH-Verbindungen verwenden
|
|
||||||
`StrictHostKeyChecking=no` sowie `/dev/null` als KnownHosts-Datei, was die
|
|
||||||
Ersteinrichtung neuer Hosts erleichtert – in produktiven Umgebungen
|
|
||||||
entsprechend restriktiver konfigurieren.
|
|
||||||
|
|
||||||
## Beitragen
|
|
||||||
|
|
||||||
1. Änderungen lokal testen – idealerweise über `./execute.sh` im Container.
|
|
||||||
2. Variablen in `defaults/main.yml` der jeweiligen Rolle pflegen und in der
|
|
||||||
Rollen-README dokumentieren.
|
|
||||||
3. Keine Secrets unverschlüsselt committen (Vault nutzen).
|
|
||||||
+4
-1
@@ -2,6 +2,9 @@
|
|||||||
host_key_checking = False
|
host_key_checking = False
|
||||||
roles_path = ./roles:/etc/ansible/roles
|
roles_path = ./roles:/etc/ansible/roles
|
||||||
group_vars = ./group_vars
|
group_vars = ./group_vars
|
||||||
|
forks = 20
|
||||||
|
strategy = free
|
||||||
|
|
||||||
[ssh_connection]
|
[ssh_connection]
|
||||||
ssh_args = -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
|
ssh_args = -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=1800s
|
||||||
|
pipelining = True
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
- hosts: all
|
- hosts: all
|
||||||
become: true
|
become: true
|
||||||
user: admin
|
remote_user: "{{ user|default('admin') }}"
|
||||||
tasks:
|
tasks:
|
||||||
- name: Verify if system is Debian
|
- name: Verify if system is Debian
|
||||||
debug:
|
debug:
|
||||||
|
|||||||
+30
-34
@@ -1,35 +1,31 @@
|
|||||||
FROM debian:trixie-slim
|
FROM debian:trixie-slim
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ENV TZ=Europe/Berlin
|
ENV TZ=Europe/Berlin
|
||||||
ENV ANSIBLE_VERSION=2.20.6
|
ENV ANSIBLE_VERSION=2.20.6
|
||||||
ENV PIP_BREAK_SYSTEM_PACKAGES=1
|
ENV PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
|
|
||||||
RUN apt update && apt install -y --no-install-recommends \
|
RUN apt update && apt install -y --no-install-recommends \
|
||||||
nano \
|
nano \
|
||||||
git \
|
git \
|
||||||
wget \
|
wget \
|
||||||
unzip \
|
unzip \
|
||||||
curl \
|
curl \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
tzdata \
|
tzdata \
|
||||||
openssh-client \
|
openssh-client \
|
||||||
iputils-ping \
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
RUN mkdir -p /etc/ssh/ssh_config.d \
|
||||||
RUN mkdir -p /etc/ssh/ssh_config.d \
|
&& printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /etc/ssh/ssh_config.d/99-no-hostkey-check.conf
|
||||||
&& printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /etc/ssh/ssh_config.d/99-no-hostkey-check.conf
|
|
||||||
|
RUN pip3 install --no-cache-dir --upgrade \
|
||||||
RUN pip3 install --no-cache-dir --upgrade \
|
ansible-core~=${ANSIBLE_VERSION}
|
||||||
ansible-core~=${ANSIBLE_VERSION}
|
|
||||||
|
RUN mkdir -p /root/.bashrc.d
|
||||||
RUN mkdir -p /root/.bashrc.d
|
COPY ansible-functs.sh /root/.bashrc.d/ansible-functs.sh
|
||||||
COPY ansible-functs.sh /root/.bashrc.d/ansible-functs.sh
|
RUN chmod +x /root/.bashrc.d/ansible-functs.sh \
|
||||||
RUN chmod +x /root/.bashrc.d/ansible-functs.sh \
|
&& printf '\n[ -f /root/.bashrc.d/ansible-functs.sh ] && . /root/.bashrc.d/ansible-functs.sh\n' >> /root/.bashrc
|
||||||
&& printf '\n[ -f /root/.bashrc.d/ansible-functs.sh ] && . /root/.bashrc.d/ansible-functs.sh\n' >> /root/.bashrc
|
|
||||||
|
WORKDIR /ansible
|
||||||
COPY requirements.yml /ansible/requirements.yml
|
|
||||||
RUN ansible-galaxy collection install -r /ansible/requirements.yml
|
|
||||||
|
|
||||||
WORKDIR /ansible
|
|
||||||
|
|
||||||
CMD ["ansible-playbook", "--version"]
|
CMD ["ansible-playbook", "--version"]
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: ansible.posix
|
|
||||||
version: 2.2.0
|
|
||||||
- name: community.general
|
|
||||||
version: 13.0.1
|
|
||||||
- name: community.docker
|
|
||||||
version: 5.2.0
|
|
||||||
Executable → Regular
@@ -1,37 +0,0 @@
|
|||||||
debian:
|
|
||||||
hosts:
|
|
||||||
rp:
|
|
||||||
ansible_host: 192.168.212.50
|
|
||||||
bitwarden:
|
|
||||||
ansible_host: 192.168.212.20
|
|
||||||
pdf:
|
|
||||||
ansible_host: 192.168.212.65
|
|
||||||
mailcow:
|
|
||||||
ansible_host: 192.168.212.70
|
|
||||||
plex:
|
|
||||||
ansible_host: 192.168.212.62
|
|
||||||
cloud:
|
|
||||||
ansible_host: 192.168.212.60
|
|
||||||
romm:
|
|
||||||
ansible_host: 192.168.212.64
|
|
||||||
gitea:
|
|
||||||
ansible_host: 192.168.212.30
|
|
||||||
ssh_service_name: ssh
|
|
||||||
ipam:
|
|
||||||
ansible_host: 192.168.212.56
|
|
||||||
ssh_service_name: ssh
|
|
||||||
teamspeck6:
|
|
||||||
ansible_host: 192.168.212.75
|
|
||||||
wiki:
|
|
||||||
ansible_host: 192.168.212.55
|
|
||||||
patchmon:
|
|
||||||
ansible_host: 192.168.212.80
|
|
||||||
einstein-dns:
|
|
||||||
ansible_host: 192.168.212.53
|
|
||||||
|
|
||||||
proxmox:
|
|
||||||
hosts:
|
|
||||||
dmc12:
|
|
||||||
ansible_host: 192.168.212.10
|
|
||||||
pbs:
|
|
||||||
ansible_host: 192.168.212.11
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
debian:
|
|
||||||
hosts:
|
|
||||||
healthcheck:
|
|
||||||
ansible_host: 2a01:4f8:1c1e:62dd::1
|
|
||||||
netbird:
|
|
||||||
ansible_host: 2a01:4f8:1c1c:8c8::1
|
|
||||||
teleport:
|
|
||||||
ansible_host: 2a01:4f8:1c19:c7d::1
|
|
||||||
podcast-linkstack:
|
|
||||||
ansible_host: 2a01:4f8:c17:de13::1
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# Standardwerte, die überschrieben werden können
|
|
||||||
os_update_auto_upgrade: true
|
|
||||||
os_also_update_mirror: false
|
|
||||||
os_update_mirrors:
|
|
||||||
# Role needs two mirros to use for the sources.list.j2 Template
|
|
||||||
- "http://deb.debian.org/debian" # Enter a main mirror here (not security)
|
|
||||||
- "http://security.debian.org/debian-security" # Enter a security mirror here
|
|
||||||
os_update_version_codename: "trixie" # KEEP UNTOUCHED!! | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
---
|
|
||||||
# SSH authorized keys for admin user
|
|
||||||
# Format: key and optional comment
|
|
||||||
admin_authorized_keys:
|
|
||||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/XwF0Na+YH7lRqGtwEcyIMVGTQZetNDrC9sZ8ofjC5 niklas@Linkman-PC"
|
|
||||||
comment: "Niklas - Linkman-PC"
|
|
||||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
|
|
||||||
comment: "Generic Ansible Key"
|
|
||||||
|
|
||||||
# Admin user password (hashed with SHA-512)
|
|
||||||
admin_password: "$6$NmIxM3ZbJDsbC1E6$BO8ag1ZyBqbhELjk0ppKV0CLnYXhHDp9oZc.jmkc62N9hjwbXihF1FmvsYgMKKINVcwaE73u2dRO8pnE6yEGH/"
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
monitoring_zabbix_passive_servers: ["10.13.37.1"]
|
|
||||||
monitoring_zabbix_active_servers: ["10.13.37.1"]
|
|
||||||
|
|
||||||
# Zabbix server API (password lives in vault.yml as monitoring_zabbix_api_password)
|
|
||||||
monitoring_zabbix_api_url: "https://zabbix/api_jsonrpc.php"
|
|
||||||
monitoring_zabbix_api_user: Admin
|
|
||||||
monitoring_zabbix_api_validate_certs: true
|
|
||||||
|
|
||||||
# Host registration defaults for the home inventory
|
|
||||||
monitoring_zabbix_host_groups: ["Linux servers"]
|
|
||||||
monitoring_zabbix_templates: ["Linux by Zabbix agent", "Zabbix agent2"]
|
|
||||||
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent2"]
|
|
||||||
|
|
||||||
# --- Zabbix Proxy (optional) -------------------------------------------------
|
|
||||||
# Leave empty to have agents talk to the Zabbix server directly.
|
|
||||||
# Per-site override example (e.g. inventory/group_vars/standort-a.yml):
|
|
||||||
# monitoring_zabbix_proxy: "fw-standort-a"
|
|
||||||
# monitoring_zabbix_proxy_address: "10.20.30.1"
|
|
||||||
monitoring_zabbix_proxy: ""
|
|
||||||
monitoring_zabbix_proxy_address: ""
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
home:
|
|
||||||
children:
|
|
||||||
debian:
|
|
||||||
hosts:
|
|
||||||
rp:
|
|
||||||
ansible_host: 10.13.37.11
|
|
||||||
paperless:
|
|
||||||
ansible_host: 10.13.37.30
|
|
||||||
homeassistant:
|
|
||||||
ansible_host: 10.13.37.15
|
|
||||||
teleport-jumper:
|
|
||||||
ansible_host: 10.13.37.50
|
|
||||||
idris-dns:
|
|
||||||
ansible_host: 10.13.37.53
|
|
||||||
it-tools:
|
|
||||||
ansible_host: 10.13.37.16
|
|
||||||
proxmox:
|
|
||||||
hosts:
|
|
||||||
tardis:
|
|
||||||
ansible_host: 10.13.37.5
|
|
||||||
+17
-17
@@ -1,18 +1,18 @@
|
|||||||
- hosts: all
|
- hosts: all
|
||||||
user: admin
|
user: admin
|
||||||
become: true
|
become: true
|
||||||
tasks:
|
tasks:
|
||||||
- name: Verify if system is Debian
|
- name: Verify if system is Debian
|
||||||
debug:
|
debug:
|
||||||
msg: "This playbook is running on a Debian system."
|
msg: "This playbook is running on a Debian system."
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
when: ansible_facts['os_family'] == "Debian"
|
||||||
|
|
||||||
- name: Stop playbook if system is not Debian
|
- name: Stop playbook if system is not Debian
|
||||||
fail:
|
fail:
|
||||||
msg: "This playbook only supports Debian."
|
msg: "This playbook only supports Debian."
|
||||||
when: ansible_facts['os_family'] != "Debian"
|
when: ansible_facts['os_family'] != "Debian"
|
||||||
|
|
||||||
- name: Include monitoring role
|
- name: Include monitoring role
|
||||||
import_role:
|
import_role:
|
||||||
name: monitoring
|
name: monitoring
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
when: ansible_facts['os_family'] == "Debian"
|
||||||
@@ -15,9 +15,4 @@
|
|||||||
- name: Include OS update role
|
- name: Include OS update role
|
||||||
include_role:
|
include_role:
|
||||||
name: os-updates
|
name: os-updates
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
|
|
||||||
- name: Include healthcheck role (post-update quality gate)
|
|
||||||
include_role:
|
|
||||||
name: healthcheck
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
when: ansible_facts['os_family'] == "Debian"
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
- hosts: all
|
|
||||||
user: admin
|
|
||||||
become: true
|
|
||||||
tasks:
|
|
||||||
- name: Verify if system is Debian
|
|
||||||
debug:
|
|
||||||
msg: "This playbook is running on a Debian system."
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
|
|
||||||
- name: Stop playbook if system is not Debian
|
|
||||||
fail:
|
|
||||||
msg: "This playbook only supports Debian."
|
|
||||||
when: ansible_facts['os_family'] != "Debian"
|
|
||||||
|
|
||||||
- name: Include hawser role
|
|
||||||
import_role:
|
|
||||||
name: hawser
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
# Rolle `bootstrap`
|
|
||||||
|
|
||||||
Ersteinrichtung (Provisioning) eines frischen Debian-Hosts. Die Rolle legt den
|
|
||||||
Admin-User an, installiert Basispakete, härtet die SSH-Konfiguration, verteilt
|
|
||||||
autorisierte SSH-Keys, konfiguriert Tastaturlayout, MOTD, Bash-Aliase und
|
|
||||||
sysctl, und bindet optional die Rollen `docker` und `monitoring` ein.
|
|
||||||
|
|
||||||
> Siehe auch das Top-Level-Playbook `bootstrap.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- SSH-Zugang als Benutzer, der `become` darf (Playbook nutzt `user: admin`)
|
|
||||||
- `ansible.posix` Collection (für `sysctl`-Modul)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
Die Rolle wird normalerweise über das Top-Level-Playbook `bootstrap.yml`
|
|
||||||
aufgerufen, kann aber auch direkt per `include_role`/`import_role` eingebunden
|
|
||||||
werden:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: bootstrap
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml --vault-password-file .vault_pass bootstrap.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` reiht die Subtasks nacheinander aus und bindet am Ende
|
|
||||||
bedarfsabhängig die Rollen `docker` und `monitoring` ein:
|
|
||||||
|
|
||||||
1. `install-basicpackages.yml` – Basispakete installieren
|
|
||||||
2. `create-admin-user.yml` – Admin-User anlegen + sudoers
|
|
||||||
3. `set-motd.yml` – MOTD via fastfetch (`tags: motd`)
|
|
||||||
4. `set-keyboardlayout.yml` – QWERTZ-Layout
|
|
||||||
5. `install-openssh.yml` – OpenSSH Server/Client (`tags: ssh`)
|
|
||||||
6. `configure-ssh.yml` – sshd_config härtbar (`tags: ssh`)
|
|
||||||
7. `add-ssh-keys.yml` – authorized_keys verteilen (`tags: ssh`)
|
|
||||||
8. `setup-bashrc.yml` – nützliche Aliase (`tags: bashrc`)
|
|
||||||
9. `configure-sysctl.yml` – vm.swappiness = 10 (`tags: sysctl`)
|
|
||||||
10. `import_role: docker` (sofern nicht `skip_docker`)
|
|
||||||
11. `import_role: monitoring` (sofern nicht `skip_monitoring`)
|
|
||||||
|
|
||||||
### Installierte Basispakete
|
|
||||||
|
|
||||||
`fastfetch`, `htop`, `curl`, `wget`, `git`, `sudo`, `console-setup`,
|
|
||||||
`qemu-guest-agent`, `cron`, `net-tools`, `tcpdump`, `locales-all`.
|
|
||||||
|
|
||||||
### SSH-Härtung
|
|
||||||
|
|
||||||
Die Vorlage `templates/sshd.conf.j2` deaktiviert Root-Login und
|
|
||||||
Passwort-Authentifizierung, erlaubt ausschließlich Publickey-Auth und setzt
|
|
||||||
restriktive Forwarding-/Logging-Optionen. Nach Änderung wird der sshd via
|
|
||||||
Handler neu gestartet.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-------------------------|----------|-------------------|-----------------------------------------------------|
|
|
||||||
| `admin_authorized_keys` | list | siehe `defaults/` | Liste von `{ key, comment }`-Einträgen für `admin` |
|
|
||||||
| `admin_password` | string | siehe `defaults/` | SHA-512-Hash des Admin-Passworts |
|
|
||||||
|
|
||||||
### Steuer-Variablen (keine Defaults, optional setzen)
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|--------------------|--------|---------|-----------------------------------------------------------|
|
|
||||||
| `skip_docker` | bool | `false` | Wenn `true`, wird die `docker`-Rolle übersprungen |
|
|
||||||
| `skip_monitoring` | bool | `false` | Wenn `true`, wird die `monitoring`-Rolle übersprungen |
|
|
||||||
| `ssh_service_name` | string | `sshd` | Name des SSH-Service (überschrieben bspw. für `ssh`) |
|
|
||||||
|
|
||||||
`admin_authorized_keys` wird auch pro Inventory in `group_vars/external.yml`
|
|
||||||
überschrieben. Der Handler `Restart sshd` verwendet `ssh_service_name`, sofern
|
|
||||||
gesetzt (z. B. `ssh` für `gitea`/`ipam` in `inventory/dmc12.yml`).
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel |
|
|
||||||
|------------------------|------------------------------------------------|
|
|
||||||
| `sshd.conf.j2` | `/etc/ssh/sshd_config` (validiert via `sshd -T`) |
|
|
||||||
| `authorized_keys.j2` | `/home/admin/.ssh/authorized_keys` |
|
|
||||||
| `sudoers-admin.j2` | `/etc/sudoers.d/10-admin` (validiert via `visudo -cf`) |
|
|
||||||
| `keyboard.j2` | `/etc/default/keyboard` |
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser |
|
|
||||||
|-------------------------|-------------------------------------------|
|
|
||||||
| `Restart sshd` | Änderung an `sshd_config` |
|
|
||||||
| `Reload keyboard layout`| Änderung an `/etc/default/keyboard` |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
`motd`, `ssh`, `bashrc`, `sysctl` – ermöglichen das gezielte Re-Apply einzelner
|
|
||||||
Teile, z. B.:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook bootstrap.yml -i inventory/dmc12.yml -t ssh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- `docker` (optional, via `import_role`)
|
|
||||||
- `monitoring` (optional, via `import_role`)
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- `configure-sysctl.yml` wird auf LXC-Containern übersprungen
|
|
||||||
(`virtualization_type != "lxc"`).
|
|
||||||
- `setup-bashrc.yml` legt Aliase für alle regulären User inkl. root an.
|
|
||||||
- `install-openssh.yml` entfernt ggf. das Meta-Paket `ssh` vor der
|
|
||||||
Installation von `openssh-server`/`openssh-client`.
|
|
||||||
@@ -3,9 +3,7 @@
|
|||||||
service:
|
service:
|
||||||
name: "{{ ssh_service_name | default('sshd') }}"
|
name: "{{ ssh_service_name | default('sshd') }}"
|
||||||
state: restarted
|
state: restarted
|
||||||
remote_user: admin
|
|
||||||
|
|
||||||
- name: Reload keyboard layout
|
- name: Reload keyboard layout
|
||||||
shell: setupcon
|
shell: setupcon
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
remote_user: admin
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Configure swappiness to reduce swap usage
|
|
||||||
become: yes
|
|
||||||
ansible.posix.sysctl:
|
|
||||||
name: vm.swappiness
|
|
||||||
value: 10
|
|
||||||
state: present
|
|
||||||
reload: yes
|
|
||||||
when: ansible_facts['virtualization_type'] != "lxc"
|
|
||||||
@@ -18,15 +18,4 @@
|
|||||||
tags: ssh
|
tags: ssh
|
||||||
|
|
||||||
- import_tasks: setup-bashrc.yml
|
- import_tasks: setup-bashrc.yml
|
||||||
tags: bashrc
|
tags: bashrc
|
||||||
|
|
||||||
- import_tasks: configure-sysctl.yml
|
|
||||||
tags: sysctl
|
|
||||||
|
|
||||||
- import_role:
|
|
||||||
name: docker
|
|
||||||
when: not skip_docker | default(false)
|
|
||||||
|
|
||||||
- import_role:
|
|
||||||
name: monitoring
|
|
||||||
when: not skip_monitoring | default(false)
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
# Rolle `docker`
|
|
||||||
|
|
||||||
Installiert die Docker Engine über das offizielle Docker-Repository für Debian.
|
|
||||||
Die Rolle fügt den Docker-GPG-Key hinzu, richtet eine APT-Quelle im deb822-Format
|
|
||||||
ein und installiert alle benötigten Pakete (Engine, CLI, containerd, Buildx- und
|
|
||||||
Compose-Plugin).
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/docker.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- Internetzugang zum Docker-Repository (`download.docker.com`)
|
|
||||||
- Benutzer mit `become`-Rechten
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
Die Rolle wird typischerweise über das Playbook `playbooks/docker.yml` oder
|
|
||||||
automatisch durch die `bootstrap`-Rolle (`import_role`) aufgerufen. Direkte
|
|
||||||
Einbindung per `import_role`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: docker
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/docker.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` inkludiert die eigentliche Installations-Logik aus
|
|
||||||
`tasks/install-docker.yml`:
|
|
||||||
|
|
||||||
1. **apt-Cache aktualisieren** – `cache_valid_time: 3600`
|
|
||||||
2. **Voraussetzungen installieren** – `ca-certificates`, `curl`
|
|
||||||
3. **Keyring-Verzeichnis anlegen** – `/etc/apt/keyrings` (Mode `0755`)
|
|
||||||
4. **Docker GPG-Key herunterladen** – nach `/etc/apt/keyrings/docker.asc`
|
|
||||||
5. **APT-Quelle einrichten** – Template `sources.list.j2` nach
|
|
||||||
`/etc/apt/sources.list.d/docker.sources` (deb822-Format)
|
|
||||||
6. **apt-Cache aktualisieren** – nach Repository-Hinzufügung
|
|
||||||
7. **Docker-Pakete installieren** – `docker_packages` (benachrichtigt Handler
|
|
||||||
`Start Docker`)
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|----------------------|---------|--------------------------------------|-------------------------------------------------------|
|
|
||||||
| `docker_mirror` | string | `https://download.docker.com/linux/debian` | Basis-URL des Docker-APT-Repositories |
|
|
||||||
| `os_version_codename`| string | `{{ ansible_lsb.codename }}` | Codename der Distribution (für `Suites:`) |
|
|
||||||
| `docker_packages` | list | siehe unten | Liste der zu installierenden Docker-Pakete |
|
|
||||||
|
|
||||||
Default `docker_packages`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
docker_packages:
|
|
||||||
- docker-ce
|
|
||||||
- docker-ce-cli
|
|
||||||
- containerd.io
|
|
||||||
- docker-buildx-plugin
|
|
||||||
- docker-compose-plugin
|
|
||||||
```
|
|
||||||
|
|
||||||
`os_version_codename` wird standardmäßig automatisch anhand von
|
|
||||||
`ansible_lsb.codename` ermittelt und kann bei Bedarf überschrieben werden.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel |
|
|
||||||
|-------------------|-------------------------------------------------|
|
|
||||||
| `sources.list.j2` | `/etc/apt/sources.list.d/docker.sources` (deb822) |
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser |
|
|
||||||
|------------------|-----------------------------------------------------|
|
|
||||||
| `Start Docker` | Installation/Aktualisierung der Docker-Pakete |
|
|
||||||
| `Restart Docker` | (reserviert) systemd-Neustart |
|
|
||||||
| `Reload Docker` | (reserviert) systemd-Reload |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags. Bei Bedarf über das Playbook steuerbar.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- Keine weiteren Rollen.
|
|
||||||
- Collections: `ansible.builtin` (Bordmittel).
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Die APT-Quelle liegt im **deb822-Format** vor, was ab Debian 12+ empfohlen
|
|
||||||
wird. Das签ierte-Keyfile liegt unter `/etc/apt/keyrings/docker.asc`.
|
|
||||||
- Der Handler `Start Docker` aktiviert und startet den Service, ohne bereits
|
|
||||||
laufende Container zu beeinflussen.
|
|
||||||
- Wird die Rolle innerhalb von `bootstrap` aufgerufen, übernimmt das Top-Level
|
|
||||||
Playbook das `become`/`user`-Handling.
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
docker_mirror: https://download.docker.com/linux/debian
|
docker_mirror: https://download.docker.com/linux/debian
|
||||||
os_version_codename: "{{ ansible_lsb.codename }}"
|
os_version_codename: "{{ ansible_facts['distribution_release'] | lower }}"
|
||||||
docker_packages:
|
docker_packages:
|
||||||
- docker-ce
|
- docker-ce
|
||||||
- docker-ce-cli
|
- docker-ce-cli
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
- name: Include Docker installation tasks
|
- name: Include Docker installation tasks
|
||||||
ansible.builtin.include_tasks: install-docker.yml
|
ansible.builtin.include_tasks: install-docker.yml
|
||||||
|
when: docker_check is failed
|
||||||
|
|
||||||
|
- name: Include Docker APT migration tasks
|
||||||
|
ansible.builtin.include_tasks: migrate-apt.yml
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
- name: Remove old Docker APT repo list files (legacy deb format)
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- /etc/apt/sources.list.d/docker.list
|
||||||
|
- /etc/apt/sources.list.d/docker-ce.list
|
||||||
|
- /etc/apt/sources.list.d/download_docker_com_linux_ubuntu.list
|
||||||
|
register: docker_apt_sources_cleanup
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Remove legacy Docker repo entries from /etc/apt/sources.list
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/apt/sources.list
|
||||||
|
regexp: '^deb\s+.*download\.docker\.com/linux/.*$'
|
||||||
|
state: absent
|
||||||
|
register: docker_sources_list_cleanup
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Update apt cache after legacy Docker repo cleanup
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: true
|
||||||
|
when: docker_apt_sources_cleanup is changed or docker_sources_list_cleanup is changed
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
# Rolle `hawser`
|
|
||||||
|
|
||||||
Aktualisiert den [Hawser](https://ghcr.io/finsys/hawser) Docker-Compose-Stack
|
|
||||||
auf den Ziel-Hosts. Hawser ist ein Docker-Management-Agent, der das Docker-
|
|
||||||
Socket nach außen freigibt. Die Rolle deployt die Compose-Datei aus einem
|
|
||||||
Template und zieht stets die neuesten Images (`pull: always`).
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/upgrade-hawser.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host mit installierter Docker Engine (Rolle `docker`)
|
|
||||||
- Bereits vorhandene Hawser-Installation
|
|
||||||
(`/opt/hawser/docker-compose.yml` muss existieren)
|
|
||||||
- `community.docker` Collection
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: hawser
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/upgrade-hawser.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` importiert `tasks/update-stack.yml`:
|
|
||||||
|
|
||||||
1. **Docker-Host-Info sammeln** – prüft, ob Docker erreichbar ist
|
|
||||||
(`community.docker.docker_host_info`). Bei Fehler werden nachfolgende
|
|
||||||
Tasks übersprungen.
|
|
||||||
2. **Compose-Datei prüfen** – `stat` auf `<hawser_compose_dir>/docker-compose.yml`.
|
|
||||||
Fehlt die Datei, wird kein Update durchgeführt (Bestandsschutz).
|
|
||||||
3. **Compose-Datei ausliefern** – Template `docker-compose.yml.j2` wird nur
|
|
||||||
geschrieben, wenn Docker erreichbar UND bereits eine Compose-Datei
|
|
||||||
vorhanden ist.
|
|
||||||
4. **Stack aktualisieren** – `community.docker.docker_compose_v2` mit
|
|
||||||
`pull: always` und `state: present` zieht die neuesten Images und
|
|
||||||
erneuert die Container.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|--------------------------------|--------|----------------|-----------------------------------------------------------|
|
|
||||||
| `hawser_project_name` | string | `hawser` | Name des Docker-Compose-Projekts |
|
|
||||||
| `hawser_compose_dir` | string | `/opt/hawser` | Verzeichnis der Compose-Datei auf dem Zielhost |
|
|
||||||
| `hawser_port` | string | `2376` | Freigegebener Port des Hawser-Agents (Host-Port) |
|
|
||||||
| `hawser_stacks_volume` | string | `hawser_stacks`| Name des externen Docker-Volumes für Stack-Dateien |
|
|
||||||
| `hawser_allow_insecure_no_auth`| bool | `true` | `ALLOW_INSECURE_NO_AUTH` – Standard-Mode ohne Token |
|
|
||||||
|
|
||||||
> **Achtung:** `hawser_allow_insecure_no_auth: true` erlaubt den Betrieb ohne
|
|
||||||
> Token-Authentifizierung auch auf Nicht-Loopback-Adressen. Nur setzen, wenn
|
|
||||||
> das Netzwerk durch andere Maßnahmen (Firewall, VPN) abgesichert ist.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel |
|
|
||||||
|------------------------|--------------------------------------------|
|
|
||||||
| `docker-compose.yml.j2`| `<hawser_compose_dir>/docker-compose.yml` |
|
|
||||||
|
|
||||||
Das Template konfiguriert den Hawser-Container mit Socket-Mount, externem
|
|
||||||
Volume, Port-Mapping, Environment-Variablen, `image: ghcr.io/finsys/hawser:latest`
|
|
||||||
und `restart: always`.
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
Keine Handler erforderlich – `docker compose up -d` ersetzt laufende Container
|
|
||||||
eigenständig.
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- `community.docker` Collection (`docker_host_info`, `docker_compose_v2`)
|
|
||||||
- Vorherige Installation der `docker`-Rolle
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Die Rolle **erzeugt keine Neuinstallation** – die Compose-Datei wird nur
|
|
||||||
geschrieben, wenn bereits eine existiert. So wird verhindert, dass Hawser
|
|
||||||
versehentlich auf Hosts ausgebracht wird, auf denen es nicht vorgesehen ist.
|
|
||||||
- Das externe Volume `hawser_stacks` muss vor dem ersten Start manuell
|
|
||||||
erstellt werden (`docker volume create hawser_stacks`).
|
|
||||||
- `pull: always` sorgt für aktuelle Images, erfordert aber Internetzugang
|
|
||||||
zum ghcr.io-Registry.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Name des Docker Compose Projekts
|
|
||||||
hawser_project_name: hawser
|
|
||||||
|
|
||||||
# Verzeichnis, in dem die Compose-Datei auf den Zielsystemen liegt
|
|
||||||
hawser_compose_dir: /opt/hawser
|
|
||||||
|
|
||||||
# Freigegebener Port des Hawser-Agents
|
|
||||||
hawser_port: "2376"
|
|
||||||
|
|
||||||
# Name des externen Docker Volumes für die Stack-Dateien
|
|
||||||
hawser_stacks_volume: hawser_stacks
|
|
||||||
|
|
||||||
# ALLOW_INSECURE_NO_AUTH=true erlaubt Standard-Mode ohne Token auf nicht-loopback Adressen.
|
|
||||||
# Nur setzen, wenn das Netzwerk durch andere Maßnahmen abgesichert ist.
|
|
||||||
hawser_allow_insecure_no_auth: true
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
---
|
|
||||||
# Keine Handler erforderlich – docker compose up -d ersetzt laufende Container eigenständig
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
- name: Update Hawser Docker stack
|
|
||||||
ansible.builtin.import_tasks: update-stack.yml
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
- name: Gather Docker host information
|
|
||||||
community.docker.docker_host_info:
|
|
||||||
register: hawser_docker_info
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: Check if Hawser compose file is present
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: "{{ hawser_compose_dir }}/docker-compose.yml"
|
|
||||||
register: hawser_compose_file
|
|
||||||
when: hawser_docker_info is not failed
|
|
||||||
|
|
||||||
- name: Deploy Hawser compose file from template
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: docker-compose.yml.j2
|
|
||||||
dest: "{{ hawser_compose_dir }}/docker-compose.yml"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0640"
|
|
||||||
when:
|
|
||||||
- hawser_docker_info is not failed
|
|
||||||
- hawser_compose_file.stat.exists
|
|
||||||
|
|
||||||
- name: Pull latest images and recreate Hawser stack
|
|
||||||
community.docker.docker_compose_v2:
|
|
||||||
project_src: "{{ hawser_compose_dir }}"
|
|
||||||
project_name: "{{ hawser_project_name }}"
|
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
when:
|
|
||||||
- hawser_docker_info is not failed
|
|
||||||
- hawser_compose_file.stat.exists
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
services:
|
|
||||||
hawser:
|
|
||||||
container_name: hawser
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- {{ hawser_stacks_volume }}:/data/stacks
|
|
||||||
ports:
|
|
||||||
- "{{ hawser_port }}:2376"
|
|
||||||
environment:
|
|
||||||
- ALLOW_INSECURE_NO_AUTH={{ hawser_allow_insecure_no_auth | string | lower }}
|
|
||||||
image: ghcr.io/finsys/hawser:latest
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
{{ hawser_stacks_volume }}:
|
|
||||||
external: true
|
|
||||||
name: {{ hawser_stacks_volume }}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
# Rolle `healthcheck`
|
|
||||||
|
|
||||||
Post-Update Quality-Gate. Die Rolle prüft nach einem OS-Update, ob alle
|
|
||||||
Docker-Container wieder laufen, und protokolliert das Ergebnis im selben
|
|
||||||
Update-Log, das auch von der `os-updates`-Rolle verwendet wird.
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/os-updates-deb.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- Optional installiertes Docker (wird automatisch erkannt)
|
|
||||||
- Idealerweise vorheriger Lauf der `os-updates`-Rolle (für gemeinsames Log)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
Die Rolle ist fest in `playbooks/os-updates-deb.yml` nach der `os-updates`-
|
|
||||||
Rolle eingebunden und wird in der Regel nicht separat aufgerufen:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: os-updates
|
|
||||||
- role: healthcheck
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` führt nacheinander folgende Schritte aus:
|
|
||||||
|
|
||||||
1. **Docker-Binary erkennen** – `which docker` (fehlertolerant)
|
|
||||||
2. **Docker-Präsenz festhalten** – Fakt `healthcheck_docker_installed`
|
|
||||||
3. **Alle Container auflisten** – `docker ps -a --format {{.Names}}`
|
|
||||||
4. **Laufende Container auflisten** – `docker ps --filter status=running`
|
|
||||||
5. **Container-Health bewerten** – Differenz aus allen und laufenden
|
|
||||||
Containern ergibt `healthcheck_non_running_containers`
|
|
||||||
6. **Gesamtergebnis bestimmen** – `healthcheck_all_running`,
|
|
||||||
`healthcheck_passed`
|
|
||||||
7. **Default-Ergebnis ohne Docker** – falls Docker nicht installiert ist,
|
|
||||||
gilt der Healthcheck als bestanden (`passed: true`, 0 Container)
|
|
||||||
8. **Log-Verzeichnis sicherstellen** – delegiert an localhost
|
|
||||||
9. **Quality-Gate in Update-Log schreiben** – `blockinfile` mit Marker
|
|
||||||
`# {mark} ANSIBLE-HEALTHCHECK`, Abschnitt `quality_gate:`
|
|
||||||
10. **Fehlschlagen bei ungesunden Containern** – nur wenn
|
|
||||||
`healthcheck_fail_on_unhealthy` gesetzt ist
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|------------------------------|-------|------------------------------------------------------------------|-----------------------------------------------|
|
|
||||||
| `healthcheck_logging_enabled`| bool | `{{ os_update_logging_enabled \| default(true) }}` | Logging aktivieren |
|
|
||||||
| `healthcheck_log_dir` | string| `{{ os_update_log_dir \| default('/ansible/logs') }}` | Basis-Verzeichnis für Logs |
|
|
||||||
| `healthcheck_log_inventory` | string| `{{ inventory_file \| basename \| splitext \| first }}` | Inventory-Name (abgeleitet) |
|
|
||||||
| `healthcheck_log_file` | string| `<log_dir>/<inventory>/<hostname>/update.log` | Pfad zur Update-Log-Datei |
|
|
||||||
| `healthcheck_fail_on_unhealthy`| bool| `false` | Playbook fehlschlagen lassen, wenn Container nicht laufen |
|
|
||||||
|
|
||||||
Die Variablen leiten sich standardmäßig aus den Werten der `os-updates`-Rolle
|
|
||||||
ab, sodass beide Rollen in dasselbe Log schreiben.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
Keine Templates.
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
Keine Handler.
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- Keine weiteren Rollen.
|
|
||||||
- Collections: `ansible.builtin` (Bordmittel).
|
|
||||||
- Empfohlener Partner: `os-updates`-Rolle (für gemeinsames Log-Format).
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Wird Docker nicht gefunden, gilt der Healthcheck als bestanden – nützlich
|
|
||||||
für Hosts, die keine Container betreiben.
|
|
||||||
- Das Log wird **delegiert auf localhost** geschrieben (auf dem Ansible-
|
|
||||||
Controller), nicht auf dem Zielhost. Das Verzeichnis `logs/` ist
|
|
||||||
git-ignored.
|
|
||||||
- Die `quality_gate`-Sektion im Log ist an denselben Eintrag gekoppelt wie
|
|
||||||
der `os-updates`-Preflight, sodass ein Update-Lauf inkl. Healthcheck
|
|
||||||
nachvollziehbar dokumentiert ist.
|
|
||||||
- `healthcheck_fail_on_unhealthy: false` (Default) bricht das Playbook nicht
|
|
||||||
ab – bewusst gewählt, damit nach Updates nicht versehentlich ganze
|
|
||||||
Host-Gruppen blockiert werden. Für kritische Hosts individuell setzen.
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# Post-update health check (quality gate) defaults.
|
|
||||||
# The role verifies that every Docker container is running after an OS update
|
|
||||||
# and records the result in the same update log used by the os-updates role.
|
|
||||||
|
|
||||||
healthcheck_logging_enabled: "{{ os_update_logging_enabled | default(true) }}"
|
|
||||||
healthcheck_log_dir: "{{ os_update_log_dir | default('/ansible/logs') }}"
|
|
||||||
healthcheck_log_inventory: "{{ inventory_file | basename | splitext | first }}"
|
|
||||||
healthcheck_log_file: "{{ healthcheck_log_dir }}/{{ healthcheck_log_inventory }}/{{ ansible_facts['hostname'] }}/update.log"
|
|
||||||
|
|
||||||
# When true, the role fails the playbook if any container is not running.
|
|
||||||
healthcheck_fail_on_unhealthy: false
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
# Post-update health check (quality gate).
|
|
||||||
# Detects whether Docker is installed and, if so, verifies that every
|
|
||||||
# container is in the running state. Results are appended to the update
|
|
||||||
# log as a "quality_gate" section, tied to the current update run via the
|
|
||||||
# os-updates preflight start timestamp.
|
|
||||||
|
|
||||||
- name: Healthcheck - Detect Docker binary
|
|
||||||
ansible.builtin.command: which docker
|
|
||||||
register: healthcheck_docker_bin
|
|
||||||
changed_when: false
|
|
||||||
failed_when: false
|
|
||||||
|
|
||||||
- name: Healthcheck - Record Docker presence
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_docker_installed: "{{ healthcheck_docker_bin.rc == 0 }}"
|
|
||||||
|
|
||||||
- name: Healthcheck - List all container names
|
|
||||||
ansible.builtin.command: "docker ps -a --format {{ '{{' }}.Names{{ '}}' }}"
|
|
||||||
register: healthcheck_all_containers
|
|
||||||
changed_when: false
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - List running container names
|
|
||||||
ansible.builtin.command: "docker ps --filter status=running --format {{ '{{' }}.Names{{ '}}' }}"
|
|
||||||
register: healthcheck_running_containers
|
|
||||||
changed_when: false
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Evaluate container health
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_total_containers: "{{ healthcheck_all_containers.stdout_lines | length }}"
|
|
||||||
healthcheck_running_count: "{{ healthcheck_running_containers.stdout_lines | length }}"
|
|
||||||
healthcheck_non_running_containers: "{{ (healthcheck_all_containers.stdout_lines | difference(healthcheck_running_containers.stdout_lines)) | list }}"
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Determine overall result
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_all_running: "{{ (healthcheck_non_running_containers | length) == 0 }}"
|
|
||||||
healthcheck_passed: "{{ (healthcheck_non_running_containers | length) == 0 }}"
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Default result when Docker is not installed
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_total_containers: 0
|
|
||||||
healthcheck_running_count: 0
|
|
||||||
healthcheck_non_running_containers: []
|
|
||||||
healthcheck_all_running: true
|
|
||||||
healthcheck_passed: true
|
|
||||||
when: not (healthcheck_docker_installed | bool)
|
|
||||||
|
|
||||||
- name: Healthcheck - Ensure log directory exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ healthcheck_log_file | dirname }}"
|
|
||||||
state: directory
|
|
||||||
delegate_to: localhost
|
|
||||||
when: healthcheck_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Write quality gate section to update log
|
|
||||||
ansible.builtin.blockinfile:
|
|
||||||
path: "{{ healthcheck_log_file }}"
|
|
||||||
create: yes
|
|
||||||
marker: "# {mark} ANSIBLE-HEALTHCHECK"
|
|
||||||
block: |
|
|
||||||
quality_gate:
|
|
||||||
docker_installed: {{ healthcheck_docker_installed }}
|
|
||||||
total_containers: {{ healthcheck_total_containers }}
|
|
||||||
running_containers: {{ healthcheck_running_count }}
|
|
||||||
all_running: {{ healthcheck_all_running }}
|
|
||||||
non_running_containers:
|
|
||||||
{% for c in healthcheck_non_running_containers %}
|
|
||||||
- {{ c }}
|
|
||||||
{% endfor %}
|
|
||||||
healthcheck_passed: {{ healthcheck_passed }}
|
|
||||||
delegate_to: localhost
|
|
||||||
when: healthcheck_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Fail when containers are unhealthy (quality gate)
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: >-
|
|
||||||
Quality gate failed: the following containers are not running:
|
|
||||||
{{ healthcheck_non_running_containers | join(', ') }}
|
|
||||||
when:
|
|
||||||
- healthcheck_fail_on_unhealthy | bool
|
|
||||||
- healthcheck_docker_installed | bool
|
|
||||||
- not (healthcheck_all_running | bool)
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
# Rolle `manage-ssh-keys`
|
|
||||||
|
|
||||||
Hardening-Rolle zur Verwaltung autorisierter SSH-Schlüssel. Sie fügt
|
|
||||||
erwünschte ("Good") Keys hinzu und entfernt unerwünschte ("Bad") Keys aus der
|
|
||||||
`authorized_keys`-Datei des Zielbenutzers.
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/hardening/manage-ssh-keys.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- SSH-Zugang als Zielbenutzer (Default: `admin`)
|
|
||||||
- `lineinfile`-/`blockinfile`-Module (Bordmittel)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: manage-ssh-keys
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/hardening/manage-ssh-keys.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
Good/Bad-Keys können per Inventory überschrieben oder über Umgebungsvariablen
|
|
||||||
übergeben werden (siehe auskommentiertes Beispiel im Playbook):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# vars:
|
|
||||||
# good_keys: "{{ lookup('env', 'good_keys') | from_json }}"
|
|
||||||
# bad_keys: "{{ lookup('env', 'bad_keys') | from_json }}"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` steuert den modularen Ablauf:
|
|
||||||
|
|
||||||
1. **`validate-authorized-keys.yml`** – stellt das `.ssh`-Verzeichnis des
|
|
||||||
eingeloggten Users sicher (Mode `0700`).
|
|
||||||
2. **`add-goodkeys.yml`** – fügt jeden Key aus `good_keys` per `lineinfile`
|
|
||||||
zur `authorized_keys` hinzu (idempotent). Benachrichtigt Handler
|
|
||||||
`Cleanup Comments` und `Add Comment`.
|
|
||||||
3. **`remove-badkeys.yml`** – entfernt jeden Key aus `bad_keys` per
|
|
||||||
`lineinfile` (state: absent). Benachrichtigt ebenfalls die Handler.
|
|
||||||
|
|
||||||
Die Handler bereinigen alle Kommentarzeilen (`^#.*$`) und fügen einen
|
|
||||||
eindeutigen "Modified by Ansible"-Block mit Datum/Uhrzeit ein.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-----------------------|---------|----------------|------------------------------------------------------|
|
|
||||||
| `ssh_user` | string | `admin` | (Referenz) Zielbenutzer – Aktionen laufen als dieser User |
|
|
||||||
| `good_keys` | list | siehe `defaults/` | Liste erwünschter SSH-Keys (vollständige Key-Zeilen) |
|
|
||||||
| `bad_keys` | list | siehe `defaults/` | Liste unerwünschter SSH-Keys (vollständige Key-Zeilen) |
|
|
||||||
|
|
||||||
### Steuer-Variablen (keine Defaults)
|
|
||||||
|
|
||||||
| Variable | Typ | Beschreibung |
|
|
||||||
|-----------------------|--------|-----------------------------------------------------------|
|
|
||||||
| `authorized_keys_file`| string | Pfad zur `authorized_keys`-Datei (muss gesetzt sein) |
|
|
||||||
|
|
||||||
> `authorized_keys_file` wird im Playbook bzw. Inventory gesetzt und muss
|
|
||||||
> auf die Datei des Zielusers verweisen (z. B.
|
|
||||||
> `/home/admin/.ssh/authorized_keys`).
|
|
||||||
|
|
||||||
Default `good_keys` enthält die Admin-Keys (Niklas, Dennis, Generic Ansible).
|
|
||||||
Default `bad_keys` enthält einen veralteten RSA-Key als Beispiel.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
Keine Templates.
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser | Beschreibung |
|
|
||||||
|-------------------|-------------------------------------------|----------------------------------------------------------|
|
|
||||||
| `Cleanup Comments`| Good/Bad-Key-Änderung | Entfernt alle Kommentarzeilen (`^#.*$`) aus der Datei |
|
|
||||||
| `Add Comment` | Good/Bad-Key-Änderung | Fügt "Modified by Ansible on <Datum> at <Uhrzeit>" ein |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- Keine weiteren Rollen.
|
|
||||||
- Collections: `ansible.builtin` (Bordmittel).
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Die Rolle ist **idempotent**: mehrfaches Ausführen führt zu keinem
|
|
||||||
geänderten Zustand, wenn Keys bereits vorhanden/abwesend sind.
|
|
||||||
- Good/Bad-Keys sind **vollständige Key-Zeilen** inkl. Typ, Key und
|
|
||||||
Kommentar (z. B. `ssh-ed25519 AAAA... user@host`). Der Vergleich erfolgt
|
|
||||||
zeilenbasiert.
|
|
||||||
- Handler laufen erst am Ende des Playbook-Laufs – bei mehreren Key-Änderungen
|
|
||||||
wird die Datei nur einmal bereinigt.
|
|
||||||
- Vorsicht bei der Definition von `bad_keys`: zu weit gefasste Patterns
|
|
||||||
könnten legitime Keys entfernen. Immer die exakte Key-Zeile angeben.
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
# Rolle `monitoring`
|
|
||||||
|
|
||||||
Installiert und konfiguriert den **Zabbix Agent 2** auf Debian-Hosts,
|
|
||||||
generiert/verteilt pro Host eine TLS-PSK, konfiguriert das Docker-Plugin
|
|
||||||
(bei vorhandenem Socket) und registriert den Host über die Zabbix-API
|
|
||||||
einschließlich Template-Verlinkung.
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/monitoring.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- Erreichbarer Zabbix-Server (API & Agent-Polling)
|
|
||||||
- `community.zabbix` Collection
|
|
||||||
- Vault-Secret `monitoring_zabbix_api_password` in `vault.yml`
|
|
||||||
- OpenSSL auf dem Ansible-Controller (für PSK-Generierung)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: monitoring
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml --vault-password-file .vault_password \
|
|
||||||
playbooks/monitoring.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` importiert die Subtasks in folgender Reihenfolge (alle mit
|
|
||||||
Tag `monitoring`):
|
|
||||||
|
|
||||||
1. **`validate.yml`** – bricht bei Nicht-Debian ab, prüft dass
|
|
||||||
`monitoring_zabbix_passive_servers` gesetzt ist und (bei aktivierter
|
|
||||||
Registrierung) API-URL/-User/-Passwort vorliegen. Stellt sicher, dass
|
|
||||||
bei gesetztem `monitoring_zabbix_proxy` auch eine Proxy-Adresse definiert ist.
|
|
||||||
2. **`install-repository.yml`** – installiert `ca-certificates`, lädt das
|
|
||||||
Zabbix-Release-Paket herunter, installiert es und aktualisiert den
|
|
||||||
apt-Cache.
|
|
||||||
3. **`install-agent.yml`** – installiert `zabbix-agent2` und aktiviert/startet
|
|
||||||
den Service.
|
|
||||||
4. **`configure-docker.yml`** – prüft, ob der Docker-Socket existiert. Falls
|
|
||||||
ja: Zabbix-User zur Docker-Gruppe hinzufügen, Plugin-Config-Verzeichnis
|
|
||||||
anlegen, `docker.conf` aus Template ausliefern. Falls nein: Plugin-Config
|
|
||||||
entfernen.
|
|
||||||
5. **`configure-psk.yml`** – stellt PSK-Store auf dem Controller sicher
|
|
||||||
(`<playbook_dir>/../.zabbix-psk`), generiert pro Host eine PSK mit
|
|
||||||
`openssl rand -hex`, persistiert sie im Store und verteilt sie auf den
|
|
||||||
Zielhost (`/etc/zabbix/zabbix_agent2.psk`, Mode `0600`).
|
|
||||||
6. **`configure-agent.yml`** – schreibt `zabbix_agent2.conf` aus Template.
|
|
||||||
7. **`register-host.yml`** – registriert bzw. aktualisiert den Host über die
|
|
||||||
Zabbix-API (`community.zabbix.zabbix_host`). Verknüpft Standard-Templates
|
|
||||||
und ggf. Docker-Templates. Unterscheidet zwischen Proxy- und
|
|
||||||
Server-Modus (zwei Tasks, gegeneinander exklusiv). Delegiert an localhost.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
### Zabbix-Agent
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|--------------------------------------------|--------|--------------------------------------|-----------------------------------------------------|
|
|
||||||
| `monitoring_zabbix_version` | string | `7.0` | Zabbix-Hauptversion |
|
|
||||||
| `monitoring_zabbix_release_package` | string | abgeleitet | Dateiname des Release-Pakets |
|
|
||||||
| `monitoring_zabbix_release_url` | string | abgeleitet | Download-URL des Release-Pakets |
|
|
||||||
| `monitoring_zabbix_release_path` | string | `/tmp/<package>` | lokaler Ablagepfad auf dem Zielhost |
|
|
||||||
| `monitoring_zabbix_agent_package` | string | `zabbix-agent2` | Zu installierendes Agent-Paket |
|
|
||||||
| `monitoring_zabbix_agent_service` | string | `zabbix-agent2` | systemd-Service-Name |
|
|
||||||
| `monitoring_zabbix_config_file` | string | `/etc/zabbix/zabbix_agent2.conf` | Pfad zur Agent-Konfiguration |
|
|
||||||
| `monitoring_zabbix_agent_user` | string | `zabbix` | Benutzer, unter dem der Agent läuft |
|
|
||||||
| `monitoring_zabbix_passive_servers` | list | `["192.168.212.1"]` | Erlaubte Server für passive Checks (Server=) |
|
|
||||||
| `monitoring_zabbix_active_servers` | list | `""` | Server für aktive Checks (ServerActive=) |
|
|
||||||
| `monitoring_zabbix_listen_port` | int | `10050` | Listen-Port des Agents |
|
|
||||||
|
|
||||||
### Docker-Plugin
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-----------------------------------------------------|--------|--------------------------------------|-----------------------------------------------|
|
|
||||||
| `monitoring_zabbix_docker_group` | string | `docker` | Docker-Gruppe für Socket-Zugriff |
|
|
||||||
| `monitoring_zabbix_docker_socket_path` | string | `/var/run/docker.sock` | Pfad zum Docker-Socket |
|
|
||||||
| `monitoring_zabbix_docker_plugin_config_file` | string | `/etc/zabbix/zabbix_agent2.d/plugins.d/docker.conf` | Pfad zur Plugin-Config |
|
|
||||||
| `monitoring_zabbix_docker_endpoint` | string | `unix://<socket>` | Docker-Endpoint für das Plugin |
|
|
||||||
|
|
||||||
### TLS / PSK
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-----------------------------------------|--------|--------------------------------------|---------------------------------------------------------|
|
|
||||||
| `monitoring_zabbix_tls_connect` | string | `psk` | TLS-Modus für ausgehende Verbindungen |
|
|
||||||
| `monitoring_zabbix_tls_accept` | string | `psk` | TLS-Modus für eingehende Verbindungen |
|
|
||||||
| `monitoring_zabbix_psk_identity` | string | `{{ inventory_hostname }}` | PSK-Identity (hostname) |
|
|
||||||
| `monitoring_zabbix_psk_file` | string | `/etc/zabbix/zabbix_agent2.psk` | Pfad zur PSK-Datei auf dem Zielhost |
|
|
||||||
| `monitoring_zabbix_psk_bits` | int | `256` | PSK-Länge in Bits (32 Byte → 64 Hex-Chars) |
|
|
||||||
| `monitoring_zabbix_psk_store` | string | `{{ playbook_dir }}/../.zabbix-psk` | PSK-Store-Verzeichnis auf dem Controller |
|
|
||||||
| `monitoring_zabbix_psk_store_mode` | string | `0700` | Berechtigung des PSK-Stores |
|
|
||||||
|
|
||||||
### Zabbix Proxy (optional)
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-------------------------------------|--------|---------|-----------------------------------------------------------|
|
|
||||||
| `monitoring_zabbix_proxy` | string | `""` | Name des Proxys in Zabbix (leer = direkter Server-Modus) |
|
|
||||||
| `monitoring_zabbix_proxy_address` | string | `""` | IP/DNS des Proxys, den der Agent kontaktiert |
|
|
||||||
|
|
||||||
### Zabbix API / Host-Registrierung
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|---------------------------------------------|--------|--------------------------------------|---------------------------------------------------------|
|
|
||||||
| `monitoring_zabbix_api_url` | string | `https://zabbix/api_jsonrpc.php` | API-URL |
|
|
||||||
| `monitoring_zabbix_api_user` | string | `Admin` | API-Benutzer |
|
|
||||||
| `monitoring_zabbix_api_password` | string | (Vault) | API-Passwort – MUSS in `vault.yml` gesetzt werden |
|
|
||||||
| `monitoring_zabbix_api_validate_certs` | bool | `true` | TLS-Zertifikate prüfen |
|
|
||||||
| `monitoring_zabbix_register_host` | bool | `true` | Host automatisch registrieren |
|
|
||||||
| `monitoring_zabbix_host_name` | string | `{{ inventory_hostname }}` | Hostname in Zabbix |
|
|
||||||
| `monitoring_zabbix_host_groups` | list | `["Linux servers"]` | Zabbix-Host-Gruppen |
|
|
||||||
| `monitoring_zabbix_host_interface_ip` | string | `{{ ansible_host }}` | Interface-IP |
|
|
||||||
| `monitoring_zabbix_host_interface_port` | string | `{{ monitoring_zabbix_listen_port }}`| Interface-Port |
|
|
||||||
| `monitoring_zabbix_host_inventory_mode` | string | `manual` | Inventory-Modus |
|
|
||||||
| `monitoring_zabbix_templates` | list | `["Linux by Zabbix agent", "Zabbix agent2"]` | Standard-Templates |
|
|
||||||
| `monitoring_zabbix_docker_templates` | list | `["Docker by Zabbix agent2"]` | Zusätzliche Templates bei vorhandenem Docker-Socket |
|
|
||||||
|
|
||||||
### Inventory-Overrides
|
|
||||||
|
|
||||||
In `inventory/group_vars/home.yml` werden u. a. überschrieben:
|
|
||||||
`monitoring_zabbix_passive_servers`, `monitoring_zabbix_active_servers`,
|
|
||||||
`monitoring_zabbix_api_url`, `monitoring_zabbix_host_groups`,
|
|
||||||
`monitoring_zabbix_templates`, `monitoring_zabbix_docker_templates`,
|
|
||||||
`monitoring_zabbix_proxy`, `monitoring_zabbix_proxy_address`.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel |
|
|
||||||
|-------------------------|------------------------------------------------|
|
|
||||||
| `zabbix_agent2.conf.j2` | `/etc/zabbix/zabbix_agent2.conf` |
|
|
||||||
| `docker.conf.j2` | `/etc/zabbix/zabbix_agent2.d/plugins.d/docker.conf` |
|
|
||||||
|
|
||||||
`zabbix_agent2.conf.j2` berücksichtigt Proxy-Konfiguration (vereinigt
|
|
||||||
Passive-Servers mit Proxy-Adresse, setzt `ServerActive` auf Proxy).
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser |
|
|
||||||
|-----------------------|--------------------------------------------|
|
|
||||||
| `Restart Zabbix Agent`| Änderungen an Config, PSK oder Docker-Plugin|
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
`monitoring` – alle Subtasks sind mit diesem Tag versehen:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/monitoring.yml -t monitoring
|
|
||||||
```
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- `community.zabbix` Collection (`zabbix_host`-Modul)
|
|
||||||
- `ansible.builtin` (Bordmittel)
|
|
||||||
- OpenSSL auf dem Controller (für PSK-Generierung)
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- **PSK-Store**: Pro Host wird eine PSK unter
|
|
||||||
`<playbook_dir>/../.zabbix-psk/<hostname>.psk` (git-ignored) gespeichert.
|
|
||||||
Bei Host-Umbenennung PSK migrieren oder neu generieren – sonst stimmt die
|
|
||||||
Zabbix-Registrierung nicht.
|
|
||||||
- **API-Passwort** MUSS in `vault.yml` als `monitoring_zabbix_api_password`
|
|
||||||
gesetzt sein; die Validate-Tasks brechen sonst ab.
|
|
||||||
- **Docker-Plugin** wird nur konfiguriert, wenn der Socket existiert – sonst
|
|
||||||
wird eine eventuell vorhandene Plugin-Config entfernt (Idempotenz).
|
|
||||||
- Die Registrierung wird **delegiert an localhost** ausgeführt, da der
|
|
||||||
Controller den API-Zugang besitzt.
|
|
||||||
- Proxy- und Server-Modus schließen sich gegenseitig aus (zwei Tasks mit
|
|
||||||
entgegengesetzten `when`-Bedingungen).
|
|
||||||
@@ -13,36 +13,3 @@ monitoring_zabbix_docker_group: docker
|
|||||||
monitoring_zabbix_docker_socket_path: /var/run/docker.sock
|
monitoring_zabbix_docker_socket_path: /var/run/docker.sock
|
||||||
monitoring_zabbix_docker_plugin_config_file: /etc/zabbix/zabbix_agent2.d/plugins.d/docker.conf
|
monitoring_zabbix_docker_plugin_config_file: /etc/zabbix/zabbix_agent2.d/plugins.d/docker.conf
|
||||||
monitoring_zabbix_docker_endpoint: "unix://{{ monitoring_zabbix_docker_socket_path }}"
|
monitoring_zabbix_docker_endpoint: "unix://{{ monitoring_zabbix_docker_socket_path }}"
|
||||||
|
|
||||||
# --- TLS / PSK ----------------------------------------------------------------
|
|
||||||
monitoring_zabbix_tls_connect: psk # outgoing connections from agent: psk
|
|
||||||
monitoring_zabbix_tls_accept: psk # incoming connections to agent: psk
|
|
||||||
monitoring_zabbix_psk_identity: "{{ inventory_hostname }}"
|
|
||||||
monitoring_zabbix_psk_file: /etc/zabbix/zabbix_agent2.psk
|
|
||||||
monitoring_zabbix_psk_bits: 256 # 32 bytes -> 64 hex chars
|
|
||||||
# Directory on the Ansible controller used to persist per-host PSKs across runs.
|
|
||||||
monitoring_zabbix_psk_store: "{{ playbook_dir }}/../.zabbix-psk"
|
|
||||||
monitoring_zabbix_psk_store_mode: "0700"
|
|
||||||
|
|
||||||
# --- Zabbix Proxy (optional) --------------------------------------------------
|
|
||||||
# Leave both empty to have the agent talk to the Zabbix server directly.
|
|
||||||
# monitoring_zabbix_proxy: name of the proxy in Zabbix (for API assignment)
|
|
||||||
# monitoring_zabbix_proxy_address: IP/DNS of the proxy the agent should contact
|
|
||||||
monitoring_zabbix_proxy: ""
|
|
||||||
monitoring_zabbix_proxy_address: ""
|
|
||||||
|
|
||||||
# --- Zabbix API / host registration ------------------------------------------
|
|
||||||
monitoring_zabbix_api_url: "https://zabbix/api_jsonrpc.php"
|
|
||||||
monitoring_zabbix_api_user: Admin
|
|
||||||
# monitoring_zabbix_api_password: <set in vault.yml>
|
|
||||||
monitoring_zabbix_api_validate_certs: true
|
|
||||||
monitoring_zabbix_register_host: true
|
|
||||||
monitoring_zabbix_host_name: "{{ inventory_hostname }}"
|
|
||||||
monitoring_zabbix_host_groups: ["Linux servers"]
|
|
||||||
monitoring_zabbix_host_interface_ip: "{{ ansible_host }}"
|
|
||||||
monitoring_zabbix_host_interface_port: "{{ monitoring_zabbix_listen_port }}"
|
|
||||||
monitoring_zabbix_host_inventory_mode: manual
|
|
||||||
# Templates linked to every host
|
|
||||||
monitoring_zabbix_templates: ["Linux by Zabbix agent", "Zabbix agent2"]
|
|
||||||
# Templates added when a Docker socket is present on the host
|
|
||||||
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent2"]
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Restart Zabbix Agent
|
- name: Restart Zabbix Agent
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: "{{ monitoring_zabbix_agent_service }}"
|
name: "{{ monitoring_zabbix_agent_service }}"
|
||||||
state: restarted
|
state: restarted
|
||||||
daemon_reload: yes
|
daemon_reload: yes
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
- name: Configure Zabbix agent
|
- name: Configure Zabbix agent
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: zabbix_agent2.conf.j2
|
src: zabbix_agent2.conf.j2
|
||||||
dest: "{{ monitoring_zabbix_config_file }}"
|
dest: "{{ monitoring_zabbix_config_file }}"
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
notify: Restart Zabbix Agent
|
notify: Restart Zabbix Agent
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
---
|
---
|
||||||
- name: Gather Docker group entries
|
- name: Gather Docker group entries
|
||||||
ansible.builtin.getent:
|
ansible.builtin.getent:
|
||||||
database: group
|
database: group
|
||||||
key: "{{ monitoring_zabbix_docker_group }}"
|
key: "{{ monitoring_zabbix_docker_group }}"
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
- name: Check whether Docker socket exists
|
- name: Check whether Docker socket exists
|
||||||
ansible.builtin.stat:
|
ansible.builtin.stat:
|
||||||
path: "{{ monitoring_zabbix_docker_socket_path }}"
|
path: "{{ monitoring_zabbix_docker_socket_path }}"
|
||||||
register: monitoring_docker_socket
|
register: monitoring_docker_socket
|
||||||
|
|
||||||
- name: Ensure Zabbix agent can access Docker socket
|
- name: Ensure Zabbix agent can access Docker socket
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
name: "{{ monitoring_zabbix_agent_user }}"
|
name: "{{ monitoring_zabbix_agent_user }}"
|
||||||
groups: "{{ monitoring_zabbix_docker_group }}"
|
groups: "{{ monitoring_zabbix_docker_group }}"
|
||||||
append: yes
|
append: yes
|
||||||
when:
|
when:
|
||||||
- monitoring_docker_socket.stat.exists
|
- monitoring_docker_socket.stat.exists
|
||||||
- monitoring_zabbix_docker_group in (ansible_facts.getent_group | default({}))
|
- monitoring_zabbix_docker_group in (ansible_facts.getent_group | default({}))
|
||||||
notify: Restart Zabbix Agent
|
notify: Restart Zabbix Agent
|
||||||
|
|
||||||
- name: Ensure Docker plugin configuration directory exists
|
- name: Ensure Docker plugin configuration directory exists
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ monitoring_zabbix_docker_plugin_config_file | dirname }}"
|
path: "{{ monitoring_zabbix_docker_plugin_config_file | dirname }}"
|
||||||
state: directory
|
state: directory
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: '0755'
|
mode: '0755'
|
||||||
when: monitoring_docker_socket.stat.exists
|
when: monitoring_docker_socket.stat.exists
|
||||||
|
|
||||||
- name: Configure Docker plugin endpoint
|
- name: Configure Docker plugin endpoint
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: docker.conf.j2
|
src: docker.conf.j2
|
||||||
dest: "{{ monitoring_zabbix_docker_plugin_config_file }}"
|
dest: "{{ monitoring_zabbix_docker_plugin_config_file }}"
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
when: monitoring_docker_socket.stat.exists
|
when: monitoring_docker_socket.stat.exists
|
||||||
notify: Restart Zabbix Agent
|
notify: Restart Zabbix Agent
|
||||||
|
|
||||||
- name: Remove Docker plugin configuration when Docker socket is absent
|
- name: Remove Docker plugin configuration when Docker socket is absent
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ monitoring_zabbix_docker_plugin_config_file }}"
|
path: "{{ monitoring_zabbix_docker_plugin_config_file }}"
|
||||||
state: absent
|
state: absent
|
||||||
when: not monitoring_docker_socket.stat.exists
|
when: not monitoring_docker_socket.stat.exists
|
||||||
notify: Restart Zabbix Agent
|
notify: Restart Zabbix Agent
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
# Generate a per-host PSK on the Ansible controller and deploy it to the agent.
|
|
||||||
# The PSK is persisted under monitoring_zabbix_psk_store so that re-runs keep
|
|
||||||
# the same secret and the Zabbix server registration stays in sync.
|
|
||||||
|
|
||||||
- name: Ensure PSK store directory exists on controller
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ monitoring_zabbix_psk_store }}"
|
|
||||||
state: directory
|
|
||||||
mode: "{{ monitoring_zabbix_psk_store_mode }}"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
run_once: false
|
|
||||||
|
|
||||||
- name: Check whether PSK already exists on controller
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: "{{ monitoring_zabbix_psk_store }}/{{ inventory_hostname }}.psk"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
register: monitoring_psk_existing
|
|
||||||
|
|
||||||
- name: Generate per-host PSK when missing
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
umask 077
|
|
||||||
openssl rand -hex {{ (monitoring_zabbix_psk_bits / 8) | int }} \
|
|
||||||
> "{{ monitoring_zabbix_psk_store }}/{{ inventory_hostname }}.psk"
|
|
||||||
args:
|
|
||||||
creates: "{{ monitoring_zabbix_psk_store }}/{{ inventory_hostname }}.psk"
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
register: monitoring_psk_generated
|
|
||||||
|
|
||||||
- name: Slurp PSK from controller
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
monitoring_zabbix_psk_value: >-
|
|
||||||
{{ lookup('ansible.builtin.file',
|
|
||||||
monitoring_zabbix_psk_store ~ '/' ~ inventory_hostname ~ '.psk')
|
|
||||||
| trim }}
|
|
||||||
|
|
||||||
- name: Ensure Zabbix agent runtime directory exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ monitoring_zabbix_psk_file | dirname | default('/etc/zabbix') }}"
|
|
||||||
state: directory
|
|
||||||
owner: root
|
|
||||||
group: "{{ monitoring_zabbix_agent_user }}"
|
|
||||||
mode: '0750'
|
|
||||||
|
|
||||||
- name: Deploy PSK file to agent host
|
|
||||||
ansible.builtin.copy:
|
|
||||||
content: "{{ monitoring_zabbix_psk_value }}\n"
|
|
||||||
dest: "{{ monitoring_zabbix_psk_file }}"
|
|
||||||
owner: "{{ monitoring_zabbix_agent_user }}"
|
|
||||||
group: "{{ monitoring_zabbix_agent_user }}"
|
|
||||||
mode: '0600'
|
|
||||||
notify: Restart Zabbix Agent
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
- name: Install Zabbix agent package
|
- name: Install Zabbix agent package
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
name: "{{ monitoring_zabbix_agent_package }}"
|
name: "{{ monitoring_zabbix_agent_package }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Ensure Zabbix agent service is enabled and started
|
- name: Ensure Zabbix agent service is enabled and started
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: "{{ monitoring_zabbix_agent_service }}"
|
name: "{{ monitoring_zabbix_agent_service }}"
|
||||||
state: started
|
state: started
|
||||||
enabled: yes
|
enabled: yes
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
---
|
---
|
||||||
- name: Install repository prerequisites
|
- name: Install repository prerequisites
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
name:
|
name:
|
||||||
- ca-certificates
|
- ca-certificates
|
||||||
state: present
|
state: present
|
||||||
update_cache: yes
|
update_cache: yes
|
||||||
cache_valid_time: 3600
|
cache_valid_time: 3600
|
||||||
|
|
||||||
- name: Download Zabbix release package
|
- name: Download Zabbix release package
|
||||||
ansible.builtin.get_url:
|
ansible.builtin.get_url:
|
||||||
url: "{{ monitoring_zabbix_release_url }}"
|
url: "{{ monitoring_zabbix_release_url }}"
|
||||||
dest: "{{ monitoring_zabbix_release_path }}"
|
dest: "{{ monitoring_zabbix_release_path }}"
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
|
|
||||||
- name: Install Zabbix release package
|
- name: Install Zabbix release package
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
deb: "{{ monitoring_zabbix_release_path }}"
|
deb: "{{ monitoring_zabbix_release_path }}"
|
||||||
|
|
||||||
- name: Update apt cache after Zabbix repository setup
|
- name: Update apt cache after Zabbix repository setup
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
update_cache: yes
|
update_cache: yes
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
- import_tasks: validate.yml
|
- import_tasks: validate.yml
|
||||||
tags: monitoring
|
tags: monitoring
|
||||||
|
|
||||||
- import_tasks: install-repository.yml
|
- import_tasks: install-repository.yml
|
||||||
tags: monitoring
|
tags: monitoring
|
||||||
|
|
||||||
- import_tasks: install-agent.yml
|
- import_tasks: install-agent.yml
|
||||||
tags: monitoring
|
tags: monitoring
|
||||||
|
|
||||||
- import_tasks: configure-docker.yml
|
- import_tasks: configure-docker.yml
|
||||||
tags: monitoring
|
tags: monitoring
|
||||||
|
|
||||||
- import_tasks: configure-psk.yml
|
- import_tasks: configure-agent.yml
|
||||||
tags: monitoring
|
tags: monitoring
|
||||||
|
|
||||||
- import_tasks: configure-agent.yml
|
|
||||||
tags: monitoring
|
|
||||||
|
|
||||||
- import_tasks: register-host.yml
|
|
||||||
tags: monitoring
|
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
---
|
|
||||||
# Register (or update) the host on the Zabbix server via the API,
|
|
||||||
# using the per-host PSK that was deployed to the agent.
|
|
||||||
|
|
||||||
- name: Combine templates (add Docker templates when socket is present)
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
monitoring_zabbix_link_templates: >-
|
|
||||||
{{
|
|
||||||
monitoring_zabbix_templates
|
|
||||||
| default([])
|
|
||||||
| union(
|
|
||||||
(monitoring_docker_socket.stat.exists | default(false))
|
|
||||||
| ternary(monitoring_zabbix_docker_templates | default([]), [])
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
|
|
||||||
- name: Build agent interface description
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
monitoring_zabbix_interfaces:
|
|
||||||
- type: agent
|
|
||||||
main: true
|
|
||||||
useip: true
|
|
||||||
ip: "{{ monitoring_zabbix_host_interface_ip }}"
|
|
||||||
dns: "{{ inventory_hostname }}"
|
|
||||||
port: "{{ monitoring_zabbix_host_interface_port }}"
|
|
||||||
|
|
||||||
- name: Register or update host in Zabbix (monitored by proxy)
|
|
||||||
community.zabbix.zabbix_host:
|
|
||||||
server_url: "{{ monitoring_zabbix_api_url }}"
|
|
||||||
login_user: "{{ monitoring_zabbix_api_user }}"
|
|
||||||
login_password: "{{ monitoring_zabbix_api_password }}"
|
|
||||||
validate_certs: "{{ monitoring_zabbix_api_validate_certs }}"
|
|
||||||
host_name: "{{ monitoring_zabbix_host_name }}"
|
|
||||||
visible_name: "{{ monitoring_zabbix_host_name }}"
|
|
||||||
host_groups: "{{ monitoring_zabbix_host_groups }}"
|
|
||||||
link_templates: "{{ monitoring_zabbix_link_templates }}"
|
|
||||||
interfaces: "{{ monitoring_zabbix_interfaces }}"
|
|
||||||
inventory_mode: "{{ monitoring_zabbix_host_inventory_mode }}"
|
|
||||||
monitored_by: proxy
|
|
||||||
proxy: "{{ monitoring_zabbix_proxy }}"
|
|
||||||
tls_connect: 2
|
|
||||||
tls_accept: 2
|
|
||||||
tls_psk_identity: "{{ monitoring_zabbix_psk_identity }}"
|
|
||||||
tls_psk: "{{ monitoring_zabbix_psk_value }}"
|
|
||||||
status: enabled
|
|
||||||
state: present
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
when:
|
|
||||||
- monitoring_zabbix_register_host | bool
|
|
||||||
- monitoring_zabbix_proxy | length > 0
|
|
||||||
|
|
||||||
- name: Register or update host in Zabbix (monitored by server)
|
|
||||||
community.zabbix.zabbix_host:
|
|
||||||
server_url: "{{ monitoring_zabbix_api_url }}"
|
|
||||||
login_user: "{{ monitoring_zabbix_api_user }}"
|
|
||||||
login_password: "{{ monitoring_zabbix_api_password }}"
|
|
||||||
validate_certs: "{{ monitoring_zabbix_api_validate_certs }}"
|
|
||||||
host_name: "{{ monitoring_zabbix_host_name }}"
|
|
||||||
visible_name: "{{ monitoring_zabbix_host_name }}"
|
|
||||||
host_groups: "{{ monitoring_zabbix_host_groups }}"
|
|
||||||
link_templates: "{{ monitoring_zabbix_link_templates }}"
|
|
||||||
interfaces: "{{ monitoring_zabbix_interfaces }}"
|
|
||||||
inventory_mode: "{{ monitoring_zabbix_host_inventory_mode }}"
|
|
||||||
tls_connect: 2
|
|
||||||
tls_accept: 2
|
|
||||||
tls_psk_identity: "{{ monitoring_zabbix_psk_identity }}"
|
|
||||||
tls_psk: "{{ monitoring_zabbix_psk_value }}"
|
|
||||||
status: enabled
|
|
||||||
state: present
|
|
||||||
delegate_to: localhost
|
|
||||||
become: false
|
|
||||||
when:
|
|
||||||
- monitoring_zabbix_register_host | bool
|
|
||||||
- monitoring_zabbix_proxy | length == 0
|
|
||||||
@@ -9,28 +9,3 @@
|
|||||||
that:
|
that:
|
||||||
- monitoring_zabbix_passive_servers | length > 0
|
- monitoring_zabbix_passive_servers | length > 0
|
||||||
fail_msg: "Set monitoring_zabbix_passive_servers to the IPs, CIDRs or DNS names allowed to query the agent."
|
fail_msg: "Set monitoring_zabbix_passive_servers to the IPs, CIDRs or DNS names allowed to query the agent."
|
||||||
|
|
||||||
- name: Ensure Zabbix API settings are defined when host registration is enabled
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- monitoring_zabbix_api_url is defined
|
|
||||||
- monitoring_zabbix_api_url | length > 0
|
|
||||||
- monitoring_zabbix_api_user is defined
|
|
||||||
- monitoring_zabbix_api_user | length > 0
|
|
||||||
- monitoring_zabbix_api_password is defined
|
|
||||||
- monitoring_zabbix_api_password | length > 0
|
|
||||||
fail_msg: >-
|
|
||||||
monitoring_zabbix_api_url, monitoring_zabbix_api_user and
|
|
||||||
monitoring_zabbix_api_password must be set (password lives in vault.yml)
|
|
||||||
when monitoring_zabbix_register_host is true.
|
|
||||||
when: monitoring_zabbix_register_host | bool
|
|
||||||
|
|
||||||
- name: Ensure proxy address is set when a proxy is configured
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- monitoring_zabbix_proxy_address is defined
|
|
||||||
- monitoring_zabbix_proxy_address | length > 0
|
|
||||||
fail_msg: >-
|
|
||||||
monitoring_zabbix_proxy_address (IP/DNS of the proxy the agent contacts)
|
|
||||||
must be set when monitoring_zabbix_proxy is defined.
|
|
||||||
when: monitoring_zabbix_proxy | length > 0
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
# {{ ansible_managed }}
|
# {{ ansible_managed }}
|
||||||
Plugins.Docker.Endpoint={{ monitoring_zabbix_docker_endpoint }}
|
Plugins.Docker.Endpoint={{ monitoring_zabbix_docker_endpoint }}
|
||||||
@@ -2,22 +2,10 @@
|
|||||||
PidFile=/run/zabbix/zabbix_agent2.pid
|
PidFile=/run/zabbix/zabbix_agent2.pid
|
||||||
LogFile=/var/log/zabbix/zabbix_agent2.log
|
LogFile=/var/log/zabbix/zabbix_agent2.log
|
||||||
LogFileSize=0
|
LogFileSize=0
|
||||||
{% if monitoring_zabbix_proxy_address | length > 0 %}
|
|
||||||
Server={{ (monitoring_zabbix_passive_servers | union([monitoring_zabbix_proxy_address])) | unique | join(',') }}
|
|
||||||
ServerActive={{ monitoring_zabbix_proxy_address }}
|
|
||||||
{% else %}
|
|
||||||
Server={{ monitoring_zabbix_passive_servers | join(',') }}
|
Server={{ monitoring_zabbix_passive_servers | join(',') }}
|
||||||
{% if monitoring_zabbix_active_servers | length > 0 %}
|
{% if monitoring_zabbix_active_servers | length > 0 %}
|
||||||
ServerActive={{ monitoring_zabbix_active_servers | join(',') }}
|
ServerActive={{ monitoring_zabbix_active_servers | join(',') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
Hostname={{ monitoring_zabbix_host_name }}
|
|
||||||
HostnameItem=system.hostname
|
HostnameItem=system.hostname
|
||||||
ListenPort={{ monitoring_zabbix_listen_port }}
|
ListenPort={{ monitoring_zabbix_listen_port }}
|
||||||
Include=/etc/zabbix/zabbix_agent2.d/*.conf
|
Include=/etc/zabbix/zabbix_agent2.d/*.conf
|
||||||
|
|
||||||
# --- TLS (PSK) ----------------------------------------------------------------
|
|
||||||
TLSConnect={{ monitoring_zabbix_tls_connect }}
|
|
||||||
TLSAccept={{ monitoring_zabbix_tls_accept }}
|
|
||||||
TLSPSKIdentity={{ monitoring_zabbix_psk_identity }}
|
|
||||||
TLSPSKFile={{ monitoring_zabbix_psk_file }}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
# Rolle `os-updates`
|
|
||||||
|
|
||||||
Aktualisiert alle installierten Pakete auf Debian-Hosts, optional mit
|
|
||||||
Spiegel-Wechsel (Mirror-Switch) und Codename-Anpassung. Die Rolle führt bei
|
|
||||||
Bedarf einen Reboot durch (nur bei neuem Kernel, nicht in LXC-Containern)
|
|
||||||
und schreibt ein detailliertes Update-Log auf den Ansible-Controller.
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/os-updates-deb.yml` (in dem direkt im
|
|
||||||
> Anschluss die `healthcheck`-Rolle läuft) sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- Benutzer mit `become`-Rechten
|
|
||||||
- Schreibrecht auf dem Controller für das Log (delegiert nach localhost)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: os-updates
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` steuert den Ablauf:
|
|
||||||
|
|
||||||
1. **`update_mirrors.yml`** (nur wenn `os_also_update_mirror`):
|
|
||||||
- Führt ggf. ein vorangestelltes `apt upgrade dist` durch, falls der
|
|
||||||
Codename des Hosts nicht dem Ziel-Codename entspricht.
|
|
||||||
- Sichert `/etc/apt/sources.list` (Debian <= 12).
|
|
||||||
- Entfernt `/etc/apt/sources.list` ab Debian 13 (Umstieg auf deb822).
|
|
||||||
- Schreibt das Template `sources.list-deb822.j2` nach
|
|
||||||
`/etc/apt/sources.list.d/debian.sources` (Debian >= 13) bzw.
|
|
||||||
`sources.list.j2` nach `/etc/apt/sources.list` (Debian < 13).
|
|
||||||
- Erkennt `.list`- und `.sources`-Fragmente in
|
|
||||||
`/etc/apt/sources.list.d` und ersetzt Codenames (z. B. `bookworm` →
|
|
||||||
`trixie`) per `replace`, sofern sie in `os_update_debian_codenames`
|
|
||||||
gelistet sind.
|
|
||||||
- Aktualisiert den apt-Cache, wenn sich Quellen geändert haben.
|
|
||||||
2. **`upgrade_packages.yml`**:
|
|
||||||
- `logging_preflight.yml` – ermittelt Anzahl und Liste der upgradbaren
|
|
||||||
Pakete, zeichnet Start-Zeitpunkt auf.
|
|
||||||
- `apt upgrade: full` – vollständiges Upgrade aller Pakete. Benachrichtigt
|
|
||||||
Handler `apt cleanup` und `apt autoremove`.
|
|
||||||
- `reboot.yml` – entscheidet über Reboot-Vergleich von laufendem und
|
|
||||||
installiertem Kernel, rebootet asynchron, wartet auf Wiederkehr,
|
|
||||||
erfasst Downtime. Wird in LXC-Containern übersprungen.
|
|
||||||
- `logging_postflight.yml` – berechnet Dauer, schreibt Log-Eintrag mit
|
|
||||||
allen Fakten in `os_update_log_file` (delegiert an localhost).
|
|
||||||
|
|
||||||
### Reboot-Entscheidung
|
|
||||||
|
|
||||||
- Läuft ein älterer Kernel als installiert, gilt `reboot_required: true`.
|
|
||||||
- Der Reboot erfolgt mit `async: 1`, `poll: 0`, gefolgt von
|
|
||||||
`wait_for_connection` (Delay 10s, Timeout 600s).
|
|
||||||
- In LXC-Containern (`virtualization_type == "lxc"`) wird der gesamte
|
|
||||||
Reboot-Block übersprungen.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-----------------------------|--------|----------------------------------------------------------|-------------------------------------------------------------|
|
|
||||||
| `os_update_auto_upgrade` | bool | `true` | (Steuer-Vorbereitung) Auto-Upgrade erlauben |
|
|
||||||
| `os_also_update_mirror` | bool | `false` | Spiegel-Wechsel und Codename-Rewrite durchführen |
|
|
||||||
| `os_update_logging_enabled`| bool | `true` | Update-Logging aktivieren |
|
|
||||||
| `os_update_log_dir` | string | `/ansible/logs` | Basis-Verzeichnis für Logs |
|
|
||||||
| `os_update_log_inventory` | string | `{{ inventory_file \| basename \| splitext \| first }}` | Inventory-Name (abgeleitet) |
|
|
||||||
| `os_update_log_file` | string | `<log_dir>/<inventory>/<hostname>/update.log` | Pfad zur Update-Log-Datei (Controller-seitig) |
|
|
||||||
| `os_update_mirrors` | list | siehe `defaults/` | Zwei Spiegel: `[0]` Haupt-Spiegel, `[1]` Security-Spiegel |
|
|
||||||
| `os_update_version_codename`| string | `{{ ansible_facts['distribution_release'] }}` | Ziel-Codename für Template-Ausfüllung |
|
|
||||||
| `os_update_debian_codenames`| list | `[trixie, bookworm, bullseye]` | Erlaubte Codenames, die in `.list`/`.sources` umgeschrieben werden |
|
|
||||||
|
|
||||||
> **Achtung:** `os_update_version_codename` wird in
|
|
||||||
> `inventory/group_vars/debian.yml` auf `trixie` überschrieben. Nicht blind
|
|
||||||
> ändern – der Wert steuert die Template-Ausfüllung der `sources.list`.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel | Debian-Version |
|
|
||||||
|---------------------------|-------------------------------------------------|----------------|
|
|
||||||
| `sources.list.j2` | `/etc/apt/sources.list` | < 13 |
|
|
||||||
| `sources.list-deb822.j2` | `/etc/apt/sources.list.d/debian.sources` | >= 13 |
|
|
||||||
|
|
||||||
Beide Templates erzeugen `main`, `-updates`, `-backports` und `-security`
|
|
||||||
Einträge mit `main contrib non-free non-free-firmware`.
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser | Beschreibung |
|
|
||||||
|------------------|-----------------------------------|-----------------------------------|
|
|
||||||
| `apt cleanup` | `apt upgrade: full` | `apt clean` + `apt autoclean` |
|
|
||||||
| `apt autoremove` | `apt upgrade: full` | `apt autoremove` |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- Keine weiteren Rollen.
|
|
||||||
- Collections: `ansible.builtin` (Bordmittel).
|
|
||||||
- Empfohlener Partner: `healthcheck`-Rolle (für Quality-Gate nach Update).
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- **Logging**: Das Log wird **delegiert an localhost** geschrieben unter
|
|
||||||
`logs/<inventory>/<hostname>/update.log`. Das Verzeichnis `logs/` ist
|
|
||||||
git-ignored. Die Struktur ist so gewählt, dass die `healthcheck`-Rolle
|
|
||||||
ihre `quality_gate`-Sektion an denselben Log-Eintrag anhängen kann.
|
|
||||||
- **Spiegel-Wechsel** (`os_also_update_mirror: true`) ist potenziell
|
|
||||||
destruktiv: bestehende `sources.list` wird gesichert bzw. entfernt.
|
|
||||||
Vorsicht beim Wechsel auf andere Debian-Releases.
|
|
||||||
- **Codename-Rewrite** greift nur bei Codenames aus
|
|
||||||
`os_update_debian_codenames` – schützt davor, Drittrepositories
|
|
||||||
versehentlich umzuschreiben.
|
|
||||||
- **LXC**: In Containern wird der Reboot-Block komplett übersprungen
|
|
||||||
(`virtualization_type != "lxc"`).
|
|
||||||
- **Idempotenz**: `apt upgrade: full` meldet `changed`, wenn Pakete
|
|
||||||
aktualisiert wurden; ohne anstehende Updates ist der Lauf "ok".
|
|
||||||
@@ -1,17 +1,11 @@
|
|||||||
# Standardwerte, die überschrieben werden können
|
# Standardwerte, die überschrieben werden können
|
||||||
os_update_auto_upgrade: true
|
os_update_auto_upgrade: true
|
||||||
os_also_update_mirror: false
|
os_also_update_mirror: false
|
||||||
|
|
||||||
# Logging of OS update runs (preflight package count/list, updated packages, duration)
|
|
||||||
os_update_logging_enabled: true
|
|
||||||
os_update_log_dir: /ansible/logs
|
|
||||||
os_update_log_inventory: "{{ inventory_file | basename | splitext | first }}"
|
|
||||||
os_update_log_file: "{{ os_update_log_dir }}/{{ os_update_log_inventory }}/{{ ansible_facts['hostname'] }}/update.log"
|
|
||||||
os_update_mirrors:
|
os_update_mirrors:
|
||||||
# Role needs two mirros to use for the sources.list.j2 Template
|
# Role needs two mirros to use for the sources.list.j2 Template
|
||||||
- "http://deb.debian.org/debian" # Enter a main mirror here (not security)
|
- "http://deb.debian.org/debian" # Enter a main mirror here (not security)
|
||||||
- "http://security.debian.org/debian-security" # Enter a security mirror here
|
- "http://security.debian.org/debian-security" # Enter a security mirror here
|
||||||
os_update_version_codename: "{{ ansible_facts['distribution_release'] }}" # KEEP UNTOUCHED!! | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on
|
os_update_version_codename: "{{ ansible_distribution_release }}" # KEEP UNTOUCHED!! | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on
|
||||||
os_update_debian_codenames:
|
os_update_debian_codenames:
|
||||||
# Only these suites are considered Debian codenames and will be rewritten in sources.list.d
|
# Only these suites are considered Debian codenames and will be rewritten in sources.list.d
|
||||||
- trixie
|
- trixie
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
clean: yes
|
clean: yes
|
||||||
autoclean: yes
|
autoclean: yes
|
||||||
|
|
||||||
- name: apt autoremove
|
- name: Reboot system
|
||||||
apt:
|
command: /sbin/reboot
|
||||||
autoremove: yes
|
async: 1
|
||||||
|
poll: 0
|
||||||
|
ignore_errors: true
|
||||||
|
when: reboot_required == "yes"
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# Postflight logging: which packages were updated and how long it took.
|
|
||||||
# Run logging steps only when os_update_logging_enabled is true.
|
|
||||||
|
|
||||||
- name: Logging - Record end epoch
|
|
||||||
command: date +%s
|
|
||||||
register: os_update_log_end_ts
|
|
||||||
changed_when: false
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Logging - Compute upgrade duration
|
|
||||||
set_fact:
|
|
||||||
os_update_duration_seconds: "{{ (os_update_log_end_ts.stdout | int) - (os_update_log_start_ts.stdout | int) }}"
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Logging - Ensure log directory exists
|
|
||||||
file:
|
|
||||||
path: "{{ os_update_log_file | dirname }}"
|
|
||||||
state: directory
|
|
||||||
delegate_to: localhost
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Logging - Write update log entry
|
|
||||||
blockinfile:
|
|
||||||
path: "{{ os_update_log_file }}"
|
|
||||||
create: yes
|
|
||||||
marker: "# {mark} ANSIBLE-OS-UPDATE"
|
|
||||||
block: |
|
|
||||||
host: {{ ansible_facts['hostname'] }}
|
|
||||||
started: {{ os_update_log_start_iso.stdout }}
|
|
||||||
duration_seconds: {{ os_update_duration_seconds }}
|
|
||||||
upgradable_packages_count: {{ os_update_upgradable_count }}
|
|
||||||
upgrade_changed: {{ os_update_upgrade_result.changed | default(false) }}
|
|
||||||
upgrade_failed: {{ os_update_upgrade_result.failed | default(false) }}
|
|
||||||
upgradable_packages:
|
|
||||||
{% for ver in os_update_upgradable_versions %}
|
|
||||||
- {{ ver.split()[0] }} ({{ ver.split()[1] }} -> {{ ver.split()[2] }})
|
|
||||||
{% endfor %}
|
|
||||||
reboot_required: {{ os_update_reboot_required }}
|
|
||||||
reboot_reason: {{ os_update_reboot_reason }}
|
|
||||||
reboot_triggered: {{ os_update_reboot_triggered }}
|
|
||||||
reboot_started: {{ os_update_reboot_start_iso }}
|
|
||||||
reboot_downtime_seconds: {{ os_update_reboot_downtime_seconds }}
|
|
||||||
kernel_before: {{ os_update_running_kernel.stdout | default('n/a') }}
|
|
||||||
kernel_after: {{ os_update_running_kernel_after }}
|
|
||||||
delegate_to: localhost
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# Preflight logging: how many and which packages need to be updated.
|
|
||||||
# Run logging steps only when os_update_logging_enabled is true.
|
|
||||||
|
|
||||||
- name: Logging - Refresh apt cache for accurate preflight
|
|
||||||
apt:
|
|
||||||
update_cache: yes
|
|
||||||
changed_when: false
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Logging - Record start epoch
|
|
||||||
command: date +%s
|
|
||||||
register: os_update_log_start_ts
|
|
||||||
changed_when: false
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Logging - Record start ISO time
|
|
||||||
command: date -Iseconds
|
|
||||||
register: os_update_log_start_iso
|
|
||||||
changed_when: false
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Preflight - Gather upgradable packages
|
|
||||||
command: apt list --upgradable
|
|
||||||
register: os_update_upgradable
|
|
||||||
changed_when: false
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Preflight - Build list of upgradable package names, versions and count
|
|
||||||
set_fact:
|
|
||||||
os_update_upgradable_names: >-
|
|
||||||
{{
|
|
||||||
os_update_upgradable.stdout_lines
|
|
||||||
| select('search', '\[upgradable')
|
|
||||||
| map('regex_replace', '^([^/]+)/.*$', '\1')
|
|
||||||
| list
|
|
||||||
}}
|
|
||||||
os_update_upgradable_versions: >-
|
|
||||||
{{
|
|
||||||
os_update_upgradable.stdout_lines
|
|
||||||
| select('search', '\[upgradable')
|
|
||||||
| map('regex_replace', '^([^/]+)/\S+\s+(\S+)\s+\S+\s+\[upgradable from: (\S+)\]$', '\1 \3 \2')
|
|
||||||
| list
|
|
||||||
}}
|
|
||||||
os_update_upgradable_count: >-
|
|
||||||
{{
|
|
||||||
(os_update_upgradable.stdout_lines | select('search', '\[upgradable') | list | length) | int
|
|
||||||
}}
|
|
||||||
when: os_update_logging_enabled | bool
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
# Reboot decision and execution.
|
|
||||||
# Determines whether a reboot is needed because a new kernel was installed,
|
|
||||||
# performs the reboot asynchronously, waits for the host to come back, and
|
|
||||||
# records timing facts for the update log.
|
|
||||||
|
|
||||||
- name: Gather running kernel
|
|
||||||
command: uname -r
|
|
||||||
register: os_update_running_kernel
|
|
||||||
changed_when: false
|
|
||||||
when: ansible_facts['virtualization_type'] != 'lxc'
|
|
||||||
|
|
||||||
- name: Gather latest installed kernel
|
|
||||||
shell: |
|
|
||||||
dpkg -l | grep -E '^ii' | grep 'linux-image-[0-9]' | awk '{print $2}' | sort | tail -n 1
|
|
||||||
register: os_update_latest_kernel
|
|
||||||
changed_when: false
|
|
||||||
failed_when: false
|
|
||||||
when: ansible_facts['virtualization_type'] != 'lxc'
|
|
||||||
|
|
||||||
- name: Determine reboot decision
|
|
||||||
set_fact:
|
|
||||||
os_update_reboot_required: true
|
|
||||||
os_update_reboot_reason: "new kernel installed ({{ os_update_running_kernel.stdout }} -> {{ os_update_latest_kernel.stdout | regex_replace('^linux-image-', '') }})"
|
|
||||||
when:
|
|
||||||
- ansible_facts['virtualization_type'] != 'lxc'
|
|
||||||
- os_update_latest_kernel.stdout | length > 0
|
|
||||||
- os_update_running_kernel.stdout not in os_update_latest_kernel.stdout
|
|
||||||
|
|
||||||
- name: Default reboot decision to false
|
|
||||||
set_fact:
|
|
||||||
os_update_reboot_required: "{{ os_update_reboot_required | default(false) }}"
|
|
||||||
os_update_reboot_reason: "{{ os_update_reboot_reason | default('none') }}"
|
|
||||||
|
|
||||||
- name: Default reboot timing facts
|
|
||||||
set_fact:
|
|
||||||
os_update_reboot_triggered: false
|
|
||||||
os_update_reboot_start_iso: "n/a"
|
|
||||||
os_update_reboot_downtime_seconds: 0
|
|
||||||
os_update_running_kernel_after: "{{ os_update_running_kernel.stdout | default('n/a') }}"
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Reboot - Record start time
|
|
||||||
command: date -Iseconds
|
|
||||||
register: os_update_reboot_start_iso_raw
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Reboot - Record start epoch
|
|
||||||
command: date +%s
|
|
||||||
register: os_update_reboot_start_ts
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Reboot - Reboot system
|
|
||||||
command: /sbin/reboot
|
|
||||||
async: 1
|
|
||||||
poll: 0
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: Reboot - Wait for host to come back online
|
|
||||||
wait_for_connection:
|
|
||||||
delay: 10
|
|
||||||
timeout: 600
|
|
||||||
register: os_update_reboot_wait
|
|
||||||
|
|
||||||
- name: Reboot - Record end epoch
|
|
||||||
command: date +%s
|
|
||||||
register: os_update_reboot_end_ts
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Reboot - Compute downtime
|
|
||||||
set_fact:
|
|
||||||
os_update_reboot_downtime_seconds: "{{ (os_update_reboot_end_ts.stdout | int) - (os_update_reboot_start_ts.stdout | int) }}"
|
|
||||||
|
|
||||||
- name: Reboot - Gather running kernel after reboot
|
|
||||||
command: uname -r
|
|
||||||
register: os_update_running_kernel_after_raw
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Reboot - Record reboot facts
|
|
||||||
set_fact:
|
|
||||||
os_update_reboot_triggered: true
|
|
||||||
os_update_reboot_start_iso: "{{ os_update_reboot_start_iso_raw.stdout }}"
|
|
||||||
os_update_running_kernel_after: "{{ os_update_running_kernel_after_raw.stdout }}"
|
|
||||||
when: os_update_reboot_required | bool
|
|
||||||
@@ -1,17 +1,30 @@
|
|||||||
- name: Run preflight logging
|
|
||||||
include_tasks: logging_preflight.yml
|
|
||||||
|
|
||||||
- name: Upgrade all installed packages
|
- name: Upgrade all installed packages
|
||||||
apt:
|
apt:
|
||||||
upgrade: full
|
upgrade: full
|
||||||
update_cache: yes
|
update_cache: yes
|
||||||
register: os_update_upgrade_result
|
notify:
|
||||||
notify:
|
|
||||||
- apt cleanup
|
- apt cleanup
|
||||||
- apt autoremove
|
|
||||||
|
|
||||||
- name: Run reboot decision and reboot if required
|
- name: Check if a kernel update is available
|
||||||
include_tasks: reboot.yml
|
shell: |
|
||||||
|
dpkg -l | grep -E '^ii' | grep 'linux-image-[0-9]' | awk '{print $2}' | sort | tail -n 1
|
||||||
|
register: latest_kernel
|
||||||
|
when: ansible_virtualization_type != 'lxc'
|
||||||
|
|
||||||
- name: Run postflight logging
|
- name: Check if running kernel matches the latest installed kernel
|
||||||
include_tasks: logging_postflight.yml
|
shell: |
|
||||||
|
echo "{{ latest_kernel.stdout }}" | grep -c $(uname -r)
|
||||||
|
register: kernel_match
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
when: ansible_facts['virtualization_type'] != 'lxc'
|
||||||
|
|
||||||
|
- name: Mark reboot required if a new kernel is installed
|
||||||
|
set_fact:
|
||||||
|
reboot_required: "yes"
|
||||||
|
changed_when: true
|
||||||
|
notify:
|
||||||
|
- Reboot system
|
||||||
|
when:
|
||||||
|
- ansible_facts['virtualization_type'] != 'lxc'
|
||||||
|
- (kernel_match.stdout | int) == 0
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export PROXMOX_URL=https://192.168.212.10:8006/
|
||||||
|
export PROXMOX_USERNAME=ansible@pve
|
||||||
|
export PROXMOX_PASSWORD=u0H1GQMsAuSYZJ
|
||||||
|
export PROXMOX_INVALID_CERT=False
|
||||||
|
export EXCLUDE_LIST="docker.*;br-*;veth*"
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
$ANSIBLE_VAULT;1.1;AES256
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
31306438393238643764333164633738323833656131303331396336346461623633623531303563
|
34323331303232653139313063663566323064373330346237653366363965303235376230396534
|
||||||
3261353763303939633537356239633937633536336530340a353462653030306433613062323861
|
3364383031333064336239653661313066383534626565320a666433333038303938333163363030
|
||||||
38313631613134646231346632653366346637316639343764313161303937656535323739636235
|
65623133356566313263616564626166396635343863353065646538343333383066333839666239
|
||||||
3933646232616635350a383165613538613264343264633466326266646463356463643565336238
|
3739643861393534360a353837636662303065623735373063313937633731636338643631623435
|
||||||
31633237386565653635366164383962386338313739646466636564653338613635653636376665
|
65613634316432373837393638636165326231616563353765376533313336373165313436353566
|
||||||
65376631373166303438663565623061333133373630626137636266333865363433653666646135
|
65346536316533343966323531333866626162363837653762383265366632323330646665643635
|
||||||
34396630633265343036623436626439636534656438303265343537353661646335316665303664
|
62653238353738613937393632336132646364633962646637353331613061363564346234333439
|
||||||
61356135386138633433373466396530373839326664623562373066303039303235386139613065
|
63356431373962343737
|
||||||
39373864333638643862386232313437376631343133353966633130623834633764643838656361
|
|
||||||
6538623334323266313139326466326633643363313563333039
|
|
||||||
|
|||||||
Reference in New Issue
Block a user