Instant updates
Through a Vault Events subscription, Vault can notify the Vault Secrets Operator (VSO) after changing a secret. VSO can instantly update corresponding Kubernetes Secret. Event message delivery is not guaranteed, so we recommend setting a periodic refresh interval.
Choose the guide for your secret type:
- KV v1 / v2 static secrets (VaultStaticSecret)
- Auto/Manually rotated credentials for static-roles (VaultDynamicSecret)
- Dynamic lease-based credentials (VaultDynamicSecret)
KV static secrets
Enable instant updates for VaultStaticSecret resources backed by a
KV v1 or KV v2 secrets engine. Vault fires kv-v1/* or kv-v2/* event on every write to the
secret path and VSO reconciles immediately, using the X-Vault-Index header to
avoid stale reads on Vault Performance Standbys.
Before you start
- You must have Vault Secrets Operator installed.
- You must use Vault Enterprise version 1.13 or later.
Step 1: Set event permissions (KV)
Grant these permissions in the policy associated with the VaultAuth role:
path "<kv mount>/<kv secret path>" {
capabilities = ["read", "list", "subscribe"]
subscribe_event_types = ["*"]
}
path "sys/events/subscribe/kv*" {
capabilities = ["read"]
}
Step 2: Enable instant updates on the VaultStaticSecret
Set syncConfig.instantUpdates: true in the VaultStaticSecret spec:
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
namespace: vso-example
name: vault-static-secret-v2
spec:
vaultAuthRef: vault-auth
mount: <kv mount>
type: kv-v2
path: <kv secret path>
refreshAfter: 1h
destination:
create: true
name: static-secret2
syncConfig:
instantUpdates: true
Auto/Manually rotated credentials for static-roles
Enable instant updates for VaultDynamicSecret resources that sync
credentials Vault rotates on a schedule, such as database or LDAP static roles.
When a rotation event fires, VSO reads the fresh credentials immediately using
the X-Vault-Index header to avoid stale reads on Vault Performance Standbys.
VSO subscribes to a single engine WebSocket (resolved from sys/mounts/<mount>,
e.g. database, ldap, or any other engine that emits rotation events).
The rotation event itself is the trigger, and no need for a lease WebSocket.
Before you start
- You must have Vault Secrets Operator v1.6.0+ installed.
- You must use Vault Enterprise version 1.16+ for database static roles, version 1.21+ for LDAP static roles, or version 2.0+ for Azure static roles.
- The VaultAuth policy must grant
readonsys/mounts/*so VSO can resolve the engine type at runtime.
Step 1: Set event permissions (database / LDAP / Azure static roles)
Grant these permissions in the policy associated with the VaultAuth role:
Database static roles:
# Allow VSO to resolve the mount's engine type
path "sys/mounts/*" {
capabilities = ["read"]
}
# Allow VSO to read credentials and subscribe to rotation events
path "database/*" {
capabilities = ["read", "list", "subscribe"]
subscribe_event_types = ["database*"]
}
# Allow subscribing to database engine events
path "sys/events/subscribe/database*" {
capabilities = ["read"]
}
LDAP static roles:
# Allow VSO to resolve the mount's engine type
path "sys/mounts/*" {
capabilities = ["read"]
}
# Allow VSO to read credentials and subscribe to rotation events
path "ldap/*" {
capabilities = ["read", "list", "subscribe"]
subscribe_event_types = ["ldap*"]
}
# Allow subscribing to LDAP engine events
path "sys/events/subscribe/ldap*" {
capabilities = ["read"]
}
Azure static roles:
# Allow VSO to resolve the mount's engine type
path "sys/mounts/*" {
capabilities = ["read"]
}
# Allow VSO to read static credentials and role definitions
path "azure/static-creds/*" {
capabilities = ["read"]
}
path "azure/static-roles/*" {
capabilities = ["read", "list", "subscribe"]
subscribe_event_types = ["azure*"]
}
# Allow subscribing to Azure engine events
path "sys/events/subscribe/azure*" {
capabilities = ["read"]
}
Step 2: Enable instant updates on the VaultDynamicSecret
Set spec.allowStaticCreds: true and syncConfig.instantUpdates: true in the
VaultDynamicSecret spec:
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
namespace: vso-example
name: vault-dynamic-secret-db-static
spec:
vaultAuthRef: vault-auth
mount: database
path: static-creds/my-static-role
allowStaticCreds: true
refreshAfter: 1h
destination:
create: true
name: db-static-secret
syncConfig:
instantUpdates: true
Dynamic lease-based credentials
Enable instant updates for VaultDynamicSecret resources that issue
new credentials on request (dynamic leases). VSO subscribes to two WebSockets:
one for the engine type (e.g. database) and one for lease events. Lease
events trigger immediate re-issuance when credentials are revoked or expire. VSO
uses the X-Vault-Index header when the event includes one to avoid stale reads
on Vault Performance Standbys.
Before you start
- You must have Vault Secrets Operator v1.6.0+ installed.
- You must use Vault Enterprise version 2.0 or later.
- The VaultAuth policy must grant
readonsys/mounts/*so VSO can resolve the engine type at runtime.
Step 1: Set event permissions (dynamic leases)
Grant these permissions in the policy associated with the VaultAuth role:
Database dynamic credentials:
# Allow VSO to resolve the mount's engine type
path "sys/mounts/*" {
capabilities = ["read"]
}
# Allow VSO to read and subscribe to credential events
path "database/*" {
capabilities = ["read", "list", "subscribe"]
subscribe_event_types = ["database*"]
}
# Allow subscribing to database engine events
path "sys/events/subscribe/database*" {
capabilities = ["read"]
}
# Allow subscribing to lease lifecycle events (revoke / expire)
path "sys/events/subscribe/lease*" {
capabilities = ["read"]
}
Step 2: Enable instant updates on the VaultDynamicSecret
Set syncConfig.instantUpdates: true in the VaultDynamicSecret spec.
Do not set allowStaticCreds: true for dynamic lease credentials:
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
namespace: vso-example
name: vault-dynamic-secret-db
spec:
vaultAuthRef: vault-auth
mount: database
path: creds/my-postgresql-role
destination:
create: true
name: dynamic-db-secret
syncConfig:
instantUpdates: true
For other engines that emit their own engine-specific events, replace the engine-specific paths and event type in the database policy with the equivalents for your engine:
| Engine | Secret paths | Event subscription path and type |
|---|---|---|
| LDAP | ldap/* | sys/events/subscribe/ldap*; subscribe_event_types = ["ldap*"] |
| Azure | azure/creds/*, azure/roles/* | sys/events/subscribe/azure*; subscribe_event_types = ["azure*"] |
Debugging
Check Kubernetes events on the resource to see if VSO subscribed to Vault event notifications successfully.
Example: Check for a subscription to Vault event notifications
$ kubectl describe vaultstaticsecret vault-static-secret-v2 -n vso-example
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SecretSynced 2s VaultStaticSecret Secret synced
Normal EventWatcherStarted 2s (x2 over 2s) VaultStaticSecret Started watching events
Normal SecretRotated 2s VaultStaticSecret Secret synced
For a VaultDynamicSecret with instantUpdates: true, the event message
includes the engine type resolved at runtime:
$ kubectl describe vaultdynamicsecret vault-dynamic-secret-db -n vso-example
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SecretSynced 5s VaultDynamicSecret Secret synced
Normal EventWatcherStarted 5s VaultDynamicSecret Started watching database events
Example: The VaultAuth role policy lacks the required event permissions
$ kubectl describe vaultstaticsecret vault-static-secret-v2 -n vso-example
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SecretSynced 2s VaultStaticSecret Secret synced
Warning EventWatcherError 2s VaultStaticSecret Error while watching events:
failed to connect to vault websocket: error returned when opening event stream
web socket to wss://vault.vault.svc.cluster.local:8200/v1/sys/events/subscribe/kv%2A?json=true,
ensure VaultAuth role has correct permissions and Vault Enterprise is version
1.13 or above: {"errors":["1 error occurred:\n\t* permission denied\n\n"]}
Normal SecretRotated 2s VaultStaticSecret Secret synced
Example: VSO cannot resolve the mount type for a VaultDynamicSecret
If the VaultAuth policy is missing sys/mounts/* read permission, VSO emits:
$ kubectl describe vaultdynamicsecret vault-dynamic-secret-db -n vso-example
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning EventWatcherError 2s VaultDynamicSecret Cannot determine Vault mount type
for "database": permission denied. Ensure the VaultAuth policy grants read on
sys/mounts/*. Engine-event subscription skipped; will retry next reconcile.
Add path "sys/mounts/*" { capabilities = ["read"] } to the VaultAuth policy
to resolve this.