Files
git.stella-ops.org/docs/security/console-security.md
root 68da90a11a
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Restructure solution layout by module
2025-10-28 15:10:40 +02:00

15 KiB
Raw Blame History

StellaOps Console Security Posture

Audience: Security Guild, Console & Authority teams, deployment engineers.
Scope: OIDC/DPoP flows, scope model, session controls, CSP and transport headers, evidence handling, offline posture, and monitoring expectations for the StellaOps Console (Sprint23).

The console is an Angular SPA fronted by the StellaOps Web gateway. It consumes Authority for identity, Concelier/Excititor for aggregation data, Policy Engine for findings, and Attestor for evidence bundles. This guide captures the security guarantees and required hardening so that the console can ship alongside the Aggregation-Only Contract (AOC) without introducing new attack surface.


1·Identity & Authentication

1.1 Authorization sequence

  1. Browser→Authority uses OAuth 2.1 Authorization Code + PKCE (S256).
  2. Upon code exchange the console requests a DPoP-bound access token (aud=console, tenant=<id>) with 120s TTL and optional rotating refresh token (rotate=true).
  3. Authority includes cnf.jkt for the ephemeral WebCrypto keypair; console stores the private key in IndexedDB (non-exportable) and keeps the public JWK in memory.
  4. All API calls attach Authorization: Bearer <token> + DPoP proof header. Nonces from the gateway are replay-protected (dpopt-nonce header).
  5. Tenanted API calls flow through the Web gateway which forwards X-Stella-Tenant and enforces tenancy headers. Missing or mismatched tenants trigger 403 with ERR_TENANT_MISMATCH.

1.2 Fresh-auth gating

  • Sensitive actions (tenant edits, token revocation, policy promote, signing key rotation) call Authority /fresh-auth using prompt=login + max_age=300.
  • Successful fresh-auth yields a 300s scoped token (fresh_auth=true) stored only in memory; the UI disables guarded buttons when the timer expires.
  • Audit events: authority.fresh_auth.start, authority.fresh_auth.success, authority.fresh_auth.expired (link to correlation IDs for the gated action).

1.3 Offline & sealed mode

  • When console.offlineMode=true the console presents an offline banner and suppresses fresh-auth prompts, replacing them with CLI guidance (stella auth fresh-auth --offline).
  • Offline mode requires pre-issued tenant-scoped tokens bundled with the Offline Kit; tokens must include offline=true claim and 15m TTL.
  • Authority availability health is polled via /api/console/status. HTTP failures raise the offline banner and switch to read-only behaviour.

2·Session & Device Binding

  • Access and refresh tokens live in memory; metadata (subject, tenant, expiry) persists in sessionStorage for reload continuity. Never store raw JWTs in localStorage.
  • Inactivity timeout defaults to 15minutes. Idle sessions trigger silent refresh; on failure the UI shows a modal requiring re-auth.
  • Tokens are device-bound through DPoP; if a new device logs in, Authority revokes the previous DPoP key and emits authority.token.binding_changed.
  • CSRF mitigations: bearer tokens plus DPoP remove cookie reliance. If cookies are required (e.g., same-origin analytics) they must be HttpOnly, SameSite=Lax, Secure.
  • Browser hardening: enforce Strict-Transport-Security, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer, Permissions-Policy: camera=(), microphone=(), geolocation=().

3·Authorization & Scope Model

The console client is registered in Authority as console-ui with scopes:

Feature area Required scopes Notes
Base navigation (Dashboard, Findings, SBOM, Runs) ui.read, findings:read, advisory:read, vex:read, aoc:verify findings:read enables Policy Engine overlays; advisory:read/vex:read load ingestion panes; aoc:verify allows on-demand guard runs.
Admin workspace ui.admin, authority:tenants.read, authority:tenants.write, authority:roles.read, authority:roles.write, authority:tokens.read, authority:tokens.revoke, authority:clients.read, authority:clients.write, authority:audit.read Scope combinations are tenant constrained. Role changes require fresh-auth.
Policy approvals policy:read, policy:review, policy:approve, policy:operate, policy:simulate policy:operate (promote/activate/run) requires fresh-auth.
Observability panes (status ticker, telemetry) ui.telemetry, scheduler:runs.read, advisory:read, vex:read ui.telemetry drives OTLP export toggles.
Orchestrator dashboard (queues, workers, rate limits) orch:read Provision via Orch.Viewer role; read-only access to job state and telemetry.
Orchestrator control actions (pause/resume, retry, sync-now, backfill) orch:operate (plus orch:read) CLI/Console must request tokens with operator_reason and operator_ticket; Authority denies issuance when either value is missing.
Downloads parity (SBOM, attestation) downloads:read, attestation:verify, sbom:export Console surfaces digests only; download links require CLI parity for write operations.

