Hari 33: SecurityContext Hardening — 20 Temuan ke 0
4 min read

Hari 33: SecurityContext Hardening — 20 Temuan ke 0

Deployment.yaml di-hardened: non-root, read-only filesystem, cap drop ALL, probes, resources. 3 scanner: Kubesec 0→11, Checkov 20→0, Trivy 16→0. Pods tetap running.

devsecops
kubernetes
securitycontext
k8s hardening
pod security
Share

Hari 33. Kemarin 3 scanner menemukan 20+ misconfiguration di deployment.yaml. Hari ini saatnya fix semua. Target: 0 findings.

Before: 26 Lines, 0 Security

spec:
  template:
    spec:
      containers:
        - name: api
          image: securebank:v1
          ports:
            - containerPort: 8080
          envFrom:
            - secretRef:
                name: securebank-secrets

Itu saja. No securityContext, no resources, no probes. Pod jalan pakai default Kubernetes security — yang artinya: bisa root, bisa escalate privilege, filesystem writable, semua capabilities aktif.

After: 65 Lines, 16 Security Properties

Hari ini aku tambah 39 lines security config. Ini perbandingan before vs after:

Property Before After
automountServiceAccountToken false
Pod securityContext runAsNonRoot: true
runAsUser 65532 (distroless nonroot)
runAsGroup 65532
fsGroup 65532
seccompProfile RuntimeDefault
Container securityContext full block
allowPrivilegeEscalation false
readOnlyRootFilesystem true
capabilities.drop ["ALL"]
resources.requests cpu 50m, mem 64Mi
resources.limits cpu 200m, mem 128Mi
livenessProbe httpGet /health
readinessProbe httpGet /health
imagePullPolicy IfNotPresent
emptyDir /tmp mounted (preventive)

Yang Ditambahkan dan Kenapa

Pod-level securityContextrunAsNonRoot: true memaksa Pod tidak boleh jalan sebagai root. runAsUser: 65532 spesifik UID distroless nonroot image. Kalau salah UID, Pod crash. seccompProfile: RuntimeDefault aktifkan seccomp filter untuk restrict syscall.

Container-level securityContextallowPrivilegeEscalation: false blok container dari sudo atau setuid. readOnlyRootFilesystem: true buat root filesystem immutable — attacker tidak bisa tulis binary. capabilities.drop: ["ALL"] hapus semua Linux capabilities (NET_RAW, SYS_ADMIN, dll).

emptyDir untuk /tmp — best practice dengan readOnlyRootFilesystem. App mungkin butuh write ke /tmp (misal Go library temporary file). Mount emptyDir = writable /tmp, tapi root filesystem tetap immutable.

Resources — requests (cpu 50m, memory 64Mi) untuk scheduler. limits (cpu 200m, memory 128Mi) untuk mencegah DoS via resource exhaustion.

Probes — livenessProbe auto-restart Pod kalau unhealthy. readinessProbe stop traffic ke Pod kalau belum siap. /health endpoint sudah ada dari Fase 1.

Hasil Scan: Before vs After

Scanner Before After
Kubesec Score 0 (14 advise) Score 11 (3 advise remain: AppArmor, SA, seccomp annotation)
Checkov 69 passed, 20 failed 85 passed, 0 failed (4 skipped with justification)
Trivy 16 findings (3 HIGH, 3 MEDIUM, 10 LOW) 0 findings (clean)

Trivy langsung clean. Checkov 0 failed dengan 4 skip (imagePullPolicy, image digest, secret as env, NetworkPolicy — semua ada remediation day tersendiri). Kubesec 11/14 — 3 yang remain akan di-fix di Day 37 (NetworkPolicy), Day 38 (RBAC), dan production (AppArmor).

UID Trap: 65532 vs 65534

Tutorial pakai runAsUser: 65534 (UID nobody). Tapi distroless gcr.io/distroless/static-debian12:nonroot pakai UID 65532. Kalau pakai 65534, Pod crash karena UID mismatch. Lesson: selalu cek image User:

docker inspect securebank:v1 --format '{{.Config.User}}'
# nonroot:nonroot → UID 65532

Pelajaran Hari Ini

readOnlyRootFilesystem + emptyDir = best practice combo. Immutable root filesystem mencegah attacker tulis binary/config. emptyDir untuk /tmp supaya app tetap bisa operasi. Preventive lebih baik daripada debug crash-loop.

UID harus match dengan image. Tutorial bisa salah — selalu validasi dengan docker inspect. Distroless nonroot = 65532, bukan 65534. Mismatch = Pod crash.

20+ findings → 0 dalam 1 commit. Kuncinya: kemarin scan dengan 3 scanner untuk lihat semua POV, hari ini fix semua sekaligus. ZAP/Checkov/Trivy hasil berbeda — pakai ketiganya untuk coverage maksimal.

Repo

Semua code, before/after comparison, dan 3 scanner reports ada di: https://github.com/stayrelevantid/chalange-devsecops

Kesimpulan

Deployment.yaml sekarang hardened: non-root, read-only filesystem, capabilities dropped, seccomp enabled, probes active, resources limited. 3 scanner: Trivy 0, Checkov 0 (dengan 4 justified skip), Kubesec 11/14. Pods tetap running, /health tetap merespons. Besok Day 34 — RBAC setup, dedicated ServiceAccount dengan least privilege.

Enjoyed this article? Share it!

Share

Diskusi & Komentar

Artikel Terkait