- Add idempotent migrations for `is_public`, `bypass_paths`, and `allowed_cidrs` in `server/db.ts`. - Update `AppRecord` and `getAppByHost` in `server/auth-session.ts` to cache bypass rules in Valkey. - Implement native Deno, fast-path prefix (`isPathBypassed`) and CIDR matchers (`isIpAllowed`). - Update `GET /api/forward-auth` to evaluate dynamic rules and properly return 302/403 for unregistered domains. - Create `ui/components/UnregisteredAppPage.tsx` SSR view for browser fallbacks. - Update `AdminAppsPage.tsx` to handle the new ingress settings visually and post to `/api/admin/apps`. - Add `POST /api/guests/sandbox` to generate ephemeral Valkey guest sessions. - Update `POST /api/register/verify` to detect `upgrade_session` and promote guests to full users in-flight. - Add `docs/TIER1_INGRESS_SPEC.md`. - Ensure tests run cleanly and add comprehensive unit test cases for the bypass matrix. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
7.1 KiB
7.1 KiB
TASK METADATA
- Target Files:
server/db.ts,server/auth-session.ts,server/main.ts,server/main.test.ts,ui/components/AdminAppsPage.tsx,ui/mod.ts,infra/setup.ts,docs/TIER1_INGRESS_SPEC.md - Core Objective: Implement Tier 1 Universal Global Edge Ingress Protection on Traefik with dynamic Valkey-cached bypass matrix, self-exemption, CIDR allowlisting, unregistered app SSR fallback, and ephemeral guest sandboxes.
- Dependencies: PostgreSQL
appsschema, Valkey 8 cache,docs/FORWARDAUTH_REDIRECT_SPEC.md. - Additional Important Notes: Must guarantee
<30\mu sedge lookups via Valkey L1/L2 caching and prevent infinite redirect deadlocks onauth-apiand ACME challenge routers.
1. TASK METADATA
(Defined in the header block above)
2. Architectural Considerations & Risks
-
Risks & Vulnerabilities:
- Recursive Deadlocks (Self-Exemption): Applying ForwardAuth globally at
entryPoints.websecure.http.middlewarescreates an infinite loop ifauth-apiintercepts its own login/verification endpoints.auth.atyg.organd/.well-known/acme-challenge/*must be explicitly exempt. - Edge Latency Regressions: Querying PostgreSQL on every incoming
ForwardAuth request for dynamic bypass rules would bottleneck cluster
throughput. All
is_public,bypass_paths, andallowed_cidrsfields must be cached inside the Valkeyauth:app_by_host:<host>key. - ReDoS in Path Matching: Evaluating wildcard bypasses using unconstrained regular expressions could allow malicious paths to trigger catastrophic backtracking. Path matching must use fast, deterministic prefix and glob matching.
- Open Redirects on Unregistered Apps: When routing unregistered domains to SSR error views, destination parameters must be strictly validated against approved hosts to prevent phishing vectors.
- Recursive Deadlocks (Self-Exemption): Applying ForwardAuth globally at
-
Alternatives & Architecture Decisions:
- Valkey App Caching over Traefik HTTP Dynamic Provider: Evaluating
dynamic bypass paths inside
auth-apivia Valkey caches eliminates Traefik config file churn, provider polling overhead, and proxy reload downtime. - Defense-in-Depth Universal Bypasses:
- Traefik Level:
/.well-known/acme-challenge/*and global/healthzbypass ForwardAuth entirely at the edge router level to avoid certificate renewal failures during container restarts. - Auth-API Level: Application-specific paths (
/api/public/*,raw/branch/main/sdk/*,/webhooks/*) and CIDR subnets are evaluated inauth-apiwith zero network overhead.
- Traefik Level:
- Dual-Response Protocol Compliance: Unregistered domains receive an HTTP
302 Redirecttohttps://auth.atyg.org/errors/unregistered?host=...for browsers (Accept: text/html) and a clean HTTP403 Forbidden({"error": "Application not registered"}) for APIs/cURL. - Ephemeral Guest Sandboxes (Use Case 11): Ephemeral sessions are held in
Valkey with
account_status: "guest"and promoted in-flight to full users upon passkey enrollment without losing UUID or state.
- Valkey App Caching over Traefik HTTP Dynamic Provider: Evaluating
dynamic bypass paths inside
3. Proposed Implementation
Phase 1: Database Schema & Valkey Caching Upgrades
- Database Migration (
server/db.ts):- Add idempotent migrations inside
initDb():ALTER TABLE apps ADD COLUMN IF NOT EXISTS is_public BOOLEAN DEFAULT FALSE; ALTER TABLE apps ADD COLUMN IF NOT EXISTS bypass_paths TEXT[] DEFAULT '{}'; ALTER TABLE apps ADD COLUMN IF NOT EXISTS allowed_cidrs TEXT[] DEFAULT '{}';
- Add idempotent migrations inside
- Valkey App Cache Hydration (
server/auth-session.ts):- Update
getAppByHost(host)to selectid, name, domain, is_public, bypass_paths, allowed_cidrs. - Cache the complete application metadata in
auth:app_by_host:<host>with 1-hour TTL.
- Update
Phase 2: Dynamic Bypass Evaluator & ForwardAuth Hardening
- Path & CIDR Matcher Helper (
server/auth-session.ts):- Implement
isPathBypassed(requestPath: string, bypassPaths: string[]): booleanusing deterministic prefix matching (path.startsWith(...)and/*wildcard support). - Implement
isIpAllowed(clientIp: string, allowedCidrs: string[]): booleanfor subnet validation.
- Implement
- Update
GET /api/forward-auth(server/main.ts):- Step 1: Unregistered App Check: If
appRecordis null:- If
Accept: text/html: Return302 Redirecttohttps://${loginDomain}/errors/unregistered?host=${encodeURIComponent(host)}. - Else: Return
403 Forbidden({"error": "Application not registered"}).
- If
- Step 2: Dynamic Bypass Check:
- If
appRecord.is_public === true, orisPathBypassed(uri, appRecord.bypass_paths), orisIpAllowed(clientIp, appRecord.allowed_cidrs):- Immediately return
200 OK(bypassing session checks).
- Immediately return
- If
- Step 3: RFC 9421 & Session Checks: Proceed with existing HTTP Signatures and WebAuthn session validation.
- Step 1: Unregistered App Check: If
Phase 3: Unregistered Application SSR Error Page & Admin UI
- Create SSR Error View (
ui/components/UnregisteredAppPage.tsx):- Pure Hono SSR JSX page explaining the domain is not registered in the Auth-Yes catalog, with a direct 1-click button for Global Admins: "Register Application in IAM Console".
- Update Route in
ui/mod.ts:- Mount
GET /errors/unregisteredrenderingUnregisteredAppPage.
- Mount
- Management Console Updates (
ui/components/AdminAppsPage.tsx&server/main.ts):- Expose
is_public,bypass_paths, andallowed_cidrsinPOST /api/admin/appsandPUT /api/admin/apps/:id. - Add toggle switches and input fields to the Admin Web UI.
- Expose
Phase 4: Ephemeral Guest Sandboxes (Use Case 11)
- Guest Endpoint (
server/main.ts):POST /api/guests/sandbox: Generates a guestsessionId, stores{ uuid: guestUuid, username: "guest-<id>", account_status: "guest" }in Valkey with 2-hour TTL, and returns the session cookie.
- In-Flight Passkey Promotion (
server/main.ts):- Update
/api/register/verifyto detectupgrade_sessionparameter, creating the PostgreSQL user with the existingguestUuidand changing status toactive.
- Update
Phase 5: Documentation & Traefik Compose Guides
- Author
docs/TIER1_INGRESS_SPEC.md:- Document static/dynamic Traefik configurations for
entryPoints.websecure.http.middlewares=auth-forward@dockerwith router-level self-exemption overrides forauth.atyg.org.
- Document static/dynamic Traefik configurations for
4. Testing & Verification Matrix
- Unit Tests (
server/main.test.ts):- Verify
GET /api/forward-authreturns200 OKwhenappRecord.is_public === true. - Verify
GET /api/forward-authreturns200 OKfor paths matchingbypass_paths(e.g./api/public/ping). - Verify
GET /api/forward-authreturns302 Redirectto/errors/unregisteredfor unauthenticated browser requests to unregistered domains. - Verify
GET /api/forward-authreturns403 Forbiddenfor API requests to unregistered domains. - Verify guest session generation and in-flight passkey promotion.
- Verify
- Quality Gates:
deno fmt,deno task lint,deno task check,deno task test(100% pass).