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

5.1 KiB
Raw Blame History

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):

{
  "$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:

{
  "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):

{
  "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.