Files
git.stella-ops.org/docs/modules/scanner/design/surface-secrets-schema.md
StellaOps Bot 029002ad05 work
2025-11-23 23:40:10 +02:00

120 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` §45 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: `<root>/<tenant>/<component>/<secretType>/<name>.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": <int>, "isBinary": <bool> }` 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.