- Add isSafeRedirectUrl utility to prevent open-redirect vulnerabilities. - Update GET /logout to handle ?redirect=, clear cookies safely, and log audit events. - Create AppLaunchpadPage.tsx using pure Hono SSR JSX for application visibility and SSO launching. - Update GET /dashboard and AuthenticatedLayout.tsx to mount the Launchpad as the default authenticated view with Zero-Knowledge querying. - Add HYBRID_INGRESS_PLAYBOOK.md documentation for Traefik ForwardAuth routing. - Implement exhaustive unit tests in server/main.test.ts for redirect preservation, anomaly logging, and Zero-Knowledge role filtering. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
97 lines
3.6 KiB
Markdown
97 lines
3.6 KiB
Markdown
# Hybrid Ingress Routing Playbook
|
|
|
|
This playbook outlines the recommended architecture for deploying consumer
|
|
applications that require a combination of public-facing endpoints (like splash
|
|
pages or APIs) and private, authenticated endpoints (like control panels or user
|
|
dashboards), while integrating with Auth-Yes.
|
|
|
|
## Context
|
|
|
|
Many applications are not entirely public or entirely private. They utilize a
|
|
hybrid approach where certain paths are accessible to anyone, while others are
|
|
strictly protected. To achieve Zero-Trust security and streamline
|
|
authentication, we use a dual-routing pattern leveraging Traefik and
|
|
application-level SSR hydration.
|
|
|
|
## The Dual-Routing Pattern
|
|
|
|
The dual-routing pattern separates responsibilities between the edge proxy
|
|
(Traefik) and the application itself.
|
|
|
|
### 1. Edge Proxy Authentication (Traefik ForwardAuth)
|
|
|
|
For paths that must be strictly private and require a valid user session (or
|
|
machine identity), we use Traefik's `ForwardAuth` middleware. This delegates the
|
|
authentication decision to the Auth-Yes edge node.
|
|
|
|
**Protected Paths:**
|
|
|
|
- `/control-panel/*`
|
|
- `/dashboard/*`
|
|
- `/ws/*` (WebSockets)
|
|
- `/api/private/*`
|
|
|
|
**How it works:**
|
|
|
|
1. A request arrives at Traefik for a protected path (e.g.,
|
|
`/control-panel/settings`).
|
|
2. Traefik intercepts the request and sends a sub-request to the Auth-Yes
|
|
`ForwardAuth` endpoint (`/api/forward-auth`).
|
|
3. Auth-Yes validates the `session_id` cookie or RFC 9421 HTTP Message
|
|
Signature.
|
|
4. If valid, Auth-Yes returns HTTP 200 OK, injecting context headers like
|
|
`X-Forwarded-User` and `X-Forwarded-Scopes`.
|
|
5. Traefik allows the original request to proceed to the application.
|
|
6. If invalid, Auth-Yes intercepts with a redirect (for browsers) or 403
|
|
Forbidden (for APIs/daemons).
|
|
|
|
**Example Traefik Configuration (Labels):**
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.myapp-private.rule=Host(`myapp.atyg.org`) && (PathPrefix(`/control-panel`) || PathPrefix(`/api/private`))"
|
|
- "traefik.http.routers.myapp-private.middlewares=auth-yes-forwardauth"
|
|
- "traefik.http.middlewares.auth-yes-forwardauth.forwardauth.address=http://auth-api:8000/api/forward-auth"
|
|
- "traefik.http.middlewares.auth-yes-forwardauth.forwardauth.trustForwardHeader=true"
|
|
- "traefik.http.middlewares.auth-yes-forwardauth.forwardauth.authResponseHeaders=X-Forwarded-User,X-Forwarded-Scopes"
|
|
```
|
|
|
|
### 2. Application-Level Authentication (SSR Hydration)
|
|
|
|
For paths that are public or require custom application logic to handle
|
|
unauthenticated users gracefully, the application itself handles the
|
|
authentication state via SDKs or custom logic.
|
|
|
|
**Public/Hybrid Paths:**
|
|
|
|
- `/` (Splash page, landing page)
|
|
- `/about`
|
|
- `/api/public/*`
|
|
- `/.well-known/*`
|
|
|
|
**How it works:**
|
|
|
|
1. A request arrives at Traefik for a public path (e.g., `/`).
|
|
2. Traefik routes the request directly to the application (no `ForwardAuth`
|
|
middleware applied).
|
|
3. The application receives the request. It can check for the presence of a
|
|
`session_id` cookie if it wants to render personalized content (e.g.,
|
|
replacing "Login" with "Go to Control Panel").
|
|
4. If no session exists, it renders the public splash page.
|
|
|
|
**Example Traefik Configuration (Labels):**
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.myapp-public.rule=Host(`myapp.atyg.org`)"
|
|
# No ForwardAuth middleware here
|
|
```
|
|
|
|
## Summary
|
|
|
|
By combining Traefik `ForwardAuth` for strict edge-level protection of critical
|
|
paths with application-level handling for public paths, we achieve a robust,
|
|
flexible, and secure ingress architecture. This ensures that sensitive routes
|
|
are never accidentally exposed, while public routes remain performant and
|
|
accessible.
|