Files
git.stella-ops.org/docs/api/gateway/tenant-auth.md
StellaOps Bot 44171930ff
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
feat: Add UI benchmark driver and scenarios for graph interactions
- Introduced `ui_bench_driver.mjs` to read scenarios and fixture manifest, generating a deterministic run plan.
- Created `ui_bench_plan.md` outlining the purpose, scope, and next steps for the benchmark.
- Added `ui_bench_scenarios.json` containing various scenarios for graph UI interactions.
- Implemented tests for CLI commands, ensuring bundle verification and telemetry defaults.
- Developed schemas for orchestrator components, including replay manifests and event envelopes.
- Added mock API for risk management, including listing and statistics functionalities.
- Implemented models for risk profiles and query options to support the new API.
2025-12-02 01:28:17 +02:00

78 lines
5.0 KiB
Markdown

# Gateway Tenant Auth & ABAC Contract (Web V)
## Status
- Final v1.0 (2025-12-01); aligns with Policy Guild checkpoint for Sprint 0216.
## Decisions (2025-12-01)
- Proof-of-possession: DPoP is **optional** for Web V. If a `DPoP` header is present the gateway verifies it; interactive clients SHOULD send DPoP, service tokens MAY omit it. A cluster flag `Gateway:Auth:RequireDpopForInteractive` can make DPoP mandatory later without changing the contract.
- Scope override header: `X-Stella-Scopes` is accepted only in pre-prod/offline bundles or when `Gateway:Auth:AllowScopeHeader=true`; otherwise the request is rejected with `ERR_SCOPE_HEADER_FORBIDDEN`.
- ABAC overlay: evaluated on every tenant-scoped route after RBAC success; failures are hard denies (no fallback). Attribute sources are frozen for Web V as listed below to keep determism.
## Scope
- Gateway header/claim contract for tenant activation and scope validation across Web V endpoints.
- ABAC overlay hooks with Policy Engine (attributes, evaluation order, failure modes).
- Audit emission requirements for auth decisions (RBAC + ABAC).
## Header & Claim Inputs
| Name | Required | Notes |
| --- | --- | --- |
| `Authorization: Bearer <jwt>` | Yes | RS256/ES256; claims: `iss`, `sub`, `aud`, `exp`, `iat`, `nbf`, `jti`, optional `scp` (space-delimited), `ten` (tenant). DPoP proof verified when `DPoP` header present. |
| `DPoP` | Cond. | Proof-of-possession JWS for interactive clients; validated against `htm`/`htu` and access token `jti`. Ignored for service tokens when absent. |
| `X-Stella-Tenant` | Yes | Tenant slug/UUID; must equal `ten` claim when provided. Missing or mismatch → `ERR_TENANT_MISMATCH` (400). |
| `X-Stella-Project` | Cond. | Required for project-scoped routes; otherwise optional. |
| `X-Stella-Scopes` | Cond. | Only honored when `Gateway:Auth:AllowScopeHeader=true`; rejected with 403 otherwise. Value is space-delimited scopes. |
| `X-Stella-Trace-Id` | Optional | If absent the gateway issues a ULID trace id and propagates downstream. |
| `X-Request-Id` | Optional | Echoed for idempotency diagnostics and response envelopes. |
## Processing Rules
1) Validate JWT signature against offline bundle trust roots; `aud` must be one of `stellaops-web` or `stellaops-gateway`; reject on `exp/nbf` drift > 60s.
2) Resolve tenant: prefer `X-Stella-Tenant`, otherwise `ten` claim. Any mismatch → `ERR_TENANT_MISMATCH` (400).
3) Resolve project: from `X-Stella-Project` when route is project-scoped; otherwise null.
4) Build scope set: start from `scp` claim; if `X-Stella-Scopes` is allowed and present, replace the set with its value.
5) RBAC: check required scopes per route (matrix below). Missing scope → `ERR_SCOPE_MISMATCH` (403).
6) ABAC overlay:
- Attributes: `subject`, `roles`, `org`, `tenant_id`, `project_id`, route vars (e.g., `finding_id`, `policy_id`), and request body keys explicitly listed in the route contract.
- Order: RBAC allow → ABAC evaluate → deny overrides → allow.
- Fail closed: on evaluation error or missing attributes return `ERR_ABAC_DENY` (403) with `reason` + `trace_id`.
7) Determinism: tenant header is mandatory; anonymous/implicit tenants are not allowed. Error codes are stable and surfaced in the response envelope.
## Route Scope Matrix (Web V)
- `/risk/*``risk:read` for GET, `risk:write` for POST/PUT; severity events additionally require `notify:emit`.
- `/vuln/*``vuln:read` for GET, `vuln:write` for mutations; exports require `vuln:export`.
- `/signals/*``signals:read` (GET) / `signals:write` (write APIs).
- `/policy/*` simulation/abac → `policy:simulate` (read) or `policy:abac` (overlay hooks).
- `/vex/consensus*``vex:read` (stream/read) or `vex:write` when mutating cache.
- `/audit/decisions`, `/tenant/*``tenant:admin`.
- Gateway health/info endpoints remain unauthenticated but include `trace_id`.
## Outputs
- Success: downstream context includes `tenant_id`, `project_id`, `subject`, `scopes`, `abac_result`, `trace_id`, `request_id`.
- Failure envelope (deterministic):
- 401: `ERR_TOKEN_INVALID`, `ERR_TOKEN_EXPIRED`, `ERR_DPOP_INVALID`.
- 400: `ERR_TENANT_MISSING`, `ERR_TENANT_MISMATCH`.
- 403: `ERR_SCOPE_MISMATCH`, `ERR_SCOPE_HEADER_FORBIDDEN`, `ERR_ABAC_DENY`.
Body: `{ "error": {"code": "ERR_SCOPE_MISMATCH", "message": "scope risk:read required"}, "trace_id": "01HXYZ...", "request_id": "abc" }`.
## Audit & Telemetry
- Emit DSSE-wrapped audit record: `{ tenant_id, project_id, subject, scopes, decision, reason_code, trace_id, request_id, route, ts_utc }`.
- Counters: `gateway.auth.success`, `gateway.auth.denied`, `gateway.auth.abac_denied`, `gateway.auth.tenant_missing`, labeled by route and tenant.
## Examples
### Successful read
```bash
curl -H "Authorization: Bearer $TOKEN" \
-H "DPoP: $PROOF" \
-H "X-Stella-Tenant: acme-tenant" \
-H "X-Stella-Trace-Id: 01HXYZABCD1234567890" \
https://gateway.stellaops.local/risk/status
```
### Scope/ABAC deny
```json
{
"error": {"code": "ERR_ABAC_DENY", "message": "project scope mismatch"},
"trace_id": "01HXYZABCD1234567890",
"request_id": "req-77c4"
}
```