Why
Part of the self-service kubeconfig bootstrap initiative (tracking issue TBD, linked once created). Lets already-bootstrapped users refresh their local kubeconfig without a new bootstrap token, using the credential they already hold to authenticate — mirrors kubelet's client-certificate rotation pattern.
Scope
POST /sync on the gateway, requiring mTLS; extracts the CN from the presented client certificate.
- Verifies the presented cert against the cluster CA (reuse the CA-retrieval logic already in
internal/controller/certs), including a bounded grace period past NotAfter so renewal still works for certs that are already expired-but-recent.
- Looks up the
User matching the CN:
- not found or
deletionTimestamp set → distinct "user deleted" response, no retry-worthy signal
spec.auth.autoRenew == false → distinct "auto-renew disabled" response
- else → compare against a version/hash the client sends for what it currently holds; return the current
<username>-credentials secret only if changed
- Audit log every sync attempt and outcome.
Acceptance criteria
Depends on
#104 (gateway skeleton), #101 (single-credentials-secret shape)
Why
Part of the self-service kubeconfig bootstrap initiative (tracking issue TBD, linked once created). Lets already-bootstrapped users refresh their local kubeconfig without a new bootstrap token, using the credential they already hold to authenticate — mirrors kubelet's client-certificate rotation pattern.
Scope
POST /syncon the gateway, requiring mTLS; extracts the CN from the presented client certificate.internal/controller/certs), including a bounded grace period pastNotAfterso renewal still works for certs that are already expired-but-recent.Usermatching the CN:deletionTimestampset → distinct "user deleted" response, no retry-worthy signalspec.auth.autoRenew == false→ distinct "auto-renew disabled" response<username>-credentialssecret only if changedAcceptance criteria
autoRenew: falseuser → distinct blocked response, verified via test/syncreturns the new credentialsDepends on
#104 (gateway skeleton), #101 (single-credentials-secret shape)