- A0: API-User 'automation' auf agh-bf1/.36 + agh-bf2/.37 (PW in ~/.secrets, TP30-Merkposten) - A: 8 clients.persistent (7 VLAN-CIDR-Gruppen + dns-bypass-exempt), Policy-Matrix (INFRA/MEDIA/MGMT filtering=aus, GUEST safe-search+parental an), live verifiziert - B: agh-sync.py (check/push), Repo-SSoT AdGuardHome.yaml mit REDIGIERTEN Hashes (Alt-Hash-Exposure im Git entfernt); Invariante .36==.37 (AGH normalisiert beim Restart) - C: agh-exception.py (allow-domain/unallow/unfilter/refilter/status) gegen beide Instanzen, end-to-end getestet; Contract in adguard/README.md - Stufe 6 (Bypass-Sperre) NICHT geschaltet; kein DHCP-/Firewall-Write Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
3.3 KiB
Markdown
58 lines
3.3 KiB
Markdown
# AdGuard Home — `agh-bf1` (.36) / `agh-bf2` (.37) · TP23 Stufe 2/4/5
|
||
|
||
Das AGH-**Paar** (pve LXC 110/111, `10.40.20.36` / `.37`) ist der Client-Resolver des BF-Netzes
|
||
(DHCP liefert beide in allen 7 VLANs). Upstream: DoH zum CF-Gateway; conditional
|
||
`[/bf.emsenhuber.net/] → 10.40.20.1`. **Kein natives HA** → Sync ist Betriebsaufwand.
|
||
|
||
## Dateien
|
||
| Datei | Zweck |
|
||
|---|---|
|
||
| `AdGuardHome.yaml` | **Repo-SSoT** der Config. **Passwort-Hashes REDIGIERT** (`'<redacted>'`) — keine Secrets im Git. Echte Hashes leben auf den Geräten; Klartext des API-Users in `~/.secrets`. |
|
||
| `agh-sync.py` | `check` (Drift `.36`↔`.37`) · `push` (SSoT auf beide, gestaffelter Restart, reinjiziert Hashes live). |
|
||
| `agh-exception.py` | Exception-Primitive (Stufe 5) gegen **beide** Instanzen. |
|
||
|
||
## Client-Policy (Stufe 4, `clients.persistent`)
|
||
Ein VLAN = eine CIDR-Gruppe. Alle nutzen denselben CF-Upstream-Filter; Divergenz = per-Client-Toggle.
|
||
|
||
| Gruppe | CIDR | filtering | safe_search | parental |
|
||
|---|---|---|---|---|
|
||
| grp-main | 10.40.10.0/24 | an (global) | – | – |
|
||
| grp-infra | 10.40.20.0/24 | **aus** | – | – |
|
||
| grp-iot | 10.40.30.0/24 | an | – | – |
|
||
| grp-media | 10.40.40.0/24 | **aus** | – | – |
|
||
| grp-untrusted | 10.40.50.0/24 | an | – | – |
|
||
| grp-guest | 10.40.90.0/24 | an | **on** | **on** |
|
||
| grp-mgmt | 10.40.99.0/24 | **aus** | – | – |
|
||
| dns-bypass-exempt | 10.40.10.183 + .82 | **aus** | – | – |
|
||
|
||
`filtering aus` bei INFRA/MEDIA/MGMT = bewusste Reduktion (Streaming/Server/Mgmt nicht brechen), per Gruppe rückholbar.
|
||
|
||
## Sync-Invariante
|
||
AGH **schreibt die YAML beim Restart um** (normalisiert) → **nicht** gegen die Repo-Datei diffen,
|
||
sondern **`.36` == `.37`**. Genau das prüft `agh-sync.py check`.
|
||
|
||
## Exception-Contract (Stufe 5 — was die HA-Schicht auslöst)
|
||
Auth: Basic, User `automation` (`~/.secrets` → `AGH_AUTOMATION_*`). **Immer auf `.36` UND `.37`.**
|
||
|
||
🔴 **Wichtig für D:** die beiden AGH-Endpunkte sind **read-modify-write**, kein simples Append —
|
||
`set_rules` **ersetzt die ganze Liste**, `clients/update` braucht das **volle Client-Objekt**.
|
||
Ein zustandsloses HA-`rest_command` reicht deshalb **nicht**; `agh-exception.py` ist die
|
||
Referenz-RMW-Implementierung, die D aufruft (Deploy-Weg auf HAOS in Etappe D zu entscheiden:
|
||
`shell_command`/`command_line` gegen die deployte CLI **oder** ein dünner Wrapper-Endpunkt).
|
||
|
||
| Aktion | CLI | AGH-API (RMW) |
|
||
|---|---|---|
|
||
| Domain global entsperren | `allow-domain <d>` | `GET /control/filtering/status` → +`@@\|\|<d>^` → `POST /control/filtering/set_rules` |
|
||
| Entsperrung zurück | `unallow-domain <d>` | dito, Regel entfernen |
|
||
| Client entfiltern | `unfilter <ip>` | `GET /control/clients` → Objekt, `filtering_enabled=false` → `POST /control/clients/update` |
|
||
| Client wieder filtern | `refilter <ip>` | dito, zurück auf global |
|
||
|
||
**Kein Timing in der CLI** — Ablauf/Revert macht der Aufrufer (HA-Timer) und, ab Stufe 6, der
|
||
RouterOS-Backstop.
|
||
|
||
## RouterOS-Backstop (Stufe 6, noch NICHT gebaut)
|
||
Analog `jit-admin` (`routeros/tp5-etappe4-input-mgmt.rsc`): Address-List `jit-dns-bypass` mit
|
||
`timeout` + Forward-Regel, die dieser Liste 53/853 nach außen erlaubt — der Fail-safe, falls HA
|
||
den Revert verpasst. Gebaut via **Nautobot GC** (kein Direkt-Write), erst wenn die Bypass-Sperre
|
||
scharf geschaltet wird.
|