New to KubeVault? Please start here.
Manage Weaviate credentials using the KubeVault operator
OpenBao’s weaviate-database-plugin manages dynamic credentials for Weaviate self-hosted using Weaviate’s User Management and RBAC REST APIs. When a client requests credentials, OpenBao creates a new database user in Weaviate, assigns the roles specified in creationStatements, and returns the dynamic username and generated API key. When the credential lease expires or is revoked, OpenBao deletes the user from Weaviate, immediately revoking access.
The same CRD shape is used both for the in-process weaviate-database-plugin and for the hub-spoke remote-weaviate-plugin; the difference is whether the Vault AppBinding referenced by SecretEngine.spec.vaultRef is marked deploymentMode: RemoteAgent (then the SecretEngine controller rewrites plugin_name to remote-weaviate-plugin and attaches spoke_name).
You need to be familiar with the following CRDs:
Before you begin
- Install KubeVault operator in your cluster from here.
- Provision a Weaviate deployment with API-key authentication and RBAC enabled (
AUTHENTICATION_DB_USERS_ENABLED=trueandAUTHORIZATION_ENABLE_RBAC=true). - Create a namespace for testing:
$ kubectl create ns demo
namespace/demo created
Vault Server
Deploy a Vault Server using the KubeVault operator: Deploy Vault Server. The KubeVault operator will create an AppBinding wiring up Kubernetes auth.
$ kubectl get appbinding -n demo vault -o yaml
AppBinding for Weaviate
Create an AppBinding pointing at the Weaviate HTTP endpoint. The secret’s AUTHENTICATION_APIKEY_ALLOWED_KEYS field carries the Weaviate admin API key (root user) — KubeVault forwards it to the plugin as api_key=, which the plugin uses to authenticate against /v1/.well-known/ready and call Weaviate’s User Management and RBAC APIs.
apiVersion: appcatalog.appscode.com/v1alpha1
kind: AppBinding
metadata:
name: weaviate
namespace: demo
spec:
clientConfig:
url: https://weaviate.demo.svc:8080
secret:
kind: Secret
name: weaviate-auth
---
apiVersion: v1
kind: Secret
metadata:
name: weaviate-auth
namespace: demo
type: Opaque
stringData:
AUTHENTICATION_APIKEY_ALLOWED_KEYS: <weaviate-admin-api-key>
Note: If Weaviate runs with mTLS, specify client certificates in the AppBinding or secret.
Enable and configure the Weaviate secret engine
apiVersion: engine.kubevault.com/v1alpha1
kind: SecretEngine
metadata:
name: weaviate-engine
namespace: demo
spec:
vaultRef:
name: vault
weaviate:
databaseRef:
name: weaviate
namespace: demo
pluginName: weaviate-database-plugin
allowedRoles:
- "*"
Apply and wait for the engine to land:
$ kubectl apply -f weaviate-secret-engine.yaml
secretengine.engine.kubevault.com/weaviate-engine created
$ kubectl get secretengines -n demo
NAME STATUS AGE
weaviate-engine Success 10s
Behind the scenes the KubeVault operator writes:
bao write database/config/k8s.<cluster>.demo.weaviate \
plugin_name=weaviate-database-plugin \
url=https://weaviate.demo.svc:8080 \
api_key=<weaviate-api-key> \
allowed_roles="*"
When the referenced AppBinding is deploymentMode: RemoteAgent, the operator substitutes plugin_name=remote-weaviate-plugin and adds spoke_name=<spoke> so the hub forwards the call to the matching bao relay run daemon.
Create a WeaviateRole
Define dynamic permissions for the role using creationStatements:
apiVersion: engine.kubevault.com/v1alpha1
kind: WeaviateRole
metadata:
name: app
namespace: demo
spec:
secretEngineRef:
name: weaviate-engine
defaultTTL: 24h
maxTTL: 168h
creationStatements:
- |
{
"roles": [
"viewer"
]
}
Custom roles can also be defined inline under custom_roles:
creationStatements:
- |
{
"roles": [
"viewer"
],
"custom_roles": [
{
"name": "customrole",
"permissions": [
{
"action": "read_data",
"collections": {
"collection": "Products"
}
}
]
}
]
}
$ kubectl apply -f weaviate-role.yaml
weaviaterole.engine.kubevault.com/app created
$ kubectl get weaviaterole -n demo
NAME STATUS AGE
app Success 8s
Generate dynamic credentials via SecretAccessRequest
To generate dynamic credentials, create a SecretAccessRequest:
apiVersion: engine.kubevault.com/v1alpha1
kind: SecretAccessRequest
metadata:
name: weaviate-credentials
namespace: demo
spec:
roleRef:
kind: WeaviateRole
name: app
subjects:
- kind: ServiceAccount
name: demo-sa
namespace: demo
ttl: 1h
$ kubectl apply -f secret-access-request.yaml
secretaccessrequest.engine.kubevault.com/weaviate-credentials created
Wait for the request to be approved:
$ kubectl get secretaccessrequest -n demo weaviate-credentials
NAME STATUS SECRET AGE
weaviate-credentials Approved weaviate-credentials-xyz123 10s
Inspect the issued credentials
Extract the generated credentials from the Kubernetes Secret:
$ SECRET_NAME=$(kubectl get secretaccessrequest weaviate-credentials -n demo -o jsonpath='{.status.secret.name}')
$ kubectl get secret $SECRET_NAME -n demo -o yaml
apiVersion: v1
data:
password: <base64-encoded-api-key>
username: <base64-encoded-username>
kind: Secret
...
The Secret contains:
username: Unique dynamic username (e.g.v-kubernet-k8s...).password: Dynamic API key generated by Weaviate for this user.
Clients present this key to Weaviate in the Authorization: Bearer <token> header.
Revocation
When the SecretAccessRequest is deleted or the lease TTL expires, KubeVault revokes the lease in OpenBao. OpenBao deletes the user from Weaviate, immediately revoking access.
$ kubectl delete secretaccessrequest -n demo weaviate-credentials
Cleanup
$ kubectl delete weaviaterole -n demo app
$ kubectl delete secretengine -n demo weaviate-engine








