# Surface.Secrets provisioning playbook (OPS-SECRETS-01) Audience: DevOps/Ops teams shipping Scanner/Zastava/Orchestrator bundles. Scope: how to provision secrets for the `StellaOps.Scanner.Surface.Secrets` providers across Kubernetes, Docker Compose, and Offline Kit. ## Secret types (handles only) - Registry pull creds (CAS / OCI / private feeds) - CAS/attestation tokens - TLS client certs for Surface.FS / RustFS (optional) - Feature flag/token bundles used by Surface.Validation (non-sensitive payloads still go through handles) All values are referenced via `secret://` handles inside service configs; plaintext never enters configs or SBOMs. ## Provider matrix | Environment | Provider | Location | Notes | | --- | --- | --- | --- | | Kubernetes | `kubernetes` | Namespace-scoped `Secret` objects | Mount-free: providers read via API using service account; RBAC must allow `get/list` on the secret names. | | Compose (connected) | `file` | Host-mounted path (e.g., `/etc/stellaops/secrets`) | Keep per-tenant subfolders; chmod 700 root; avoid embedding in images. | | Airgap/Offline Kit | `file` | Unpacked bundle `surface-secrets//...` | Bundled as encrypted payloads; decrypt/unpack to the expected directory before first boot. | | Tests | `inline` | Environment variables or minimal inline JSON | Only for unit/system tests; disable in prod (`SCANNER_SURFACE_SECRETS_ALLOW_INLINE=false`). | ## Kubernetes workflow 1) Namespace: choose one per environment (e.g., `stellaops-prod`). 2) Secret layout: one K8s Secret per tenant+component to keep RBAC narrow. ``` apiVersion: v1 kind: Secret metadata: name: scanner-secrets-default namespace: stellaops-prod stringData: registry.json: | { "type": "registry", "name": "default", "username": "svc", "password": "********", "scopes": ["stella/*"] } cas.json: | { "type": "cas-token", "name": "default", "token": "********" } ``` 3) RBAC: service accounts for Scanner Worker/WebService and Zastava Observer/Webhook need `get/list` on these secrets. 4) Values: set in Helm via `surface.secrets.provider=kubernetes` and `surface.secrets.namespace=` (already templated in `values*.yaml`). ## Compose workflow 1) Create secrets directory (default `/etc/stellaops/secrets`). 2) Layout per schema (see `docs/modules/scanner/design/surface-secrets-schema.md`): ``` /etc/stellaops/secrets/ tenants/default/registry/default.json tenants/default/cas/default.json ``` 3) Set env in `.env` files: ``` SCANNER_SURFACE_SECRETS_PROVIDER=file SCANNER_SURFACE_SECRETS_ROOT=/etc/stellaops/secrets SCANNER_SURFACE_SECRETS_NAMESPACE= SCANNER_SURFACE_SECRETS_ALLOW_INLINE=false ZASTAVA_SURFACE_SECRETS_PROVIDER=${SCANNER_SURFACE_SECRETS_PROVIDER} ZASTAVA_SURFACE_SECRETS_ROOT=${SCANNER_SURFACE_SECRETS_ROOT} ``` 4) Ensure docker-compose mounts the secrets path read-only to the services that need it. Use `SURFACE_SECRETS_HOST_PATH` to point at the decrypted bundle on the host (defaults to `./offline/surface-secrets` in the Compose profiles). ## Offline Kit workflow - The offline kit already ships encrypted `surface-secrets` bundles (see `docs/24_OFFLINE_KIT.md`). - Operators must: (a) decrypt using the provided key, (b) place contents under `/etc/stellaops/secrets` (or override `*_SURFACE_SECRETS_ROOT`), (c) keep permissions 700/600. - Set `*_SURFACE_SECRETS_PROVIDER=file` and root path envs as in Compose; Kubernetes provider is not available offline. ## Validation & observability - Surface.Validation will fail readiness if required secrets are missing or malformed. - Metrics/Logs: look for `surface.secrets.*` issue codes; readiness should fail on `Error` severities. - For CI smoke: run service with `SURFACE_SECRETS_ALLOW_INLINE=true` and inject test secrets via env for deterministic integration tests. ## Quick checklist - [ ] Provider selected per environment (`kubernetes`/`file`/`inline`) - [ ] Secrets directory or namespace populated per schema - [ ] RBAC (K8s) or file permissions (Compose/offline) locked down - [ ] Env variables set for both Scanner (`SCANNER_*`) and Zastava (`ZASTAVA_*` prefixes) - [ ] Readiness wired to Surface.Validation so missing secrets block rollout