13 KiB
Handoff 2026-09-01 — TP41 CF-Access-Reparatur + Zero-Trust-Konsolidierung
Branch
tp41-cf-access-repair. Alle CF-Änderungen sind live via API gemacht (SchreibpfadCF_API_TOKEN+ curl, cf-tunnel-mapping.md §11). Working-Tree:docs/cf-backup/tp41-20260901/(Snapshots, secret-frei) + dieser Handoff +teilprojekte.md-Eintrag;mcp/cloudflare/.env(gitignored) wurde geändert (Token-Konsolidierung). Helper-Skripte lagen im Scratchpad//tmp(cf_session.py,cf_harden.py,cf_groups.py,cf_vwadmin.py,cf_carveout.py,t4a.py).
Auslöser
Zugriff auf CF-geschützte Apps zwang Christoph und Geli faktisch täglich zum E-Mail-OTP-Login,
obwohl 30 Tage gelten sollten; föderierte Logins (GitHub/Google) „funktionieren nicht". Root-Causes:
(1) Team-Domain-Rename bf4 → emsenhuber ⇒ Provider-OAuth-Apps kennen die neue Callback-URL nicht;
(2) App-Session 24h; (3) diverse Ordnungs-/Sicherheitslecks. Daraus wurde eine
Zero-Trust-Konsolidierungs-Runde.
✅ LIVE erledigt (verifiziert)
- Session 720h auf Wildcard (
16aaec78), vw-App (1dbc45ca), Warp-Login (6c32fe23). - login_method-Loch geschlossen: reusable Policy
bf-users(4ccc9b7e) =allowmit nuremail:christoph@emsenhuber.com+email:<geli>@outlook.de(keinlogin_method-Include mehr). Attached an Wildcard / App-Launcher (6df5c431) / Warp-Login. Reusable Policy8e44f5d1entkoppelt → hängt jetzt nur noch an Terpenfinder (Fremdprojekt, nicht angefasst). - Access-Gruppen (Prefix
zt-):zt-humans(6eeec7f3, christoph+geli),zt-home(c0f8ba0d, IP90.146.33.177/32),zt-automation(1b60b608, svc-token65f1821a). Policiesbf-users/bf4(5165d139) /claude-mcp(39fe0e9d) zeigen jetzt auf die Gruppen → Personen-/IP-/Token-Pflege künftig nur noch in der Gruppe. - vw = voll Bypass (Passwort-Lebensader: Web-Vault + Bitwarden-App/Extension/Desktop offen, kein
CF-Login davor). Ein Carve-out-Versuch (nur Client-Pfade bypass, Rest gaten) wurde verworfen:
CF-Bypass kurzschließt spezifischere path-Apps, und
/(Web-Vault-Root) teilt den Prefix mit/admin— nicht trennbar. Die 3 Experiment-Apps wurden wieder gelöscht. vw.emsenhuber.net/adminöffentlich geblockt per WAF-Custom-Rule (Zone-Ruleset416af72d0dd54853805875bf5752afd7, Regelf26744eb…,action=block, exprhttp.host eq "vw.emsenhuber.net" and (path eq "/admin" or starts_with(path,"/admin/"))). Verifiziert über CF-Edge und vom User per Mobilfunk („you have been blocked"). Lokal (Heim-LAN, Split-Horizon → Caddy) und später WARP-intern bleibt/adminerreichbar.- API-Token konsolidiert:
mcp/cloudflare/.envCF_API_TOKEN=…4148(id493ed8bd…), Backupmcp/cloudflare/.env.bak-tp41-20260901. Der User hat…4148anschließend vollständig gemacht (u.a. Access: Service Tokens Write + Zero Trust Write + WAF + Groups + DNS für emsenhuber.net und teilzeitladen.xyz). Altes Token…2174(id9984078812bc18d4ebb6a64b570144f2) ist am 2026-09-01 vom User revoked ✅.
⚠️ API-Token-Altlast → ARBEITSPAKET für die Folgesession (User 2026-09-01): der User fand ein weiteres API-Token
b00722522c685920f73cfcc62e9555d9mit exakt denselben Permissions wied47435d5c86b764bbf7c5b19ae827033— vermutlich eine blaueblüten/Terpene-Altlast. Auftrag: Projekte nachziehen — feststellen, welcher Consumer welches der beiden Tokens nutzt, auf eines konsolidieren, das verwaiste dann abbauen. Token-/Credentials-Hygiene (TP30-nah).
🔜 OFFEN (Token reicht jetzt für alles außer T5)
- T4 — kumulatives Service-Token
zt-svc(Basis:t4a.py, war nur an fehlender Perm gescheitert):claude-mcp(65f1821a) rename →zt-svc+ rotate (Secret einmalig).terpene-svc-Policy (bf7d2e5e) additiv += groupzt-automation(akzeptiert dann alt und neu).- Secret ablegen:
mcp/cloudflare/.env(CF_ACCESS_CLIENT_ID/SECRET) und~/.secrets/credentials.env— dort auch die Terpene-AliaseTERPENE_ACCESS_CLIENT_ID/SECRET(die die Tools lesen) undTERPENE_VERIFY_CF_CLIENT_ID/SECRET(beide zeigten auf terpene-verify-v2). - Verify Terpene:
python3 ~/dev/blaueblueten-n8n/tools/test_whoami.py(→420.teilzeitladen.xyz/api/admin/whoami, muss weiter funktionieren). - Erst nach grünem Verify:
terpene-verify-v2austerpene-svcentfernen, dannterpene-verify(a6be7efa) +terpene-verify-v2(1082bad1) löschen. ~/.secrets/README.md-Index nachziehen. opencode/exports.zshoptional (gui-env-sync). → End: ein Service-Tokenzt-svcüber Gruppezt-automationin allen Apps + Consumern.
- T3 — WARP löst
emsenhuber.netintern auf (User-Wahl „Variante 2"): WARP-Device-Profilefallback_domains+=emsenhuber.net→ interner Resolver10.40.20.1(liefert Split-Horizon*.emsenhuber.net→ Caddy10.40.20.40). Route10.40.0.0/16existiert (tunneld1da7c8a). Danach/admin+ alle internen Namen über WARP via Caddy erreichbar (kein CF/WAF). ⚠️ account-/ profilweit → als Lifecycle-Change proaktiv melden. (Token hat jetzt Zero-Trust-Write.) - T2 — 404 statt 403 (User-Wunsch): WAF-Custom-Response ist Free-Plan-gesperrt („not entitled to
use a custom response"). 403-Block bleibt — außer man macht es Origin-seitig in Caddy (
respond 404wenn HeaderCF-Connecting-IPgesetzt = via CF gekommen; lokal/WARP-intern ohne Header → durchlassen). Das komponiert sauber mit T3 (WARP-intern trifft Caddy ohne CF-Header). Eigener Caddy-Deploy (LXC 130). - T5 — IdP-Konsolen (USER-Hausaufgabe, DER Daily-OTP-Fix, bestätigt kaputt): User-Test lieferte
GitHub „The redirect_uri is not associated with this application". Fix in den Provider-Konsolen:
- GitHub OAuth-App
Ov23li2h96hAkGRPJXYV→ Authorization callback URL - Google OAuth-Client → Authorized redirect URIs
- beide =
https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback. Danach Login-Test je Provider; Gegenprobe CF-AuditGET /accounts/…/access/logs/access_requests(identity_provider=github/googlestattonetimepin).
- GitHub OAuth-App
- T6 (optional) — Rate-Limit: vw
/identity/connect/token+ gitea-Login. Kein Managed-Challenge vor vw-API//identity, git-/api-Pfaden,assetlinks.json(bricht Bitwarden-Clients / git / MCP). - T7 — Doku: ggf.
docs/tp41-cf-access-repair-runbook.md(Detail-Runbook) ergänzen.
🆕 NEU — dw/Geli an der Auth vorbei (Terpenfinder, CGNAT)
Ziel: dw erreicht 420.teilzeitladen.xyz ohne CF-Login. IP-Bypass wie bf4 scheitert an Gelis
CGNAT. Eleganteste Lösung (User-Idee): Split-Horizon am dw-Standort — dw-FritzBox setzt lokalen
DNS-Override 420.teilzeitladen.xyz → BF-Caddy (caddy-bf1 / 10.40.20.40), erreichbar über den
bestehenden WG-Tunnel dw↔core; Caddy braucht einen Block 420.teilzeitladen.xyz → macmini-Worker
(10.40.20.167:8890) mit Cert (DNS-01; Token hat jetzt DNS-Write für teilzeitladen.xyz).
Vorab prüfen: (a) FritzBox-Host-Override möglich; (b) WG-Route dw→10.40.20.40; (c) Worker wirklich auf
macmini:8890 von Caddy erreichbar. Cross-Projekt (teilzeitladen.xyz). Alternative: Geli-Gerät in
WARP (Session statt Login, CGNAT unkritisch) + Access-Policy auf WARP-Identität.
❓ Scope-Klärung für die neue Session
Der User nannte „TP3/TP4/TP5 gleich mitnehmen" — diese sind laut teilprojekte.md abgeschlossen
(TP3 WLAN-Rebuild ✅, TP4 ap1-Router/WAN-Edge ✅, TP5 deny-by-default ✅). Vermutlich Zahlendreher.
Offene Kandidaten: TP6 (CAKE, Projektziel), TP16.1 (WARP-Mesh nativ), TP16.3, TP24 (DC-USV),
TP25 (WLAN-Signal/Re-Walk). Vor Start klären, welche gemeint sind (je eigene Session empfohlen;
Subagenten nur für parallele, abgegrenzte Teilaufgaben innerhalb einer Session).
🧭 Test-Vantage-Lehre (wichtig, hat hier Stunden gekostet)
Von der Heim-IP löst *.emsenhuber.net → 10.40.20.40 (Caddy) und umgeht CF komplett — CF-Access/
WAF-Gating ist von zuhause nicht sichtbar (alles wirkt „offen"). Edge-Verhalten erzwingen mit
curl --resolve <host>:443:<CF-anycast-IP> (CF-IP via dig @1.1.1.1 +short <host>). WebFetch ist für
Access/Redirects unzuverlässig (erreichte Origin trotz Gating) — nicht als Beweis verwenden; echter
Remote-Test = User-Gerät im Mobilfunk.
Referenz-IDs
Apps: Wildcard 16aaec78 · vw/hass/gitea-Bundle 1dbc45ca · App-Launcher 6df5c431 · Warp-Login
6c32fe23 · Terpenfinder v3 e6a7991f. Policies: bf-users 4ccc9b7e · bf4 5165d139 · claude-mcp
39fe0e9d · terpene-svc bf7d2e5e · (Terpene-only) 8e44f5d1. Gruppen: zt-humans 6eeec7f3 ·
zt-home c0f8ba0d · zt-automation 1b60b608. Service-Tokens: claude-mcp→zt-svc 65f1821a ·
terpene-verify a6be7efa (Waise) · terpene-verify-v2 1082bad1. WAF: Ruleset 416af72d…, Regel
f26744eb…. Team-Domain emsenhuber.cloudflareaccess.com (Org-name-Altlabel bf4… nicht anfassen).
✅ Update — Folgesession 2026-09-01 (T4 durch, Token-Altlast geklärt, Drift-Korrekturen)
T4 — zt-svc ✅ DURCH (Variante B, inkl. Worker)
claude-mcp(65f1821a) →zt-svcumbenannt und rotiert (Secret inmcp/cloudflare/.envCF_ACCESS_CLIENT_ID/SECRET+~/.secrets/credentials.env; dortTERPENE_ACCESS_*undTERPENE_VERIFY_CF_*jetzt = zt-svc). client_idad1b47dee8ba9625eebb30247d163dda.access.- Worker-Pin gefunden (
blaueblueten-n8n/worker/src/index.js:44): Admin wird nur dem Token mitcommon_name == env.TERPENE_SVC_CLIENT_IDgewährt. Deshalb Variante B:wrangler secret put TERPENE_SVC_CLIENT_ID= zt-svc-client_id (wrangler-OAuth-Session,workers_scripts:write— die „Deploy blockiert"-Notiz galt nur für API-Tokens). Kein Code-Redeploy nötig. terpene-svc(bf7d2e5e) include = nur noch Gruppezt-automation(1b60b608).terpene-verify(a6be7efa) +terpene-verify-v2(1082bad1) gelöscht. Einziges verbleibendes Access-Service-Token =zt-svc. Verify:test_whoami.py→admin:true, common_name = zt-svc. ✅
Token-Altlast (b00722 / d47435) — GEKLÄRT (Rollen waren im Ur-Handoff vertauscht)
b00722ist NICHT die Altlast, sondern das LIVE von Caddy genutzte DNS-01-Token (LXC130/etc/caddy/caddy.env, SSoT). Certs valide bis Nov 2026.d47435= stale Klartext-Kopie incredentials.env(gleiche Perms, kein Live-Consumer). n8n hält 0 Credentials, blaueblüten hält keinen der beiden.credentials.env-Kopie am 2026-09-01 auf b00722 realignt (SSoT-Abgleich).- 🔜 USER-Aktion:
d47435revoken (Dashboard oder…4148kurz „Account API Tokens Write" geben —…4148kann API-Tokens weder listen noch revoken, Bestätigung 9109/1000).
Drift-Korrekturen (live gemessen)
- T3-Resolver: interner Split-Horizon liegt auf
10.40.20.36/.37(→*.emsenhuber.net = .40), nicht auf10.40.20.1(der liefert public CF). T3-fallback_domains müssen auf.36/.37zeigen. 10.40.20.16/.17(AdGuard laut CLAUDE.md) sind stale → neu als TP42 angelegt (docs/handoff-20260901-tp42-naming.md):.bf.lan/.bf.emsenhuber.net-Vereinheitlichung.
🔴 Leak (Transparenz)
Beim maskierten Lesen von credentials.env ist der Wert TERPENE_ANDROID_KEYSTORE_PW ins
Sitzungstranskript geraten (Regex-Loch _PW). Rotation erwägen (Terpene-Android-Signing).
T3 — WARP-intern ✅ APPLIED (2026-09-01)
- Ziel-Profil geklärt: das custom „Cloudflare Mesh"-Profil matcht nur
warp_connector@…→ Christoph/Geli laufen im Default-Profil (0197d1b3).fallback_domains += emsenhuber.net → [10.40.20.36, 10.40.20.37]dort gesetzt (15 Suffixe). Tunnel-Route10.40.0.0/16viad1da7c8aexistiert; Exclude-Liste enthält kein10.0.0.0/8(nur192.168/16+ CGNAT-minus-Mesh) →.36/.37sind über WARP routbar. - ⏳ User-Verify: WARP am Gerät neu verbinden (Profil-Cache), dann
dig vw.emsenhuber.net → .40und/adminüber WARP erreichbar.
T2 — 404 statt 403 ✅ DURCH (2026-09-01)
- Caddyfile
vw-Block:@cf_admin {header CF-Connecting-IP *; path /admin /admin/*} → respond 404. Deploy LXC130 (Backup/etc/caddy/Caddyfile.bak-tp41-20260901), reload ok. - WAF-Regel
f26744ebgelöscht (nur noch die gitea-skip-Regel3c707c3cim Ruleset). - Verify: Edge
/admin= 404 (war 403), Edge/= 200, lokal/WARP/admin= 200. ✅
Noch offen
- d47435-Revoke (User, Account API Tokens Write). T3-Client-Verify (User, WARP neu verbinden).
- T5 (GitHub/Google-Callbacks — der eigentliche OTP-Fix, User). T6/T7/dw-Geli.
- 🔴
TERPENE_ANDROID_KEYSTORE_PW-Rotation erwägen (Transkript-Leak, s.o.).