# Surface.Secrets Schema (Security-approved) Status: Final · 2025-11-23 Owners: Security Guild · Scanner Guild · Zastava Guild Related tasks: SURFACE-SECRETS-01/02/03/04/05/06, SCANNER-SECRETS-03, ZASTAVA-SECRETS-01/02 ## Purpose Canonical schema for declaring and validating secret providers used by Surface consumers (Scanner, Zastava, Scheduler). Supersedes the draft notes in `surface-secrets.md` §4–5 and unblocks validation + integration tasks. ## Configuration Document Location: `Surface:Secrets` (appsettings, env, or offline kit manifest). JSON Schema (v2020-12): ```json { "$id": "https://stellaops/policy/surface-secrets.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "required": ["provider", "providers"], "properties": { "provider": {"type": "string", "enum": ["kubernetes", "file", "inline"], "description": "active provider id"}, "fallbackProvider": {"type": "string", "enum": ["kubernetes", "file", "inline"], "nullable": true}, "providers": { "type": "object", "properties": { "kubernetes": { "type": "object", "required": ["namespace", "prefix"], "properties": { "namespace": {"type": "string", "pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"}, "prefix": {"type": "string", "default": "surface-"}, "ttlSeconds": {"type": "integer", "minimum": 30, "default": 600}, "allowServiceAccountFallback": {"type": "boolean", "default": false} } }, "file": { "type": "object", "required": ["root"], "properties": { "root": {"type": "string", "pattern": "^/.+"}, "format": {"type": "string", "enum": ["json", "yaml"], "default": "json"}, "permissions": {"type": "string", "enum": ["0600"], "default": "0600"} } }, "inline": { "type": "object", "properties": { "payloadBase64": {"type": "string", "contentEncoding": "base64"}, "enabled": {"type": "boolean", "default": false} } } }, "additionalProperties": false }, "requiredSecrets": { "type": "array", "items": { "type": "object", "required": ["tenant", "component", "secretType"], "properties": { "tenant": {"type": "string"}, "component": {"type": "string"}, "secretType": {"type": "string", "enum": ["cas-access", "registry", "attestation", "tls"]}, "name": {"type": "string"} } }, "uniqueItems": true } }, "additionalProperties": false } ``` ### Secret Object Shape Secrets resolved by providers must conform to one of: - `cas-access`: `{ "accessKey": "...", "secretKey": "...", "sessionToken": "..." }` - `registry`: `{ "username": "...", "password": "..." }` or `{ "token": "..." }` - `attestation`: `{ "privateKeyPem": "...", "keyId": "...", "rekorApiKey": "..." }` - `tls`: `{ "certPem": "...", "keyPem": "..." }` Binary values may be base64 but must decode to UTF-8 cleanly; otherwise return base64 string and mark `isBinary: true` in handle metadata. ## Determinism & Validation - Deterministic ordering: providers resolved in request order; when multiple secrets share tenant/component/type, choose lexicographically smallest `name` then earliest `ingestedAt` metadata. - `Surface.Validation` codes: `SURFACE_SECRET_PROVIDER_UNKNOWN`, `SURFACE_SECRET_MISSING`, `SURFACE_SECRET_STALE`, `SURFACE_SECRET_FORMAT_INVALID` (new). - Validators must reject world-readable files (`permissions != 0600`) and inline payloads when `enabled=false` (air-gapped safety). ## Offline / Air-Gap Profile - Offline kit must ship `offline/secrets/manifest.json` matching this schema with hashes for each secret blob (SHA-256 hex) and `createdAt` in UTC. - Importer scripts map manifest entries to file provider layout: `////.json`. - No external network calls during validation or resolution. ## Examples Minimal Kubernetes config: ```json { "provider": "kubernetes", "providers": {"kubernetes": {"namespace": "stellaops-runtime", "prefix": "surface-"}}, "requiredSecrets": [ {"tenant": "acme", "component": "scanner-worker", "secretType": "cas-access"}, {"tenant": "acme", "component": "scanner-worker", "secretType": "registry", "name": "primary"} ] } ``` File provider (offline): ```json { "provider": "file", "providers": {"file": {"root": "/etc/stellaops/secrets", "format": "json"}}, "requiredSecrets": [] } ``` ## Implementation Notes - Aligns with design doc `surface-secrets.md`; this file is the authoritative schema for SURFACE-SECRETS-01/02/03. - `ISurfaceSecretProvider` must emit metadata `{ "provider": "kubernetes", "ageDays": , "isBinary": }` for observability. - Add JSON Schema to `schemas/surface/surface-secrets.schema.json` (mirrored in Offline Kit) when code lands. ## Acceptance - SECURITY sign-off requires adherence to this schema and validation rules. - SURFACE-SECRETS-01 moves to DONE; SURFACE-SECRETS-02 to TODO (implementation); SURFACE-VAL-01 unblocks because schema is defined.