TP49 widerlegt und geschlossen — kein Fix, Doku korrigiert

Christoph hat die Praemisse am 2026-10-06 selbst widerlegt: testus@emsenhuber.com
wird von CF Access abgelehnt. Die E-Mail-Bindung der Policy gilt, login_method
hebelt sie nicht aus. Es gab nie eine offene Tuer.

Der Fehler war ein Fehlschluss, kein Raten: Doku-Semantik zu login_method
("welche Methode wurde benutzt") 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 "GitHub
allein genuegt", und das stand als Tatsache in der Akte (Fund 2026-07-10).

Belegt: kein IdP traegt eine Domain-Bindung (github/google/onetimepin alle nur
client_id + redirect_url, live per GET .../identity_providers). Die Einschraenkung
kann also nur aus der Policy kommen — und sie greift nachweislich.

Grenze der Aussage: der GitHub-Pfad selbst wurde nicht gemessen, nur geschlossen.

Korrigiert: teilprojekte.md TP49 (Herkunft des Fehlers mitgenannt), cf-tunnel-
mapping.md Paragraf 10 (Ursprungsfund widerlegt, nicht geloescht), Startauftrag
als "NICHT AUSFUEHREN" markiert. Kein Schreibzugriff auf die Terpenfinder-Policy;
blauebluethen-Projektgrenze gewahrt.

Erhalten bleiben nur die Gotchas: 32-Hex-App-IDs, cloudflare-MCP ist read-only
(Write-Probe no-op-PUT -> 1010), Reusable Policy nur per App-PUT detachbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 07:37:46 +02:00
parent 81cd7bfb7e
commit 4b307315f0
3 changed files with 108 additions and 90 deletions

View File

