Belajar DevSecOps Engineer - Kubernetes Security
Episode 8 of 28

Belajar DevSecOps Engineer - Kubernetes Security

Kubernetes adalah runtime produksi kalian dan default-nya belum aman; di episode ini kalian memahami model 4C, menerapkan Pod Security Admission restricted, menulis RBAC least privilege, memasang NetworkPolicy default-deny, dan menambah admission control Kyverno sebagai policy gate cluster

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah mengamankan IaC di episode 7, kita turun ke tempat workload benar-benar hidup: Kubernetes. Cluster adalah lingkungan yang unik dari sisi security — semua komponennya saling berkomunikasi via API, default-nya permisif (pod bebas bicara ke pod lain), dan satu RBAC yang salah bisa berarti root seluruh armada.

Episode ini menyusun pertahanan berlapis dengan urutan yang akan kalian pakai di setiap cluster production: memahami model 4C → Pod Security Admission → RBAC least privilege → NetworkPolicy → admission control. Cluster kind dari lab episode 0 sudah cukup untuk semua praktiknya.

Model 4C: Cloud, Cluster, Container, Code

Kubernetes tidak bisa diamankan secara terpisah — ia bertumpuk pada lapisan-lapisan di bawahnya:

Model 4C (berlapis)
Cloud      -> IAM akun cloud, network VPC, enkripsi storage   (episode 7 & 9)
Cluster    -> API server, RBAC, policies, node hardening      (episode ini)
Container  -> image minimal, non-root, scan                   (episode 6)
Code       -> SAST/DAST, dependency aman                      (episode 4)

Prinsipnya: kelemahan di lapisan bawah meruntuhkan lapisan atas. Pod yang jalan sebagai root membuat pengerasan cluster kurang berarti; cluster yang terbuka membuat image distroless tetap bisa disusupi lewat API. Amankan dari luar ke dalam.

Pod Security Admission (PSA)

PSA adalah mekanisme bawaan K8s (sejak 1.25) yang menerapkan Pod Security Standards pada level namespace — tanpa perlu tool tambahan:

LevelEfekUntuk Siapa
privilegedTanpa batasanInfra khusus (CNI, monitoring agent)
baselineBlokir privilege escalation, hostNetwork, dsb.Workload umum
restricted+ wajib non-root, drop ALL capabilities, seccompProduction ideal

Terapkan restricted pada namespace aplikasi:

Label namespace dengan PSA restricted
kubectl label namespace app-prod \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/warn=restricted

Konsekuensinya, manifest pod harus memenuhi syarat ketat:

Kubernetesdeployment.yaml — compliant restricted
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  template:
    spec:
      serviceAccountName: api-sa          # SA khusus, bukan default
      automountServiceAccountToken: false # matikan jika tak butuh API K8s
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: api
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: ["ALL"]
            readOnlyRootFilesystem: true

Baris-baris yang disorot adalah dua kesalahan paling umum: lupa ganti ServiceAccount default, dan lupa mematikan token API untuk pod yang tidak membutuhkannya.

RBAC Least Privilege

RBAC mengatur siapa boleh apa di API server. Dua aturan emas: hindari cluster-admin untuk apapun selain break-glass, dan bind ke ServiceAccount per-workload, bukan group generik.

Kubernetesrbac.yaml — role minimalis
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: app-prod
  name: api-reader
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: app-prod
  name: api-reader-binding
subjects:
  - kind: ServiceAccount
    name: api-sa
roleRef:
  kind: Role
  name: api-reader
  apiGroup: rbac.authorization.k8s.io

Perhatikan Role (namespace-scoped), bukan ClusterRole — prinsip blast radius. Audit cepat untuk mencari binding berbahaya:

Temukan siapa punya cluster-admin
kubectl get clusterrolebindings -o json | jq '.items[] |
  select(.roleRef.name=="cluster-admin") |
  .metadata.name'

Warning

Binding system:anonymous atau subject system:unauthenticated pada role berprivilege adalah konfigurasi berbahaya yang masih ditemukan di cluster nyata. Jalankan audit query di atas sekarang terhadap cluster kalian.

NetworkPolicy Default-Deny

Secara default semua pod bisa saling komunikasi — model flat yang berbahaya saat satu pod dicompromise. Pola standar: tolak semua traffic masuk di namespace, lalu izinkan eksplisit.

Kubernetesnetpol-deny-all.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: app-prod
spec:
  podSelector: {}
  policyTypes:
    - Ingress

Policy tanpa ingress rules = tolak semuanya. Lalu buka hanya jalur yang dibutuhkan, misal frontend → api port 8080:

Kubernetesnetpol-allow-api.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-from-frontend
  namespace: app-prod
spec:
  podSelector:
    matchLabels:
      app: api
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - port: 8080

Catatan penting: NetworkPolicy butuh CNI yang mendukungnya (Calico, Cilium; kind default tidak — install Cilium di kind untuk praktik). Segmentasi lanjutan termasuk egress control dan mTLS mesh dibahas tuntas di episode 18.

Admission Control: Kyverno

PSA hanya menangkap standar pod. Untuk policy organisasi ("image harus dari registry internal", "wajib label owner"), pasang policy engine di admission webhook. Kyverno paling ramah pemula karena policy-nya YAML murni:

kyverno-policy.yaml — wajib registry internal
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-image-registries
spec:
  validationFailureAction: Enforce
  rules:
    - name: only-internal-registry
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "Image harus dari registry organisasi."
        pattern:
          spec:
            containers:
              - image: "registry.internal.example/*"

Setiap Pod baru dievaluasi sebelum dibuat — melanggar policy = ditolak dengan pesan jelas. Ini adalah policy-as-code versi cluster, saudara dari OPA di episode 7.

Penutup

Inti yang harus dibawa pulang:

  • Model 4C: keamanan cluster bergantung pada Cloud, Container, dan Code di bawahnya.
  • PSA restricted per-namespace memberi baseline kuat tanpa tool eksternal.
  • RBAC least privilege: no cluster-admin harian, SA per-workload, token off jika tak dipakai.
  • Default-deny NetworkPolicy + Kyverno admission = pertahanan berlapis di runtime platform.

Di episode 9 selanjutnya kita naik lagi ke lapisan Cloud: Cloud Security in Pipeline — bagaimana deploy yang aman memakai OIDC tanpa static key, guardrails tingkat organisasi seperti SCP/Azure Policy, dan cara mencegah misconfigurasi cloud sejak pipeline. Sampai jumpa!

Belajar DevSecOps Engineer - Kubernetes Security | Belajar DevSecOps Engineer