fix: respect user-provided container capabilities under PodSecurity restricted#176
Open
1fanwang wants to merge 2 commits intoClickHouse:mainfrom
Open
fix: respect user-provided container capabilities under PodSecurity restricted#1761fanwang wants to merge 2 commits intoClickHouse:mainfrom
1fanwang wants to merge 2 commits intoClickHouse:mainfrom
Conversation
…estricted Strategic merge patch on corev1.Capabilities deep-merges Add and Drop independently, so a user setting only `drop: [ALL]` leaves the operator-defaulted `add: [IPC_LOCK, PERFMON, SYS_PTRACE]` in place — which the `restricted` PodSecurity profile rejects. Treat user-provided Capabilities as authoritative for the whole sub-struct by clearing it on the base before the merge, while keeping deep-merge semantics for the rest of SecurityContext. Fixes ClickHouse#174
6043e38 to
fab9810
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes how container Linux capabilities are merged when applying containerTemplate overrides, ensuring user-provided securityContext.capabilities fully overrides operator-defaulted capabilities so pods can start under the Kubernetes PodSecurity restricted standard.
Changes:
- Update
ApplyContainerTemplateOverridesto clear the base container’sSecurityContext.Capabilitieswhenever the user provides their ownCapabilities, preventing Strategic Merge Patch from deep-mergingAddlists. - Add a focused test suite covering the original bug repro, replacement semantics, preservation semantics, and non-mutation of caller-owned pointers.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
internal/controller/overrides.go |
Makes user-provided Capabilities authoritative by pre-clearing base capabilities before SMP merge. |
internal/controller/overrides_test.go |
Adds tests validating capabilities override behavior and ensuring inputs aren’t mutated. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
#174 reports that ClickHouseCluster / KeeperCluster pods fail to start in namespaces that enforce the
restrictedPodSecurity Standard. SettingcontainerTemplate.securityContext.capabilities.drop: [ALL]is expected to leave the merged container with noaddcapabilities, but the operator-defaultedadd: [IPC_LOCK, PERFMON, SYS_PTRACE]survives the merge — andrestrictedforbids anyaddoutsideNET_BIND_SERVICE.What
ApplyContainerTemplateOverridesininternal/controller/overrides.gomerges the user-suppliedContainerTemplateSpeconto the operator-built container via Strategic Merge Patch (SMP) withcorev1.Containersemantics. SMP deep-merges nested structs field-by-field unless the schema carries apatchStrategy=replacedirective — andcorev1.Capabilitiescarries none. So a patch of{Capabilities: {Drop: [ALL]}}over a base of{Capabilities: {Add: [IPC_LOCK, PERFMON, SYS_PTRACE]}}yields a merged{Capabilities: {Add: [IPC_LOCK, PERFMON, SYS_PTRACE], Drop: [ALL]}}. PodSecurity then rejects the pod.(The issue points at
ApplyDefault, butdefaultSpecinkeepercluster_types.goandclickhousecluster_types.gocarries noSecurityContext— the operator-defaultedAddis set ininternal/controller/{clickhouse,keeper}/templates.goand survives via SMP inoverrides.go. Same observable symptom; the fix lives at the merge boundary.)This change pre-clears the base container's
Capabilitieswhen the spec author supplies their own, making user-providedCapabilitiesauthoritative for the whole sub-struct. OtherSecurityContextfields (runAsUser,runAsNonRoot, …) still deep-merge as before.Tests
Added
Describe("Capabilities")ininternal/controller/overrides_test.go:Drop:[ALL]against operator-defaultedAdd:[IPC_LOCK,…]→ merged has emptyAddandDrop:[ALL]. Fails onmain.Add:[NET_BIND_SERVICE]replaces operatorAdd:[IPC_LOCK,…]rather than merging.SecurityContextwithoutCapabilitiespreserves operator defaults.*Containerand*SecurityContextpointers are not mutated.Local checks:
make lint-fix(0 issues),go test ./internal/controller/ -count=1(all pass), andgo test ./internal/controller/clickhouse/ -count=1 --ginkgo.label-filter='!integration'(all pass). Skipped[integration]-labelled tests because they require a local Docker daemon; nothing in this change touches that path.Happy to iterate on the choice of merge-boundary fix vs. an alternative like adding a
patchStrategy=replacedirective — went with the boundary fix because it's contained to the operator and doesn't depend on upstream schema changes.Related Issues
Fixes #174