- Introduced AuthorityAdvisoryAiOptions and related classes for managing advisory AI configurations, including remote inference options and tenant-specific settings. - Added AuthorityApiLifecycleOptions to control API lifecycle settings, including legacy OAuth endpoint configurations. - Implemented validation and normalization methods for both advisory AI and API lifecycle options to ensure proper configuration. - Created AuthorityNotificationsOptions and its related classes for managing notification settings, including ack tokens, webhooks, and escalation options. - Developed IssuerDirectoryClient and related models for interacting with the issuer directory service, including caching mechanisms and HTTP client configurations. - Added support for dependency injection through ServiceCollectionExtensions for the Issuer Directory Client. - Updated project file to include necessary package references for the new Issuer Directory Client library.
133 lines
5.8 KiB
Markdown
133 lines
5.8 KiB
Markdown
# Surface.Secrets Design (Epic: SURFACE-SHARING)
|
||
|
||
> **Status:** Draft v1.0 — aligns with tasks `SURFACE-SECRETS-01..06`, `SCANNER-SECRETS-01..03`, `ZASTAVA-SECRETS-01..02`, `OPS-SECRETS-01..02`.
|
||
>
|
||
> **Audience:** Scanner/Zastava engineers, Security Guild, DevOps/Ops teams.
|
||
|
||
## 1. Goals
|
||
|
||
Surface.Secrets standardises how Scanner, Zastava, Scheduler, and related services obtain credentials and sensitive material required for surface operations (registry pull secrets, CAS tokens, manifest signing keys). Key requirements:
|
||
|
||
- Consistent, pluggable providers (Kubernetes Secret, file, inline, future vaults).
|
||
- Deterministic lookup keyed by tenant/component to avoid accidental leakage.
|
||
- Integration with Surface.Env & Surface.Validation for configuration and pre-flight checks.
|
||
- Minimal in-memory exposure; secrets wrapped in secure handles with automatic disposal.
|
||
|
||
## 2. Secret Types
|
||
|
||
| Secret Type | Description | Example Consumers |
|
||
|-------------|-------------|-------------------|
|
||
| `cas-access` | Credentials for RustFS/S3 object storage (access key/secret, session token). | Scanner Worker/WebService, Zastava Observer/Webhook |
|
||
| `registry` | Container registry auth (username/password or token). | Scanner Worker (pulling layers for SBOM) |
|
||
| `attestation` | DSSE signing key material, Rekor API tokens. | Scanner WebService (delegation), Attestor (future integration) |
|
||
| `tls` | Client TLS certificates for Surface.FS or other services. | Scanner Worker, Zastava Observer |
|
||
|
||
Additional secret types can be registered via `ISurfaceSecretTypeRegistry`.
|
||
|
||
## 3. Provider Model
|
||
|
||
```csharp
|
||
public interface ISurfaceSecretProvider
|
||
{
|
||
ValueTask<SurfaceSecretHandle> GetAsync(SurfaceSecretRequest request, CancellationToken ct = default);
|
||
}
|
||
|
||
public sealed record SurfaceSecretRequest
|
||
(
|
||
string Tenant,
|
||
string Component, // e.g. "Scanner.Worker"
|
||
string SecretType, // e.g. "cas-access"
|
||
string? Name // optional override (e.g., "primary", "mirror-eu")
|
||
);
|
||
```
|
||
|
||
### 3.1 Built-in providers
|
||
|
||
1. **Kubernetes** – Reads from `Secret` objects. Configuration:
|
||
- `namespace`: derived from `SCANNER_SURFACE_SECRETS_ROOT` or component override.
|
||
- Secret name format: `surface-{tenant}-{component}-{secretType}`.
|
||
- Supports key mapping (e.g., `accessKey`, `secretKey`, `sessionToken`).
|
||
2. **File** – Loads JSON/YAML files from a directory (for offline kit, dev). File path derived from root + tenant/component.
|
||
3. **Inline** – Accepts base64 encoded JSON from env (useful for tests).
|
||
|
||
### 3.2 Secret Handle
|
||
|
||
`SurfaceSecretHandle` exposes typed accessors (`AsBytes()`, `AsCredentials()`, `AsTlsCertificate()`) and ensures sensitive data is cleared when disposed. Consumers that expect string material attempt UTF-8 decoding first and, if decoding fails, fall back to returning a base64 representation rather than dropping binary content.
|
||
|
||
### 3.3 Environment & Config References
|
||
|
||
Runtime configuration can reference secrets using the URI scheme `secret://{secretType}/{name?}`. Example:
|
||
|
||
```
|
||
SCANNER_ENTRYTRACE_ENV__0=API_TOKEN=secret://registry/primary
|
||
SCANNER_ENTRYTRACE_ENV__1=TLS_CERT=secret://tls/edge-gateway
|
||
```
|
||
|
||
During scan execution, Scanner.Worker resolves each placeholder via `ISurfaceSecretProvider` before invoking analyzers, replacing the environment variable with the resolved value (base64 when non-text). Missing secrets raise `SurfaceSecretNotFoundException` and are surfaced as warnings without hard-failing the scan.
|
||
|
||
## 4. Configuration
|
||
|
||
Surface.Env supplies provider configuration (`SecretsProviderConfiguration`). Example:
|
||
|
||
```json
|
||
{
|
||
"provider": "kubernetes",
|
||
"namespace": "stellaops-runtime",
|
||
"prefix": "surface-",
|
||
"fallbackProvider": "file",
|
||
"file": {
|
||
"root": "/etc/stellaops/secrets"
|
||
}
|
||
}
|
||
```
|
||
|
||
Fallback provider allows offline development (use file provider if K8s secret missing).
|
||
|
||
## 5. Validation
|
||
|
||
Surface.Validation supplies validators:
|
||
|
||
- `SecretProviderValidator` – ensures provider ID is known; checks required configuration (namespace/root).
|
||
- `SecretExistenceValidator` – optional check verifying required secret types exist at startup (configurable list).
|
||
- `SecretRotationValidator` – warns when secrets are older than rotation window (uses metadata stored in provider).
|
||
|
||
Failures produce error codes (`SURFACE_SECRET_PROVIDER_UNKNOWN`, `SURFACE_SECRET_MISSING`, `SURFACE_SECRET_STALE`).
|
||
|
||
## 6. Security Considerations
|
||
|
||
- Secrets returned as `SecureString`/byte arrays; never log values.
|
||
- Kubernetes provider caches secrets in-memory with TTL (default 10 minutes) to reduce API calls; cache invalidated when `generation` changes.
|
||
- File provider enforces permissions (`0600`); rejects world-readable files.
|
||
- Inline provider meant for tests only; flag `Surface:Secrets:AllowInline` enables it explicitly.
|
||
|
||
## 7. Offline & Air-Gap Support
|
||
|
||
- Offline kits include `offline/secrets/` with encrypted archive plus manifest file enumerating secret metadata (tenant, component, type, checksum).
|
||
- Import script decrypts archive using site-specific key and populates file provider root.
|
||
- Documented workflow lives in `ops/offline-kit/TASKS.md` and associated runbooks.
|
||
|
||
## 8. Observability
|
||
|
||
- Metrics: `surface_secrets_requests_total{provider,result}`.
|
||
- Logs: only log secret identifiers, never values.
|
||
- Traces: `surface.secrets.get` span showing provider latency.
|
||
|
||
## 9. Testing Strategy
|
||
|
||
- Unit tests per provider with fake backends.
|
||
- Integration tests in Scanner/Zastava verifying provider selection, fallback, and rotation.
|
||
- Security tests ensuring secrets aren’t leaked in logs or exceptions.
|
||
|
||
## 10. Future Enhancements
|
||
|
||
- Support for HashiCorp Vault / AWS Secrets Manager providers.
|
||
- Built-in DSSE signing key management for Attestor/Signer.
|
||
- Automatic rotation notifications via Notifier.
|
||
|
||
## 11. References
|
||
|
||
- `docs/modules/scanner/design/surface-env.md`
|
||
- `docs/modules/scanner/design/surface-fs.md`
|
||
- `docs/modules/scanner/design/surface-validation.md`
|
||
- `docs/modules/airgap/airgap-mode.md`
|