SecretsManagement
Scope: namespaced · Required by every workload
Selects the credential backend for a namespace. Workloads in the same namespace can bind it via secretsRef and reference the materialized Secret names; a workload without secretsRef uses Secrets you create yourself instead. One backend per resource. For the full secrets model, providers, and the Key Vault matrix, see Secrets Management.
Spec
| Field | Type | Description |
|---|---|---|
backend | enum eso | sealedSecrets (required) | The credential backend |
eso | object | ESO configuration (when backend: eso) |
sealedSecrets | object | Sealed Secrets configuration (when backend: sealedSecrets) |
eso
| Field | Type | Description |
|---|---|---|
provider | enum azureKeyVault (default) | hashicorpVault | raw | The ESO SecretStore provider |
vaultURL | string | Azure Key Vault URL (azureKeyVault provider) |
authType | enum WorkloadIdentity (default) | ServicePrincipal | Azure auth method |
serviceAccountName | string | SA ESO authenticates as (Workload Identity). The operator creates this ServiceAccount if it's missing (owned by the CR, annotated from clientID/tenantID); a pre-existing SA is adopted untouched |
clientID | string | Azure user-assigned managed-identity client ID. Stamped onto the created SA as azure.workload.identity/client-id, which ESO reads to exchange the SA token. Required for Workload Identity unless you pre-create the SA with that annotation |
tenantID / authSecretRef | string / refs | Service Principal credentials. tenantID is also stamped onto the Workload-Identity SA as azure.workload.identity/tenant-id |
hashicorpVault | object | HashiCorp Vault connection — see hashicorpVault |
providerConfig | object | Raw ESO spec.provider block (provider raw) |
refreshInterval | duration | Default 1h |
externalSecrets | list | The Secrets to materialize |
hashicorpVault
| Field | Type | Description |
|---|---|---|
server | string (required) | Vault address, e.g. https://vault.example.internal:8200 |
path | string | KV mount, default secret |
version | enum v2 (default) | v1 | KV engine version |
namespace | string | Vault Enterprise namespace (e.g. team-a); empty for open-source Vault |
caSecretRef | { name, key } | Secret holding the PEM certificate of the CA that signed Vault's TLS certificate (key default ca.crt) — needed when Vault uses a private CA, the norm on-prem |
auth | object (required) | Exactly one of the three below |
auth.kubernetes | { role, mountPath, serviceAccountName } | Vault Kubernetes auth (recommended in-cluster). The Vault role is bound to serviceAccountName; the operator creates that ServiceAccount if it is missing (an existing one is used untouched). Empty ⇒ ESO's own ServiceAccount. mountPath default kubernetes |
auth.appRole | { path, roleId, secretIdSecretRef } | Vault AppRole auth (common on-prem): the role ID plus a Secret holding the secret ID (key default secret-id). path default approle |
auth.tokenSecretRef | { name, key } | A Secret holding a Vault token (key default token). Tokens expire — prefer the methods above |
With Vault, each keys entry maps a key of the Kubernetes Secret to a secret path under the mount; the Kubernetes key is also the field read from that Vault secret (OPENAI_API_KEY: navique/models reads field OPENAI_API_KEY of secret/navique/models).
The Vault side — a read-only policy on the mount and the role for your auth method — is set up once by your Vault administrator; the management console writes the exact commands for your settings.
externalSecrets[]
| Field | Description |
|---|---|
name | Target Kubernetes Secret name |
keys | { k8sKey: remoteSecretName } shortcut mapping |
data | Full ESO remoteRef form (secretKey, remoteKey, property, version) for providers where property/version matter |
findRegexp | Bulk dataFrom.find by regexp |
sealedSecrets
| Field | Description |
|---|---|
controllerNamespace | Where the Sealed Secrets controller lives; defaults to this namespace |
Examples
ESO — Azure Key Vault via Workload Identity (production default)
apiVersion: core.navique.com/v1alpha1
kind: SecretsManagement
metadata:
name: forge-secrets
namespace: forge-gateway
spec:
backend: eso
eso:
vaultURL: https://kvforgepltprod.vault.azure.net/
serviceAccountName: forge-sa # created by the operator if absent (adopted if it exists)
clientID: 11111111-2222-3333-4444-555555555555 # managed-identity client ID (SA annotation)
refreshInterval: 1h
externalSecrets:
- name: model-credentials
keys:
OPENAI_API_KEY: gateway-foundry-api-key
ANTHROPIC_API_KEY: gateway-foundry-api-keyESO — Service Principal (non-AKS / Kind)
spec:
backend: eso
eso:
vaultURL: https://kv.vault.azure.net/
authType: ServicePrincipal
tenantID: <tenant-guid>
authSecretRef:
clientID: { name: azure-sp, key: client-id }
clientSecret: { name: azure-sp, key: client-secret }ESO — HashiCorp Vault on-prem (Kubernetes auth, private CA)
spec:
backend: eso
eso:
provider: hashicorpVault
hashicorpVault:
server: https://vault.example.internal:8200
namespace: team-a # Vault Enterprise only
caSecretRef: { name: vault-ca }
auth:
kubernetes: { role: navique, serviceAccountName: navique-vault }
externalSecrets:
- name: model-credentials
keys: { OPENAI_API_KEY: navique/models }ESO — HashiCorp Vault with AppRole
spec:
backend: eso
eso:
provider: hashicorpVault
hashicorpVault:
server: https://vault.example.internal:8200
caSecretRef: { name: vault-ca }
auth:
appRole:
roleId: 0f3c… # not a secret
secretIdSecretRef: { name: vault-approle } # key secret-id
externalSecrets:
- name: model-credentials
keys: { OPENAI_API_KEY: navique/models }ESO — HashiCorp Vault with a token (dev / hermetic)
spec:
backend: eso
eso:
provider: hashicorpVault
hashicorpVault:
server: http://vault.vault.svc:8200
auth:
tokenSecretRef: { name: vault-token, key: token }
externalSecrets:
- name: model-credentials
keys: { OPENAI_API_KEY: model-credentials }ESO — any provider (raw passthrough)
provider: raw injects the ESO spec.provider block verbatim, so every ESO provider works (AWS, GCP, IBM, Akeyless, 1Password, …) with no operator changes:
spec:
backend: eso
eso:
provider: raw
providerConfig:
aws:
service: SecretsManager
region: eu-central-1
auth: { jwt: { serviceAccountRef: { name: forge-sa } } }
externalSecrets:
- name: model-credentials
data:
- { secretKey: OPENAI_API_KEY, remoteKey: prod/model, property: openai, version: AWSCURRENT }Sealed Secrets
spec:
backend: sealedSecrets
sealedSecrets:
controllerNamespace: sealed-secretsBehavior
- ESO ⇒ the operator ensures the External Secrets Operator (provenance-aware), waits for its CRDs to be
Established, then applies a namespacedSecretStoreand the configuredExternalSecrets. A namespaced store (not aClusterSecretStore) keeps each namespace's credentials isolated. - Sealed Secrets ⇒ the operator ensures the Sealed Secrets controller and reconciles the referenced
SealedSecrets.
Workloads that set secretsRef reconcile only once that SecretsManagement is ready.
Status
{ phase, backend, storeReady, materializedSecrets[], conditions, observedGeneration }.
For every ESO backend, conditions carries SecretStoreReady: whether ESO can reach and sign in to the secret store. When ESO reports that it cannot, the condition — and Ready, since nothing can sync — is False with ESO's own cause, e.g. x509: certificate signed by unknown authority (set caSecretRef), permission denied (check the Vault role and policy) or a wrong Vault namespace.
For an Azure Key Vault + WorkloadIdentity backend, conditions also carries FederatedCredentialReady — the passive signal for whether the Azure federated identity credential exists for the ESO ServiceAccount subject. See Secrets operations → the federated credential.