Dua chapter terakhir kita habiskan untuk memangkas hak: identitas diturunkan ke user biasa, capability dicabut sampai tersisa hanya yang dibuktikan dibutuhkan aplikasi. Sekarang kita berhadapan dengan bendera yang bekerja ke arah sebaliknya — satu kata pada docker run yang membalik seluruh kerja keras itu dalam sekejap: --privileged. Bendera ini tetap muncul di banyak tutorial internet, sering dijalankan begitu saja untuk “menghilangkan error”, dan hampir selalu tanpa penjelasan apa yang sebenarnya dilepasnya. Chapter ini membongkar keempat pembatas yang dicabut --privileged sekaligus, membuktikan dampaknya lewat mount yang tiba-tiba berhasil dan disk host yang tiba-tiba terlihat, lalu memetakan lima alternatif yang lebih aman untuk setiap alasan klasik yang biasanya dikemukakan.
Empat Pembatas yang Dilepas Sekaligus #
--privileged bukan menambah satu hak — ia membongkar empat keluarga pembatas dalam satu tarikan napas:
| Pembatas | Container bawaan | Container --privileged |
|---|---|---|
| Capabilities | 12 bawaan; sisanya dicabut | semua capability diberikan, termasuk SYS_ADMIN |
Device /dev | hanya node minimal buatan Docker | seluruh device host terlihat |
| Seccomp | profil default menyaring syscall | dimatikan |
| AppArmor dan SELinux | profil default terpasang | dilepas |
Mari kita telaah arti keempat baris tersebut bersama-sama:
- Semua capability diberikan — daftar dua belas dari Chapter Linux Capabilities berubah menjadi daftar lengkap milik root host;
SYS_ADMINyang kita tandai sebagai pintu utama breakout kini melekat pada proses. - Seluruh device host terlihat — antarmuka
/devcontainer yang biasanya hanya berisi belasan node aman kini menampilkan semua device yang dimiliki host, termasuk disk fisik. - Seccomp dimatikan — filter syscall yang menolak syscall berbahaya sebelum menyentuh kernel ikut dicabut; pintu depan berdiri terbuka.
- Profil LSM dilepas — cangkang kelima pada diagram Chapter Prinsip Keamanan Container ikut menyingkir; operasi sensitif tidak lagi diperiksa profil AppArmor atau SELinux.
Digabungkan dengan rumus chapter pembuka: root di dalam container --privileged berarti kekuatan penuh root di host tanpa capability yang dicabut — hanya pandangan namespace masih tersisa, dan itupun tidak lagi menyembunyikan device host.
Membuktikannya dengan mount #
mount adalah syscall yang dijaga SYS_ADMIN — capability yang tidak pernah dibawa container bawaan. Kita coba memasang tmpfs pada container biasa:
$ docker run --rm ubuntu:24.04 mount -t tmpfs none /mntOutput yang Dihasilkan:
mount: /mnt: permission denied.
dmesg(1) may have more details after failed mount(8) system call.Kernel menolak mount dengan galat izin — persis perilaku yang kita ramalkan dari tabel capability. Sekarang perintah yang sama pada container --privileged:
$ docker run --rm --privileged ubuntu:24.04 sh -c "mount -t tmpfs none /mnt && touch /mnt/berhasil && echo mount-berhasil"Output yang Dihasilkan:
mount-berhasilSatu bendera, dan syscall yang tadinya ditolak kini dikerjakan kernel tanpa komplain. SYS_ADMIN yang diberikan --privileged membukakan tidak hanya mount tmpfs — yang sama berlaku untuk me-mount filesystem host, membentuk namespace baru, dan puluhan operasi administratif kernel lainnya.
Bukti Bahaya: Disk Host yang Tiba-tiba Terlihat #
Baris kedua tabel di atas terasa abstrak sampai kita melihatnya langsung. Berikut isi /dev container ubuntu biasa:
$ docker run --rm ubuntu:24.04 ls /devOutput yang Dihasilkan:
core fd full mqueue mqueue-priority null ptmx random shm stderr stdin stdout tty urandom zeroBelasan node yang seluruhnya buatan Docker — aman, tanpa satu pun device fisik host. Pada container --privileged, daftar itu meledak menjadi seluruh device host:
$ docker run --rm --privileged ubuntu:24.04 ls /dev | wc -lOutput yang Dihasilkan:
168$ docker run --rm --privileged ubuntu:24.04 ls /dev | grep -E "^sd|^nvme"Output yang Dihasilkan:
nvme0n1
nvme0n1p1
nvme0n1p2
nvme0n1p3
sda
sda1
sda2Mari kita telaah apa yang baru saja terlihat:
nvme0n1adalah SSD utama host Budi — partisinvme0n1p1sampainvme0n1p3adalah pembagian disk itu, termasuk partisi sistem tempat kernel host dan seluruh data berada.sdaadalah disk data yang terpasang di host — container biasa tidak pernah tahu keberadaannya; container--privilegedbisa membuka dan menulisnya seperti proses root di host.- Satu perintah
ddyang menulis ke/dev/sdaberarti host terformat — tidak ada lapisan Docker yang menghalangi; device node yang terlihat adalah device sungguhan, dan hak menulisnya kini dimiliki proses di dalam container.
Kenapa –privileged Tetap Ada #
Bendera ini tidak diciptakan untuk menghabisi keamanan — ada tiga kebutuhan sah yang memang menuntutnya. Yang pertama dan paling klasik: Docker-in-Docker sungguhan — image docker:dind menjalankan daemon Docker kedua di dalam container, dan daemon itu perlu membuat namespace, mount, dan cgroups sendiri; pekerjaan yang menuntut SYS_ADMIN dan kawan-kawannya. Yang kedua: akses perangkat keras yang butuh lebih dari satu device dan kontrol penuh atasnya — lab kernel, pengujian modul, atau fuzzing syscall pada kernel yang berjalan. Yang ketiga: sebagian tool diagnosa tingkat rendah yang memang membaca keadaan kernel host secara langsung.
Masalahnya bukan keberadaan benderanya, melainkan pemakaiannya: sembilan dari sepuluh --privileged yang kita temui di tutorial internet menyelesaikan masalah yang sebenarnya hanya butuh satu capability, satu device, atau satu pola arsitektur yang berbeda.
Lima Alternatif yang Lebih Aman #
| Kebutuhan klasik | Alternatif lebih aman | Pembahasan |
|---|---|---|
| “Error permission, butuh hak lebih” | --cap-add satu capability spesifik | Chapter Linux Capabilities |
| Bicara dengan device hardware | --device /dev/ttyUSB0 | demo di bawah |
| Menjalankan Docker untuk CI di container | pola sibling: pasang docker.sock + socket-proxy | demo di bawah |
| Daemon Docker tanpa root sama sekali | rootless mode | Chapter Docker Socket Security |
| Beban tak dipercaya yang butuh isolasi mendekati VM | Sysbox | disebut nama |
Demo --device menunjukkan betapa sempitnya pintu yang sebenarnya dibutuhkan. Container berikut diminta bicara dengan satu device serial fisik — dan hanya device itu:
$ docker run --rm --device /dev/ttyUSB0 ubuntu:24.04 ls -l /dev/ttyUSB0Output yang Dihasilkan:
crw-rw---- 1 root dialout 188, 0 Oct 13 11:07 /dev/ttyUSB0Mari kita telaah sempitnya izin tersebut:
- Hanya
/dev/ttyUSB0yang dibukakan — cgroup device controller memberi container hak membuka device itu dan tidak ada yang lain;ls /devtetap menampilkan daftar minimal seperti container biasa. - Device node muncul dengan identitas aslinya — major/minor number 188,0 dan grup
dialoutsama persis seperti di host, sehingga aplikasi di dalam container bisa langsung membuka dan membaca-menulis port serial. - Proses non-root tinggal menambah grup — flag
--group-add 20memasukkan proses ke grup dialout bernomor 20 tanpa memberikan capability apa pun; akses device diatur izin berkas biasa, bukan privilege kernel.
Kontras dengan --privileged terang benderang: satu pintu kecil yang dibuka dengan kunci pas, dibanding empat tembok yang diratakan sekaligus.
Docker-in-Docker versus Pola Sibling #
Kebutuhan paling sering dikutip sebagai pembenaran --privileged adalah “saya butuh Docker di dalam Docker” — biasanya untuk menjalankan build bercontainer di dalam CI. Dua rancangan sangat berbeda berbagi kebutuhan itu. Docker-in-Docker (DinD) sungguhan menjalankan daemon kedua di dalam container dan memang menuntut --privileged. Pola sibling justru tidak menjalankan daemon sama sekali: container hanya membawa klien CLI, dan berbicara ke daemon host lewat docker.sock yang dipasang sebagai bind mount. Kita buktikan bahwa daemon yang menjawab memang daemon host:
$ docker run --rm --name cli-saudara \
-v /var/run/docker.sock:/var/run/docker.sock \
docker:29-cli docker psOutput yang Dihasilkan:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4b7e2a91c8d3 docker:29-cli "docker ps" 5 seconds ago Up 3 seconds cli-saudaraMari kita telaah bukti di dalam output tersebut:
docker psmenampilkan container CLI itu sendiri — containercli-saudarasedang berjalan sebagai container di daemon host, dan klien di dalamnya melihat dirinya dari luar; kalau ini DinD sungguhan, daftar justru kosong karena daemon di dalamnya baru menyala tanpa container.- Container CLI adalah saudara, bukan induk — container yang nanti diluncurkan lewat CLI ini menjadi container host juga, sejajar dengan siapa pun yang menjalankan
docker rundi mesin itu. - Socket adalah kunci kerajaan — siapa pun yang bisa membaca
/var/run/docker.sockbisa menjalankan container baru dengan--privileged, mem-mount root filesystem host, dan menarik serta menjalankan image dari registry mana pun; socket itu setara root host. Pola pengamanan socket-proxy yang menyaring perintah yang lewat adalah materi penutup section ini, Chapter Docker Socket Security.
Verifikasi #
Status privileged sebuah container terbaca dari docker inspect — berguna untuk mengaudit container yang dibuat orang lain atau oleh template lama:
$ docker run -d --name contoh-priv --privileged nginx:1.29Output yang Dihasilkan:
f1a9c3e7b2d64f8a0c5e9b3d7f1a4c6e8b0d2f5a7c9e1b3d5f7a0c4e8b2d6f9a$ docker inspect --format '{{.HostConfig.Privileged}}' contoh-privOutput yang Dihasilkan:
trueContainer uji itu langsung kita buang — docker rm -f contoh-priv — karena tidak ada alasan membiarkannya menyala lebih lama dari yang diperlukan demo.
Empat pembatas kini kita kenal sisi longgarnya; chapter-chapter berikutnya menegakkan sisi sebaliknya satu per satu. Yang pertama paling murah sekaligus paling mengejutkan dayanya: membekukan seluruh filesystem container sehingga proses mana pun — root sekalipun — tidak bisa menulis satu byte pun ke disk. Chapter Read-Only Filesystem membahas flag --read-only, pola tmpfs sebagai satu-satunya lubang tulis yang diberikan dengan sengaja, dan kombinasi emas yang menggabungkan seluruh pelajaran section ini.
Referensi #
- Docker security
— pembahasan resmi efek
--privilegedterhadap capabilities, device, seccomp, dan LSM. - docker container run — CLI Reference
— referensi flag
--privilegeddan--device. - Rootless mode — daemon Docker tanpa root sebagai alternatif fundamental.