Langkah-langkah untuk membatasi koneksi luar ke wadah docker dengan iptables?

Tujuan saya adalah membatasi akses ke wadah docker hanya ke beberapa alamat IP publik. Apakah ada proses yang sederhana dan berulang untuk mencapai tujuan saya? Memahami hanya dasar-dasar iptables saat menggunakan opsi default Docker, saya merasa sangat sulit.

Saya ingin menjalankan wadah, membuatnya terlihat oleh internet publik, tetapi hanya mengizinkan koneksi dari host tertentu. Saya berharap untuk menetapkan kebijakan input default penolakan dan kemudian hanya mengizinkan koneksi dari host saya. Tetapi aturan dan rantai Nat Docker menghalangi dan aturan INPUT saya diabaikan.

Dapatkah seseorang memberikan contoh bagaimana mencapai tujuan saya dengan asumsi berikut?

  • Host IP publik 80.80.80.80 di eth0
  • Host IP pribadi 192.168.1.10 di eth1
  • docker run -d -p 3306:3306 mysql
  • Blokir semua koneksi ke host / container 3306 kecuali dari host 4.4.4.4 dan 8.8.8.8

Saya senang mengikat wadah hanya ke alamat ip lokal tetapi akan memerlukan instruksi tentang cara mengatur aturan penerusan iptables dengan benar yang bertahan dari proses buruh pelabuhan dan host dimulai ulang.

Terima kasih!

Dua hal yang perlu diingat saat bekerja dengan aturan firewall docker:

  1. Untuk menghindari aturan yang musnah oleh docker, gunakan DOCKER-USER rantai
  2. Docker melakukan pemetaan port di PREROUTING rantai nat meja. Hal ini terjadi sebelum filter aturan, jadi --dest dan --dport akan melihat IP internal dan port wadah. Untuk mengakses tujuan awal, Anda dapat menggunakan -m conntrack --ctorigdstport.

Misalnya:

iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPTiptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPTiptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

Catatan: tanpa --ctdir ORIGINAL, ini juga akan cocok dengan paket balasan yang kembali untuk koneksi dari wadah ke port 3306 di beberapa server lain, yang hampir pasti bukan yang anda inginkan! Anda tidak benar-benar membutuhkan ini jika seperti saya aturan pertama Anda adalah -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, karena itu akan menangani semua paket balasan, tetapi akan lebih aman untuk tetap menggunakan --ctdir ORIGINAL pokoknya.

Dengan Docker v. 17.06 ada rantai iptables baru yang disebut DOCKER-USER. Yang ini untuk aturan khusus Anda: https://docs.docker.com/network/iptables/

Berbeda dengan chain DOCKER, ini tidak diatur ulang saat membangun/memulai kontainer. Jadi, Anda dapat menambahkan baris ini ke konfigurasi/skrip iptables Anda untuk menyediakan server bahkan sebelum menginstal docker dan memulai wadah:

-N DOCKER-N DOCKER-ISOLATION-N DOCKER-USER-A DOCKER-ISOLATION -j RETURN-A DOCKER-USER -i eth0 -p tcp -m tcp --dport 3306 -j DROP-A DOCKER-USER -j RETURN

Sekarang port untuk MySQL diblokir dari akses eksternal (eth0) bahkan berpikir docker membuka port untuk dunia. (Aturan ini mengasumsikan, antarmuka eksternal Anda adalah eth0.)

Akhirnya, Anda harus membersihkan iptables restart layanan docker terlebih dahulu, jika Anda terlalu mengacaukannya mencoba mengunci port seperti yang saya lakukan.

Pembaruan: Sementara jawaban ini masih valid jawaban oleh @ SystemParadox menggunakan DOCKER-USER dalam kombinasi dengan --ctorigdstport lebih baik.

Berikut adalah solusi yang bertahan dengan baik antara restart dan memungkinkan Anda untuk mempengaruhi terkena port daripada internal pelabuhan.

iptables -t mangle -N DOCKER-mysqliptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURNiptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURNiptables -t mangle -A DOCKER-mysql -j DROPiptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --dport 3306 -j DOCKER-mysql

Saya telah membuat gambar buruh pelabuhan yang menggunakan metode ini untuk mengelola iptables secara otomatis untuk Anda, menggunakan variabel lingkungan atau secara dinamis dengan etcd (atau keduanya):

https://hub.docker.com/r/colinmollenhour/confd-firewall/

Pembaruan: Meskipun berlaku pada tahun 2015, solusi ini bukan lagi cara yang tepat untuk melakukannya.

Jawabannya tampaknya ada dalam dokumentasi Docker di https://docs.docker.com/articles/networking/#the-world

Aturan maju Docker mengizinkan semua IP sumber eksternal secara default. Untuk mengizinkan hanya IP atau jaringan tertentu untuk mengakses wadah, masukkan aturan yang dinegasikan di bagian atas rantai filter DOCKER. Misalnya, untuk membatasi akses eksternal sehingga hanya IP sumber 8.8.8.8 yang dapat mengakses wadah, aturan berikut dapat ditambahkan: iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

Apa yang akhirnya saya lakukan adalah:

iptables -I DOCKER -i eth0 -s 8.8.8.8 -p tcp --dport 3306 -j ACCEPTiptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPTiptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

Saya tidak menyentuh --iptables atau --icc pilihan.