Skip to content

fix(security): harden containers with read-only root filesystems (Kubescape C-0017)#2455

Merged
devantler merged 3 commits into
mainfrom
claude/security-context-readonly-rootfs
Jul 4, 2026
Merged

fix(security): harden containers with read-only root filesystems (Kubescape C-0017)#2455
devantler merged 3 commits into
mainfrom
claude/security-context-readonly-rootfs

Conversation

@devantler

Copy link
Copy Markdown
Contributor

🤖 Generated by the Daily AI Assistant

Why: Kubescape control C-0017 (immutable container filesystem) was failing cluster-wide. The platform suppressed the finding with a blanket exception instead of actually hardening the workloads, so several apps genuinely ran with a writable root filesystem. Investigating also surfaced a live bug — the UniFi Crossplane provider is currently failing to reconcile (its cluster-wireguard resource is unsynced) because its read-only root has no writable temp dir.

What: Give a genuine read-only root filesystem (with only the minimal writable mounts each app truly needs) to every workload that tolerates it — homepage, umami, actual-budget, backstage, crossview (+ its bundled Postgres), ascoachingogvaner, and the four Crossplane providers — so C-0017 passes for real rather than being suppressed. The blanket exception is narrowed to only the genuinely-incompatible cases: opencost's nginx UI (rewrites its baked assets on boot — upstream bug) and wedding-app (securityContext lives in its own repo), plus the privileged infra namespaces. Adding a writable /tmp to the UniFi provider also fixes its stalled reconciliation.

Each workload's writable-path list was researched against its live image and adversarially verified not to crash the app.

Operational notes (post-promotion):

  • Direct-merge after promotion (own PR).
  • Verify the UniFi provider's cluster-wireguard flips to SYNCED=True once the new DeploymentRuntimeConfig rolls out.
  • Follow-up: harden wedding-app in its own repo (readOnlyRootFilesystem + /tmp), then drop it from the pending exception.

…escape C-0017)

Set readOnlyRootFilesystem: true (plus the minimal writable emptyDir mounts each
workload genuinely needs) on every non-privileged workload that tolerates it —
homepage, umami, actual-budget, backstage, crossview + its bundled Postgres,
ascoachingogvaner, and the four Crossplane providers — so Kubescape C-0017 passes
for real instead of being suppressed by a blanket exception.

