TP49 — CF-Access: login_method:github im include der Terpenfinder-Policy — ✅ behoben (require statt include) #76

Closed
opened 2026-10-06 06:46:56 +02:00 by admin · 3 comments
Owner

Steuerungs-SSoT: Index/Status hier in Gitea; Prosa/Detail im Repo unter docs/teilprojekte.md (Abschnitt TP49).

  • Status: 🔴 (status:todo) — ABSOLUTE PRIORITÄT
  • Abschluss: —
  • Angelegt 2026-10-06 (Christoph-Direktive). Befund am 2026-10-06 live nachgeprüft — er ist kleiner als der Ursprungsfund, siehe unten.

⚠️ Korrigierte Lage (live geprüft 2026-10-06)

Der Ursprungsfund (2026-07-10) beschrieb einen login_method-Include am internen Wildcard
*.emsenhuber.net. Dieser Teil ist behoben — TP41 hat den Wildcard auf Access-Groups umgestellt:

Policy am Wildcard 16aaec78 decision Bindung
bf-users allow Group zt-humans = drei einzelne E-Mail-Adressen
bf4 non_identity Group zt-home = ip:90.146.33.177/32
claude-mcp non_identity Group zt-automation = service_token

✅ Kein login_method mehr an der kritischen Infrastruktur (hass, grafana, portainer, pve).

🔴 Was offen ist — der einzige echte Fund

Sweep über alle 9 Access-Apps ergab eine App mit login_method-Includes:
420.teilzeitladen.xyz (Terpenfinder, öffentlich), Policies christoph und geli.

IdP-ID Typ Bewertung
72c1291b-a38d-4bc7-af97-5dee04a4f84a github 🔴 jeder GitHub-Account kommt durch
9024c7a6-2d1f-4432-9f48-51593acd1361 onetimepin ✅ unkritisch — E-Mail-Einmalcode an die eingetragene Adresse

Scharf ist nur login_method:github in Policy christoph auf 420.teilzeitladen.xyz.

Auswirkung: Der Terpenfinder ist eine öffentliche App (kein Teil der internen Infrastruktur).
Ein beliebiger GitHub-Account sieht ihn. Kein Zugriff auf hass/pve/portainer — der Schaden
ist Begrenztheit, nicht Kompromittierung der Infrastruktur. Aber: die App liegt auf einer
öffentlichen Domain und war als „nur für uns" gedacht.

Fix

login_method:github aus dem Include entfernen — die onetimepin-Einträge können bleiben
(sie sind der gewünschte E-Mail-Login). Danach prüfen, dass christoph und geli weiterhin
über ihre E-Mail-Adressen hineinkommen.

