Skip to content

fix(storagenode): self-heal storage node ServiceAccount token expiration - #535

Closed
boddumanohar wants to merge 2 commits into
mainfrom
fix/storagenode-deletion-satoken-selfheal
Closed

boddumanohar wants to merge 2 commits into
mainfrom
fix/storagenode-deletion-satoken-selfheal

Conversation

@boddumanohar

@boddumanohar boddumanohar commented Sep 14, 2026

Copy link
Copy Markdown
Member

Split out of #437 (lblk device-mode support): found while testing that work on config-israel, but unrelated to lblk itself.

Storage node ServiceAccount token expiration

The storage node pods used Kubernetes' default auto-injected ServiceAccount token, which lives roughly an hour. If simplyblock-storage-node-sa was ever deleted, every already-running pod kept its stale token until the hour expired, then started failing API calls with 401 — recoverable only by deleting every pod by hand.

Root cause: reconcileRBAC gave the shared simplyblock-storage-node-sa ServiceAccount a controller owner reference to whichever StorageNodeSet last reconciled it, even though the ServiceAccount is shared by every StorageNodeSet in the namespace (e.g. one StorageNodeSet per storage cluster, a supported topology). Deleting any StorageNodeSet that currently owned it — not necessarily the one being decommissioned — cascade-deleted the ServiceAccount via Kubernetes garbage collection, taking every other StorageNodeSet's pods' tokens down with it. reconcileRBAC now clears any owner reference on the ServiceAccount instead of setting one, matching the ClusterRole/ClusterRoleBinding it builds alongside it, which never carried one.

Defense in depth: pods now also mount an explicit ten-minute projected token instead of the default hour-long one (AutomountServiceAccountToken: false, with a kube-api-access-short projected volume built to match the shape of Kubernetes' own auto-injected one). kubelet refreshes a projected token at ~80% of its expiration, so if the ServiceAccount is ever recreated for any other reason, pods self-heal within minutes instead of up to an hour.

🤖 Generated with Claude Code

Storage node pods used Kubernetes' default auto-injected ServiceAccount
token, which lives roughly an hour. If simplyblock-storage-node-sa was
ever deleted and recreated (e.g. during a chart upgrade), every
already-running pod kept its stale token until the hour expired, then
started failing API calls with 401 — recoverable only by deleting every
pod by hand.

Pods now mount an explicit ten-minute projected token instead
(AutomountServiceAccountToken: false, with a kube-api-access-short
projected volume built to match the shape of Kubernetes' own
auto-injected one). kubelet refreshes a projected token at ~80% of its
expiration, so a ServiceAccount recreation now self-heals within
minutes.

Found while testing #437's lblk device-mode work on config-israel, but
unrelated to lblk itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@boddumanohar
boddumanohar force-pushed the fix/storagenode-deletion-satoken-selfheal branch from d22b209 to c7610e4 Compare September 15, 2026 08:48
@boddumanohar boddumanohar changed the title fix(storagenode): finalize deletion when parent StorageNodeSet is gone, self-heal SA token fix(storagenode): self-heal storage node ServiceAccount token expiration Sep 15, 2026
…t to one StorageNodeSet

reconcileRBAC gave "simplyblock-storage-node-sa" a controller owner
reference to whichever StorageNodeSet last reconciled it, even though
the ServiceAccount is shared by every StorageNodeSet in the namespace
(e.g., one StorageNodeSet per storage cluster, a supported topology).
Deleting any StorageNodeSet that currently owned it, regardless of
whether that StorageNodeSet was itself the one being decommissioned,
cascade-deleted the ServiceAccount via Kubernetes garbage collection
and took every other StorageNodeSet's pods' tokens down with it. This
is the actual root cause behind the SA token expiring and needing a
manual pod-by-pod restart to recover, previously worked around by
shortening the token TTL alone.

The ClusterRole and ClusterRoleBinding built by the same function
already carry no owner reference, for the same reason. The
ServiceAccount now matches: reconcileRBAC clears any owner reference on
apply instead of setting one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant