Creates a new task markdown file in `tasks/new` detailing the architecture and implementation steps required to inject flattened RBAC grants via Valkey caching for `/api/forward-auth`. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
3.7 KiB
3.7 KiB
TASK METADATA
- Target Files:
server/main.ts,server/db.ts,server/auth-session.ts - Core Objective: Implement Ingress Grant Vector Injection in
/api/forward-authto resolveX-Forwarded-Hostagainst registered apps, evaluate RBAC grants via Valkey caching, and inject flattened user grant headers into downstream requests. - Dependencies: Valkey caching infrastructure, database migration for
domaincolumn onappstable. - Additional Important Notes: Latency is critical; ForwardAuth must resolve in <30μs using Valkey and must not hit PostgreSQL on every request. Global Admins bypass app-specific grant checks.
Architectural Considerations & Risks
Risks
- Cache Invalidation: Stale data in Valkey could allow revoked users to retain access or prevent newly granted users from accessing apps. We must ensure that grants and app updates properly invalidate or update their respective Valkey keys.
- Header Spoofing / Parsing Issues: Ensure the
X-Forwarded-*headers are safely injected and override any existing headers from the client to prevent privilege escalation (handled by Traefik, but good to be mindful of). - Performance Bottlenecks: While caching resolves database latency, improper cache interactions (e.g., waiting for multiple sequential round-trips to Valkey instead of using pipelining or MGET where appropriate) could still add overhead.
Alternatives Evaluated
- Direct PostgreSQL queries: Rejected due to the high volume of requests
hitting the edge proxy
/api/forward-auth. - JWT Injection: Instead of flattened headers, injecting a signed JWT was
considered. However, flattened headers (
X-Forwarded-User-Id,X-Forwarded-Scopes) are native to Traefik ForwardAuth and simpler for downstream SSR hydration without requiring public key distribution to every downstream app.
Proposed Implementation
1. Database Schema Update (server/db.ts)
- Modify
initDb()to add thedomaincolumn to theappstable:ALTER TABLE apps ADD COLUMN IF NOT EXISTS domain TEXT;. - Ensure application seeding or registry logic accounts for the new
domainfield if necessary.
2. Caching Strategy Implementation
- Implement helper functions to fetch from Valkey or fallback to DB and populate Valkey.
- App Resolution Cache (
auth:app_by_host:<host>):- Match
X-Forwarded-Hostagainstapps.domain. - Fallback: Match
apps.nameagainst the first subdomain segment. - Cache the resulting
app_idandnamein Valkey as JSON.
- Match
- Grants Cache (
auth:grants:<userId>:<appId>):- Cache the user's roles for the specific app.
3. ForwardAuth Endpoint Logic (server/main.ts)
- Update
GET /api/forward-authto:- Extract
X-Forwarded-Hostfrom the request. - Resolve the target application via the App Resolution Cache (Valkey). If no app matches, decide whether to allow pass-through without scopes or strictly deny (typically 403 for protected routes without an app, or allow pass-through if unmapped). Assuming strict mapping per requirements, return 403 or 404 if not found.
- Validate the user session (existing logic).
- Check if the user is a Global Admin (
isGlobalAdmin). If yes, authorize automatically and setX-Forwarded-Scopes: admin. - For regular users, resolve their scopes for the target app via the Grants Cache (Valkey).
- Enforce Default-Deny: If no scopes are found, return 403 Forbidden.
- On success, inject headers:
X-Forwarded-User-Id: <user.id>X-Forwarded-User-Name: <user.username>X-Forwarded-Scopes: <comma-separated list of roles>X-Forwarded-App-Id: <app_id>- Return HTTP 200 OK.
- Extract