⚠️ Vorher abstimmen, wer Zugang braucht — Christoph-Entscheid von 2026-07-10 („user-gated").
Eine Aussperrung wäre der teurere Fehler.

Gotchas (live bestätigt, spart Suchzeit)

  • 🔴 Access-App-IDs sind 32 Hex — die im Fund notierte Kurzform 16aaec78 liefert
    12045 invalid_application_id. Volle ID erst per GET /accounts/{id}/access/apps holen.
    (Dieselbe Falle wie „truncated Record-ID" bei DNS.)
  • Writes nur via CF_API_TOKEN/curl; der cloudflare-MCP (OAuth) ist read-only.
    CF_API_TOKEN ist am 2026-10-06 als active verifiziert (lesen + schreiben).
    Account-ID/Token in mcp/cloudflare/.env.
  • Reusable Policy nur per App-PUT (policies:[{id,precedence}]) detachbar — nicht via
    /policies-DELETE. Policy-precedence muss eindeutig sein.

Abgrenzung

Nicht TP41 (abgeschlossen — hat genau diesen Wildcard bereits saniert).
Nicht TP44 (Dokumentation). Verwandt: TP46 (#72), TP34.2 (#73).
⚠️ 420.teilzeitladen.xyz gehört zum Projekt blaueblüten — Änderung dort nur nach Absprache
mit Christoph (Projektgrenze).

Prosa/Detail: docs/teilprojekte.md → ### TP49.

Steuerungs-SSoT: Index/Status hier in Gitea; **Prosa/Detail** im Repo unter `docs/teilprojekte.md` (Abschnitt `TP49`). - Status: 🔴 (status:todo) — **ABSOLUTE PRIORITÄT** - Abschluss: — - Angelegt 2026-10-06 (Christoph-Direktive). **Befund am 2026-10-06 live nachgeprüft — er ist kleiner als der Ursprungsfund, siehe unten.** ## ⚠️ Korrigierte Lage (live geprüft 2026-10-06) Der Ursprungsfund (2026-07-10) beschrieb einen `login_method`-Include am **internen** Wildcard `*.emsenhuber.net`. **Dieser Teil ist behoben** — TP41 hat den Wildcard auf Access-Groups umgestellt: | Policy am Wildcard `16aaec78` | decision | Bindung | |---|---|---| | `bf-users` | allow | Group `zt-humans` = drei einzelne E-Mail-Adressen | | `bf4` | non_identity | Group `zt-home` = `ip:90.146.33.177/32` | | `claude-mcp` | non_identity | Group `zt-automation` = service_token | ✅ **Kein `login_method` mehr an der kritischen Infrastruktur** (`hass`, `grafana`, `portainer`, `pve`). ## 🔴 Was offen ist — der einzige echte Fund Sweep über alle 9 Access-Apps ergab **eine** App mit `login_method`-Includes: **`420.teilzeitladen.xyz`** (Terpenfinder, öffentlich), Policies `christoph` und `geli`. | IdP-ID | Typ | Bewertung | |---|---|---| | `72c1291b-a38d-4bc7-af97-5dee04a4f84a` | **github** | 🔴 **jeder GitHub-Account kommt durch** | | `9024c7a6-2d1f-4432-9f48-51593acd1361` | onetimepin | ✅ unkritisch — E-Mail-Einmalcode an die eingetragene Adresse | **Scharf ist nur `login_method:github`** in Policy `christoph` auf `420.teilzeitladen.xyz`. **Auswirkung:** Der Terpenfinder ist eine öffentliche App (kein Teil der internen Infrastruktur). Ein beliebiger GitHub-Account sieht ihn. Kein Zugriff auf `hass`/`pve`/`portainer` — der Schaden ist Begrenztheit, nicht Kompromittierung der Infrastruktur. **Aber:** die App liegt auf einer öffentlichen Domain und war als „nur für uns" gedacht. ## Fix `login_method:github` aus dem Include entfernen — die `onetimepin`-Einträge können bleiben (sie sind der gewünschte E-Mail-Login). Danach prüfen, dass `christoph` und `geli` weiterhin über ihre E-Mail-Adressen hineinkommen. ⚠️ **Vorher abstimmen**, wer Zugang braucht — Christoph-Entscheid von 2026-07-10 („user-gated"). Eine Aussperrung wäre der teurere Fehler. ## Gotchas (live bestätigt, spart Suchzeit) - 🔴 **Access-App-IDs sind 32 Hex** — die im Fund notierte Kurzform `16aaec78` liefert `12045 invalid_application_id`. Volle ID erst per `GET /accounts/{id}/access/apps` holen. (Dieselbe Falle wie „truncated Record-ID" bei DNS.) - Writes nur via `CF_API_TOKEN`/curl; der `cloudflare`-MCP (OAuth) ist **read-only**. `CF_API_TOKEN` ist am 2026-10-06 als **`active`** verifiziert (lesen + schreiben). Account-ID/Token in `mcp/cloudflare/.env`. - Reusable Policy nur per **App-PUT** (`policies:[{id,precedence}]`) detachbar — **nicht** via `/policies`-DELETE. Policy-`precedence` muss eindeutig sein. ## Abgrenzung **Nicht** TP41 (abgeschlossen — hat genau diesen Wildcard bereits saniert). **Nicht** TP44 (Dokumentation). Verwandt: TP46 (#72), TP34.2 (#73). ⚠️ `420.teilzeitladen.xyz` gehört zum Projekt **blaueblüten** — Änderung dort nur nach Absprache mit Christoph (Projektgrenze). Prosa/Detail: `docs/teilprojekte.md` → `### TP49`.
admin added the status:todothema:cloudflare-proxy labels 2026-10-06 06:46:56 +02:00
Author
Owner

❌ WIDERLEGT am 2026-10-06 — kein Handlungsbedarf. Geschlossen.

Der Befund war falsch

Der Titel („öffnet alle internen Dienste für jeden GitHub/Google-User") und der Body dieses
Issues behaupteten, login_method:github im include der Policy christoph lasse jeden
GitHub-Account durch. Das stimmt nicht.

Gegenbeweis (Christoph, live getestet 2026-10-06): testus@emsenhuber.com wird
abgelehnt. Nur explizit freigeschaltete Adressen kommen durch — die E-Mail-Bindung der
Policy gilt, login_method hebelt sie nicht aus.

Wie der Fehler entstand

Die Doku-Aussage zu login_method („asks which identity service was used for authentication")
wurde so gelesen, als ersetze der Include die danebenstehende email-Zeile. include ist
ein OR — die Zeilen sind Alternativen, nicht Bedingungen. Aus „GitHub ist eine Alternative
zur E-Mail" wurde fälschlich „GitHub allein genügt". Belegt war das nie.

Es stand trotzdem fünf Tage als „🔴 ABSOLUTE PRIORITÄT" in der Akte (Fund 2026-07-10 → heute),
gestützt allein auf einen Lese-Schluss. Der Test dauerte zwei Minuten.

Belegte Gegenlage

IdP Typ config
72c1291b… github client_id, redirect_url — kein Domain-Filter
c7571880… google client_id, redirect_url — kein Domain-Filter
9024c7a6… onetimepin redirect_url

Kein IdP trägt eine Domain-/Tenant-Bindung (live: GET /accounts/{id}/access/identity_providers).
Die Einschränkung kann also nur aus der Policy kommen — und sie greift nachweislich.
Google ist auf GitHub übertragbar, weil beide IdPs konfigurationsgleich sind.

⚠️ Grenze: der GitHub-Pfad selbst wurde nicht separat gemessen. Die Aussage ist
„Google→GitHub geschlossen", nicht „GitHub getestet" — deshalb ungetestet, nicht bewiesen sauber.
Das ist aber kein Grund für eine Änderung.

Ergebnis

Kein Schreibzugriff auf die Terpenfinder-Policy ist erfolgt. 420.teilzeitladen.xyz gehört
zum Projekt blaueblüten — es wurde nichts angefasst.

Was erhalten bleibt

Nur die Gotchas (unabhängig vom widerlegten Fund, live bestätigt):

  1. Access-App-IDs sind 32 Hex — Kurzform 16aaec78 → 12045 invalid_application_id.
  2. 🔴 Der cloudflare-MCP ist strikt read-only. Write-Probe 2026-10-06: no-op-PUT
    (byte-identischer Body) → 1010: undefined. Writes nur via CF_API_TOKEN/curl.
  3. Reusable Policy nur per App-PUT detachbar, nicht per /policies-DELETE.

✅ Unberührt gültig: TP41 hat den internen Wildcard *.emsenhuber.net auf Access-Groups
(zt-humans/zt-home/zt-automation) umgestellt — dort steht heute kein login_method mehr.

Prosa korrigiert in docs/teilprojekte.md → ### TP49 (und docs/cf-tunnel-mapping.md §10,
wo der Ursprungsfund stand).

❌ **WIDERLEGT am 2026-10-06 — kein Handlungsbedarf. Geschlossen.** ## Der Befund war falsch Der Titel („öffnet alle internen Dienste für jeden GitHub/Google-User") und der Body dieses Issues behaupteten, `login_method:github` im `include` der Policy `christoph` lasse **jeden** GitHub-Account durch. **Das stimmt nicht.** **Gegenbeweis (Christoph, live getestet 2026-10-06):** `testus@emsenhuber.com` wird **abgelehnt**. Nur explizit freigeschaltete Adressen kommen durch — die E-Mail-Bindung der Policy gilt, `login_method` hebelt sie nicht aus. ## Wie der Fehler entstand Die Doku-Aussage zu `login_method` („asks which identity service was used for authentication") wurde so gelesen, als **ersetze** der Include die danebenstehende `email`-Zeile. `include` ist ein **OR** — die Zeilen sind Alternativen, **nicht** Bedingungen. Aus „GitHub ist eine Alternative zur E-Mail" wurde fälschlich „GitHub allein genügt". **Belegt war das nie.** Es stand trotzdem fünf Tage als „🔴 ABSOLUTE PRIORITÄT" in der Akte (Fund 2026-07-10 → heute), gestützt allein auf einen Lese-Schluss. Der Test dauerte zwei Minuten. ## Belegte Gegenlage | IdP | Typ | `config` | |---|---|---| | `72c1291b…` | github | `client_id`, `redirect_url` — **kein** Domain-Filter | | `c7571880…` | google | `client_id`, `redirect_url` — **kein** Domain-Filter | | `9024c7a6…` | onetimepin | `redirect_url` | **Kein** IdP trägt eine Domain-/Tenant-Bindung (live: `GET /accounts/{id}/access/identity_providers`). Die Einschränkung kann also **nur** aus der Policy kommen — und sie greift nachweislich. Google ist auf GitHub übertragbar, weil beide IdPs konfigurationsgleich sind. ⚠️ **Grenze:** der GitHub-Pfad selbst wurde **nicht** separat gemessen. Die Aussage ist „Google→GitHub geschlossen", nicht „GitHub getestet" — deshalb ungetestet, **nicht** bewiesen sauber. Das ist aber kein Grund für eine Änderung. ## Ergebnis **Kein Schreibzugriff auf die Terpenfinder-Policy ist erfolgt.** `420.teilzeitladen.xyz` gehört zum Projekt **blaueblüten** — es wurde nichts angefasst. ## Was erhalten bleibt Nur die **Gotchas** (unabhängig vom widerlegten Fund, live bestätigt): 1. **Access-App-IDs sind 32 Hex** — Kurzform `16aaec78` → `12045 invalid_application_id`. 2. 🔴 **Der `cloudflare`-MCP ist strikt read-only.** Write-Probe 2026-10-06: no-op-PUT (byte-identischer Body) → **`1010: undefined`**. Writes nur via `CF_API_TOKEN`/curl. 3. **Reusable Policy** nur per **App-PUT** detachbar, nicht per `/policies`-DELETE. ✅ **Unberührt gültig:** TP41 hat den internen Wildcard `*.emsenhuber.net` auf Access-Groups (`zt-humans`/`zt-home`/`zt-automation`) umgestellt — dort steht heute kein `login_method` mehr. **Prosa korrigiert in** `docs/teilprojekte.md` → `### TP49` (und `docs/cf-tunnel-mapping.md` §10, wo der Ursprungsfund stand).
admin changed title from TP49 — CF-Access: Wildcard-Policy öffnet alle internen Dienste für jeden GitHub/Google-User to TP49 — CF-Access: `login_method`-Includes auf Policy-Ebene — ❌ widerlegt, kein Handlungsbedarf 2026-10-06 07:31:39 +02:00
admin closed this issue 2026-10-06 07:31:39 +02:00
admin added status:dropped and removed status:todo labels 2026-10-06 07:31:43 +02:00
Author
Owner

✅ BEHOBEN am 2026-10-06 — der Befund war echt.

Was passiert ist

Policy christoph (reusable 8e44f5d1…) auf App Terpenfinder v3 (e6a7991f…,
420.teilzeitladen.xyz): login_method:github von include nach require verschoben
⇒ email AND github.

vorher jetzt
include email · github · onetimepin email · onetimepin
require — github

Gesetzt via PUT /accounts/{id}/access/policies/{policy_id}, zurückgelesen über beide
Endpunkte (App-Pfad + reusable) — identisch. Dem success:true wurde nicht geglaubt.

Sweep über alle Apps (login_method in include/require/exclude): genau zwei Treffer, beide in
Terpenfinder v3 — christoph (github+onetimepin) und geli (nur onetimepin = harmlos).
Interne Apps + Wildcard: sauber (TP41).

⚠️ Korrektur am eigenen Kommentar von heute Vormittag

Dieses Issue war zwischenzeitlich als Phantom geschlossen und auf status:dropped gesetzt.
Das war falsch. Der Schluss stützte sich auf einen Google-Test (testus@emsenhuber.com
→ abgelehnt) und übertrug ihn ungeprüft auf GitHub. Der Google-Test zeigt nur Googles Verhalten;
die IdP-Configs sind konfigurationsgleich, das unterscheidende Feld steht nicht in der Config.

Christoph hat mit einem zweiten GitHub-Account getestet — er kam durch. Damit war der
Ursprungsfund bestätigt. Der Kommentar von heute Vormittag ist damit überholt.

Zur ursprünglichen Absicht

Die Berechtigung sollte an den GitHub-Username gekoppelt werden. Das gibt Access nicht her:
login_method prüft die Methode, nicht den Nutzer; einen Username-Selector gibt es nicht.
Der einzige GitHub-bezogene Identitäts-Selector ist Identity provider group — der braucht
SCIM, und am hiesigen GitHub-IdP ist scim_config.enabled = false
(GET …/scim/groups → 500 (12158)). ⇒ email AND github ist die vollständige Umsetzung
des hier Möglichen. Eine echte Org-Kopplung bräuchte SCIM aktiviert — eigener TP.

Gotchas (neu)

  • 🔴 Reusable Policies ändern geht NICHT über den App-Pfad: PUT …/apps/{app}/policies/{pol}
    → 12130. Korrekt ist PUT …/access/policies/{policy_id}.
  • 🔴 Der cloudflare-MCP ist strikt read-only — Write-Probe (no-op-PUT) → 1010.
  • 🔴 App-IDs sind 32 Hex — Kurzform 16aaec78 → 12045.

Offen

Bestätigungstest: dass ein fremder GitHub-Account jetzt abgewiesen wird.
Bis dahin ist der Fix gesetzt und zurückgelesen, aber nicht durch einen Login bewiesen.

Prosa korrigiert in docs/teilprojekte.md → ### TP49 und docs/cf-tunnel-mapping.md §10.

✅ **BEHOBEN am 2026-10-06 — der Befund war echt.** ## Was passiert ist Policy `christoph` (reusable `8e44f5d1…`) auf App `Terpenfinder v3` (`e6a7991f…`, `420.teilzeitladen.xyz`): `login_method:github` von **`include`** nach **`require`** verschoben ⇒ **`email AND github`**. | | vorher | jetzt | |---|---|---| | `include` | email · **github** · onetimepin | email · onetimepin | | `require` | — | **github** | Gesetzt via `PUT /accounts/{id}/access/policies/{policy_id}`, **zurückgelesen** über beide Endpunkte (App-Pfad + reusable) — identisch. Dem `success:true` wurde nicht geglaubt. **Sweep über alle Apps** (`login_method` in include/require/exclude): genau zwei Treffer, beide in `Terpenfinder v3` — `christoph` (github+onetimepin) und `geli` (nur onetimepin = harmlos). Interne Apps + Wildcard: sauber (TP41). ## ⚠️ Korrektur am eigenen Kommentar von heute Vormittag Dieses Issue war zwischenzeitlich als **Phantom geschlossen** und auf `status:dropped` gesetzt. **Das war falsch.** Der Schluss stützte sich auf einen **Google**-Test (`testus@emsenhuber.com` → abgelehnt) und übertrug ihn ungeprüft auf GitHub. Der Google-Test zeigt nur Googles Verhalten; die IdP-Configs sind konfigurationsgleich, das unterscheidende Feld steht nicht in der Config. Christoph hat mit einem **zweiten GitHub-Account** getestet — **er kam durch.** Damit war der Ursprungsfund bestätigt. Der Kommentar von heute Vormittag ist damit überholt. ## Zur ursprünglichen Absicht Die Berechtigung sollte an den **GitHub-Username** gekoppelt werden. **Das gibt Access nicht her:** `login_method` prüft die *Methode*, nicht den Nutzer; einen Username-Selector gibt es nicht. Der einzige GitHub-bezogene Identitäts-Selector ist *Identity provider group* — der braucht **SCIM**, und am hiesigen GitHub-IdP ist `scim_config.enabled = false` (`GET …/scim/groups` → `500 (12158)`). ⇒ `email AND github` ist die **vollständige** Umsetzung des hier Möglichen. Eine echte Org-Kopplung bräuchte SCIM aktiviert — eigener TP. ## Gotchas (neu) - 🔴 **Reusable Policies ändern geht NICHT über den App-Pfad:** `PUT …/apps/{app}/policies/{pol}` → **`12130`**. Korrekt ist `PUT …/access/policies/{policy_id}`. - 🔴 **Der `cloudflare`-MCP ist strikt read-only** — Write-Probe (no-op-PUT) → `1010`. - 🔴 **App-IDs sind 32 Hex** — Kurzform `16aaec78` → `12045`. ## Offen **Bestätigungstest:** dass ein fremder GitHub-Account jetzt **abgewiesen** wird. Bis dahin ist der Fix gesetzt und zurückgelesen, aber nicht durch einen Login bewiesen. Prosa korrigiert in `docs/teilprojekte.md` → `### TP49` und `docs/cf-tunnel-mapping.md` §10.
admin added status:done and removed status:dropped labels 2026-10-06 08:04:05 +02:00
admin changed title from TP49 — CF-Access: `login_method`-Includes auf Policy-Ebene — ❌ widerlegt, kein Handlungsbedarf to TP49 — CF-Access: `login_method:github` im include der Terpenfinder-Policy — ✅ behoben (require statt include) 2026-10-06 08:04:05 +02:00
Author
Owner

✅ ABNAHME BESTANDEN — verhaltensbestätigt durch echten Login (2026-10-06).

Christoph hat nach dem Fix alle Auth-Pfade neu getestet:

Test Ergebnis
Fremder GitHub-Account (2. Konto, fremde Adresse) ✅ wird abgewiesen
Eigener Zugang via GitHub (christoph@emsenhuber.com) ✅ funktioniert
Geli (Einmalcode/IP, unverändert) ✅ funktioniert
Übrige Auth-Wege ✅ wie erwartet

Damit ist email AND github verhaltensbestätigt — es trennt das eigene Konto vom fremden,
ohne jemanden auszusperren. Kein Regress an den Nachbar-Policies (geli, terpene-svc),
kein Kollateral am internen Wildcard.

Der Fix war bis hierhin nur gesetzt und zurückgelesen (API-Ebene). Der zweite Test mit einem
fremden GitHub-Account war nötig — die API sagt nichts darüber, ob die Regel greift.
Er greift.


Status: closed / status:done. Kein offener Punkt.

Prosa final: docs/teilprojekte.md → ### TP49. Der Umweg (Fehlschluss → Schließung →
Wiedereröffnung → Fix → Abnahme) bleibt dort als Aktenhistorie dokumentiert.

✅ **ABNAHME BESTANDEN — verhaltensbestätigt durch echten Login (2026-10-06).** Christoph hat nach dem Fix **alle Auth-Pfade neu getestet**: | Test | Ergebnis | |---|---| | Fremder GitHub-Account (2. Konto, fremde Adresse) | ✅ **wird abgewiesen** | | Eigener Zugang via GitHub (`christoph@emsenhuber.com`) | ✅ funktioniert | | Geli (Einmalcode/IP, unverändert) | ✅ funktioniert | | Übrige Auth-Wege | ✅ wie erwartet | **Damit ist `email AND github` verhaltensbestätigt** — es trennt das eigene Konto vom fremden, ohne jemanden auszusperren. Kein Regress an den Nachbar-Policies (`geli`, `terpene-svc`), kein Kollateral am internen Wildcard. Der Fix war bis hierhin nur *gesetzt und zurückgelesen* (API-Ebene). Der zweite Test mit einem fremden GitHub-Account war nötig — die API sagt nichts darüber, ob die Regel **greift**. Er greift. --- **Status: `closed` / `status:done`.** Kein offener Punkt. Prosa final: `docs/teilprojekte.md` → `### TP49`. Der Umweg (Fehlschluss → Schließung → Wiedereröffnung → Fix → Abnahme) bleibt dort als Aktenhistorie dokumentiert.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/bf-infra#76