fix(k8s): harden securityContext + add postgres PVC (unblocks repo-wide Trivy gate)#923
Open
seonghobae wants to merge 2 commits into
Open
fix(k8s): harden securityContext + add postgres PVC (unblocks repo-wide Trivy gate)#923seonghobae wants to merge 2 commits into
seonghobae wants to merge 2 commits into
Conversation
…ate) The Trivy filesystem scan (trivy-fs) fails on EVERY PR because the k8s manifests trip misconfig rules KSV-0014 (readOnlyRootFilesystem) and KSV-0118 (default security context) on all three workloads — a repo-wide baseline failure unrelated to individual PRs. Harden all three: - Pod/container securityContext: runAsNonRoot, drop ALL capabilities, allowPrivilegeEscalation=false, readOnlyRootFilesystem, seccomp RuntimeDefault. App images already run non-root (Dockerfile USER appuser / frontend USER node); postgres runs as uid/gid 999 with fsGroup. - Add writable emptyDir mounts required by readOnlyRootFilesystem: /tmp for backend (email import extracts archives via tempfile), /app/.next/cache + /tmp for the frontend (next start runtime caches), and the postgres socket dir + /tmp. - Add volumeClaimTemplates to the postgres StatefulSet. Without it the database lived on the pod's ephemeral filesystem and was lost on every restart/reschedule (separately flagged P0 in the cloud-native assessment). PGDATA moved to a subdir of the mounted volume. Verified locally with the same scanners CI uses: trivy config --severity HIGH,CRITICAL k8s/ -> 0 trivy fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL . -> exit 0 Runtime note for the deployer: the postgres non-root + PVC (fsGroup) and the frontend readOnlyRootFilesystem writable-cache mounts should be smoke-tested on a cluster before rollout; these manifests use REPLACE_ME_VERSION image placeholders and are deploy templates. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RkKdtHRLG4wSLh6PVsp8J
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RkKdtHRLG4wSLh6PVsp8J
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.
Root cause
trivy-fsfails on every open PR (verified on #919, #920, and my own #921/#922) — not because of any PR's diff, but because the k8s manifests trip Trivy misconfig rules on all three workloads:readOnlyRootFilesystem: trueopencode-reviewthen fails only downstream of this (it REQUEST_CHANGES when another check fails, then can't diagnose it). So this one baseline is what blocks the security gate across the repo.Fix
Harden
backend-deployment,frontend-deployment, anddb-statefulset:runAsNonRoot,capabilities.drop: [ALL],allowPrivilegeEscalation: false,readOnlyRootFilesystem: true,seccompProfile: RuntimeDefault. App images already run non-root (DockerfileUSER appuser,frontend/DockerfileUSER node); postgres runs as uid/gid999withfsGroup: 999.readOnlyRootFilesystem:/tmpfor backend (email import extracts.zip/.mboxviatempfile),/app/.next/cache+/tmpfor the frontend (next startruntime caches), postgres socket dir +/tmp.volumeClaimTemplates. Without it the DB lived on the pod's ephemeral filesystem and was lost on every restart/reschedule (separately flagged P0 indocs/assessment/cloud-native-deployability-assessment.md).PGDATAmoved to a subdir of the mounted volume.Verification (same scanners CI uses, run locally)
(Before: 3 HIGH per workload = 9 findings, exit 1.)
Deployer note (please smoke-test before rollout)
These are deploy templates (
REPLACE_ME_VERSIONimage placeholders), not live manifests, so there's no running infra to break. Two things warrant a cluster smoke-test before production rollout: (1) postgres non-root + PVC ownership viafsGroup, and (2) the frontendreadOnlyRootFilesystemwith the.next/cacheemptyDir mount. Everything is Trivy-green and reasoned for runtime-safety, but a livekubectl rollout statusis the right final check.🤖 Generated with Claude Code