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

20

Tujuan saya adalah membatasi akses ke kontainer buruh pelabuhan hanya ke beberapa alamat IP publik. Apakah ada proses 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 standar dari REJECT dan kemudian hanya mengizinkan koneksi dari host saya. Tapi aturan dan rantai Docker menghalangi dan aturan INPUT saya diabaikan.

Adakah yang bisa 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 pada eth1
  • docker run -d -p 3306:3306 mysql
  • Blokir semua koneksi ke host / wadah 3306 kecuali dari host 4.4.4.4 dan 8.8.8.8

Saya senang untuk mengikat wadah hanya ke alamat ip lokal tetapi akan membutuhkan instruksi tentang cara mengatur aturan penerusan iptables dengan benar yang selamat dari proses buruh pelabuhan dan host restart.

Terima kasih!

GGGforce
sumber

Jawaban:

15

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

  1. Untuk menghindari aturan Anda dihancurkan oleh buruh pelabuhan, gunakan DOCKER-USERrantai
  2. Docker melakukan pemetaan-port di PREROUTINGrantai nattabel. Ini terjadi sebelum filteraturan, jadi --destdan --dportakan melihat IP internal dan port wadah. Untuk mengakses tujuan awal, Anda bisa menggunakan -m conntrack --ctorigdstport.

Sebagai contoh:

iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -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 datang kembali untuk koneksi dari wadah ke port 3306 pada 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 tetap akan lebih aman untuk tetap menggunakannya --ctdir ORIGINAL.

SystemParadox
sumber
Haruskah ini diedit untuk memasukkan --ctdir ? Saya menggunakan-m conntrack --ctstate NEW --ctorigdstport 3306 --ctdir ORIGINAL
lonix
@Ionix, ya seharusnya, meskipun saya baru saja mengetahui mengapa itu membingungkan saya. Saya telah menambahkan sedikit penjelasan.
SystemParadox
1
Perhatikan DOCKER-USERtabel default berisi entri: -A DOCKER-USER -j RETURNyang akan berjalan sebelum di atas jika Anda gunakan -A. Solusinya adalah dengan memasukkan aturan di kepala dalam urutan terbalik -I.
BMitch
@BMitch Atau bahkan lebih baik lagi , tambahkan semua aturan dalam FILTERSrantai baru , dan -Imasukkan aturan baru (seperti yang Anda katakan), untuk melompat ke sana: -I INPUT -j FILTERSdan-I DOCKER-USER -i eth0 -j FILTERS
lonix
@BMitch Namun, saya baru saja memeriksa server saya, dan aturan pengembalian tidak ada, mungkin versi buruh pelabuhan terbaru tidak lagi menyisipkannya? Ide bagus untuk digunakan -I, hanya untuk aman.
Lonix
8

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/

Tidak seperti rantai DOCKER itu tidak diatur ulang pada membangun / memulai wadah. Jadi Anda bisa menambahkan baris-baris ini ke konfigurasi / skrip iptables Anda untuk menyediakan server bahkan sebelum menginstal buruh pelabuhan 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 buruh pelabuhan membuka port untuk dunia. (Aturan ini menganggap, antarmuka eksternal Anda adalah eth0.)

Akhirnya, Anda harus membersihkan iptables untuk me-restart layanan buruh pelabuhan terlebih dahulu, jika Anda mengacaukannya terlalu banyak mencoba untuk mengunci port seperti yang saya lakukan.

ck1
sumber
Saya rindu mengapa tabel DOCKER-USER ini berbeda dari tabel yang ditambahkan pengguna lainnya. Tabel ini tidak memiliki filter yang diterapkan sebelumnya sehingga Anda masih harus menentukan sendiri nama antarmuka. Jika Anda membuat "RANTAI SAYA" dan memasukkannya ke rantai FORWARD, hasilnya akan sama, bukan?
ColinM
Ya, itu membuat perbedaan, karena Docker menyisipkan rantai DOCKER-USER ke dalam rantai FORWARD: -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION Itulah sebabnya, instruksi khusus dijalankan sebelum rantai DOCKER.
ck1
Perhatikan bahwa jika Anda menggunakan --dportdi dalam DOCKER-USER ini harus cocok dengan IP internal layanan kontainer, bukan port yang terbuka. Ini sering cocok tetapi tidak selalu dan ini dapat dengan mudah bertentangan dengan layanan lain jadi saya masih berpendapat bahwa solusi DOCKER-USER ini setengah matang.
ColinM
4

MEMPERBARUI : Meskipun valid pada tahun 2015, solusi ini tidak lagi merupakan cara yang tepat untuk melakukannya.

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

Aturan penerusan 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 sumber IP 8.8.8.8 yang dapat mengakses kontainer, 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 ACCEPT
iptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

Saya tidak menyentuh opsi --iptablesatau --icc.

GGGforce
sumber
1
Jika Anda melakukannya iptables -vnL DOCKER, port tujuan adalah semua port di dalam wadah. Jika saya benar, itu berarti aturan di atas hanya akan mempengaruhi port 3306di dalam wadah - yaitu, jika Anda ke -p 12345:3306wadah Anda, aturan Anda masih akan menjadi yang diperlukan untuk mengunci akses (yaitu --dport 12345tidak akan berfungsi) , karena aturan ACCEPT rantai DOCKER bersifat post-NAT.
sunside
Itu benar, aturan harus terkait dengan port di dalam wadah.
GGGforce
1
Hum, itu agak jelek jika Anda menjalankan beberapa kontainer yang menggunakan, katakanlah, sebuah NGINX internal untuk melakukan reverse proxying (mis. Zabbix, penyeimbang beban khusus, dll.) Karena itu mengharuskan Anda untuk mengetahui IP kontainer di muka. Saya masih mencari solusi untuk masalah yang tidak memerlukan --iptables=false, karena ini tampaknya menjadi pilihan terburuk dari semuanya.
sunside
Terima kasih! Anda telah memecahkan masalah saya setelah beberapa jam mencari. Sekarang saya akhirnya dapat mem-jailed MySQL hanya ke alamat IP rumah saya tanpa mengekspos perut lunak ke seluruh dunia.
Matt Cavanagh
1
Rantai DOCKER tidak seharusnya dimanipulasi secara langsung oleh pengguna! Gunakan rantai DOCKER-USER untuk itu. Periksa jawaban yang diterima.
Paul-Sebastian Manole
3

UPDATE: Meskipun jawaban ini masih valid, jawaban yang digunakan oleh @SystemParadox DOCKER-USERdalam kombinasi dengan --ctorigdstportlebih baik.

Berikut ini adalah solusi yang bertahan dengan baik di antara restart dan memungkinkan Anda untuk memengaruhi port yang terbuka daripada port internal .

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

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

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

ColinM
sumber