- 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>
92 lines
3.4 KiB
Markdown
92 lines
3.4 KiB
Markdown
# Tier 1 Universal Global Edge Ingress Protection Specification
|
|
|
|
**Specification ID:** RFC-SPEC-2026-INGRESS-01 **Classification:** Ingress
|
|
Security & Traefik Routing **Status:** Canonical / Implemented
|
|
|
|
---
|
|
|
|
## 1. Executive Summary
|
|
|
|
This specification outlines the Tier 1 Ingress Control strategy using Traefik's
|
|
`ForwardAuth` middleware combined with a dynamic Valkey-backed authorization
|
|
matrix within `auth-api`. The system provides highly performant (microsecond
|
|
latency) dynamic bypasses, strict SSR unregistered fallbacks, and router-level
|
|
self-exemptions.
|
|
|
|
---
|
|
|
|
## 2. Traefik Entrypoint Configuration
|
|
|
|
To enforce zero-trust global edge protection, the `ForwardAuth` middleware is
|
|
bound directly to the global HTTPS entrypoint. This ensures that _every_ service
|
|
routed through Traefik is automatically intercepted without relying on
|
|
developers to attach middleware to individual container labels.
|
|
|
|
### Global ForwardAuth Middleware
|
|
|
|
```yaml
|
|
# infra/compose.yml snippet (Traefik labels)
|
|
services:
|
|
traefik:
|
|
labels:
|
|
- "traefik.http.middlewares.auth-forward.forwardauth.address=http://auth-api:3000/api/forward-auth"
|
|
- "traefik.http.middlewares.auth-forward.forwardauth.trustForwardHeader=true"
|
|
- "traefik.http.middlewares.auth-forward.forwardauth.authResponseHeaders=X-Forwarded-User,X-Forwarded-User-Id,X-Forwarded-Scopes,X-Forwarded-App-Id"
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Router-Level Self-Exemptions
|
|
|
|
Applying ForwardAuth globally creates an infinite redirect deadlock if
|
|
`auth-api` intercepts requests destined for its own login mechanisms. To resolve
|
|
this, explicit routes must be exempted at the Traefik router level by
|
|
intentionally _not_ attaching the `auth-forward` middleware or configuring a
|
|
bypass.
|
|
|
|
### Required Exemptions
|
|
|
|
1. **Authentication API / UI (`auth.atyg.org`)**
|
|
- The central Identity Provider must be explicitly bypassed.
|
|
2. **ACME Challenge (`/.well-known/acme-challenge/*`)**
|
|
- Let's Encrypt automated HTTP-01 certificate renewals must proceed
|
|
unauthenticated.
|
|
3. **Global Health Checks (`/healthz`)**
|
|
- Orchestration systems must be able to verify container readiness.
|
|
|
|
---
|
|
|
|
## 4. Auth-API Dynamic Bypass Rules
|
|
|
|
Instead of volatile Traefik HTTP Dynamic Providers, Auth-Yes maintains a
|
|
highly-performant cache in Valkey (L1/L2) under the key
|
|
`auth:app_by_host:<host>`. When a request arrives at `/api/forward-auth`, the
|
|
gateway evaluates the following dynamic properties before validating sessions:
|
|
|
|
1. **`is_public` (Boolean)**
|
|
- If true, the entire application domain bypasses session checks.
|
|
2. **`bypass_paths` (List of Strings)**
|
|
- Fast deterministic prefix matching (`/api/public/*`) and exact matching
|
|
(`/webhook`).
|
|
3. **`allowed_cidrs` (List of Strings)**
|
|
- Fast native Deno IPv4 subnet matching to allowlist specific networks (e.g.,
|
|
internal CI/CD).
|
|
|
|
If any of the above rules evaluate to true, `auth-api` immediately returns
|
|
`200 OK` (with `X-Forwarded-App-Id` injected).
|
|
|
|
---
|
|
|
|
## 5. Unregistered Application Protocol
|
|
|
|
If a domain is not registered in the central `apps` table (and therefore not in
|
|
the Valkey cache), `auth-api` strictly denies the request.
|
|
|
|
- **Browser Access (`Accept: text/html`):** The proxy returns an HTTP
|
|
`302 Redirect` to `https://auth.atyg.org/errors/unregistered?host=<domain>`.
|
|
- **API Access (Non-HTML):** The proxy returns an HTTP `403 Forbidden`
|
|
(`{"error": "Application not registered"}`).
|
|
|
|
This mechanism explicitly prevents open-redirect and infrastructure mapping
|
|
attacks.
|