Filesystem container kini terkunci rapat: writable layer dibuang, lubang tulis hanya tmpfs yang kita pilih, dan proses root sekalipun ditolak kernel saat mencoba menulis ke disk. Namun penutup Chapter Read-Only Filesystem sengaja meninggalkan dua lapisan terdalam dari lima lapisan isolasi yang masih bekerja diam-diam dengan pengaturan bawaannya: seccomp dan LSM. Keduanyalah yang tetap bertugas pada detik terburuk — ketika penyerang sudah memegang shell di dalam container — karena keduanya menyaring di tempat yang belum pernah kita sentuh sejauh ini: pintu syscall menuju kernel host. Chapter ini membuka kedua lapisan tersebut, dari filter seccomp yang dipasang runc, profil AppArmor yang menempel otomatis di Ubuntu, label SELinux di keluarga Red Hat, sampai cara ketiganya diverifikasi dan dikustomisasi.
Seccomp: Menyaring Syscall di Pintu Kernel #
Setiap hal yang dilakukan proses container — membuka berkas, mengirim paket, mengalokasikan memori — pada akhirnya adalah satu panggilan syscall ke kernel host, persis pemahaman yang kita bangun sejak Chapter Prinsip Keamanan Container. Seccomp (secure computing mode) berdiri tepat di pintu itu: sebuah filter BPF (Berkeley Packet Filter) yang dipasang runc ke proses container sesaat sebelum proses pertama dieksekusi. Sejak detik itu, setiap syscall dari proses container melewati filter lebih dulu; syscall yang tidak lolos tidak pernah menyentuh kode kernel.
Profil bawaan Docker bekerja sebagai allowlist: sekitar 300 syscall yang dikenal aman dan umum dibutuhkan aplikasi diizinkan lewat, sementara sekitar 60 syscall lainnya ditolak. Penolakan itu tidak berupa pesan “syscall tidak dikenal”, melainkan galat EPERM — aplikasi melihat Operation not permitted, sama persis dengan penolakan capability yang kita amati pada Chapter Linux Capabilities. Daftar yang ditolak memuat syscall yang hampir tidak pernah dibutuhkan aplikasi normal, tetapi sangat dibutuhkan eksploit yang ingin melompat dari container ke host:
| Syscall yang diblokir | Tugas aslinya di kernel | Kenapa diblokir untuk container |
|---|---|---|
kexec_load, kexec_file_load | memuat kernel pengganti untuk reboot tanpa hidup ulang mesin | mengganti kernel host yang sedang berjalan |
bpf | memuat program eBPF untuk diproses di dalam kernel | mengeksekusi kode di dalam kernel host |
perf_event_open | mengukur event kernel untuk profiling | kebocoran data lintas proses lewat pengukuran |
init_module, finit_module | memuat modul kernel | menyuntik kode ke kernel host |
open_by_handle_at | membuka berkas lewat handle, bukan path | menembus isolasi mount menuju berkas host |
keyctl | mengelola keyring kredensial di kernel | membaca rahasia milik proses lain |
Baris bpf pada tabel itu bekerja dengan aturan bersyarat: profil bawaan memuat aturan yang mengizinkan bpf hanya bila container sengaja diberi CAP_SYS_ADMIN. Container bawaan tidak membawa capability itu — daftar dua belas dari Chapter Linux Capabilities tidak memuatnya — sehingga bpf tetap tertutup; hanya container yang secara sadar diberi capability tinggi yang membukanya.
Profil Kustom: Allowlist yang Dirancang Sendiri #
Skenario nyatanya begini: Siti diminta menjalankan sebuah alat profiling internal di dalam container — alat itu sudah ia telusuri dengan tracer selama development sehingga ia tahu persis syscall mana yang dipanggilnya. Daripada mewarisi allowlist 300 syscall profil bawaan, Siti menyempitkan dunia alat itu menjadi belasan syscall yang terbukti dipakai, dalam berkas profil-diagnostik.json:
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
],
"syscalls": [
{
"names": [
"access", "arch_prctl", "brk", "close", "execve", "exit_group",
"fstat", "getdents64", "getuid", "ioctl", "mmap", "mprotect",
"munmap", "newfstatat", "open", "openat", "pread64", "prlimit64",
"read", "rt_sigaction", "rt_sigprocmask", "set_tid_address",
"set_robust_list", "write", "writev"
],
"action": "SCMP_ACT_ALLOW"
}
]
}Mari kita telaah tiga komponen utama berkas tersebut:
"defaultAction": "SCMP_ACT_ERRNO"— kebijakan untuk semua syscall yang tidak disebut di berkas: tolak dengan galatEPERM; ini yang membuat profil bekerja sebagai allowlist ketat, kebalikan dari blocklist."architectures"— daftar tabel nama syscall yang dikenal filter; nomor syscall berbeda antar arsitektur, jadi daftar ini memastikan nama yang sama berlaku konsisten pada host x86_64 maupun turunannya."syscalls"dengannamesdan"action": "SCMP_ACT_ALLOW"— satu-satunya pintu terbuka: 25 syscall hasil telusuran Siti, mencakup membaca direktori (getdents64), membuka berkas (openat,newfstatat), dan menulis keluaran (write,writev) — tetapi tidak memuatsocket,connect, atauunshare.
Profil itu ditempelkan lewat flag --security-opt, dan hasilnya bisa kita uji dengan dua perintah yang berbeda nasib:
$ docker run --rm --security-opt seccomp=profil-diagnostik.json \
alpine:3.20 ls /Output yang Dihasilkan:
bin etc lib proc run srv tmp var
dev home media root sbin sys usr$ docker run --rm --security-opt seccomp=profil-diagnostik.json \
alpine:3.20 ping -c 1 127.0.0.1Output yang Dihasilkan:
ping: socket: Operation not permittedMari kita telaah kontras kedua output tersebut:
ls /berhasil — seluruh syscall yang dibutuhkannya (openat,newfstatat,getdents64,write) ada di daftar allowlist Siti.pingditolak sebelum menyentuh kernel — membuat socket jaringan menuntut syscallsocketyang tidak ada di daftar; filter mengembalikanEPERMdan busybox melaporkannya sebagaiOperation not permitted.- Penolakan terjadi di dunia jaringan, bukan berkas — profil Siti memang sengaja membiarkan alat profiling bekerja pada berkas lokal tanpa satu pun pintu keluar jaringan.
AppArmor: Profil per Program di Ubuntu #
Seccomp menyaring berdasarkan nomor syscall; LSM (Linux Security Modules) memeriksa operasi yang dibangun di atasnya. AppArmor — bawaan keluarga Ubuntu — bekerja dengan profil per program yang menyatakan operasi apa yang boleh: profil docker-default dipasang Docker pada setiap container di host Ubuntu yang mengaktifkan AppArmor, membatasi operasi klasik yang dipakai breakout — mount dengan tipe berbahaya, pembuatan raw socket, dan penulisan ke area sensitif /proc dan /sys.
Profil itu aktif tanpa satu flag pun dari kita, dan statusnya bisa diganti per container: --security-opt apparmor=nama-profil menempelkan profil kustom yang dimuat lebih dulu ke kernel host dengan apparmor_parser, sementara --security-opt apparmor=unconfined melepasnya. Kustomisasi profil AppArmor biasanya dimulai dari profil bawaan yang disalin lalu disempitkan — menambah aturan penolakan untuk path yang aplikasi kita pasti tidak butuh.
SELinux: Label pada Setiap Objek di Keluarga Red Hat #
SELinux menegakkan kebijakan lewat label yang menempel pada setiap subjek dan objek: proses container berjalan dengan tipe container_t, berkas milik image bertipe container_file_t, dan kernel menolak interaksi yang tidak diizinkan kebijakan antara kedua tipe itu. Docker menambah satu lapisan lagi bernama label MCS (Multi-Category Security): setiap container mendapat pasangan kategori acak seperti s0:c412,c743, sehingga container A tidak bisa membaca berkas yang dilabeli kategori container B — isolasi antar container yang seccomp dan AppArmor tidak memberikan. Kontrolnya tersedia lewat --security-opt label=type:container_t untuk mengganti tipe, dan label=disable untuk mematikan pelabelan sama sekali.
Satu gotcha yang hampir semua orang temui saat pertama kali memakai SELinux: volume atau bind mount dari host tidak membawa label container_file_t, sehingga proses container yang tampak punya izin berkas tetap ditolak kernel. Suffix :z pada deklarasi mount memerintahkan Docker melabeli ulang isi volume agar cocok dengan label container (dipakai bersama), sedangkan :Z melabeli khusus untuk satu container itu saja — mekanisme mount yang kita kenal dari Chapter Volume, kini dengan makna label di baliknya.
Ketiganya dalam Satu Pandangan #
| Aspek | Seccomp | AppArmor | SELinux |
|---|---|---|---|
| Objek yang disaring | nomor syscall | operasi per profil program | operasi per label tipe dan kategori |
| Cara kerja | filter BPF di depan syscall | profil path dan kapabilitas | kebijakan label pada kernel |
| Status bawaan Docker | profil allowlist ±300 syscall | profil docker-default aktif di Ubuntu | tipe container_t + label MCS di Red Hat |
| Cara mengganti | --security-opt seccomp=berkas.json | --security-opt apparmor=nama-profil | --security-opt label=type:... |
| Kapan butuh kustom | aplikasi minimal atau alat diagnosa | aturan path lebih ketat | integrasi label dengan storage host |
Bendera --privileged yang kita bedah pada Chapter Privileged Container mematikan ketiganya sekaligus: seccomp tidak dipasang, profil AppArmor dilepas, dan pelabelan SELinux dinonaktifkan — satu alasan lagi mengapa bendera itu dibaca sebagai bendera merah. Satu opsi pelengkap yang layak dihafal: --security-opt no-new-privileges mencegah proses di dalam container memperoleh privilege baru lewat berkas setuid — murah, tanpa efek samping bagi aplikasi normal, dan menutup satu trik eskalasi klasik.
Membaca Status di docker info #
Ketiga mekanisme bergantung pada kernel host, jadi langkah pertama di mesin mana pun adalah membaca apa yang sebenarnya aktif:
$ docker infoOutput yang Dihasilkan (dipotong):
Client:
Version: 29.9.0
...
Server:
Containers: 14
...
Security Options:
apparmor
seccomp
Profile: builtin
Kernel Version: 6.8.0-52-generic
Operating System: Ubuntu 24.04.1 LTS
...Mari kita telaah baris-baris yang penting bagi kita:
apparmortercantum di Security Options — host ini mengaktifkan AppArmor, dan daemon mendeteksinya; profildocker-defaultakan menempel pada container berikutnya.seccompdenganProfile: builtin— filter seccomp aktif memakai profil bawaan Docker; kalau baris ini hilang, setiap container di host ini berjalan tanpa penyaringan syscall.Ubuntu 24.04.1 LTSpada Engine 29.9.0 — konteks penting saat membaca dokumentasi: perintah dan perilaku keamanan yang kita bahas di chapter ini diuji pada kombinasi ini.
Lapisan demi lapisan, kerangka keamanan container kini lengkap kita kendalikan: identitas diturunkan, capability dicabut, filesystem dibekukan, syscall disaring, dan operasi diperiksa LSM. Namun satu kelas barang masih berpindah tangan dalam bentuk paling rapuh sepanjang course ini: rahasia. Password database rahasia123 kita masih melintas sebagai teks polos di environment variable sejak Section Docker Compose. Chapter Secret Management membangun tangga enam tingkat — dari hardcode yang paling buruk sampai secret manager produksi — lengkap dengan demonstrasi bagaimana rahasia di environment bocor dalam satu perintah docker inspect.
Referensi #
- Seccomp security profiles — format berkas profil seccomp, profil bawaan, dan aturan bersyarat berbasis capability.
- AppArmor security profiles
— isi profil
docker-defaultdan cara memuat profil kustom. - Docker security — posisi seccomp dan LSM dalam kerangka isolasi berlapis.
- docker container run — CLI Reference
— referensi flag
--security-optuntuk seccomp, apparmor, label, dan no-new-privileges.