Belajar Seccomp - Seccomp di Kubernetes
Episode 10 of 23

Belajar Seccomp - Seccomp di Kubernetes

Menerapkan seccomp di Kubernetes lewat field seccompProfile pada securityContext, evolusinya dari annotation alpha, dan kaitannya dengan Pod Security Standards. Termasuk distribusi profil kustom antar node serta seccomp-profiles-operator.

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

Pendahuluan

Di episode 9 kalian mengunci service langsung di host. Di cluster Kubernetes, tantangannya lebih besar: ada banyak node, banyak pod, dan runtime yang berbeda. Namun prinsipnya sama — pod menjalankan container yang berbagi kernel node, dan syscall berbahaya harus dipangkas. Bedanya, Kubernetes menambahkan satu lapisan abstraksi: seccompProfile di securityContext.

Episode 10 ini membahas cara menerapkan seccomp di Kubernetes: field seccompProfile, evolusinya dari annotation alpha, Pod Security Standards, distribusi profil kustom antar node, dan seccomp-profiles-operator.

Evolusi: Annotation Alpha ke Field seccompProfile

Kubernetes punya sejarah panjang soal seccomp. Awalnya (jauh sebelum versi 1.19), satu-satunya cara adalah annotation alpha:

pod-legacy.yaml — annotation alpha (historis)
apiVersion: v1
kind: Pod
metadata:
  name: legacy-app
  annotations:
    seccomp.security.alpha.kubernetes.io/pod: "runtime/default"
spec:
  containers:
    - name: app
      image: busybox
      command: ["sleep", "3600"]

Annotation ini rapuh: tidak ada validasi schema, sulit diterapkan per-container, dan statusnya alpha membuatnya berubah kapan saja. Karena itu Kubernetes memperkenalkan field proper seccompProfile di securityContext (beta sejak 1.19, GA sejak 1.25). Sejak itu, seccomp dianggap infrastruktur — bukan eksperimen.

Note

Bila kalian menemukan dokumentasi lama atau chart Helm yang masih memakai annotation seccomp.security.alpha.kubernetes.io/pod, rencanakan migrasi ke field seccompProfile. Annotation lama tetap terbaca sebagai kompatibilitas, tapi bukan cara yang direkomendasikan untuk konfigurasi baru.

Tiga Nilai seccompProfile

Field securityContext.seccompProfile.type menerima tiga nilai:

  • Unconfined — tanpa filter seccomp. Ini default historis Kubernetes; hindari kecuali benar-benar yakin.
  • RuntimeDefault — profil bawaan runtime container. Di Docker/containerd ini adalah docker-default dari episode 8: denylist syscall berbahaya yang dirawat komunitas.
  • Localhost — profil kustom berupa file JSON yang ada di setiap node, dirujuk lewat localhostProfile.

Aturan penetapannya sederhana: seccompProfile di level pod berlaku sebagai default untuk semua container, dan container bisa menimpanya lewat seccompProfile-nya sendiri. Level paling spesifik menang.

Contoh: RuntimeDefault dan Localhost

Ini pola yang paling umum — pod memakai profil bawaan runtime:

pod-secure.yaml — RuntimeDefault di level pod
apiVersion: v1
kind: Pod
metadata:
  name: webapp
spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: nginx
      image: nginx:1.27

Untuk kontrol penuh, arahkan ke profil kustom yang disimpan di node:

pod-localhost.yaml — profil kustom dari node
apiVersion: v1
kind: Pod
metadata:
  name: webapp-custom
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      securityContext:
        seccompProfile:
          type: Localhost
          localhostProfile: profiles/webapp-allowlist.json

localhostProfile bersifat relatif terhadap /var/lib/kubelet/seccomp/ di node. File profil harus ada di semua node tempat pod dijadwalkan — inilah sumber masalah operasional yang akan kita bahas sebentar lagi.

Tip

Mulailah dengan RuntimeDefault untuk seluruh beban kerja. Ini memberi baseline seccomp yang kuat dengan biaya operasional nol. Setelah itu, naikkan secara bertahap ke Localhost dengan allowlist khusus untuk workload yang kalian pahami (mengikuti alur baseline strace dari episode 7 dan 8).

Pod Security Standards: Baseline dan Restricted

Kubernetes tidak berhenti di level API — ia juga menstandarkan kebijakan. Pod Security Standards mendefinisikan dua level yang berhubungan dengan seccomp:

  • Baseline — mengharuskan seccompProfile.type: RuntimeDefault untuk semua pod.
  • Restricted — mewarisi persyaratan Baseline, ditambah pembatasan lain seperti allowPrivilegeEscalation: false dan pembuangan capabilities.

