
Hari 52: K8s Escape, Falco Blind, Banjir 1000 Alert Palsu
Simulasi red team: keluar dari container Kubernetes, baca kredensial node. Falco diam total. Saat diperbaiki, malah banjir alert palsu. Ini ceritanya.
Hari ke-52 dari challenge 60 Days DevSecOps. Topiknya: red team — simulasi penyerang yang berhasil keluar dari container Kubernetes dan mencoba mencuri kredensial node.
Hasilnya? Escape-nya berhasil. Tapi yang lebih menarik adalah apa yang terjadi setelahnya: alat deteksi Falco awalnya diam total, dan saat diperbaiki, malah banjir 1000+ alert palsu. Mari saya ceritakan urutannya.
Skenarionya
Bayangkan ada penyerang yang sudah berhasil masuk ke cluster Kubernetes. Target berikutnya: keluar dari container untuk sampai ke mesin node. Caranya? Deploy pod khusus dengan hak akses penuh.
spec:
hostPID: true
containers:
- name: attacker
image: alpine
securityContext:
privileged: true
Ada dua kunci di sini. privileged: true kasih akses ke device dan capabilities penuh. hostPID: true kasih akses ke daftar proses di mesin node. Tanpa hostPID, tool escape hanya melihat proses di dalam pod sendiri — bukan mesin host. Kombinasi keduanya seperti kasih kunci master ke penyerang.
Escape Berhasil
Di dalam pod itu, penyerang pakai tool nsenter untuk "loncat" ke namespace mesin host:
nsenter -t 1 -m -u -n -i sh
Sekali jalan, shell sudah pindah ke mesin node. Buktnya: hostname berubah dari nama pod jadi nama node. Penyerang sekarang jalan sebagai root di mesin host.
Dari situ, tinggal baca file kredensial:
cat /var/lib/rancher/k3s/agent/kubelet.kubeconfig
File itu berisi identitas node untuk bicara dengan Kubernetes API. Kalau ini production, penyerang bisa kontrol seluruh cluster.
Plot Twist 1: Falco Diam Total
Saya yakin Falco akan langsung membunyikan alarm. Ternyata: diam total. Tidak ada satupun alert.
Setelah dibongkar, penyebabnya menarik. Falco seharusnya punya 300+ rule deteksi standar. Tapi cluster k3d saya tanpa internet, jadi proses download rules otomatis gagal diam-diam. Yang aktif cuma 26 rule minimal dari image. Rule untuk deteksi privileged dan nsenter tidak ada.
Ini pelajaran pertama: jangan pernah berkata "pasti terdeteksi" sebelum cek ruleset yang benar-benar terpasang. Asumsi bahwa Falco otomatis deteksi semuanya ternyata salah.
Plot Twist 2: Banjir 1000+ Alert Palsu
Saya tambahkan 3 rule baru: deteksi privileged container, deteksi nsenter, dan deteksi baca kredensial node. Jalankan attack lagi — alarm berbunyi, semua CRITICAL. Mantap.
Tapi beberapa menit kemudian, Slack banjir. Bukan karena serangan — tapi karena false positive. Rule kredensial yang saya tulis pakai prefix match: "baca file di folder /var/lib/rancher/k3s/agent". Ternyata containerd juga simpan rootfs semua container di folder yang sama. Setiap container baca file apapun = alert CRITICAL.
Sekitar 1000+ notifikasi palsu dalam hitungan menit. Buffer Slack jebak. Tim security kalau lihat ini pasti mute channel.
Perbaikannya butuh 3 iterasi:
- Ganti prefix match jadi nama file persis (
endswith client-kubelet.crt). Banjir berhenti, tapi masih bocor. - Ternyata kubelet sendiri baca cert-nya berkali-kali untuk rotasi sertifikat. Tambah filter: hanya trigger kalau baca dari dalam container, bukan proses host. Masih bocor.
- Ternyata
traefikdanpause(container sistem) juga baca cert yang sama. Tambah exclude namespace sistem dan proses sistem. Akhirnya: 0 alert palsu, alert asli tetap jalan.
Pelajaran kedua: rule yang match terlalu banyak lebih berbahaya dari rule yang kurang. Alert palsu menenggelamkan alert asli. Setelah tulis rule, selalu amati 5-10 menit untuk pastikan tidak ada noise.
Plot Twist 3: OPA Tidak Benar-benar Menjaga
Saya juga iseng test OPA Gatekeeper — alat yang seharusnya memblokir pod berbahaya. Deploy pod privileged di namespace yang "dilindungi OPA". Hasilnya? Lolos begitu saja.
Ternyata OPA saya cuma punya 1 kebijakan: wajib isi resource limits. Tidak ada kebijakan melarang privileged container atau hostPID. Saya deploy OPA 16 hari lalu, dan selama 16 hari tidak pernah sadar ada gap.
Dua file kebijakan baru, dan sekarang pod privileged + hostPID diblokir dengan pesan jelas:
Container 'attacker' is privileged — K8s escape risk
Pod sets hostPID: true — host PID namespace access is a K8s escape risk
Pelajaran ketiga: asumsi bahwa security control berjalan = lubang keamanan terbesar. Trust but verify, bahkan terhadap konfigurasi sendiri. Setelah deploy security control, test negatif: coba deploy yang harusnya diblokir.
Bonus: Falco Sendiri Sedang Sakit
Saat troubleshooting, ketemu masalah lain: Falcosidekick WebUI CrashLoopBackOff selama 8 hari. 5 pod sampah stuck di agent nodes yang NotReady. Daemonset tidak bisa rollout rules baru karena pod lama tidak mau mati.
Solusi: disable WebUI (rusak dan tidak esensial), force-delete semua pod sampah, restart. Final state: 3 pod bersih, 0 restart, 0 CrashLoop. Pipeline end-to-end jalan normal lagi: Falco deteksi → forward → webhook → Slack.
Lessons Learned
Dari simulasi ini, ada beberapa pelajaran yang saya bawa:
- Keamanan harus berlapis. Pod privileged harus diblokir di admission (OPA), tapi kalau lolos, harus tetap terdeteksi di runtime (Falco). Jangan andalkan satu lapis saja.
- Verifikasi ruleset, jangan asumsi. Falco "seharusnya" punya 300+ rule, kenyataannya cuma 26. Selalu cek apa yang benar-benar terpasang.
- Detection rule harus presisi. Butuh 3 iterasi untuk dapet rule yang bersih dari false positive. Rule yang terlalu lebar = alert fatigue = tim security mute semuanya.
- Test negatif setelah deploy control. Coba deploy yang harusnya diblokir. Kalau lolos, policy tidak lengkap. OPA saya lolos 16 hari tanpa disadari.
- Cluster health itu prasyarat. Node NotReady, pod stuck, CrashLoopBackOff — semua bisa block deployment security control. Lab yang tidak di-maintain menghasilkan result yang menyesatkan.
Kesimpulan
Hari ini adalah salah satu hari paling berharga di challenge ini. Bukan karena escape-nya berhasil — itu ekspektasi. Tapi karena menemukan 3 hal yang tidak sesuai ekspektasi: Falco blind, rule banjir FP, dan OPA tidak menjaga. Semua ditemukan karena red team test, bukan karena audit dokumen.
Kode lengkap simulasi ini ada di repo: chalange-devsecops — lihat folder securebank-api/k8s/ untuk attacker pod, securebank-api/security/falco-rules/ untuk rule deteksi, dan securebank-api/k8s/gatekeeper/ untuk kebijakan OPA.
Besok: lanjut ke skenario leaked credentials — kunci AWS yang sengaja dibocorkan, lalu observasi CloudTrail dan script auto-revoke.
Diskusi & Komentar
Artikel Terkait
Hari 20: Terraform + Checkov, 15 Celah IaC Ketahuan
Bikin infrastructure as code pakai Terraform, lalu scan dengan Checkov. Hasilnya 15 celah keamanan ketahuan — S3 tanpa enkripsi, security group terbuka ke dunia.
Hari 22: Pipeline IaC, Dua Scanner Barengan Gagal
Bikin workflow GitHub Actions khusus infrastructure security. Checkov dan Trivy IaC scan Terraform barengan. Hasilnya pipeline MERAH — security gate bekerja!
Hari 22 Bonus: Perbaikan Pipeline Gitleaks yang Merah Diam-diam
Pipeline Gitleaks merah sejak Day 14 karena flag --no-gitignore tidak pernah ada. Gitleaks detect scan git history, bukan working directory. Fix: hapus flag.