# Architekturskizze — `demo-gymburgdorf`
Diese Skizze zeigt, wie das `reference-ansible`-Repo am Beispiel der
Inventory `demo-gymburgdorf` funktioniert: welche Hosts existieren,
welche Rollen darauf laufen, wo welche Variablen hingehören und wie
Secrets aus OpenBao gelookupt werden.
## 1. Variablen-Hierarchie (Ansible Precedence)
```mermaid
flowchart TB
classDef rolelayer fill:#fef3c7,stroke:#92400e,color:#000
classDef grouplayer fill:#dbeafe,stroke:#1e40af,color:#000
classDef hostlayer fill:#dcfce7,stroke:#166534,color:#000
classDef vaultlayer fill:#fee2e2,stroke:#991b1b,color:#000
R["role defaults/main.yml
(niedrigste Precedence)
~180 Variablen über 12 Rollen
z.B. traefik_use_ssl: false
keycloak_admin_password: changeme"]:::rolelayer
GA["group_vars/all/
docker.yml → docker_registry_mirrors
vault.yml → vault_addr, vault_mount"]:::grouplayer
GT["group_vars/traefik_servers/
traefik.yml
traefik_use_ssl, traefik_cert_mode: acme
traefik_acme_dns_zone
traefik_acme_tsig_* (Vault-Lookup!)"]:::grouplayer
GB["group_vars/backend_servers/
traefik.yml → traefik_mode: backend"]:::grouplayer
HR["host_vars/reverseproxy/
traefik.yml → traefik_mode: dmz"]:::hostlayer
HA["host_vars/application/ (fehlt aktuell!)
FQDNs, OIDC-Clients, DB-Passwords
nextcloud_domain, authentik_domain, ..."]:::hostlayer
HS["host_vars/storage/ (fehlt aktuell!)
garage_s3_domain, garage_*_token
traefik_dmz_exposed_services (für DMZ)"]:::hostlayer
V["HashiCorp Vault / OpenBao
bao.digitalboard.ch
mount: demo-gymburgdorf
z.B. demo-gymburgdorf/data/acme-tsig"]:::vaultlayer
R --> GA --> GT --> GB --> HR
GB --> HA
GB --> HS
GT -.Lookup zur Laufzeit.-> V
HA -.Lookup zur Laufzeit.-> V
HS -.Lookup zur Laufzeit.-> V
```
Höhere Ebene überschreibt tiefere. `host_vars/reverseproxy/traefik_mode: dmz`
schlägt also `group_vars/backend_servers/traefik_mode: backend` —
möglich, weil `reverseproxy` *nicht* in `backend_servers` ist.
## 2. Inventory-Topologie demo-gymburgdorf
```mermaid
flowchart LR
classDef dmz fill:#fee2e2,stroke:#991b1b,color:#000
classDef app fill:#dcfce7,stroke:#166534,color:#000
classDef stor fill:#dbeafe,stroke:#1e40af,color:#000
classDef turn fill:#fef9c3,stroke:#854d0e,color:#000
subgraph ALL["group: all_servers (alle Hosts)"]
direction LR
subgraph DMZ["DMZ-Segment 172.16.9.0/24"]
RP["reverseproxy
172.16.9.111
traefik_mode: dmz"]:::dmz
TURN["turn
172.16.9.112
(STUN/TURN)"]:::turn
end
subgraph BE["Backend-Segment 172.16.19.0/24
(group: backend_servers)"]
APP["application
172.16.19.101
traefik_mode: backend
+ nextcloud, opencloud,
collabora, drawio,
authentik, authentik_outpost_ldap"]:::app
ST["storage
172.16.19.102
traefik_mode: backend
+ garage (S3)"]:::stor
end
end
RP -.HTTP/HTTPS reverse proxy.-> APP
RP -.HTTP/HTTPS reverse proxy.-> ST
```
Gruppen-Mitgliedschaften (`hosts.yml`):
- `traefik_servers` ⊇ `all_servers` → **alle 4 Hosts** bekommen Traefik
(DMZ-Modus für `reverseproxy`, Backend-Modus für `application`/`storage`).
- `backend_servers = {application, storage}` → setzt
`traefik_mode: backend` via group_vars.
- Service-Gruppen (`nextcloud_servers`, `garage_servers`, …) sind
Single-Host-Wrapper, mit denen `playbooks/site.yml` gezielt
deploybare Rollen targetet.
## 3. Service-Layout & Variablen-Verortung
```mermaid
flowchart TB
classDef rp fill:#fee2e2,stroke:#991b1b,color:#000
classDef ap fill:#dcfce7,stroke:#166534,color:#000
classDef st fill:#dbeafe,stroke:#1e40af,color:#000
classDef ext fill:#e9d5ff,stroke:#6b21a8,color:#000
Internet((Internet))
DNS["DNS ns1.digitalboard.ch
RFC2136 TSIG (key: acme_update_key_demo_gymb)
dynamic zone: demo-gymb._acme.digitalboard.ch
CNAME-bridge: _acme-challenge.*.gymb.souveredu.ch"]:::ext
BAO["OpenBao
bao.digitalboard.ch
mount: demo-gymburgdorf"]:::ext
subgraph RP["reverseproxy — traefik dmz"]
TRDMZ["traefik (file provider)
📍 group_vars/traefik_servers/traefik.yml
→ acme, tsig, ssl
📍 host_vars/reverseproxy/traefik.yml
→ traefik_mode: dmz
📍 host_vars/reverseproxy/...
→ traefik_dmz_exposed_services"]:::rp
end
subgraph APP["application — backend"]
TRA["traefik (docker provider)
📍 group_vars/backend_servers
→ traefik_mode: backend"]:::ap
NC["nextcloud
📍 host_vars/application/nextcloud.yml
domain, postgres_pw, oidc, s3, ldap"]:::ap
OC["opencloud
📍 host_vars/application/opencloud.yml
oidc_issuer, ldap, s3"]:::ap
AK["authentik
📍 host_vars/application/authentik.yml
secret_key, postgres, ldap_apps, oidc_apps"]:::ap
AKO["authentik_outpost_ldap
📍 host_vars/application/authentik_outpost_ldap.yml
host, token"]:::ap
COL["collabora
📍 host_vars/application/collabora.yml
domain, allowed_domains"]:::ap
DRW["drawio
📍 host_vars/application/drawio.yml"]:::ap
end
subgraph ST["storage — backend"]
TRS["traefik (docker provider)"]:::st
GAR["garage (S3)
📍 host_vars/storage/garage.yml
s3_domain, rpc_secret,
admin_token, s3_keys"]:::st
end
Internet -->|HTTPS :443| TRDMZ
TRDMZ -->|HTTP backend| TRA
TRDMZ -->|HTTP backend| TRS
TRA --> NC & OC & AK & COL & DRW & AKO
TRS --> GAR
NC -. S3 .-> GAR
OC -. S3 .-> GAR
NC -. OIDC .-> AK
OC -. OIDC .-> AK
NC -. WOPI .-> COL
OC -. WOPI .-> COL
NC -. LDAP .-> AKO
OC -. LDAP .-> AKO
AKO -. RPC + token .-> AK
TRDMZ -. ACME DNS-01 TSIG .-> DNS
TRDMZ -. lookup acme-tsig .-> BAO
AK -. lookup secrets .-> BAO
NC -. lookup secrets .-> BAO
GAR -. lookup secrets .-> BAO
```
## 4. Deploy-Flow
```mermaid
sequenceDiagram
participant U as User (make)
participant M as Makefile
participant A as ansible-playbook
participant V as OpenBao
participant H as Hosts
U->>M: make bao
M->>V: bao login (OIDC)
V-->>M: VAULT_TOKEN
U->>M: make deploy_site_demo_gymburgdorf
M->>A: ansible-playbook site.yml -i inventories/demo-gymburgdorf/hosts.yml
A->>A: lade group_vars/all → group_vars/traefik_servers → group_vars/backend_servers → host_vars/*
A->>V: community.hashi_vault Lookups (acme-tsig, secrets)
V-->>A: secret values
A->>H: Play "base" → all_servers
A->>H: Play "traefik" → traefik_servers (dmz auf reverseproxy, backend auf application/storage)
A->>H: Play "garage" → storage
A->>H: Play "authentik / nextcloud / collabora / ..." → application
```
## 5. Variablen-Cheatsheet — wo gehört was hin?
| Variable | Wohin in `demo-gymburgdorf/` | Warum |
|---|---|---|
| `vault_addr`, `vault_mount` | `group_vars/all/vault.yml` ✅ | Vault-Endpoint gilt site-weit |
| `docker_registry_mirrors` | `group_vars/all/docker.yml` ✅ | Pulls aus Mirror auf allen Hosts |
| `traefik_acme_*`, `traefik_use_ssl`, `traefik_cert_mode` | `group_vars/traefik_servers/traefik.yml` ✅ | Gilt für alle Traefik-Instanzen (dmz + backend) |
| `traefik_mode: backend` | `group_vars/backend_servers/traefik.yml` ✅ | Default für app + storage |
| `traefik_mode: dmz` | `host_vars/reverseproxy/traefik.yml` ✅ | Host-spezifischer Override |
| `traefik_dmz_exposed_services` | **`host_vars/reverseproxy/`** | Liste, welche Backend-Services die DMZ proxyt (nur dort sinnvoll) |
| `nextcloud_*`, `authentik_*`, `opencloud_*`, `collabora_*`, `drawio_*` | **`host_vars/application/.yml`** | Service läuft genau auf `application` |
| `garage_*` | **`host_vars/storage/garage.yml`** | Service läuft genau auf `storage` |
| Secrets (Passwords, Tokens, Keys) | Inline-Variable mit `lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/', url=vault_addr)` | Single source of truth; Pattern wie bei `_acme_tsig` |
## 6. Traefik-Modi (zentral für die Architektur)
**`traefik_mode: dmz`** (Public-facing Reverse Proxy auf `reverseproxy`):
- Aggregiert Services von Backend-Servern via
`traefik_dmz_exposed_services` (Host-Variablen).
- Nutzt **file provider** mit `services.yml` für statisches Routing.
- Kein Docker-Socket gemountet — keine lokalen Container.
- Routet zu `backend_host` auf anderen Maschinen.
- Selektive Backend-Auswahl via `traefik_backend_servers_to_proxy`.
**`traefik_mode: backend`** (Application/Storage Server):
- Mountet Docker-Socket (`/var/run/docker.sock`).
- Nutzt **docker provider** für Auto-Discovery lokaler Container.
- Services mit Label `traefik.enable=true` werden automatisch exponiert.
- Beide Modi unterstützen ACME (RFC2136 DNS Challenge) oder Self-Signed.
## 7. Was im aktuellen `demo-gymburgdorf` noch fehlt
Im Vergleich zur `vagrant`-Inventory (Referenz) fehlen für eine
vollständige Deployment:
- `host_vars/application/main.yml` — Backbone-Vars für den Host
(FQDN-Pattern, gemeinsame Defaults).
- `host_vars/application/{nextcloud,opencloud,authentik,authentik_outpost_ldap,collabora,drawio}.yml`
— die service-spezifischen Konfigurationen.
- `host_vars/storage/{main.yml,garage.yml}` — Garage-Cluster-Setup.
- `host_vars/reverseproxy/<…>.yml` mit `traefik_dmz_exposed_services`
— sonst routet die DMZ nichts.
Die `vagrant`-Inventory ist das Template: dieselbe Struktur auf
`application`/`storage` mappen, FQDNs auf `*.gymb.souveredu.ch`
umstellen, Secrets durch Bao-Lookups ersetzen.