Compare commits

...
3 Commits
Author SHA1 Message Date
DerLinkman 2fbcd14169 added zabbix psk options + api host add 2026-07-18 21:37:32 +02:00
DerLinkmanandDerLinkman cab59c1658 added readmes (#1)
Co-authored-by: DerLinkman <derlinkman@gmail.com>
Reviewed-on: #1
2026-07-18 19:36:54 +00:00
DerLinkman 8d64bf5982 added AGENTS.md 2026-07-18 21:36:16 +02:00
18 changed files with 1400 additions and 47 deletions
+3 -1
View File
@@ -2,4 +2,6 @@ hosts
proxmox.*
.vscode
.vault_pass
logs
logs
.zabbix-psk
setenv.sh
+166
View File
@@ -0,0 +1,166 @@
# 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.
+138
View File
@@ -0,0 +1,138 @@
# 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).
+20 -1
View File
@@ -1 +1,20 @@
monitoring_zabbix_passive_servers: ["10.13.37.1"]
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: ""
+119
View File
@@ -0,0 +1,119 @@
# 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`.
+102
View File
@@ -0,0 +1,102 @@
# 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.
+94
View File
@@ -0,0 +1,94 @@
# 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.
+97
View File
@@ -0,0 +1,97 @@
# 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.
+104
View File
@@ -0,0 +1,104 @@
# 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.
+176
View File
@@ -0,0 +1,176 @@
# 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).
+48 -15
View File
@@ -1,15 +1,48 @@
monitoring_zabbix_version: "7.0"
monitoring_zabbix_release_package: "zabbix-release_latest_{{ monitoring_zabbix_version }}+debian{{ ansible_distribution_major_version }}_all.deb"
monitoring_zabbix_release_url: "https://repo.zabbix.com/zabbix/{{ monitoring_zabbix_version }}/debian/pool/main/z/zabbix-release/{{ monitoring_zabbix_release_package }}"
monitoring_zabbix_release_path: "/tmp/{{ monitoring_zabbix_release_package }}"
monitoring_zabbix_agent_package: zabbix-agent2
monitoring_zabbix_agent_service: zabbix-agent2
monitoring_zabbix_config_file: /etc/zabbix/zabbix_agent2.conf
monitoring_zabbix_agent_user: zabbix
monitoring_zabbix_passive_servers: ["192.168.212.1"]
monitoring_zabbix_active_servers: ""
monitoring_zabbix_listen_port: 10050
monitoring_zabbix_docker_group: docker
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_endpoint: "unix://{{ monitoring_zabbix_docker_socket_path }}"
monitoring_zabbix_version: "7.0"
monitoring_zabbix_release_package: "zabbix-release_latest_{{ monitoring_zabbix_version }}+debian{{ ansible_distribution_major_version }}_all.deb"
monitoring_zabbix_release_url: "https://repo.zabbix.com/zabbix/{{ monitoring_zabbix_version }}/debian/pool/main/z/zabbix-release/{{ monitoring_zabbix_release_package }}"
monitoring_zabbix_release_path: "/tmp/{{ monitoring_zabbix_release_package }}"
monitoring_zabbix_agent_package: zabbix-agent2
monitoring_zabbix_agent_service: zabbix-agent2
monitoring_zabbix_config_file: /etc/zabbix/zabbix_agent2.conf
monitoring_zabbix_agent_user: zabbix
monitoring_zabbix_passive_servers: ["192.168.212.1"]
monitoring_zabbix_active_servers: ""
monitoring_zabbix_listen_port: 10050
monitoring_zabbix_docker_group: docker
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_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"]
+55
View File
@@ -0,0 +1,55 @@
---
# 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
+6
View File
@@ -10,5 +10,11 @@
- import_tasks: configure-docker.yml
tags: monitoring
- import_tasks: configure-psk.yml
tags: monitoring
- import_tasks: configure-agent.yml
tags: monitoring
- import_tasks: register-host.yml
tags: monitoring
+75
View File
@@ -0,0 +1,75 @@
---
# 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
+36 -11
View File
@@ -1,11 +1,36 @@
---
- name: Stop playbook if system is not Debian
ansible.builtin.fail:
msg: "This role only supports Debian."
when: ansible_facts['os_family'] != "Debian"
- name: Ensure Zabbix passive servers are defined
ansible.builtin.assert:
that:
- 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."
---
- name: Stop playbook if system is not Debian
ansible.builtin.fail:
msg: "This role only supports Debian."
when: ansible_facts['os_family'] != "Debian"
- name: Ensure Zabbix passive servers are defined
ansible.builtin.assert:
that:
- 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."
- 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,11 +1,23 @@
# {{ ansible_managed }}
PidFile=/run/zabbix/zabbix_agent2.pid
LogFile=/var/log/zabbix/zabbix_agent2.log
LogFileSize=0
Server={{ monitoring_zabbix_passive_servers | join(',') }}
{% if monitoring_zabbix_active_servers | length > 0 %}
ServerActive={{ monitoring_zabbix_active_servers | join(',') }}
{% endif %}
HostnameItem=system.hostname
ListenPort={{ monitoring_zabbix_listen_port }}
Include=/etc/zabbix/zabbix_agent2.d/*.conf
# {{ ansible_managed }}
PidFile=/run/zabbix/zabbix_agent2.pid
LogFile=/var/log/zabbix/zabbix_agent2.log
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(',') }}
{% if monitoring_zabbix_active_servers | length > 0 %}
ServerActive={{ monitoring_zabbix_active_servers | join(',') }}
{% endif %}
{% endif %}
Hostname={{ monitoring_zabbix_host_name }}
HostnameItem=system.hostname
ListenPort={{ monitoring_zabbix_listen_port }}
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 }}
+128
View File
@@ -0,0 +1,128 @@
# 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".
+10 -8
View File
@@ -1,9 +1,11 @@
$ANSIBLE_VAULT;1.1;AES256
34323331303232653139313063663566323064373330346237653366363965303235376230396534
3364383031333064336239653661313066383534626565320a666433333038303938333163363030
65623133356566313263616564626166396635343863353065646538343333383066333839666239
3739643861393534360a353837636662303065623735373063313937633731636338643631623435
65613634316432373837393638636165326231616563353765376533313336373165313436353566
65346536316533343966323531333866626162363837653762383265366632323330646665643635
62653238353738613937393632336132646364633962646637353331613061363564346234333439
63356431373962343737
31306438393238643764333164633738323833656131303331396336346461623633623531303563
3261353763303939633537356239633937633536336530340a353462653030306433613062323861
38313631613134646231346632653366346637316639343764313161303937656535323739636235
3933646232616635350a383165613538613264343264633466326266646463356463643565336238
31633237386565653635366164383962386338313739646466636564653338613635653636376665
65376631373166303438663565623061333133373630626137636266333865363433653666646135
34396630633265343036623436626439636534656438303265343537353661646335316665303664
61356135386138633433373466396530373839326664623562373066303039303235386139613065
39373864333638643862386232313437376631343133353966633130623834633764643838656361
6538623334323266313139326466326633643363313563333039