Celah Keamanan Docker dan UFW

Secara default, kombinasi UFW dengan Docker tidak akan berjalan sebagaimana mestinya. UFW berfungsi sebagai aplikasi firewall yang memanipulasi aturan iptables, di sisi lain, Docker juga mengkonfikurasi iptables secara langsung untuk mengatur jalannya aplikasi ini tersendiri. Dengan demikian, ada dua hal yang bertabrakan sehingga Docker tidak akan mematuhi perintah dan konfigurasi UFW.

Cara Kerja UFW

UFW(Uncomplicated Firewall) merupakan sebuah front-end untuk aplikasi iptables. Aplikasi ini dibuat dengan tujuan untuk mensimplifikasi pengaturan firewall pada Linux, dikarenakan konfigurasi iptables ini cukup rumit, yang dimana berhubungan atau berinteraksi langsung dengan aturan netfilter.

Netfilter sendiri merupakan sebuah framework pada kernel Linux untuk mengatur packet filtering, network address [dan port]translation (NA[P]T), packet logging, userspace packet queueing dan other packet mangling.[1]

Syntax UFW mempermudah pengaturan firewall dengan cara memanipulasi perintah iptables. Sebagai contoh, perintah seperti ufw allow from <IP> to any akan diterjemahkan menjadi syntax yang dimengerti oleh iptables, iptables -A INPUT -s <IP> -j ACCEPT. Dan juga berbagai perintah lainnya yang berfungsi untuk logging serta juga rate limiting.

Proses Kerja Docker

Docker mengisolasi proses networking-nya dengan cara memanipulasi langsung iptables.[2] Oleh karena itu, Docker secara otomatis membuat dua aturan utama pada iptables sebelum aturan iptables lainnya, sehingga, segala paket apapun yang masuk akan dicek terlebih dahulu melalui dua aturan terkait yang berasal dari Docker.

Penyebab

Infomasi bagaiamana Docker memanipulasi iptables tersedia di halaman dokumentasi Docker, ada poin penting yang mengindikasi di mana letak permasalahannya ketika memakai aplikasi firewall.

Docker installs two custom iptables chains named DOCKER-USER and DOCKER, and it ensures that incoming packets are always checked by these two chains first.

All of Docker’s iptables rules are added to the DOCKER chain. Do not manipulate this chain manually. If you need to add rules which load before Docker’s rules, add them to the DOCKER-USER chain. These rules are applied before any rules Docker creates automatically.

Rules added to the FORWARD chain -- either manually, or by another iptables-based firewall -- are evaluated after these chains. This means that if you expose a port through Docker, this port gets exposed no matter what rules your firewall has configured. If you want those rules to apply even when a port gets exposed through Docker, you must add these rules to the DOCKER-USER chain.

https://docs.docker.com/network/iptables/#add-iptables-policies-before-dockers-rules

Singkatnya, pada iptables aturan DOCKER akan mendahului aturan mendatang lainnya, jadi, jika suatu port tidak terlebih dahulu dijelaskan pada aturan DOCKER, port terkait akan terekspos.

Solusi

Sebagaimana letak permasalahannya di atas, ada cara untuk menanggulangi masalah tersebut. Yaitu, dengan cara mengubah konfigurasi default atas bagaimana UFW berinteraksi dengan iptables, dengan menambahakan aturan khusus pada DOCKER-USER.

Untungnya, sudah ada developer dan para komunitas yang berkontribusi untuk memperbaiki celah keamanan ini.[3] Cara menanggulanginya adalah sebagai berikut.

  1. Buka file /etc/ufw/after.rules
  2. Tambahkan aturan khusus di bawah ini pada akhir file tersebut
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER
  1. Lalu, restart UFW. Pada kasus tertentu, aturan tersebut baru bisa berlaku ketika sudah merestart server, jadi pastikan aturan di atas sudah teraplikasi.

Ada pun penjelasan dan alasan akan konfigurasi tersebut tersedia pada link yang saya kaitkan di footnote ketiga.

Penutup

Referensi bacaan lebih mendalam yang berkaitan dengan beberapa hal pada tulisan ini sebagai berikut.'


  1. https://netfilter.org/ ↩︎

  2. https://docs.docker.com/network/iptables/ ↩︎

  3. https://github.com/chaifeng/ufw-docker#solving-ufw-and-docker-issues ↩︎