Guidance:

  • Role mapping: Provision Authority role role/ui-console-admin encapsulating the admin scopes above.
  • Orchestrator viewers: Assign Authority role role/orch-viewer (Authority role string Orch.Viewer) to consoles that require read-only access to Orchestrator telemetry.
  • Orchestrator operators: Assign Authority role role/orch-operator (Authority role string Orch.Operator) to identities allowed to pause/resume or backfill. Tokens must include operator_reason (≤256 chars) and operator_ticket (≤128 chars); Authority records the values in audit logs.
  • Tenant enforcement: Gateway injects X-Stella-Tenant from token claims. Requests missing the header must be rejected by downstream services (Concelier, Excititor, Policy Engine) and logged.
  • Separation of duties: Never grant ui.admin and policy:approve/policy:operate to the same human role without SOC sign-off; automation accounts should use least-privilege dedicated clients.

3.1 Console Authority endpoints

Console uses dedicated Authority endpoints scoped under /console/*. All requests must include the tenant header injected by the gateway (X-Stella-Tenant); calls without the header fail with tenant_header_missing and emit a structured audit event. Keep reverse proxies configured to pass the header end-to-end.

Endpoint Required scopes Purpose Notes
GET /console/tenants authority:tenants.read Returns the tenant catalogue for the authenticated principal. Validates X-Stella-Tenant; rejects tenants not configured in Authority.
GET /console/profile ui.read Surfaces subject metadata (roles, scopes, session id, fresh-auth state). Response includes freshAuth (bool) based on a 300s window since auth_time.
POST /console/token/introspect ui.read Introspects the access token currently in use and reports expiry + tenant. Console polls this endpoint to drive session inactivity prompts; intended for SPA usage via fetch POST.

Fresh-auth & session inactivity: Authority stamps auth_time on issued tokens and considers privileged actions “fresh” for five minutes. When /console/profile returns freshAuth: false, the UI must require an interactive re-authentication before allowing admin operations (ui.admin, authority:* mutations, policy:activate, exceptions:approve). Access tokens remain short-lived (00:02:00 by default); pair this with Console session timeouts so idle dashboards prompt the user before two minutes of inactivity.

DPoP + tenant binding: All /console/* endpoints require DPoP-bound access tokens. Audit events include tenant.resolved, scope, correlationId, and (when applicable) token.expires_at. Staple the same headers into downstream services so cross-component troubleshooting uses the same correlation identifiers.


4·Transport, CSP & Browser Hardening

4.1 Gateway requirements

  • TLS 1.2+ with modern cipher suites; enable HTTP/2 for SSE streams.
  • Terminate TLS at the reverse proxy (Traefik, NGINX) and forward X-Forwarded-* headers (ASPNETCORE_FORWARDEDHEADERS_ENABLED=true).
  • Rate-limit /authorize and /token according to Authority rate-limit guidance.

4.2 Content Security Policy

Default CSP served by the console container:

default-src 'self';
connect-src 'self' https://*.stella-ops.local;
img-src 'self' data:;
script-src 'self';
style-src 'self' 'unsafe-inline';
font-src 'self';
frame-ancestors 'none';

Recommendations:

  • Extend connect-src only for known internal APIs (e.g., telemetry collector). Use console.config.cspOverrides instead of editing NGINX directly.
  • Enable COOP/COEP (Cross-Origin-Opener-Policy: same-origin, Cross-Origin-Embedder-Policy: require-corp) to support WASM policy previews.
  • Use Subresource Integrity (SRI) hashes when adding third-party fonts or scripts.
  • For embedded screenshots/GIFs sourced from Offline Kit, use img-src 'self' data: blob: and verify assets during build.
  • Enforce X-Frame-Options: DENY, X-XSS-Protection: 0, and Cache-Control: no-store on JSON API responses (HTML assets remain cacheable).

4.3 SSE & WebSocket hygiene

  • SSE endpoints (/console/status/stream, /console/runs/{id}/events) must set Cache-Control: no-store and disable proxy buffering.
  • Gate SSE behind the same DPoP tokens; reject without Authorization.
  • Proxy timeouts ≥60s to avoid disconnect storms; clients use exponential backoff with jitter.

5·Evidence & Data Handling

  • Evidence bundles: Download links trigger attestor.verify or downloads.manifest APIs. The UI never caches bundle contents; it only surfaces SHA-256 digests and cosign signatures. Operators must use CLI to fetch the signed artefact.
  • Secrets: UI redacts tokens, emails, and attachment paths in logs. Structured logs include only subject, tenant, action, correlationId.
  • Aggregation data: Console honours Aggregation-Only contract—no client-side rewriting of Concelier/Excititor precedence. Provenance badges display source IDs and merge-event hashes.
  • PII minimisation: User lists show minimal identity (display name, email hash). Full email addresses require ui.admin + fresh-auth.
  • Downloads parity: Every downloadable artefact includes a CLI parity link (e.g., stella downloads fetch --artifact <id>). If CLI parity fails, the console displays a warning banner and links to troubleshooting docs.

6·Logging, Monitoring & Alerts

  • Structured logs: ui.action, tenantId, subject, scope, correlationId, dpop.jkt. Log level Information for key actions; Warning for security anomalies (failed DPoP, tenant mismatch).
  • Metrics (Prometheus): ui_request_duration_seconds, ui_dpop_failure_total, ui_fresh_auth_prompt_total, ui_tenant_switch_total, ui_offline_banner_seconds.
  • Alerts:
    1. Fresh-auth failures >5 per minute per tenant → security review.
    2. DPoP mismatches sustained >1% of requests → potential replay attempt.
    3. Tenant mismatches >0 triggers an audit incident (could indicate scope misconfiguration).
  • Correlate with Authority audit events (authority.scope.granted, authority.token.revoked) and Concelier/Excititor ingestion logs to trace user impact.

7·Offline & Air-Gapped Posture

  • Offline deployments require mirrored container images and Offline Kit manifest verification (see /docs/deploy/console.md §7).
  • Console reads offlineManifest.json at boot to validate asset digests; mismatches block startup until the manifest is refreshed.
  • Tenant and role edits queue change manifests for export; UI instructs operators to run stella auth apply --bundle <file> on the offline Authority host.
    Evidence viewing remains read-only; download buttons provide scripts to export from local Attestor snapshots.
  • Fresh-auth prompts display instructions for hardware-token usage on bastion hosts; system logs mark actions executed under offline fallback.

8·Threat Model Alignment

Threat (Authority TM §5) Console control
Spoofed revocation bundle Console verifies manifest signatures before showing revocation status; links to stella auth revoke verify.
Parameter tampering on /token PKCE + DPoP enforced; console propagates correlation IDs so Authority logs can link anomalies.
Bootstrap invite replay Admin UI surfaces invite status with expiry; fresh-auth required before issuing new invites.
Token replay by stolen agent DPoP binding prevents reuse; console surfaces revocation latency warnings sourced from Zastava metrics.
Offline bundle tampering Console refuses unsigned Offline Kit assets; prompts operators to re-import verified bundles.
Privilege escalation via plug-in overrides Plug-in manifest viewer warns when a plug-in downgrades password policy; UI restricts plug-in activation to fresh-auth + ui.admin scoped users.

Document gaps and remediation hooks in SEC5.* backlog as they are addressed.


9·Compliance checklist

  • Authority client console-ui registered with PKCE, DPoP, tenant claim requirement, and scopes from §3. (see console security sign-off)
  • CSP enforced per §4 with overrides documented in deployment manifests. (see console security sign-off)
  • Fresh-auth timer (300s) validated for admin and policy actions; audit events captured. (see console security sign-off)
  • DPoP binding tested (replay attempt blocked; logs show ui_dpop_failure_total increment). (see console security sign-off)
  • Offline mode exercises performed (banner, CLI guidance, manifest verification). (see console security sign-off)
  • Evidence download parity verified with CLI scripts; console never caches sensitive artefacts. (see console security sign-off)
  • Monitoring dashboards show metrics and alerts outlined in §6; alert runbooks reviewed with Security Guild. (see console security sign-off)
  • Security review sign-off recorded in sprint log with links to Authority threat model references. (see console security sign-off)
  • /console Authority endpoints validated for tenant header enforcement, fresh-auth prompts, and introspection flows (Audit IDs authority.console.tenants.read, authority.console.profile.read, authority.console.token.introspect). (see console security sign-off)

Last updated: 2025-10-31 (Sprint23).