issues: #0110 — the hardening that only existed on the host

Two write endpoints without authentication were bound to every interface in this
repository and to a private address on the machine. The machine was right. A pull
would have silently undone it, and the only reason it did not is that git refused
over an unrelated local edit.

The ports are fixed. What is not fixed is that nothing compares the working copy
on CFGMON to the repository — it was behind by four commits and locally modified
at the same time, and neither showed anywhere. The firewall rules themselves live
in no repository at all, which makes every statement about that host's exposure a
memory rather than a source.

Measured rather than asserted, and the measurement needed care: from my own
network all three ports look shut, but so does 443, because the firewall drops
that source first. Only from a host the firewall admits does the result mean
anything — there 443 answers and 9090 does not.
This commit is contained in:
Thore Cimbal
2026-08-21 12:00:00 +00:00
parent df06c4cc7c
commit e3958ebe51
2 changed files with 120 additions and 3 deletions
+4 -3
View File
@@ -2,9 +2,9 @@
<!-- Generated by scripts/gen_status.py — do not edit. -->
## Issues (49 open, 54 closed)
## Issues (50 open, 54 closed)
Verteilung: M2 16 · M3 4 · M4 11 · M5 17 · M6 1
Verteilung: M2 16 · M3 4 · M4 11 · M5 18 · M6 1
Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
@@ -54,12 +54,13 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
| [0100](docs/issues/0100-threadnet-web-13-asset-pfade-tragen-weiterhin-element-themes-e.md) | low | open | Asset-Pfade tragen weiterhin "element" (themes/element/…) |
| [0101](docs/issues/0101-threadnet-call-4-kaputtes-paket-0-19-2-threadnet-6-in-der-regi.md) | low | open | Kaputtes Paket 0.19.2-threadnet.6 in der Registry — Herkunft ungeklärt |
### M5 (17)
### M5 (18)
| Issue | Priorität | Status | Title |
|---|---|---|---|
| [0065](docs/issues/0065-gitops-25-k3s-api-security-hardening.md) | high | open | K3s API security hardening |
| [0109](docs/issues/0109-der-weg-vom-commit-ins-cluster-meldet-seinen-stillstand-nicht.md) | high | open | Der Weg vom Commit ins Cluster meldet seinen Stillstand nicht |
| [0110](docs/issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md) | high | open | Härtung lebt auf dem Host, das Repo weiß nichts davon |
| [0058](docs/issues/0058-gitops-14-web-application-firewall-waf.md) | medium | open | Web Application Firewall (WAF) |
| [0059](docs/issues/0059-gitops-16-pod-security-admission-restricted.md) | medium | open | Pod Security Admission (Restricted) |
| [0062](docs/issues/0062-gitops-21-renovate-dependabot-for-chart-and-image-updat.md) | medium | open | Renovate/Dependabot for chart and image updates |
@@ -0,0 +1,116 @@
---
type: issue
id: "0110"
status: open
created: 2026-08-22
milestone: M5
priority: high
area: security
host: cfgmon
related:
- "docs/issues/0108-erlaubnisliste-veraltet-still-wenn-das-chart-die-verdrahtung-ver.md"
- "docs/issues/0109-der-weg-vom-commit-ins-cluster-meldet-seinen-stillstand-nicht.md"
- "docs/aar/2026-08-21-spiegel-ausfall.md"
---
# Härtung lebt auf dem Host, das Repo weiß nichts davon
Der Betriebs-Stack auf CFGMON läuft aus einer Arbeitskopie unter
`/opt/threadnet-operating`. Was dort steht, muss nicht sein, was im Repo steht —
und **nichts vergleicht die beiden**. Eine Änderung von Hand am Host ist damit
unsichtbar, bis jemand zufällig darüber stolpert.
## Der Beinahe-Unfall vom 2026-08-21
Prometheus und Loki nehmen Schreibzugriffe **ohne Authentisierung** an. Im Repo
standen ihre Ports auf `0.0.0.0`:
```yaml
ports:
- "9090:9090" # Prometheus, remote-write-receiver
- "3100:3100" # Loki, Log-Push
- "9100:9100" # node-exporter
```
Bei den Firewall-Arbeiten desselben Tages wurden sie **auf dem Host** an
Adressen gebunden — privater vSwitch für die pushenden Absender, localhost für
den Host selbst. Richtig, wirksam, und **nirgends im Repo**. Der Kommentar
daneben behauptete weiter, die Ports seien öffentlich und nur durch die
Hetzner-Firewall gedeckt.
⚠️ **Ein `git pull` hätte alle drei wieder geöffnet.** Verhindert hat es allein,
dass git den Pull wegen der lokalen Änderung abgebrochen hat:
```
error: Your local changes to the following files would be overwritten by merge:
monitoring/docker-compose.yml
```
Der Zufall, der es gerettet hat, ist keine Kontrolle. Wäre die Datei am Host
sauber gewesen — weil jemand die Änderung „aufgeräumt" oder neu ausgecheckt
hätte —, wären zwei nicht authentisierte Schreib-Endpunkte still wieder
öffentlich geworden, und die Meldung darüber wäre: keine.
Die Bindungen sind am 2026-08-22 ins Repo nachgezogen (`1ce4b55` in
`threadnet-operating`), samt Berichtigung der Kommentare und des Abschnitts
„Offene Punkte / Sicherheit". **Der Einzelfall ist erledigt; der Mechanismus
nicht.**
## Gemessen, nicht behauptet
Von einer Quelle aus, die die Firewall durchlässt (Matrix-Host):
| Ziel | Ergebnis |
|---|---|
| `188.245.193.243:443` (öffentlich) | **offen** — die Quelle ist nicht pauschal gesperrt |
| `188.245.193.243:9090` | dicht |
| `188.245.193.243:3100` | dicht |
| `10.0.0.3:9090` (vSwitch) | **offen** |
⚠️ Vom Arbeitsplatz aus war **auch 443 dicht** — von dort lässt sich die Frage
gar nicht beantworten, weil die Firewall die Quelle schon abweist. Eine Messung
„von außen" ist nur dann eine Aussage über die Bindung, wenn dieselbe Quelle
etwas anderes am selben Host erreicht.
## Was zu tun ist
Der Befund ist derselbe wie in
[#0108](0108-erlaubnisliste-veraltet-still-wenn-das-chart-die-verdrahtung-ver.md)
und [#0109](0109-der-weg-vom-commit-ins-cluster-meldet-seinen-stillstand-nicht.md):
Ein Zustand weicht ab, und niemand erfährt es. Hier ist die Abweichung
besonders billig zu erkennen, weil beide Seiten dieselbe Datei sind.
1. **Ein Abgleich zwischen Arbeitskopie und Repo**, der sich meldet, wenn sie
auseinanderlaufen — lokale Änderungen ebenso wie ein Stand, der Commits
hinterherhinkt. Am 2026-08-22 waren es **beide gleichzeitig**: `59c75c8`
statt `422b651` **und** eine geänderte Datei.
2. **Die Firewall-Regeln selbst gehören unter Versionskontrolle.** ufw und
iptables auf CFGMON stehen in **keinem** Repo. Solange das so ist, ist jede
Aussage über die Abschottung eine Erinnerung, keine Quelle.
⚠️ **Punkt 2 ist der größere und gehört zuerst zugeschnitten.** Ob das
Ansible-Rollen werden, eine exportierte Regelliste mit Vergleich oder etwas
Drittes, entscheidet das Design-Gate — nicht dieses Issue.
## Abnahmekriterien
1. Eine Arbeitskopie, die vom Repo abweicht, führt binnen **24 h** zu einer
Meldung — mit der Angabe, **wie** sie abweicht (Rückstand, lokale Änderung
oder beides).
2. Die Prüfung wird **rot vorgeführt**: eine Datei am Host ändern, Meldung
erscheint, zurücknehmen, Meldung geht weg.
3. ⚠️ Ein Abgleich, der den Host **nicht erreichen** konnte, meldet einen
**Fehler** — nicht „keine Abweichung". Sonst sieht ein blinder Prüfer aus
wie ein sauberer Stand
([meldet-erfolg-ist-aber-blind](../wiki/stolpersteine/meldet-erfolg-ist-aber-blind.md)).
4. Die Bindungen von `9090`, `3100`, `9100` sind aus einer **zugelassenen
Quelle** geprüft, nicht aus einem Netz, das die Firewall ohnehin abweist.
## Nicht Teil davon
- **Die Ports selbst** — erledigt in `1ce4b55`, hier nur noch als Beleg.
- **Der k3s-Cluster.** Dort ist Flux der Abgleich; das Problem hat genau die
Hosts, die *keinen* haben.
- **Zugangsdaten und Schlüssel.** Was verschlüsselt ins Repo gehört, ist eine
eigene Frage (#0015-Linie), nicht diese.
- Das Homelab und `game-operating`.