Meninjau bagaimana SELinux mengamankan container: domain container_t dan spc_t, relabeling bind mount dengan opsi :Z dan :z, pengaturan label keamanan pada Podman dan Docker, serta konfigurasi SELinux di Kubernetes pod security context dan integrasi dengan seccomp dan LSM.

Di episode 9, kalian melindungi web server dan database dengan label yang tepat. Sekarang saatnya teknologi yang mengubah cara deployment berjalan: container. Namespaces dan cgroups memisahkan container secara logika, tetapi keduanya tidak menghentikan proses yang lolos untuk mengakses resource host. Di sinilah SELinux muncul sebagai lapisan isolasi kedua — dan karena itu ia berperan besar di runtime seperti Podman, Docker, dan CRI-O.
Jika SELinux mati di host container, satu container yang kompromi bisa membaca data container lain di host yang sama. Episode ini menjelaskan bagaimana SELinux mencegah skenario itu.
Policy container SELinux memperkenalkan dua domain penting:
spc_t (Super Privileged Container) — domain untuk runtime engine seperti dockerd, containerd, podman, dan conmon. Engine ini dipercaya penuh: ia yang membangun dan mengelola semua container.container_t — domain untuk proses yang berjalan di dalam container. Ia terkunci ketat dan tidak otomatis bisa membaca file host.Note
Analoginya: spc_t adalah manajer gedung yang memegang kunci master semua unit, sedangkan container_t adalah penyewa yang hanya punya kunci unitnya sendiri. Pisahkan keduanya dengan tegas — ketika kalian mengeksekusi sesuatu di dalam container, kalian berada di dunia container_t, bukan di dunia host.
Karena proses container berada dalam domain berbeda dari proses host, privilege yang bocor dari dalam container tidak langsung menjadi akses penuh ke host — ia tetap harus melewati aturan tipe SELinux. Inilah alasan container yang menjalankan proses sebagai root tetap bukan "root host" di mata SELinux.
Kebutuhan paling umum adalah memindahkan direktori host ke dalam container dengan bind mount: -v /data:/data. Masalahnya, file /data biasanya berlabel untuk domain tertentu (misalnya default_t atau home user), dan container_t tidak diizinkan membacanya.
Solusinya bukan mengubah label host selamanya, melainkan relabeling saat mount. Dua opsi utama:
:Z — relabel mount dengan label unik per container (privasi penuh). Setiap container mendapat kategori MCS sendiri, sehingga container lain tidak bisa membaca file tersebut.:z — relabel mount dengan label yang dibagi oleh semua container (berbagi). Semua container yang memakai volume itu bisa saling mengakses.podman run -v /data:/data:Z nginxdocker run -v /data:/data:Z nginxImportant
Pilih dengan sadar. :Z memberi isolasi antar container, :z mengizinkan berbagi antar semua container. Jika sebuah volume dipakai bersama beberapa container yang memang harus saling membaca — misalnya volume cache — pakai :z. Untuk data yang hanya milik satu container, selalu :Z. Salah memakai :z pada data sensitif berarti membuka pintu antar container yang seharusnya terisolasi.
Selain :Z dan :z, kedua runtime menyediakan kontrol label yang lebih halus melalui --security-opt:
podman run --security-opt label=type:container_t nginx
podman run --security-opt label=level:s0:c123,c456 nginx
podman run --security-opt label=disable nginxOpsi yang tersedia:
label=type:... — paksa tipe domain tertentu.label=user:... dan label=role:... — set user dan role pada label.label=level:... — set kategori MCS, berguna untuk isolasi antar tenant.label=disable — matikan SELinux untuk container tersebut.Warning
label=disable menghapus lapisan SELinux sepenuhnya untuk container itu. Gunakan hanya untuk troubleshooting jangka pendek atau kasus khusus yang memang memerlukannya — dan pahami bahwa ia meniadakan proteksi yang sedang kita bangun. Kebiasaan "tinggal tambah label=disable" saat denial muncul adalah jalan pintas yang mahal di kemudian hari.
Podman memiliki keuntungan ergonomis: ia otomatis merelabel volume yang dipasang, sehingga banyak kasus :Z/:z tidak perlu ditulis manual. Namun tetap penting memahami apa yang terjadi di balik layar.
Di Kubernetes, runtime (biasanya CRI-O atau containerd) mengambil instruksi SELinux dari pod security context. Konfigurasi dibuat per pod, bukan per container:
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
securityContext:
seLinuxOptions:
user: system_u
role: system_r
type: container_t
level: "s0:c123,c456"
containers:
- name: app
image: nginxSetiap pod diberi level MCS unik. Konsekuensinya sangat penting: pod A dengan level s0:c123 tidak bisa membaca file milik pod B dengan level s0:c456 — meski keduanya sama-sama bertipe container_t. Inilah isolasi antar workload yang sama-sama berjalan di host, tanpa perlu repot mengubah label satu per satu.
Tip
Di cluster besar, jangan mengelola level MCS manual — biarkan runtime atau tooling (misalnya melalui PSP/GAC atau policy engine seperti Kyverno) yang mengalokasikan level unik per pod. Pengelolaan manual mudah salah dan justru menciptakan celah isolasi. Yang perlu dikelola manusia hanyalah pilihan type, user, dan role yang benar untuk beban kerja.
Container runtime memakai beberapa mekanisme keamanan sekaligus, dan penting membedakannya:
Kombinasi ideal di Kubernetes: profile seccomp membatasi syscall, SELinux membatasi akses berdasarkan label, dan cgroups membatasi resource. Tiga lapisan yang bekerja di level berbeda dan saling melengkapi — inilah arti defense in depth yang sesungguhnya.
Pada episode 10 ini kalian sudah melihat bagaimana SELinux menjadi lapisan isolasi kedua untuk container: domain spc_t untuk runtime dan container_t untuk proses container, relabeling bind mount dengan :Z dan :z, kontrol label halus lewat --security-opt, serta konfigurasi seLinuxOptions di Kubernetes dengan level MCS unik per pod.
Kunci yang harus dibawa pulang:
container_t tidak otomatis bisa membaca host — itulah proteksinya.:Z untuk privasi per container, :z untuk berbagi antar container.Sejauh ini semua storage masih lokal di host. Di episode 11, kita akan membawa SELinux ke dunia terdistribusi: NFS, Samba & Network Services — bagaimana labeling bekerja di NFS dengan opsi mount dan noexec, konsekuensi berbagi storage antar host, boolean samba untuk ekspor direktori dan home, serta labeling port untuk layanan non-standar.