Mau Docker Kamu Aman Begini Cara Pakai Docker Socket Proxy

Mau Docker Kamu Aman Begini Cara Pakai Docker Socket Proxy
Photo by Yung Chang/Unsplash

Bro, pernah gak sih kepikiran, gimana caranya biar server Docker kamu itu aman? Terutama nih, bagian yang paling krusial, yaitu Docker socket-nya. Nah, kalau kamu masih sering asal kasih akses ke docker.sock ini, siap-siap aja deh, karena itu sama aja kayak ngasih kunci brankas ke siapa aja tanpa pengawasan. Bahaya banget, cuy! Tapi tenang, ada kok solusinya biar Docker kamu tetap aman dan tenang, namanya Docker Socket Proxy. Mari kita kupas tuntas gimana cara kerjanya dan kenapa ini penting banget buat kamu yang mainan Docker.

Kenapa Sih Docker Socket itu Bahaya Banget Kalau Terbuka?

Oke, pertama-tama, kita ngomongin dulu nih si biang kerok yang sering jadi celah keamanan, yaitu Docker socket atau file /var/run/docker.sock. Ini tuh semacam pintu gerbang utama ke Docker daemon kamu. Bayangin aja, ini itu API endpoint yang dipakai sama client Docker (macam CLI docker yang biasa kamu pakai) buat ngobrol sama Docker daemon di balik layar. Lewat socket ini, kamu bisa ngelakuin apa aja: bikin container baru, ngehapus, nge-stop, bahkan ngakses host filesystem, pokoknya semua yang bisa dilakuin sama root user di sistem kamu.

Gini lho, kalau ada aplikasi atau user yang bisa ngakses langsung si docker.sock ini, itu sama aja kayak mereka punya akses sudo penuh ke server kamu. Mereka bisa aja bikin container baru, terus pasangin volume ke / (root directory) host kamu, dan boom! Mereka punya akses root penuh ke server kamu. Ngeri kan? Ini bukan cuma sekadar "bisa bikin container aja", tapi ini level "bisa ngancurin server kamu dalam hitungan detik".

Skenario paling umum di mana ini jadi masalah serius:

  1. CI/CD Pipelines: Sering banget kan, kita setup Jenkins, GitLab CI, atau GitHub Actions runner yang butuh akses ke Docker buat nge-build atau nge-deploy aplikasi. Kalau runner ini langsung dikasih akses penuh ke docker.sock, dan runner itu compromised, habislah server CI/CD kamu.
  2. Aplikasi Pihak Ketiga: Beberapa tools monitoring, manajemen container kayak Portainer, atau bahkan aplikasi kustom, seringnya butuh interaksi sama Docker. Kalau kamu asal kasih akses, tanpa filter, ya sama aja kayak ngasih kunci rumah ke semua orang yang lewat.
  3. Pengembangan Lokal yang Kurang Hati-hati: Kadang di lingkungan dev, kita cenderung "ah, gampangin aja". Padahal, kebiasaan buruk ini bisa terbawa sampai ke production.

Intinya, akses langsung ke docker.sock itu memberikan "God mode" atau mode dewa ke siapa pun yang punya akses. Kalau udah gitu, ya udah, siap-siap aja terima nasib kalau ada apa-apa.

Apa Itu Docker Socket Proxy dan Gimana Cara Dia Nolong?

Nah, di sinilah Docker Socket Proxy masuk sebagai pahlawan. Secara simpel, Docker Socket Proxy itu semacam "satpam" atau "filter" yang duduk di antara client Docker dan Docker daemon yang sebenarnya. Jadi, semua permintaan dari client enggak langsung nyelonong ke Docker daemon, tapi disaring dulu sama si proxy ini.

Idenya itu sederhana tapi brilian: alih-alih ngasih akses langsung ke docker.sock, kamu ngasih akses ke Docker Socket Proxy. Si proxy ini, yang biasanya jalan di container terpisah, akan menerima semua permintaan, ngecek apakah permintaan itu diizinkan berdasarkan aturan yang sudah kamu set, dan kalau diizinkan, baru diteruskan ke Docker daemon yang asli. Kalau enggak diizinkan? Ya langsung diblokir.

Dengan begitu, kamu bisa punya kontrol yang super granular tentang perintah Docker apa aja yang boleh dieksekusi, image apa aja yang boleh di-pull, container mana aja yang boleh di-start/stop, dan seterusnya. Ini jauh lebih aman daripada cuma modal doa biar server kamu gak diapa-apain.

