ADR-080: Atomic Client Secret Rotation¶
Category: architecture Provenance: human
Decision¶
Implement atomic rotation for the standard client-secret authenticator without intrinsic grace periods. The operator will support a configurable rotation schedule (period + specific time window).
Rotation involves: 1. Operator calculates eligibility based on the keycloak-operator/rotated-at annotation on the K8s Secret. 2. Operator calls Keycloak API to regenerate the secret (invalidating the old one immediately). 3. Operator updates the K8s Secret with the new value.
To handle the immediate invalidation ("Atomic Rotation"), we rely on external "Day 2" operational tools like Stakater Reloader or Kyverno to detect the K8s Secret change and trigger a rolling restart of the dependent applications.
Rationale¶
Keycloak's client-secret authenticator is a shared secret mechanism that does not support history or multiple active values. The only way to support true grace periods is to switch to private_key_jwt (JWKS), which requires significant changes to the consuming applications (JWT signing vs simple password).
To provide rotation capabilities for the vast majority of users who use standard client secrets, we accept the constraint of atomic rotation and mitigate the impact via standard Kubernetes rollout mechanisms (Reloader).
Agent Instructions¶
When implementing secret rotation, ensure you strictly adhere to the client-secret mechanism. Do not attempt to implement "grace periods" by storing multiple secrets, as Keycloak does not support this for this authenticator type. Direct users to use Reloader or Kyverno in the documentation. Use pytz or zoneinfo for robust timezone handling when scheduling rotations.
Rejected Alternatives¶
Store previous secret in K8s¶
Pointless complexity. Keycloak invalidates the old secret immediately upon regeneration, so the 'previous' secret stored in K8s would be useless for authentication.
Switch default to private_key_jwt¶
Too invasive. It changes the authentication protocol for the application, breaking existing deployments.