Secret Management Operator
The Secret Management Operator automates syncing secrets from an upstream, Armada-managed secret store to HashiCorp Vault (HCP Vault) on the Galleon. It creates the necessary Vault policies, roles, and External Secrets resources to make secrets available as native Kubernetes secrets.
The following custom resources are available:
- ManagedSecretConfig (v1alpha2) — recommended for most use cases; auto-generates all intermediate resources
- SecretConfig (v1alpha1) — gives full control over Vault policy rules, role bindings, and resource naming
ManagedSecretConfig (v1alpha2)
The simplified interface. You specify which secrets you need and the target Kubernetes secret name. The operator handles everything else: ServiceAccount, Vault policy, Vault role, SecretStore, and ExternalSecret.
Example
apiVersion: security.armada.ai/v1alpha2
kind: ManagedSecretConfig
metadata:
name: my-app-secrets
namespace: app-namespace
spec:
secretVaultName: my-tenant-vault
secretMapping:
- sourceKey: client-id
targetKey: client_id
- sourceKey: client-secret
targetKey: client_secret
targetSecretName: my-app-secret
This fetches client-id and client-secret from the upstream secret store my-tenant-vault, syncs them through HCP Vault, and delivers them as a Kubernetes secret named my-app-secret in the app-namespace namespace.
Spec
| Field | Type | Required | Description |
|---|---|---|---|
secretVaultName | string | Yes | Secret store name. 3-24 characters, alphanumeric and hyphens, must start with a letter and end with alphanumeric. |
secretMapping | []SecretMapping | Yes | Mapping between Armada secret keys and Kubernetes secret keys. 1-50 items. |
targetSecretName | string | Yes | Name of the Kubernetes secret to create. Must be a valid DNS subdomain (lowercase alphanumeric, dots, hyphens). |
SecretMapping
| Field | Type | Required | Description |
|---|---|---|---|
sourceKey | string | Yes | Secret key name in Armada secret store. 1-127 characters, alphanumeric and hyphens. |
targetKey | string | Yes | Key name in the resulting Kubernetes secret. 1-253 characters, starts with letter or underscore, then alphanumeric, underscores, dots, or hyphens. |
Status
| Field | Type | Description |
|---|---|---|
conditions | []Condition | Reconciliation state (see Condition Types below). |
observedGeneration | int64 | Latest spec generation observed by the controller. |
lastSyncTime | Time | Timestamp of last successful secret synchronization. |
Generated Resources
The operator auto-generates intermediate resources using a naming convention based on the CR's namespace and name:
| Resource | Name Pattern | Description |
|---|---|---|
| ServiceAccount | sa-{namespace}-{name} | Used for Vault Kubernetes auth |
| Vault Policy | policy-{namespace}-{name} | Grants read/list on the secret path |
| Vault Role | role-{namespace}-{name} | Binds the ServiceAccount to the policy |
| SecretStore | ss-{namespace}-{name} | External Secrets store pointing to HCP Vault |
| ExternalSecret | es-{namespace}-{name} | Syncs secrets from HCP Vault to Kubernetes |
| HCP Vault Path | {namespace}/{name} | Where secrets are stored in HCP Vault |
SecretConfig (v1alpha1)
Provides full control over Vault configuration. You specify the policy rules, role bindings, secret paths, and resource names directly.
Spec
| Field | Type | Required | Description |
|---|---|---|---|
namespace | string | Yes | Target Kubernetes namespace. |
serviceAccount | string | Yes | Existing ServiceAccount to bind to the Vault role. |
secretVaultName | string | Yes | Armada secret store name (seed vault). |
seedSecretKeys | []string | Yes | Secret key names to fetch from Armada secret store. |
hcpSecretPath | string | Yes | HCP Vault path where secrets will be stored. |
hcpPolicyName | string | Yes | Name of the Vault policy to create. |
hcpPolicyRules | []PolicyRule | Yes | Policy rules defining Vault access permissions. |
hcpRoleName | string | Yes | Name of the Kubernetes auth role in HCP Vault. |
boundServiceAccountNames | []string | Yes | ServiceAccount names allowed to authenticate with this role. |
boundServiceAccountNamespaces | []string | Yes | Namespaces for ServiceAccount binding. |
policies | []string | Yes | Vault policies to attach to the role. |
ttl | string | Yes | Token TTL for the Vault role (e.g., 1h). |
ssName | string | Yes | Name of the SecretStore resource to create. |
PolicyRule
| Field | Type | Description |
|---|---|---|
path | string | Vault secret path. |
capabilities | []string | Vault capabilities: read, write, list, delete, etc. |
Status
| Field | Type | Description |
|---|---|---|
conditions | []Condition | Reconciliation state (see Condition Types below). |
Condition Types
Both CRDs report reconciliation progress through status conditions:
| Condition | Description |
|---|---|
NamespacePresent | Target namespace exists. |
ServiceAccountPresent | ServiceAccount exists (or was created). |
SecretFetched | Secrets retrieved from Armada secret store. |
SecretCreated | Secrets stored in HCP Vault. |
PolicyCreated | HCP Vault policy created. |
RoleCreated | HCP Vault Kubernetes auth role created. |
SecretStoreCreated | External Secrets SecretStore created. |
ExternalSecretCreated | ExternalSecret created and synced (ManagedSecretConfig only). |
Reconciliation Flow
The operator reconciles on a 1-minute interval. For ManagedSecretConfig, the flow is:
- Ensure target namespace exists
- Create or verify ServiceAccount
- Fetch secrets from Armada secret store using the secret mapping
- Store secrets in HCP Vault (KV v2)
- Create Vault policy with read/list on the secret path
- Create Vault Kubernetes auth role binding the ServiceAccount to the policy
- Create SecretStore (External Secrets Operator)
- Create ExternalSecret to sync from HCP Vault to a Kubernetes secret
- Monitor ExternalSecret sync status and update
lastSyncTime
SecretConfig follows the same flow through step 7, but uses your explicitly provided configuration for policy rules, role bindings, and naming.
Cleanup
Both CRDs use finalizers. Deleting the custom resource cleans up the Vault policy and role. Kubernetes resources with owner references (ServiceAccount, SecretStore, ExternalSecret) are garbage collected automatically.