Surface.Secrets Design
FROZEN — LEGACY (bootstrap/file material only). As of SPRINT_20260703_004 (S5) this design is frozen.
Surface.Secretsremains the mechanism for bootstrap/file secret material only (offline file provider + inline-for-tests). Its ownsecret://scheme and the “future approved vault providers” described below are not the path for new secret-bearing features.New secret-bearing features MUST use the unified secret provider and URL secret references — see ADR-031 (unified secret provider) and ADR-032 (URL secret references + multi-provider routing). Registry pull credentials are resolved through the Integrations catalog and, since SPRINT_20260703_004 (S1), returned to the scanner AEAD-sealed under the shared master-KEK chain (
StellaOps.Cryptography.CredentialStore.CredentialAead), not via aSurface.Secretsprovider. No code is removed by the freeze; existing file/inline provider behaviour is unchanged.
Status
This design is updated for the current Stella Ops deployment model: Docker Compose, Offline Kit, signed release manifests, and host/service-manager operations.
Kubernetes Secret support is retired from active Stella Ops deployment support. Any remaining source code or tests for Kubernetes secret providers must be handled through docs/implplan/SPRINT_20260501_058_Scanner_kubernetes_surface_retirement.md.
Goals
Surface.Secrets standardises how Scanner, Scheduler, and related services obtain credentials and sensitive material required for surface operations, including registry pull credentials, CAS tokens, manifest signing keys, and TLS material.
Key requirements:
- Consistent pluggable providers: file provider, inline provider for tests, and future approved vault providers.
- Deterministic lookup keyed by tenant, component, secret type, and optional name.
- Minimal in-memory exposure.
- No secret values in logs, metrics, traces, exceptions, or analyzer output.
- Offline-friendly file-provider layout.
Secret Types
| Secret Type | Description | Example Consumers |
|---|---|---|
cas-access | RustFS/S3-compatible object storage credentials. | Scanner Worker/WebService |
registry | Container registry auth. | Scanner Worker |
attestation | DSSE signing key material or transparency tokens. | Scanner WebService, Attestor |
github-integration | GitHub API token JSON used for code-scanning SARIF upload and alert readback. | Scanner WebService |
tls | Client TLS certificate material. | Scanner Worker |
Provider Model
public interface ISurfaceSecretProvider
{
ValueTask<SurfaceSecretHandle> GetAsync(SurfaceSecretRequest request, CancellationToken ct = default);
}
public sealed record SurfaceSecretRequest(
string Tenant,
string Component,
string SecretType,
string? Name);
Built-in active providers:
- File - loads JSON/YAML files from a directory. The path is derived from root, tenant, component, secret type, and optional name.
- Inline - accepts base64 encoded JSON from environment/config for tests only.
Future provider candidates, such as Vault or cloud secret stores, require a separate license/security review and release documentation. (Frozen, S5): do not add new providers here — route new secret-bearing needs through the unified secret provider (ADR-031) and URL secret references (ADR-032) instead.
Configuration
{
"provider": "file",
"prefix": "surface-",
"file": {
"root": "/etc/stellaops/secrets"
}
}
Runtime configuration can reference secrets using secret://{secretType}/{name?}. Scanner.Worker resolves each placeholder before analyzer invocation. Missing or unreadable secrets raise typed Worker failures; unresolved placeholders must never reach analyzers.
Security Rules
- File provider enforces restrictive permissions and rejects world-readable files.
- Inline provider requires an explicit test/development enable flag.
- Secret handles clear sensitive byte arrays when disposed.
- Logs and metrics may include secret identifiers, provider ids, and age metadata only.
Offline Support
Offline kits include offline/secrets/manifest.json with tenant, component, secret type, optional name, checksum, and creation metadata. Import scripts map entries into:
<root>/<tenant>/<component>/<secretType>/<name>.json
Validation performs no external network calls.
