Skip to content

fix(security): declare the C-0211 baseline context on the Hetzner CSI workloads - #3878

Merged
devantler merged 2 commits into
mainfrom
claude/c0211-hcloud-csi-3239
Sep 17, 2026
Merged

devantler merged 2 commits into
mainfrom
claude/c0211-hcloud-csi-3239

Conversation

@devantler

Copy link
Copy Markdown
Contributor

🤖 Generated by the Agentic Engineer

Motivation

Our cluster-security scan flags every workload in kube-system for two missing
declarations, because that namespace is deliberately excluded from the mutation that
supplies them everywhere else. The exclusion exists to protect privilege settings, but
these two fields are not privilege settings — so the scan has been reporting a gap we
never needed to have.

Changes

Declares the two fields on both Hetzner CSI workloads (the node agent and the controller),
clearing 2 of the 13 remaining kube-system workloads. The values are chosen so nothing
about how these pods run actually changes: one field is provably a no-op for the volume
types these pods use, and the other declares the setting while leaving SELinux entirely to
the runtime, exactly as today.

No operational action needed. Pods restart once as the change rolls out.

Part of #3239

… workloads

kube-system is excluded from add-security-context, so both Hetzner CSI
workloads miss the two field gaps that account for C-0211's whole residual
population: fsGroupChangePolicy on the pod spec, and seLinuxOptions on every
container. Chart 2.23.0 exposes only `enabled` and `fsGroup` under
podSecurityContext and no container securityContext at all, so both fields are
post-rendered.

OnRootMismatch is inert for both workloads. The node DaemonSet mounts only
hostPath volumes, and kubelet never applies fsGroup ownership management to
hostPath. The controller's one volume is an emptyDir, created root-owned on
every pod start, so the root GID always mismatches and kubelet performs exactly
the same recursive chown it performs today.

The empty seLinuxOptions object declares the field without pinning a type,
level or MCS category, so every container keeps the runtime's own SELinux
defaults -- including the privileged hcloud-csi-driver container, whose
existing `privileged: true` the patch preserves.

Part of #3239

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ost-renderer

The hcloud-csi HelmRelease is a controller-RBAC emitter, so adding post-renderer
patches to it moves the pinned aggregate even though nothing is granted.

Conservation against main 20240da: 573 rendered identities per side with an
identical sorted identity list; exactly one rendered document differs, and it is
the hcloud-csi HelmRelease, whose only delta is the postRenderers block this
branch adds. All 94 grant-bearing ClusterRole, Role, ClusterRoleBinding,
RoleBinding and ServiceAccount documents hash byte-identically on both sides,
and appending one synthetic ClusterRole to the branch render changes that hash,
so the identical result is a finding rather than a blind read.

The new aggregate was read from CI's own failure on job 105324573289.

Part of #3239

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

@devantler I will review the changes.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Advanced

Run ID: c3e68f68-f655-4b68-a5f4-1731fa7c67d2

📥 Commits

Reviewing files that changed from the base of the PR and between 20240da and aec94a3.

📒 Files selected for processing (2)
  • k8s/providers/hetzner/infrastructure/controllers/hcloud-csi/helm-release.yaml
  • scripts/validate-eks-ci-role-policy/main.go

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
🔇 Additional comments (2)
k8s/providers/hetzner/infrastructure/controllers/hcloud-csi/helm-release.yaml (1)

136-198: LGTM!

scripts/validate-eks-ci-role-policy/main.go (1)

2578-2605: LGTM!

Also applies to: 2618-2618


📝 Walkthrough

Walkthrough

The Hetzner CSI HelmRelease now uses a Kustomize post-renderer to patch pod and container security contexts for its DaemonSet and Deployment. The patches set fsGroupChangePolicy: OnRootMismatch and add empty seLinuxOptions. The authorization-surface validator records the change and updates the approved rendered-surface fingerprints.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to aec94

The Hetzner CSI security-context declarations and their approved rendered-surface fingerprint update are consistent with the stated change. No actionable merge risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the security-related change and the affected Hetzner CSI workloads.
Description check ✅ Passed The description explains the motivation, affected workloads, declared fields, behavior, rollout impact, and related issue. It directly matches the changeset.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

@devantler I will review the changes.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Readiness at aec94a3f29f57ef1600adc59b45ebcc67989d286

1. Programmatically tested. All required checks green at this head (30 total: 23 success,
7 skipped, 0 failing). The three that matter here:

  • 🔐 Validate Production Authorization = SUCCESS — it ran and passed, i.e. the in-PR
    fingerprint re-approval (a4781e58) is accepted, not skipped.
  • 🧪 Validate Manifests = SUCCESS
  • CI - Required Checks = SUCCESS

2. Reviewed. CodeRabbit green at this exact head: its auto-generated summary names
aec94a3f29f57ef1600adc59b45ebcc67989d286 and states "No actionable comments were generated in the
recent review"; the head's CodeRabbit commit status reads Review completed (20:17:58Z), so a
review genuinely ran rather than being skipped or rate-limited. Its own note on the change:
"The Hetzner CSI security-context declarations and their approved rendered-surface fingerprint
update are consistent with the stated change. No actionable merge risk remains."
Review threads: 0 total, 0 unresolved (paginated, fetched == totalCount). No non-thread
finding sections.

3. Tried and evaluated as a user. For a GitOps manifest change the cluster applies exactly the
rendered output, so the patched render is the surface that actually observes the effect, and it was
exercised rather than reasoned about — recorded earlier on this PR: the patched-vs-unpatched render
diff is exactly the 10 intended additions (fsGroupChangePolicy: OnRootMismatch plus per-container
seLinuxOptions: {} across the node DaemonSet's 3 containers and the controller Deployment's 5),
with privileged: true preserved on the node plugin container, and ksail workload validate rc=0 for
both the local and prod configs.

One thing worth stating plainly, because it is the part a reader should not take on trust:
OnRootMismatch is inert for these two workloads today. The node DaemonSet mounts only
hostPath volumes, and the kubelet never applies fsGroup ownership to hostPath; the controller's
single volume is an emptyDir, which is root-owned at every start so the GID always mismatches and
the same chown happens either way. The field is declared so the C-0211 baseline is explicit and a
future volume type inherits the right policy — it is not expected to change behaviour now.

Live post-merge verification (DaemonSet/Deployment template fields present, rollouts Ready, restart
counts) follows the same pattern as #3874 / #3875 / #3876 and will be recorded on #3239.

@devantler
devantler marked this pull request as ready for review September 17, 2026 20:21
@devantler
devantler added this pull request to the merge queue Sep 17, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 17, 2026
@devantler
devantler added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit eea5453 Sep 17, 2026
30 checks passed
@devantler
devantler deleted the claude/c0211-hcloud-csi-3239 branch September 17, 2026 21:16
@github-project-automation github-project-automation Bot moved this from 🫴 Ready to ✅ Done in 🌊 Project Board Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

1 participant