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
- 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.
78 lines
5.0 KiB
Markdown
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"
|
|
}
|
|
```
|