Narrow the exception layer: drop C-0017 from the cluster-wide pod-security-mutations
exception (now set in-spec), add the kubescape namespace to infrastructure-privileged
(its node-agent + storage APIserver genuinely need host/writable access), and scope
the remaining C-0017 exception (readonly-rootfs-pending) to just opencost (its nginx
UI rewrites baked /var/www assets on boot — opencost/opencost#2655) and wedding-app
(securityContext lives in its own OCI artifact — app-repo follow-up).

Adding a writable /tmp emptyDir to provider-upjet-unifi's DeploymentRuntimeConfig
also fixes its currently-stalled reconciliation (cluster-wireguard SYNCED=False:
"mkdir /tmp/<uuid>: read-only file system"). Crossplane appends its TLS/SA volumes
after the DRC template, so the emptyDir coexists with them.

Each workload's writable-path list was researched against its live image and
adversarially verified not to crash the app. Both overlays validate
(ksail workload validate).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4af946fa-adeb-420c-99d3-30f89f506c8e

📥 Commits

Reviewing files that changed from the base of the PR and between 4916a63 and 930fc64.

📒 Files selected for processing (6)
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • devantler-tech/actions (auto-detected)
  • devantler-tech/aws (auto-detected)
  • devantler-tech/reusable-workflows (auto-detected)
  • devantler-tech/ksail (auto-detected)
  • devantler-tech/ascoachingogvaner (auto-detected)
  • devantler-tech/wedding-app (auto-detected)
  • devantler-tech/agent-skills (auto-detected)
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{yaml,yml}: Use Kustomize overlays rather than editing base resources directly; k8s/bases/ is immutable from overlays and changes should be made with patches: in provider or cluster overlays.
Keep manifest changes small and use YAML/schema validation before submitting a manifest PR; for files with cluster context, prefer ksail workload validate / kubectl kustomize / kubectl apply --dry-run=client as appropriate.

Files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
k8s/**

📄 CodeRabbit inference engine (AGENTS.md)

k8s/**: Respect Flux dependency order: bootstrapinfrastructure-controllersinfrastructureapps, with the prod-only infrastructure-overprovisioning layer hanging off infrastructure without gating apps.
Follow the hierarchical Kustomization flow: base configurations in k8s/bases/ feed provider overlays in k8s/providers/, which feed cluster overlays in k8s/clusters/.

Files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
k8s/bases/infrastructure/**

📄 CodeRabbit inference engine (AGENTS.md)

k8s/bases/infrastructure/**: Under k8s/bases/infrastructure/, organize resources component-folder-first: a component's HelmRelease/HelmRepository and its own CRs should live together in a folder named after the component unless a split is required.
Split a custom resource into its own plural-Kind folder only when it cannot live with its component, such as for CRD dependency ordering or because it is cluster-scoped/cross-cutting.

Files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
k8s/bases/infrastructure/**/*.{yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

k8s/bases/infrastructure/**/*.{yaml,yml}: For component-folder files, name manifests after the resource Kind in kebab-case; if a folder contains multiple resources of the same Kind, qualify filenames with a purpose suffix.
For CR-folder files, omit the folder-implied Kind from the filename and use the verb-purpose.yaml form.
Name Flux Kustomization resources flux-kustomization*.yaml; keep the kustomize build file named exactly kustomization.yaml.

Files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
🧠 Learnings (2)
📚 Learning: 2026-07-01T21:13:36.950Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 2359
File: k8s/bases/apps/actual-budget/helm-release.yaml:62-111
Timestamp: 2026-07-01T21:13:36.950Z
Learning: When reviewing Kustomize/Helm YAML in this repo, keep the base vs provider overlay split: `k8s/bases/apps/**` and `k8s/bases/infrastructure/**` should contain each app’s full, environment-agnostic configuration (including base-level postRenderer Kustomize patches such as deployment strategy, topology spread, probes, and env injection). `k8s/providers/{docker,hetzner}/**` should only add small provider-specific deltas (e.g., `interval`, `persistence.size`) via patch files (like `k8s/providers/<provider>/apps/<app>/patches/helm-release-patch.yaml`). If configuration is identical across providers (e.g., OIDC/OAuth env vars where `${domain}` is resolved per cluster via envsubst), it belongs in the base and must not be duplicated into provider overlays.

Applied to files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
📚 Learning: 2026-07-04T13:30:04.759Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 2446
File: k8s/bases/infrastructure/cluster-security-exceptions/delete-rbac.yaml:38-125
Timestamp: 2026-07-04T13:30:04.759Z
Learning: For Kubescape ClusterSecurityException (apiVersion kubescape.io/v1beta1) and the mirrored Headlamp exception config, do NOT pin `spec.match.resources[].name` (and Headlamp `attributes.name`) to a single literal value when the identifier includes a generated hash. These fields are compared using `regexCompare`, so match such resources with an anchored regular expression that covers the stable prefix and the hash pattern (e.g., `^crossplane:provider:provider-upjet-github-[0-9a-f]+:system$`) rather than the current hash, so the exception remains valid across provider re-installs/revisions.

Applied to files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
🪛 Trivy (0.69.3)
k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml

[info] 17-53: limit range usage

A LimitRange policy with a default requests and limits for each container should be configured

Rule: KSV-0039

Learn more

(IaC/Kubernetes)

🔀 Multi-repo context devantler-tech/wedding-app, devantler-tech/ascoachingogvaner

Linked repositories findings

devantler-tech/wedding-app

  • deploy/deployment.yaml:82-85 — the container still sets readOnlyRootFilesystem: false, so the new temporary C-0017 exception in the platform repo matches the current downstream state. [::devantler-tech/wedding-app::]

devantler-tech/ascoachingogvaner

  • deploy/deployment.yaml:58-62 — the container securityContext still leaves readOnlyRootFilesystem: false, which aligns with the platform PR’s new workload-specific hardening patch for this app. [::devantler-tech/ascoachingogvaner::]
🔇 Additional comments (6)
k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml (1)

10-13: LGTM!

Also applies to: 22-23

k8s/bases/infrastructure/cluster-security-exceptions/kubescape-privileged.yaml (1)

1-53: LGTM!

k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml (1)

15-17: LGTM!

k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml (1)

47-78: LGTM!

k8s/bases/apps/crossview/helm-release.yaml (1)

38-94: LGTM!

k8s/bases/apps/umami/helm-release.yaml (1)

147-172: LGTM!


📝 Walkthrough

Walkthrough

This PR enables readOnlyRootFilesystem across multiple application HelmReleases and Crossplane DeploymentRuntimeConfigs, adding writable emptyDir volumes and mounts where runtime write access is still required. It also updates Kubescape ClusterSecurityException resources for control C-0017, adds a new namespace-scoped exception manifest, and adds an explanatory comment for the remaining opencost exception.

Changes

Cohort / Area Changes
Application workloads Enabled readOnlyRootFilesystem: true for actual-budget, backstage, ascoachingogvaner, crossview, homepage, and umami; added emptyDir volumes/mounts for /tmp, /var/cache/nginx, /var/run, /app/.next/cache, and /var/lib/postgresql as needed
Cluster security exceptions Updated infrastructure-privileged comments/reason text; removed C-0017 ignore from pod-security-mutations; added new readonly-rootfs-pending exception scoped to opencost and wedding-app; registered it in kustomization
opencost documentation Added a comment explaining why readOnlyRootFilesystem remains false for opencost-ui
Crossplane provider hardening Added securityContext hardening and writable /tmp emptyDir volumes to DeploymentRuntimeConfigs for the base config and the aws-iam, family-aws, and upjet-unifi providers

Sequence Diagram(s)

Not applicable — these are declarative Kubernetes manifest updates without a new runtime interaction flow.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: hardening containers with read-only root filesystems for Kubescape C-0017.
Description check ✅ Passed The description is directly aligned with the changeset, describing the C-0017 hardening, writable mounts, and narrowed exceptions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

@devantler

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
✅ 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

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
✅ 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 Daily AI Assistant

Heads-up: #2467 fast-tracks the provider-upjet-unifi /tmp fix (that provider is live-broken — every managed resource SYNCED=False on the read-only /tmp, and the user needs it to manage their controller). It mirrors this PR's deployment-runtime-config-upjet-unifi.yaml hunk verbatim, so whichever merges first, the other's identical hunk should auto-resolve — or you can drop that one file from here once the fix PR lands. The rest of #2455's C-0017 hardening is untouched by it.

@devantler

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

🤖 Generated by the Daily AI Assistant

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

@devantler Reviewing the changes now.

✅ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml`:
- Around line 69-75: The three new emptyDir volumes in the volume list are
unbounded, so cap each one with a sizeLimit to match the /tmp pattern used
elsewhere in the PR. Update the tmp, nginx-cache, and nginx-run volume
definitions in the kustomization so each emptyDir includes an explicit limit
(for example, 1Gi) to prevent unchecked node disk usage. Keep the change
localized to the volume specs in this manifest.

In `@k8s/bases/apps/crossview/helm-release.yaml`:
- Around line 88-92: The postgres-data emptyDir volume is uncapped and can grow
with live PGDATA usage, unlike the tmp scratch mount. Update the volume
definition in the Helm release manifest for the Postgres pod so postgres-data
has an explicit size limit while leaving the tmp volume unchanged. Use the
existing volumes block in the crossview release to locate the postgres-data
entry and add the cap there.

In `@k8s/bases/apps/umami/helm-release.yaml`:
- Around line 161-170: The `extraVolumes` entries for `next-cache` and `tmp` are
using uncapped `emptyDir` volumes, which can grow without bound. Update the
`helm-release.yaml` volume definitions for these mounts to include a
`sizeLimit`, following the same pattern used for backstage’s `/tmp` volume in
this PR. Keep the fix scoped to the `extraVolumes`/`extraVolumeMounts` section
so the `next-cache` and `tmp` mounts remain unchanged except for the new limits.

In
`@k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml`:
- Around line 10-12: Scope the exception in the cluster security policy to only
the intended Kubescape workloads instead of the whole namespace. Update the
policy around the `kubescape` node-agent/storage exception to use
`match.resources` with kind/name globs for the specific objects, so the
`kubescape` operator and kubevuln are not exempted. Refer to the existing
`infrastructure-privileged` exception definition and replace the namespace-level
selector with resource-level matching for the node-agent and storage workloads
only.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c42991a1-2973-4c8b-9efb-bf9247786121

📥 Commits

Reviewing files that changed from the base of the PR and between 32ce888 and 4916a63.

📒 Files selected for processing (15)
  • k8s/bases/apps/actual-budget/helm-release.yaml
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/apps/backstage/helm-release.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/bases/apps/homepage/helm-release.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml
  • k8s/bases/infrastructure/opencost/helm-release.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-aws-iam.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-family-aws.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-upjet-unifi.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config.yaml
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • devantler-tech/actions (auto-detected)
  • devantler-tech/aws (auto-detected)
  • devantler-tech/reusable-workflows (auto-detected)
  • devantler-tech/ksail (auto-detected)
  • devantler-tech/ascoachingogvaner (auto-detected)
  • devantler-tech/wedding-app (auto-detected)
  • devantler-tech/agent-skills (auto-detected)
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{yaml,yml}: Use Kustomize overlays rather than editing base resources directly; k8s/bases/ is immutable from overlays and changes should be made with patches: in provider or cluster overlays.
Keep manifest changes small and use YAML/schema validation before submitting a manifest PR; for files with cluster context, prefer ksail workload validate / kubectl kustomize / kubectl apply --dry-run=client as appropriate.

Files:

  • k8s/bases/apps/backstage/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml
  • k8s/bases/infrastructure/opencost/helm-release.yaml
  • k8s/bases/apps/homepage/helm-release.yaml
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/apps/actual-budget/helm-release.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-upjet-unifi.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-family-aws.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-aws-iam.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml
k8s/**

📄 CodeRabbit inference engine (AGENTS.md)

k8s/**: Respect Flux dependency order: bootstrapinfrastructure-controllersinfrastructureapps, with the prod-only infrastructure-overprovisioning layer hanging off infrastructure without gating apps.
Follow the hierarchical Kustomization flow: base configurations in k8s/bases/ feed provider overlays in k8s/providers/, which feed cluster overlays in k8s/clusters/.

Files:

  • k8s/bases/apps/backstage/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml
  • k8s/bases/infrastructure/opencost/helm-release.yaml
  • k8s/bases/apps/homepage/helm-release.yaml
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/apps/actual-budget/helm-release.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-upjet-unifi.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-family-aws.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-aws-iam.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml
k8s/bases/infrastructure/**

📄 CodeRabbit inference engine (AGENTS.md)

k8s/bases/infrastructure/**: Under k8s/bases/infrastructure/, organize resources component-folder-first: a component's HelmRelease/HelmRepository and its own CRs should live together in a folder named after the component unless a split is required.
Split a custom resource into its own plural-Kind folder only when it cannot live with its component, such as for CRD dependency ordering or because it is cluster-scoped/cross-cutting.

Files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml
  • k8s/bases/infrastructure/opencost/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml
k8s/bases/infrastructure/**/*.{yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

k8s/bases/infrastructure/**/*.{yaml,yml}: For component-folder files, name manifests after the resource Kind in kebab-case; if a folder contains multiple resources of the same Kind, qualify filenames with a purpose suffix.
For CR-folder files, omit the folder-implied Kind from the filename and use the verb-purpose.yaml form.
Name Flux Kustomization resources flux-kustomization*.yaml; keep the kustomize build file named exactly kustomization.yaml.

Files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml
  • k8s/bases/infrastructure/opencost/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml
🧠 Learnings (2)
📚 Learning: 2026-07-01T21:13:36.950Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 2359
File: k8s/bases/apps/actual-budget/helm-release.yaml:62-111
Timestamp: 2026-07-01T21:13:36.950Z
Learning: When reviewing Kustomize/Helm YAML in this repo, keep the base vs provider overlay split: `k8s/bases/apps/**` and `k8s/bases/infrastructure/**` should contain each app’s full, environment-agnostic configuration (including base-level postRenderer Kustomize patches such as deployment strategy, topology spread, probes, and env injection). `k8s/providers/{docker,hetzner}/**` should only add small provider-specific deltas (e.g., `interval`, `persistence.size`) via patch files (like `k8s/providers/<provider>/apps/<app>/patches/helm-release-patch.yaml`). If configuration is identical across providers (e.g., OIDC/OAuth env vars where `${domain}` is resolved per cluster via envsubst), it belongs in the base and must not be duplicated into provider overlays.

Applied to files:

  • k8s/bases/apps/backstage/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml
  • k8s/bases/infrastructure/opencost/helm-release.yaml
  • k8s/bases/apps/homepage/helm-release.yaml
  • k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml
  • k8s/bases/apps/actual-budget/helm-release.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-upjet-unifi.yaml
  • k8s/bases/apps/crossview/helm-release.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-family-aws.yaml
  • k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-aws-iam.yaml
  • k8s/bases/apps/umami/helm-release.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml
📚 Learning: 2026-07-04T13:30:04.759Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 2446
File: k8s/bases/infrastructure/cluster-security-exceptions/delete-rbac.yaml:38-125
Timestamp: 2026-07-04T13:30:04.759Z
Learning: For Kubescape ClusterSecurityException (apiVersion kubescape.io/v1beta1) and the mirrored Headlamp exception config, do NOT pin `spec.match.resources[].name` (and Headlamp `attributes.name`) to a single literal value when the identifier includes a generated hash. These fields are compared using `regexCompare`, so match such resources with an anchored regular expression that covers the stable prefix and the hash pattern (e.g., `^crossplane:provider:provider-upjet-github-[0-9a-f]+:system$`) rather than the current hash, so the exception remains valid across provider re-installs/revisions.

Applied to files:

  • k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml
  • k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml
🪛 Trivy (0.69.3)
k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml

[info] 23-40: limit range usage

A LimitRange policy with a default requests and limits for each container should be configured

Rule: KSV-0039

Learn more

(IaC/Kubernetes)

k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-upjet-unifi.yaml

[info] 9-49: limit range usage

A LimitRange policy with a default requests and limits for each container should be configured

Rule: KSV-0039

Learn more

(IaC/Kubernetes)

k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-family-aws.yaml

[info] 8-47: limit range usage

A LimitRange policy with a default requests and limits for each container should be configured

Rule: KSV-0039

Learn more

(IaC/Kubernetes)

k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-aws-iam.yaml

[info] 6-45: limit range usage

A LimitRange policy with a default requests and limits for each container should be configured

Rule: KSV-0039

Learn more

(IaC/Kubernetes)

k8s/bases/infrastructure/cluster-security-exceptions/infrastructure-privileged.yaml

[info] 17-58: limit range usage

A LimitRange policy with a default requests and limits for each container should be configured

Rule: KSV-0039

Learn more

(IaC/Kubernetes)

🔀 Multi-repo context devantler-tech/wedding-app, devantler-tech/ascoachingogvaner, devantler-tech/ksail

Linked repositories findings

devantler-tech/wedding-app

  • deploy/deployment.yaml:35-60 — the deployment already has pod-level hardening, but the container securityContext still sets readOnlyRootFilesystem: false. This matches the PR’s new temporary C-0017 exception for wedding-app; the downstream repo is not yet hardened. [::devantler-tech/wedding-app::]

devantler-tech/ascoachingogvaner

  • deploy/deployment.yaml:30-60 — the deployment also has container hardening in place, but readOnlyRootFilesystem remains false. This lines up with the PR change that hardens ascoachingogvaner via a Flux patch. [::devantler-tech/ascoachingogvaner::]

devantler-tech/ksail

  • pkg/svc/mirror/inject.go:144-148 — ksail’s mirror injection already defaults ReadOnlyRootFilesystem to true, so the PR’s hardening direction is consistent with existing ksail behavior. [::devantler-tech/ksail::]
🔇 Additional comments (12)
k8s/bases/apps/actual-budget/helm-release.yaml (1)

189-199: LGTM!

k8s/bases/apps/backstage/helm-release.yaml (1)

130-156: LGTM!

k8s/bases/apps/crossview/helm-release.yaml (1)

38-56: LGTM!

k8s/bases/apps/homepage/helm-release.yaml (1)

164-190: LGTM!

k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-aws-iam.yaml (1)

14-45: LGTM!

k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-family-aws.yaml (1)

16-47: LGTM!

k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config-upjet-unifi.yaml (1)

17-49: LGTM!

k8s/providers/hetzner/infrastructure/crossplane/deployment-runtime-config.yaml (1)

17-37: 🩺 Stability & Availability

Double-check the no-/tmp assumption for provider-upjet-github. This runtime omits a writable /tmp; any reconcile/init path that still writes workspaces locally will fail under the read-only root.

k8s/bases/infrastructure/cluster-security-exceptions/pod-security-mutations.yaml (1)

2-34: LGTM!

k8s/bases/infrastructure/cluster-security-exceptions/readonly-rootfs-pending.yaml (1)

1-41: LGTM!

k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml (1)

13-13: LGTM!

k8s/bases/infrastructure/opencost/helm-release.yaml (1)

190-199: LGTM!

Comment thread k8s/bases/apps/ascoachingogvaner/flux-kustomization.yaml Outdated
Comment thread k8s/bases/apps/crossview/helm-release.yaml Outdated
Comment thread k8s/bases/apps/umami/helm-release.yaml
@github-project-automation github-project-automation Bot moved this from 🫴 Ready to 🏃🏻‍♂️ In Progress in 🌊 Project Board Jul 4, 2026
devantler and others added 2 commits July 4, 2026 21:10
…xception to node-agent/storage

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@devantler devantler marked this pull request as ready for review July 4, 2026 19:56
@devantler devantler added this pull request to the merge queue Jul 4, 2026
Merged via the queue into main with commit a016008 Jul 4, 2026
15 checks passed
@devantler devantler deleted the claude/security-context-readonly-rootfs branch July 4, 2026 20:16
@github-project-automation github-project-automation Bot moved this from 🏃🏻‍♂️ In Progress to ✅ Done in 🌊 Project Board Jul 4, 2026
@botantler-1

botantler-1 Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.98.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

1 participant