Gimana Cara Kerja Si "Satpam" Ini?

Secara teknis, Docker Socket Proxy itu beroperasi sebagai reverse proxy. Dia mendengarkan koneksi di port atau socket Unix tertentu (bukan langsung di docker.sock asli), terus setiap kali ada permintaan, dia akan:

  1. Menerima Permintaan: Client Docker (misalnya, aplikasi monitoring) mengirimkan permintaan ke proxy.
  2. Menerapkan Aturan: Proxy punya daftar aturan yang sudah kamu konfigurasikan. Aturan ini bisa berupa whitelist perintah Docker (misalnya, cuma ps dan images aja yang boleh), whitelist image, bahkan sampai ke level label container atau kemampuan tertentu.
  3. Meneruskan atau Memblokir: Kalau permintaan itu sesuai sama aturan yang diizinkan, baru deh proxy meneruskan permintaan itu ke docker.sock yang asli. Kalau enggak, ya langsung ditolak mentah-mentah dan log-nya dicatat.

Ini ibaratnya kayak kamu punya filter air. Air kotor masuk, difilter, yang bersih keluar, yang kotor dibuang. Sama kayak gitu, permintaan yang "bersih" dan diizinkan diteruskan, yang "kotor" dan berbahaya diblokir.

Yuk, Kita Setup Docker Socket Proxy (Praktis!)

Pasti udah gak sabar kan gimana cara implementasinya? Tenang, gampang kok. Kita bakal pakai image tecnativa/docker-socket-proxy yang lumayan populer dan stabil. Pastikan kamu sudah punya Docker di server kamu, ya.

Dasar-dasarnya, kamu bisa menjalankan proxy ini sebagai container Docker. Kuncinya ada di environment variables yang kamu set buat container proxy ini. Di sinilah kamu mendefinisikan aturan mainnya.

bash
docker run -d \
  --name docker-socket-proxy \
  -p 127.0.0.1:2375:2375 \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -e LOG_LEVEL="info" \
  -e CONTAINERS="1" \
  -e COMMANDS="1" \
  -e ALLOW_COMMANDS="info,ping,version,ps,images,inspect" \
  tecnativa/docker-socket-proxy

Mari kita bedah satu per satu argumen di atas biar kamu ngerti:

  • docker run -d: Jalanin container di background.
  • --name docker-socket-proxy: Ngasih nama biar gampang ngatur-nya.
  • -p 127.0.0.1:2375:2375: Ini bagian penting! Kita nge-publish port 2375 dari container ke port 2375 di host. Kenapa 127.0.0.1? Biar cuma bisa diakses dari localhost aja, alias dari server itu sendiri. Ini penting banget biar proxy-mu enggak bisa diakses dari luar. Kalau kamu perlu akses dari network lain, kamu harus pasang security tambahan (misalnya TLS) dan firewall yang ketat.
  • -v /var/run/docker.sock:/var/run/docker.sock:ro: Mount Docker socket asli ke dalam container proxy. Penting banget pakai :ro (read-only) biar si proxy enggak bisa mengubah socket asli. Ini prinsip keamanan dasar.
  • -e LOG_LEVEL="info": Untuk ngatur verbosity log dari proxy. Berguna banget buat debugging atau audit.
  • -e CONTAINERS="1" dan -e COMMANDS="1": Ini wajib diset "1" kalau kamu mau pakai filtering berdasarkan container dan command.

-e ALLOW_COMMANDS="info,ping,version,ps,images,inspect": Nah, ini dia intinya! Kamu ngasih tahu perintah Docker apa aja yang diizinkan. Di contoh ini, cuma info, ping, version, ps (list container), images (list image), dan inspect (cek detail objek Docker) yang boleh lewat. Perintah-perintah bahaya kayak create, start, stop, remove, build, exec, tidak diizinkan. Ini contoh paling basic untuk akses read-only*.

Setelah proxy jalan, gimana cara pakai-nya? Gampang. Aplikasi atau client yang tadinya ngakses docker.sock langsung, sekarang kamu arahkan ke proxy. Misalnya, kalau kamu mau pakai CLI docker via proxy:

bash
DOCKER_HOST="tcp://127.0.0.1:2375" docker ps
DOCKER_HOST="tcp://127.0.0.1:2375" docker images

