Skip to main content

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

FieldTypeRequiredDescription
secretVaultNamestringYesSecret store name. 3-24 characters, alphanumeric and hyphens, must start with a letter and end with alphanumeric.
secretMapping[]SecretMappingYesMapping between Armada secret keys and Kubernetes secret keys. 1-50 items.
targetSecretNamestringYesName of the Kubernetes secret to create. Must be a valid DNS subdomain (lowercase alphanumeric, dots, hyphens).

SecretMapping

FieldTypeRequiredDescription
sourceKeystringYesSecret key name in Armada secret store. 1-127 characters, alphanumeric and hyphens.
targetKeystringYesKey name in the resulting Kubernetes secret. 1-253 characters, starts with letter or underscore, then alphanumeric, underscores, dots, or hyphens.

Status

FieldTypeDescription
conditions[]ConditionReconciliation state (see Condition Types below).
observedGenerationint64Latest spec generation observed by the controller.
lastSyncTimeTimeTimestamp 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:

ResourceName PatternDescription
ServiceAccountsa-{namespace}-{name}Used for Vault Kubernetes auth
Vault Policypolicy-{namespace}-{name}Grants read/list on the secret path
Vault Rolerole-{namespace}-{name}Binds the ServiceAccount to the policy
SecretStoress-{namespace}-{name}External Secrets store pointing to HCP Vault
ExternalSecretes-{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

FieldTypeRequiredDescription
namespacestringYesTarget Kubernetes namespace.
serviceAccountstringYesExisting ServiceAccount to bind to the Vault role.
secretVaultNamestringYesArmada secret store name (seed vault).
seedSecretKeys[]stringYesSecret key names to fetch from Armada secret store.
hcpSecretPathstringYesHCP Vault path where secrets will be stored.
hcpPolicyNamestringYesName of the Vault policy to create.
hcpPolicyRules[]PolicyRuleYesPolicy rules defining Vault access permissions.
hcpRoleNamestringYesName of the Kubernetes auth role in HCP Vault.
boundServiceAccountNames[]stringYesServiceAccount names allowed to authenticate with this role.
boundServiceAccountNamespaces[]stringYesNamespaces for ServiceAccount binding.
policies[]stringYesVault policies to attach to the role.
ttlstringYesToken TTL for the Vault role (e.g., 1h).
ssNamestringYesName of the SecretStore resource to create.

PolicyRule

FieldTypeDescription
pathstringVault secret path.
capabilities[]stringVault capabilities: read, write, list, delete, etc.

Status

FieldTypeDescription
conditions[]ConditionReconciliation state (see Condition Types below).

Condition Types

Both CRDs report reconciliation progress through status conditions:

ConditionDescription
NamespacePresentTarget namespace exists.
ServiceAccountPresentServiceAccount exists (or was created).
SecretFetchedSecrets retrieved from Armada secret store.
SecretCreatedSecrets stored in HCP Vault.
PolicyCreatedHCP Vault policy created.
RoleCreatedHCP Vault Kubernetes auth role created.
SecretStoreCreatedExternal Secrets SecretStore created.
ExternalSecretCreatedExternalSecret created and synced (ManagedSecretConfig only).

Reconciliation Flow

The operator reconciles on a 1-minute interval. For ManagedSecretConfig, the flow is:

  1. Ensure target namespace exists
  2. Create or verify ServiceAccount
  3. Fetch secrets from Armada secret store using the secret mapping
  4. Store secrets in HCP Vault (KV v2)
  5. Create Vault policy with read/list on the secret path
  6. Create Vault Kubernetes auth role binding the ServiceAccount to the policy
  7. Create SecretStore (External Secrets Operator)
  8. Create ExternalSecret to sync from HCP Vault to a Kubernetes secret
  9. 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.