Skip to main content

Secrets management

A secret is the one thing a platform cannot govern by describing. It has to be stored, resolved, handed to exactly one caller, and destroyed, and every step is somewhere it can leak.

System9 runs one secret substrate with pluggable backends, so the sovereignty decision is a configuration choice rather than a product choice.

Where secrets live: your call​

BackendFor
LocalFully in-platform. Nothing external is reachable or required
AWS Secrets ManagerAn estate already standardised on it
AWS Systems Manager Parameter StoreThe lighter-weight AWS option
Azure Key Vault
GCP Secret Manager

The same resolution path serves all of them, so an application does not know or care which one a deployment chose, and changing backends is not a rewrite.

For sovereign and air-gapped operation, the local backend is the whole story. Secrets never leave the cell, no external vault has to be reachable, and nothing in the resolution path requires egress. That is the default posture rather than a hardened variant of a cloud-first design.

Addressing a secret​

Secrets are addressed by URI rather than by a filesystem path or a backend-specific handle:

s9://secrets/{namespace}/{key}

Some namespaces carry structured, slash-delimited sub-paths rather than one flat key. Identity federation is the worked example, where a provider's OIDC client secret, SAML signing key, LDAP bind password and SCIM token each live under the provider's own sub-path.

Every path segment is validated against a strict character set, so a crafted identifier cannot traverse out of its namespace.

Encryption at rest​

Local secrets are envelope-encrypted before they touch disk.

LayerMechanism
Key derivationA per-scope key-encryption-key derived from a master key via HKDF-SHA256
SealingA per-blob data-encryption key under one enterprise envelope, carrying a key version and identity as additional authenticated data
CipherAES-256-GCM
RotationBuilt into the envelope, with dedicated key and key-encryption-key rotation paths

The envelope carrying identity as additional authenticated data is the part worth noticing: a sealed blob is bound to who it belongs to, so a ciphertext lifted from one scope cannot be decrypted under another even with the right key version.

Scopes​

Secrets resolve within a scope, and the scope is checked rather than trusted:

  • Entity scope, for a principal's own material.
  • Workspace scope, so a workspace resolves its own secrets without reaching entity scope.
  • Service scope, for platform services.

A scope principal checker enforces that the caller is entitled to the scope it is asking within, so a workspace-scoped resolution cannot quietly widen.

In memory, secrets are handled as secrets​

Resolved plaintext is wrapped in a secure buffer with explicit zeroization, so secret material is overwritten when it is no longer needed rather than left for the garbage collector.

Around it sits a bounded, thread-safe cache with a TTL that zeroizes evicted and expired entries automatically. A cache that merely drops its reference leaves the plaintext in memory until something else overwrites the page; this one does not.

The credential never crosses a service boundary​

This is the strongest property in the secrets story, and it shows up where you would least expect it: cloud inventory scanning.

A workspace's cloud connector credential lives in the compute secret substrate. A live scan has to resolve that credential and call the provider's APIs. The arrangement is deliberate:

Resolution and the cloud API calls both happen in-process, inside the owning service. Only the enumerated inventory is returned. The credential plaintext never crosses a service boundary.

The enumeration logic is owned by the assessment domain and imported into the service that holds the secret, rather than the secret being shipped to the service that holds the logic. The worker that wanted the inventory receives inventory, and never sees the credential.

That inversion is the whole trick, and it generalises: move the code to the secret, not the secret to the code.

What secrets are actually for​

UseExample
Cloud storageCredentials for external S3, Azure and GCS buckets backing lakehouse tables
Data-platform connectivityCredentials for federated sources: PostgreSQL, MySQL, SQL Server, BigQuery, Snowflake, Databricks
SaaS contentOAuth connections to OneDrive, SharePoint, Google Drive and Dropbox, scoped per workspace and entity
Identity federationOIDC client secrets, SAML signing keys, LDAP bind passwords, SCIM tokens
ConnectorsPer-connector authentication across the stream connector catalog
Model providersWhere a deployment's tier permits a third-party provider at all

Connection provisioning and scanning are first-class, so a credential is provisioned into the substrate as part of creating a connection rather than pasted somewhere afterward.

Secrets at the edge​

An Edge Agent holds its own secret material on the device, and the posture is different because the threat is different: the device may be captured.

The device's own identity key is generated on-device and never traverses the wire. Material at rest is sealed, and zeroize destroys agent keys, revokes certificates and overwrites workflow state, journal and local model weights.

Software zeroize is not capture-resistant

The tactical profile's zeroize is software-only. Where physical capture is in the threat model, pair it with hardware key custody rather than relying on software zeroize alone.

Access is logged​

Secret access is recorded to its own audit trail, so "who resolved this credential and when" is answerable. That is separate from, and in addition to, the audit planes covering everything else.