feat(kernel-deploy): admit the repartition workflow's agent pods #250

Merged
binjovi-bot merged 1 commit from feat/repartition-admission into trunk 2026-09-04 11:00:04 +00:00
Owner

pipeline-repartition-node (sean/pipelines) gives each worker's whole disk tail to ZFS. It uses the same one-shot privileged agent pattern as the kernel roll — pinned image, nodeName set, hostNetwork, no volumes, no SA token — and satisfies every validation in this policy. It just isn't named as a creator.

kernel-deploy-guard is failurePolicy: Fail, so this must land and converge before the workflow runs. The failure mode of getting the order wrong is the good one: an unlisted creator is denied at the first agent pod, which is the preflight, before anything is cordoned or drained.

Why a separate ServiceAccount

Not a wider role on the existing one. The kernel roll runs unattended — its Environment is approvalMode: automatic, so nobody looks between nodes. "May reboot a node" and "may delete any PersistentVolume in the cluster" are different powers and must not share a subject.

The storage verbs live only on the repartition SA, and that role has no nodes: delete either — a repartitioned node keeps its identity.

The RoleBinding moves with the policy in the same commit: admission permission alone isn't enough, because without the second subject a create is 403'd by RBAC before the VAP is ever consulted.

The contract test was weaker than it claimed

tests/kernel-deploy-agent-contract.sh grepped for the literal string pipeline-deploy-kernel. That keeps passing while the creator list is widened to anything at all — a guard reporting a restriction it no longer checks.

It now pins the creator set exactly, and asserts the match is an in [...] literal list rather than a prefix or regex:

creators="$(grep -oE "system:serviceaccount:[a-z0-9-]+:[a-z0-9-]+" "$manifest" | sort -u ...)"
[ "$creators" = "$expected" ] || fail "VAP creator list changed: ..."

Verified by mutation — slipping in a third ServiceAccount turns it red:

FAIL: VAP creator list changed: expected exactly [...deploy-kernel ...repartition-node ]
      but found [system:serviceaccount:default:sneaky ...]

Checks

bash tests/check.sh exits 0. kustomize build kubernetes/flux/infrastructure/kernel-deploy renders 7 objects.

https://claude.ai/code/session_01MdSbMhzabSbpG8TtP9Ur3H

`pipeline-repartition-node` (sean/pipelines) gives each worker's whole disk tail to ZFS. It uses the **same** one-shot privileged agent pattern as the kernel roll — pinned image, `nodeName` set, `hostNetwork`, no volumes, no SA token — and satisfies every validation in this policy. It just isn't named as a creator. `kernel-deploy-guard` is `failurePolicy: Fail`, so **this must land and converge before the workflow runs.** The failure mode of getting the order wrong is the good one: an unlisted creator is denied at the *first* agent pod, which is the preflight, before anything is cordoned or drained. ## Why a separate ServiceAccount Not a wider role on the existing one. The kernel roll runs **unattended** — its Environment is `approvalMode: automatic`, so nobody looks between nodes. "May reboot a node" and "may delete any PersistentVolume in the cluster" are different powers and must not share a subject. The storage verbs live only on the repartition SA, and that role has no `nodes: delete` either — a repartitioned node keeps its identity. The RoleBinding moves with the policy in the same commit: admission permission alone isn't enough, because without the second subject a create is 403'd by RBAC before the VAP is ever consulted. ## The contract test was weaker than it claimed `tests/kernel-deploy-agent-contract.sh` grepped for the literal string `pipeline-deploy-kernel`. That keeps passing while the creator list is widened to **anything at all** — a guard reporting a restriction it no longer checks. It now pins the creator set **exactly**, and asserts the match is an `in [...]` literal list rather than a prefix or regex: ``` creators="$(grep -oE "system:serviceaccount:[a-z0-9-]+:[a-z0-9-]+" "$manifest" | sort -u ...)" [ "$creators" = "$expected" ] || fail "VAP creator list changed: ..." ``` Verified by mutation — slipping in a third ServiceAccount turns it red: ``` FAIL: VAP creator list changed: expected exactly [...deploy-kernel ...repartition-node ] but found [system:serviceaccount:default:sneaky ...] ``` ## Checks `bash tests/check.sh` exits 0. `kustomize build kubernetes/flux/infrastructure/kernel-deploy` renders 7 objects. https://claude.ai/code/session_01MdSbMhzabSbpG8TtP9Ur3H
feat(kernel-deploy): admit the repartition workflow's agent pods
All checks were successful
binjovi/ci Binjovi completed the frozen plan
cfea079cf2
pipeline-repartition-node gives each worker's whole disk tail to ZFS. It
uses the same one-shot privileged agent pattern as the kernel roll — pinned
image, nodeName set, hostNetwork, no volumes, no SA token — and satisfies
every validation in this policy. It just is not named as a creator.

kernel-deploy-guard is failurePolicy: Fail, so this must land and converge
BEFORE the workflow runs. The failure mode of getting the order wrong is
good: an unlisted creator is denied at the FIRST agent pod, which is the
preflight, before anything is cordoned or drained.

A SEPARATE ServiceAccount, not a wider role on the existing one. The kernel
roll runs unattended: its Environment is approvalMode: automatic, so nobody
looks between nodes. "May reboot a node" and "may delete any
PersistentVolume in the cluster" are different powers and must not share a
subject. The storage verbs live only on the repartition SA, in sean/pipelines
infra/workflows/repartition-node-rbac-bare.yaml, and that role has no
nodes: delete either.

The RoleBinding moves with the policy. Admission permission alone is not
enough — without the second subject a create is 403'd by RBAC before the VAP
is ever consulted.

tests/kernel-deploy-agent-contract.sh is strengthened, not just updated. It
grepped for the literal string pipeline-deploy-kernel, which would have kept
passing while the creator list was widened to anything at all — a guard
reporting a restriction it no longer checked. It now pins the creator set
EXACTLY and asserts the match is an `in [...]` list rather than a prefix or
regex. Verified by mutation: adding a third ServiceAccount turns it red.

tests/check.sh exits 0.

Claude-Session: https://claude.ai/code/session_01MdSbMhzabSbpG8TtP9Ur3H
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
sean/seanfarm!250
No description provided.