Files
git.stella-ops.org/ops/devops/secrets/surface-secrets-provisioning.md
StellaOps Bot bc0762e97d up
2025-12-09 00:20:52 +02:00

75 lines
4.1 KiB
Markdown

# 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/<tenant>/...` | 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=<ns>` (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