Kalau kamu coba DOCKER_HOST="tcp://127.0.0.1:2375" docker run hello-world, harusnya akan muncul error 403 Forbidden atau semacamnya di log proxy, karena perintah run (yang sebenarnya adalah kombinasi create dan start) tidak diizinkan. Keren kan?

Konfigurasi yang Lebih Detail (Biar Makin Aman)

ALLOW_COMMANDS itu cuma awalannya. Ada banyak banget variabel environment yang bisa kamu pakai buat ngatur si proxy ini biar makin ketat dan sesuai kebutuhan:

ALLOW_COMMANDS: Seperti yang kita bahas, daftar perintah yang diizinkan (dipisahkan koma). Contohnya: ps,images,inspect,start,stop,restart,rm. Jangan pernah pakai (asterisk) di sini, karena itu sama saja tidak pakai proxy!

  • ALLOWPULL: Kalau kamu cuma mau ngizinin pull image tertentu. Contoh: ALLOWPULL="nginx,ubuntu:latest".
  • ALLOWCREATEIMAGE: Kalau kamu cuma mau ngizinin build image dari Dockerfile tertentu. Agak jarang dipakai tapi ada.
  • ALLOW_LABELS: Ini super berguna! Kamu bisa filter berdasarkan label yang ada di container. Misalnya, kamu cuma mau ngizinin start atau stop container yang punya label project=my-app.

ALLOW_LABELS="project=my-app"

  • ALLOWCREATELABELS: Mengizinkan pembuatan container dengan label tertentu.
  • ALLOWBINDMOUNTS: Kalau kamu pengen ngontrol volume mount. Misalnya, cuma boleh mount ke /var/www/html aja. Contoh: ALLOWBINDMOUNTS="/var/www/html"
  • ALLOW_NETWORKS: Mengizinkan container yang dibuat terhubung ke network tertentu.
  • ALLOWEDIMAGES: Ini juga penting banget buat ngebatasin image apa aja yang boleh di-run atau di-pull. Contoh: ALLOWEDIMAGES="nginx:stable,my-custom-app:1.0".

Contoh yang lebih kompleks untuk CI/CD runner yang cuma boleh nge-build image dengan nama dan tag tertentu, serta menjalankan container dengan batasan:

bash
docker run -d \
  --name ci-docker-proxy \
  -p 127.0.0.1:2376:2375 \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -e LOG_LEVEL="debug" \
  -e COMMANDS="1" \
  -e CONTAINERS="1" \
  -e ALLOW_COMMANDS="build,create,start,stop,rm,inspect,ps" \
  -e ALLOW_PULL="debian:latest,alpine:latest" \
  -e ALLOWCREATELABELS="ci-job=,branch=" \
  -e ALLOW_LABELS="ci-job=,branch=" \
  -e ALLOWED_IMAGES="my-app-image:,test-image:" \
  -e ALLOWBINDMOUNTS="/home/jenkins/workspace,/tmp" \
  tecnativa/docker-socket-proxy

Dalam contoh ini, CI runner cuma bisa:

  • Mengeksekusi build, create, start, stop, rm, inspect, ps.
  • Boleh pull debian:latest atau alpine:latest doang.
  • Kalau bikin container, harus ada label ci-job dan branch. Dan cuma boleh ngatur container yang ada label tersebut.

Cuma boleh bikin atau pakai image yang namanya my-app-image: atau test-image:*.

  • Cuma boleh mount volume ke /home/jenkins/workspace atau /tmp.

Ini jauh lebih aman daripada langsung kasih akses ke docker.sock!

Skenario Penggunaan yang Relevan

  1. Jenkins/GitLab CI/GitHub Actions Runners: Ini use case paling populer. Daripada ngasih runner akses root ke Docker daemon, mending kasih akses ke Docker Socket Proxy dengan ALLOWCOMMANDS yang terbatas cuma buat build, create, start, stop, dan rm (kalau perlu ngebersihin container sementara). Plus, pakai ALLOWEDIMAGES dan ALLOWBINDMOUNTS buat ngebatasin apa yang boleh dibuild dan di-run.
  2. Aplikasi Monitoring atau Manajemen: Kalau kamu pakai Portainer, cAdvisor, atau tools serupa yang cuma butuh informasi tentang container (misalnya, list container, status, resource usage), kamu cukup kasih ALLOW_COMMANDS="info,ps,images,inspect,stats". Mereka gak perlu bisa start/stop container sembarangan.
  3. Lingkungan Multi-User Development: Kalau beberapa developer share satu mesin Docker daemon, setiap developer bisa pakai proxy-nya sendiri dengan aturan yang berbeda, atau satu proxy dengan aturan yang ketat berdasarkan label container.
  4. Self-Service Deployment Tools: Misal kamu bikin tools internal yang bisa start/stop aplikasi tertentu. Dengan proxy, tools itu cuma bisa interaksi dengan container yang kamu izinkan via label atau nama.

