Skip to content

Commit df70e5f

Browse files
committed
fix(services/keycloak): refresh bootstrap credentials when secret rotates server-side
1 parent 623cb4c commit df70e5f

2 files changed

Lines changed: 23 additions & 9 deletions

File tree

services/keycloak/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,12 @@ realm). The pairing offers two paths:
5454
`admin` composite role, and persists the
5555
resulting `client_id`/`client_secret` 0600 under
5656
`/var/lib/declarative-keycloak-bootstrap/`. The reconciler picks them up
57-
via systemd `LoadCredential=` on every run; the file pair is the
58-
"already bootstrapped" marker, so the oneshot is a no-op on subsequent
59-
boots.
57+
via systemd `LoadCredential=` on every run. On subsequent boots the
58+
oneshot probes the saved pair against keycloak's token endpoint --
59+
if the secret has been rotated server-side (e.g. through the admin
60+
console) the pair is refreshed in place from the existing client.
61+
Recovery is therefore a `systemctl restart declarative-keycloak-bootstrap`
62+
away.
6063

6164
2. **Operator-supplied.** Set both `clientIdFile` and `clientSecretFile` to
6265
host paths for a service-account client you've created externally. The

services/keycloak/module.nix

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,6 @@ in
182182
client_id_file="$STATE_DIRECTORY/client_id"
183183
client_secret_file="$STATE_DIRECTORY/client_secret"
184184
185-
# the saved credential pair is the "already bootstrapped"
186-
# marker. /var/lib persists across reboots.
187-
if [ -s "$client_id_file" ] && [ -s "$client_secret_file" ]; then
188-
exit 0
189-
fi
190-
191185
# wait up to 3 minutes for keycloak to come up.
192186
for _ in $(seq 1 90); do
193187
if curl -fsS -o /dev/null "${cfg.baseUrl}/realms/master"; then
@@ -196,6 +190,23 @@ in
196190
sleep 2
197191
done
198192
193+
# saved credential pair exists -- probe it against the token
194+
# endpoint. valid means already-bootstrapped; otherwise the
195+
# secret has been rotated server-side and we fall through to
196+
# re-fetch the current one (same client, same id).
197+
if [ -s "$client_id_file" ] && [ -s "$client_secret_file" ]; then
198+
saved_id="$(cat "$client_id_file")"
199+
saved_secret="$(cat "$client_secret_file")"
200+
if curl -fsS -o /dev/null -X POST \
201+
${lib.escapeShellArg "${cfg.baseUrl}/realms/master/protocol/openid-connect/token"} \
202+
--data-urlencode 'grant_type=client_credentials' \
203+
--data-urlencode "client_id=$saved_id" \
204+
--data-urlencode "client_secret=$saved_secret"; then
205+
exit 0
206+
fi
207+
echo "saved service-account credentials no longer accepted; refreshing from keycloak admin." >&2
208+
fi
209+
199210
kcadm.sh config credentials \
200211
--server ${lib.escapeShellArg cfg.baseUrl} \
201212
--realm master \

0 commit comments

Comments
 (0)