Kebijakan ini ditegakkan per-namespace lewat label pod-security.kubernetes.io/enforce:

namespace.yaml — enforce Restricted
apiVersion: v1
kind: Namespace
metadata:
  name: secure-ns
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted

Pod yang tidak memenuhi level Restricted akan ditolak (karena enforce) atau dilaporkan di audit log (karena audit) — pasangan label yang tepat untuk roll out bertahap. Ini cara tercepat menormalkan seccomp di seluruh cluster: bukan mengandalkan disiplin individu, tapi menegakkan lewat platform.

Distribusi Profil Kustom Antar Node

Inilah tantangan nyata Localhost: profil adalah file di filesystem node, dan file itu harus identik di semua node — termasuk node yang ditambahkan nanti. Mengelola ini manual adalah resep bencana. Tiga pendekatan yang umum:

  1. Bake ke image node — masukkan file profil ke image node (immutable infrastructure). Konsisten, tapi menambah profil baru berarti build image node baru.
  2. Provisi via config management — Ansible/Cloud-Init menaruh file di setiap node. Fleksibel, tapi jangan lupa node baru.
  3. seccomp-profiles-operator — operator Kubernetes yang mengelola profil sebagai resource dan mendistribusikannya ke semua node secara otomatis.

Pendekatan ketiga paling cocok untuk cluster yang terus berubah. Dengan operator, profil dideklarasikan sebagai CRD:

seccomp-profile.yaml — profil via operator
apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
  name: webapp-allowlist
  namespace: security
spec:
  defaultAction: SCMP_ACT_ERRNO
  defaultErrnoRet: 1
  archs:
    - SCMP_ARCH_X86_64
  syscalls:
    - action: SCMP_ACT_ALLOW
      names:
        - read
        - write
        - openat
        - close
        - mmap
        - mprotect
        - exit_group

Operator lalu menulis file profil ke setiap node dan memaparkannya pada path standar /var/lib/kubelet/seccomp/operator/<namespace>/<name>.json. Pod kalian tinggal merujuk: localhostProfile: operator/security/webapp-allowlist.json. Saat node baru bergabung, operator otomatis menaruh profilnya — tidak ada yang terlewat.

Important

Sebelum mengadopsi Localhost, pastikan kalian punya jawaban untuk satu pertanyaan: apa yang terjadi saat node baru bergabung? Jika jawabannya "untung-untungan", gunakan RuntimeDefault dulu atau segera pasang operator. Pod yang menunjuk profil yang tidak ada akan gagal dijadwalkan — dan kegagalan itu menyakitkan saat sedang oncall malam.

Verifikasi di Node

Profil yang dideklarasikan bukan berarti profil itu ada. Verifikasi di node tempat pod berjalan:

KubernetesCek file profil dan runtime di node
ls -la /var/lib/kubelet/seccomp/
crictl info | grep seccomp

crictl adalah CLI untuk containerd — crictl info | grep seccomp memastikan runtime node mengaktifkan dukungannya. Kombinasikan dengan inspeksi pod yang sedang berjalan via kubectl describe:

KubernetesLihat status seccomp pod
kubectl describe pod webapp | grep -i seccomp

Tiga lapis verifikasi ini — file ada, runtime mendukung, pod mengacu — menutup lingkaran dari deklarasi sampai eksekusi.

Penutup

Di episode 10 ini kalian telah memahami cara menerapkan seccomp di Kubernetes: field seccompProfile dengan tiga tipe (Unconfined, RuntimeDefault, Localhost) yang menggantikan annotation alpha, kaitan dengan Pod Security Standards (Baseline dan Restricted), serta tantangan distribusi profil antar node yang dijawab dengan seccomp-profiles-operator. Kalian juga tahu cara memverifikasi profil di node lewat crictl dan kubectl describe.

Kunci yang harus dibawa pulang:

  • Mulai dari RuntimeDefault; naik ke Localhost saat beban kerja sudah dipahami.
  • Enforce lewat Pod Security Standards, bukan disiplin per-orang.
  • Profil Localhost harus ada di semua node — pakai operator atau jawab dulu pertanyaannya.

Sejauh ini seccomp datang dari luar: container, service unit, pod. Tetapi ada satu pendekatan yang lebih dekat ke garis pertahanan — di dalam aplikasi itu sendiri. Di episode 11, kita masuk ke Seccomp untuk Aplikasi & Daemon: memuat filter lewat libseccomp, python-seccomp, dan Go, membatasi keluarga socket untuk daemon jaringan, dan memblokir syscall berbahaya seperti unshare, mount, dan ptrace.

Belajar Seccomp - Seccomp di Kubernetes | Belajar Seccomp