@@ -1,84 +1,61 @@
# Startauftrag — TP49: CF-Access `login_method`-Include entfernen
# Startauftrag — TP49: CF-Access `login_method`-Include entfernen ❌ NICHT AUSFÜHREN — gegenstandslos
> **Für eine frische Session.** Gitea **#76**, Prosa in `docs/teilprojekte.md` → `### TP49`.
> Angelegt 2026-10-06 auf Christoph-Direktive („absolute prio").
> **Geschlossen am 2026-10-06.** Gitea #76, Prosa in `docs/teilprojekte.md` → `### TP49`.
>
> 🔴 **Dieser Auftrag ist ungültig. Er basiert auf einer falschen Prämisse, die am 2026-10-06
> widerlegt wurde. Nicht ausführen.** Die Datei bleibt als Beleg stehen, damit die Prämisse
> nicht in einer künftigen Session wieder als Auftrag auftaucht.
## Der Auftrag in einem Satz
## Warum gegenstandslos
Entferne `login_method:github` aus der Policy `christoph` der CF-Access-App
`420.teilzeitladen.xyz` — **nach** Rücksprache mit Christoph, wen der Zugang treffen soll.
Der Auftrag verlangte, `login_method:github` aus der Policy `christoph` der App
`420.teilzeitladen.xyz` zu entfernen, weil **„ein beliebiger GitHub-Account"** hineinkäme.
## Lage (live geprüft 2026-10-06, nicht geraten)
**Das ist falsch.** Christoph hat am 2026-10-06 mit `testus@emsenhuber.com` getestet:
die Adresse wurde **abgelehnt**. Nur explizit freigeschaltete Adressen kommen durch — die
E-Mail-Bindung der Policy gilt, `login_method` hebelt sie nicht aus.
Der Ursprungsfund von 2026-07-10 war **größer beschrieben als er ist**. Nachprüfung:
## Wie der Fehler entstand
| App | Status |
|---|---|
| `*.emsenhuber.net` (intern: hass/grafana/portainer/pve) | ✅ **sauber** — TP41 hat auf Groups umgestellt (E-Mail/IP/service_token) |
| `420.teilzeitladen.xyz` (öffentlich) | 🔴 **offen** — `login_method:github` in Policy `christoph` |
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 als Tatsache in Auftrag und Prosa-Abschnitt.
`onetimepin` ist **kein** Problem — das ist der E-Mail-Einmalcode an die eingetragene Adresse.
Scharf ist ausschließlich **`github`**.
## Belegte Gegenlage (live geprüft 2026-10-06)
## Konkrete Daten
| 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` |
```
Account-ID : siehe mcp/cloudflare/.env (CF_ACCOUNT_ID)
Token : CF_API_TOKEN (aktiv, lesen+schreiben, verifiziert 2026-10-06)
App : 420.teilzeitladen.xyz → volle ID per GET .../access/apps holen
Policy : "christoph"
Entfernen : include {"login_method":{"id":"72c1291b-a38d-4bc7-af97-5dee04a4f84a"}} (type=github)
Behalten : include {"login_method":{"id":"9024c7a6-2d1f-4432-9f48-51593acd1361"}} (type=onetimepin)
```
**Kein** IdP trägt eine Domain-/Tenant-Bindung (`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.
## 🔴 ZUERST: MCP-Verfügbarkeit prüfen — und anhalten, wenn er fehlt
⚠️ **Grenze:** der GitHub-Pfad wurde **nicht** separat gemessen. Die Aussage ist
„Google→GitHub geschlossen", nicht „GitHub getestet". Das ist der einzige Grund, den Eintrag
nicht als bewiesen sauber zu führen — **kein** Grund für eine Änderung.
Christoph-Direktive für diese Session: **zu Sessionbeginn prüfen, ob der Cloudflare-MCP läuft.
Wenn nicht: anhalten und melden, nicht improvisieren.**
## Ergebnis
Der MCP ist in `~/.claude/settings.json` aktiviert (`enabledMcpjsonServers`) und in `.mcp.json`
definiert als **Remote-Server** `https://mcp.cloudflare.com/mcp` (OAuth-Login, nicht der lokale
`.env`-Token). Prüfschritt:
**Kein Schreibzugriff auf die Terpenfinder-Policy ist erfolgt.** `420.teilzeitladen.xyz`
gehört zum Projekt **blaueblüten**; es wurde nichts angefasst.
```
ToolSearch("cloudflare access apps") → erscheinen mcp__cloudflare__* Tools?
```
## Was aus diesem TP erhalten bleibt
**Wenn nein:** stoppen, dem User melden. Nicht auf `curl` ausweichen, ohne das zu sagen —
der Wechsel ist eine Entscheidung, keine Nebensache.
Nur die **Gotchas** — sie sind unabhängig vom widerlegten Fund und live bestätigt:
### ⚠️ Der MCP ist READ-ONLY — er kann den Fix nicht ausführen
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 (`policies:[{id,precedence}]`),
nicht per `/policies`-DELETE.
`docs/cf-tunnel-mapping.md:321`: der `cloudflare`-MCP (OAuth) ist **read-only**; ein
Create/Write-Versuch endet mit `10000 Authentication error`. **Der gesamte Bestandsaufnahme-Teil
(Schritte 1–2) läuft über den MCP. Die Änderung (Schritt 3) braucht `curl` + `CF_API_TOKEN`.**
Diese Trennung nicht verwischen — sonst sucht die Session den Fehler an der falschen Stelle.
## Lehre
## 🔴 Gotchas — sonst läuft die Session in bekannte Fallen
1. **App-IDs sind 32 Hex.** Die Kurzform `16aaec78` liefert `12045 invalid_application_id`.
Volle ID zuerst per `GET /accounts/{id}/access/apps` holen.
2. **Writes nur via `CF_API_TOKEN`/curl.** Der `cloudflare`-MCP (OAuth) ist **read-only**.
Muster: `cd mcp/cloudflare && set -a; . ./.env; set +a` → dann `curl -H "Authorization: Bearer $CF_API_TOKEN"`.
🔴 Token **nie** ausgeben; im Output maskieren.
3. **Reusable Policy nur per App-PUT detachbar** (`policies:[{id,precedence}]`), **nicht** via
`/policies`-DELETE („can not delete reusable policies"). Policy-`precedence` muss eindeutig sein.
4. **Projektgrenze:** `420.teilzeitladen.xyz` gehört zu **blaueblüten**. Änderung nur nach
ausdrücklicher Freigabe — nicht „mal eben" mitnehmen.
## Ablauf
1. **Bestandsaufnahme** (read-only): Policies der App lesen, Ist-Zustand protokollieren.
2. **Rücksprache:** Wen soll der Zugang treffen? Ohne diese Antwort nicht ändern —
eine Aussperrung wäre der teurere Fehler (Christoph-Entscheid 2026-07-10, „user-gated").
3. **Änderung:** `login_method:github` aus dem Include entfernen, `onetimepin` behalten.
4. **Abnahme:** Policy neu lesen und zeigen, dass nur noch `onetimepin` + die E-Mail-Includes
drinstehen. **Nicht** dem API-`success` glauben — die Policy zurücklesen.
Dann: kommt `christoph`/`geli` über die E-Mail weiterhin hinein?
5. **Abschluss:** Gitea #76 `closed` + `status:done`, Prosa-Abschnitt finalisieren.
## Wenn die Änderung sich als unnötig erweist
Falls Christoph entscheidet, dass der GitHub-Login beim Terpenfinder bleiben soll (etwa weil
die App ohnehin öffentlich ist): dann ist TP49 **`status:dropped`** — mit der Begründung im Issue,
damit der Fund nicht wieder als „offen" in einer Memory auftaucht. Auch das ist ein gültiges Ende.
**Eine Sicherheitsaussage über fremde Infrastruktur braucht einen Test, nicht eine Ableitung.**
Der Befund stand fünf Tage (2026-07-10 → 2026-10-06) als „🔴 ABSOLUTE PRIORITÄT" in der Akte,
gestützt allein auf einen Lese-Schluss. Der Test dauerte zwei Minuten.