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

5.0 KiB

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

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

{
  "error": {"code": "ERR_ABAC_DENY", "message": "project scope mismatch"},
  "trace_id": "01HXYZABCD1234567890",
  "request_id": "req-77c4"
}