Best Practices dan Tips Lanjutan

  • Prinsip Least Privilege (PoLP): Ini kuncinya! Selalu berikan hak akses seminimal mungkin yang diperlukan. Kalau aplikasi cuma butuh ngelihat container, ya kasih ps dan inspect aja. Jangan kasih create atau rm.
  • Jangan Ekspos Sembarangan: Kalau kamu pake -p 0.0.0.0:2375:2375 (nge-bind ke semua interface), itu bahaya banget kalau enggak di-firewall dengan ketat dan pakai autentikasi (TLS/mTLS). Lebih baik bind ke 127.0.0.1 atau private network yang aman.
  • Gunakan TLS/mTLS: Kalau memang terpaksa harus ekspos Docker Socket Proxy via TCP di network, WAJIB pakai TLS (Transport Layer Security) untuk enkripsi dan mTLS (mutual TLS) untuk autentikasi client. Jadi, cuma client dengan sertifikat yang valid yang bisa ngobrol sama proxy.
  • Monitor Log Proxy: Rajin-rajinlah cek log dari container docker-socket-proxy kamu. Kalau ada percobaan akses yang ditolak, itu bisa jadi indikasi ada yang aneh atau ada yang kurang pas sama konfigurasi kamu.
  • Kombinasikan dengan Keamanan Lain: Docker Socket Proxy ini bukan peluru perak yang bisa menyelesaikan semua masalah keamanan Docker. Ini harus jadi bagian dari strategi keamanan yang lebih luas, termasuk:

* Firewall: Batasi siapa saja yang bisa mengakses port proxy. * AppArmor/SELinux: Gunakan profil keamanan untuk container Docker itu sendiri. * User Namespaces: Kalau memungkinkan, jalankan Docker daemon dengan user namespaces buat isolasi tambahan. * Docker Content Trust: Pastikan image yang kamu pakai udah ditandatangani dan terpercaya. * Scan Vulnerability: Selalu scan image Docker kamu buat celah keamanan.

  • Review Berkala: Aturan ALLOWCOMMANDS atau ALLOWEDIMAGES yang kamu set hari ini, mungkin besok sudah tidak relevan. Lakukan review berkala untuk memastikan aturan itu masih sesuai dengan kebutuhan dan standar keamanan.

Potensi Kesulitan atau Batasan

Meskipun powerfull, Docker Socket Proxy juga punya beberapa "kelemahan" minor:

  • Kompleksitas Konfigurasi: Untuk skenario yang super kompleks dengan banyak aturan yang saling tumpang tindih, konfigurasinya bisa jadi lumayan ribet dan butuh waktu buat nge-tune-nya.
  • Bukan Pengganti Keamanan Daemon: Proxy ini melindungi akses ke Docker socket, tapi tidak melindungi Docker daemon itu sendiri dari celah keamanan internal. Misalnya, kalau ada bug di Docker daemon, proxy ini tidak bisa banyak membantu.
  • Overhead Kinerja: Secara teori ada sedikit overhead kinerja karena setiap permintaan harus lewat proxy dulu. Tapi dalam prakteknya, untuk kebanyakan kasus, overhead ini sangat minimal dan tidak signifikan.

Kesimpulan

Jadi, kalau kamu mau Docker kamu aman dan terkontrol, Docker Socket Proxy itu wajib banget buat kamu pertimbangkan. Jangan lagi deh ngasih akses God mode ke docker.sock sembarangan. Dengan investasi waktu sedikit untuk konfigurasi, kamu bisa tidur lebih nyenyak karena tahu server kamu gak gampang diutak-atik dari lubang Docker socket. Ingat, keamanan itu investasi, bukan pengeluaran! Yuk, mulai sekarang terapin Docker Socket Proxy di lingkungan kamu. Dijamin, kamu gak bakal nyesel!

Read more