Rotating Secrets
Rotate the OIDC client secrets in the boltmcp-oidc Secret and propagate the new values to Keycloak and the pods that use them.
The boltmcp-oidc Secret holds one client secret per confidential Keycloak client that BoltMCP authenticates as. Each value lives in two places: the Kubernetes Secret, which you manage, and the matching client inside Keycloak, which BoltMCP manages. Rotation means changing both. Helm does not watch the Secret's contents, and Kubernetes does not restart pods when a Secret changes, so a rotation is three deliberate steps.
| Key | Keycloak client | Restart after rotating |
|---|---|---|
web-client-secret | boltmcp-web | deployment/boltmcp-web |
mcp-server-client-secret | boltmcp-mcp-server | deployment/boltmcp-mcp-server |
rest-api-to-keycloak-client-secret | boltmcp-rest-api-to-keycloak | deployment/boltmcp-rest-api |
keycloak-reconcile-client-secret | boltmcp-keycloak-reconcile | none (used only by the keycloak-reconcile hook Job) |
Set Variables
export RELEASE=boltmcp
export NAMESPACE=boltmcp1. Update the Secret
Generate the new value and patch it into the Secret under the right key. A merge patch against stringData leaves the other keys untouched:
NEW_SECRET=$(openssl rand -hex 32)
kubectl patch secret ${RELEASE}-oidc -n ${NAMESPACE} --type merge -p "{
\"stringData\": { \"web-client-secret\": \"${NEW_SECRET:?not generated}\" }
}"If the Secret is populated from an external system (External Secrets Operator, Sealed Secrets, SOPS), change the value at the source instead and wait for the controller to sync it, or force a sync. Either way, confirm the Secret in the cluster carries the new value before continuing:
kubectl get secret ${RELEASE}-oidc -n ${NAMESPACE} \
-o go-template='{{range $k, $v := .data}}{{$k}}={{len $v}}{{"\n"}}{{end}}'2. Stamp the new value onto the Keycloak client
Re-run helm upgrade with your existing values and the unchanged chart version (see Manual Upgrade). Its keycloak-reconcile pre-upgrade hook reads the Secret and patches the matching Keycloak client to the new secret. The hook pod's log shows the change as client <id>: updated (secret).
Alternatively, set the new value by hand in the Keycloak admin console (boltmcp realm → Clients → the client → Credentials), then skip to step 3. The next helm upgrade finds the client already in sync.
3. Restart the consumers
Pods read the Secret only at startup. Restart the Deployment(s) listed in the table above for the key you rotated:
kubectl rollout restart -n ${NAMESPACE} deployment/${RELEASE}-webBetween steps 1 and 3 the running pods still hold the old value while Keycloak already expects the new one, so sign-ins and token refreshes for that client fail until the restart completes. Do steps 2 and 3 back to back.
Do the steps in this order. Restarting a pod before the Keycloak client is updated puts the new secret on the pod and the old one in Keycloak, which fails the same way. If a rotation has gone wrong, see Client Secret Mismatch.
Other Secrets
The boltmcp-database and boltmcp-auth Secrets are not covered here. Database passwords must also be changed in PostgreSQL (ALTER USER ... PASSWORD ...), and the Keycloak operator and first-user passwords are only read at Keycloak's first boot, so changing them in the Secret has no effect on an existing install. See Values-Only Changes for restarting the Deployments that consume a changed Secret.