Moby: Jaringan Docker melewati Firewall, tidak ada opsi untuk menonaktifkan

Dibuat pada 14 Apr 2016  ·  114Komentar  ·  Sumber: moby/moby

Keluaran dari docker version :

Client:
 Version:      1.10.3
 API version:  1.22
 Go version:   go1.5.3
 Git commit:   20f81dd
 Built:        Thu Mar 10 15:54:52 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.10.3
 API version:  1.22
 Go version:   go1.5.3
 Git commit:   20f81dd
 Built:        Thu Mar 10 15:54:52 2016
 OS/Arch:      linux/amd64

Keluaran dari docker info :

Containers: 14
 Running: 5
 Paused: 0
 Stopped: 9
Images: 152
Server Version: 1.10.3
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 204
 Dirperm1 Supported: false
Execution Driver: native-0.2
Logging Driver: json-file
Plugins: 
 Volume: local
 Network: bridge null host
Kernel Version: 3.13.0-58-generic
Operating System: Ubuntu 14.04.4 LTS
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 7.793 GiB
Name: brm-pheonix-dev
ID: Y6Z4:6D53:RFOL:Z3CM:P7ZK:H6HL:RLV5:JT73:LZMC:DTBD:7ILK:2RS5
Username: benjamenmeyer
Registry: https://index.docker.io/v1/

Detail lingkungan tambahan (AWS, VirtualBox, fisik, dll.):
Rackspace Cloud Server, Ubuntu 14.04, tapi itu tidak terlalu penting

Langkah-langkah untuk mereproduksi masalah:

  1. Siapkan sistem dengan firewall yang terkunci
  2. Buat satu set wadah buruh pelabuhan dengan port terbuka
  3. Periksa firewallnya; buruh pelabuhan akan menggunakan "di mana saja" sebagai sumbernya, dengan demikian semua wadah diekspos ke publik.

Jelaskan hasil yang Anda terima:
root@brm-pheonix-dev :~/rse# iptables --list DOCKER
Rantai DOCKER (1 referensi)
target prot opt ​​sumber tujuan
TERIMA tcp -- di mana saja 172.17.0.2 tcp dpt:6379

Jelaskan hasil yang Anda harapkan:
root@brm-pheonix-dev :~/rse# iptables --list DOCKER
Rantai DOCKER (1 referensi)
target prot opt ​​sumber tujuan
TERIMA tcp -- 127.0.0.0/24 172.17.0.2 tcp dpt:6379
TERIMA tcp -- 172.16.0.0/16 172.17.0.2 tcp dpt:6379

Informasi tambahan yang Anda anggap penting (misalnya masalah hanya terjadi sesekali):

Secara default, buruh pelabuhan membungkam firewall dengan cara yang merusak keamanan - ini memungkinkan semua lalu lintas dari semua perangkat jaringan untuk mengakses port yang terbuka pada wadah. Pertimbangkan situs yang memiliki 2 kontainer: Kontainer A mengekspos 443 menjalankan Nginx, dan Kontainer B menjalankan API pada port 8000. Sebaiknya buka Kontainer A untuk umum untuk digunakan, tetapi sembunyikan Kontainer B seluruhnya sehingga hanya dapat berbicara dengan localhost (untuk pengujian oleh pengguna) dan jaringan buruh pelabuhan (untuk berbicara dengan Wadah A). Mungkin juga diinginkan untuk tujuan pengujian agar Wadah C menjadi database yang digunakan oleh Wadah B dengan jenis pembatasan yang sama.

Saya menemukan ini karena memantau log pada layanan yang saya _pikir_ tidak terbuka untuk umum. Setelah menemukan entri log dari sumber yang mencoba masuk, saya memeriksa aturan firewall dan menemukan tidak ada batasan pada alamat sumber atau antarmuka. Saya menggunakan UFW dan hanya mengizinkan SSH ke kotak khusus ini, dan lebih suka tetap seperti itu. Ini dapat secara dramatis memengaruhi penggunaan wadah Docker untuk menyebarkan layanan dan menyebabkan potensi masalah keamanan jika orang tidak berhati-hati.

Praktik keamanan terbaik adalah secara default membatasi jaringan agar berfungsi seperti contoh efek yang diinginkan di atas, dan kemudian mengizinkan pengguna untuk menambahkan firewall yang sesuai, dll. aturan untuk mengesampingkan perilaku tersebut, atau memiliki opsi untuk kembali ke perilaku saat ini. Saya tahu bahwa untuk alasan warisan itu tidak mungkin karena akan merusak banyak hal saat diperbarui; jadi setidaknya memiliki opsi untuk mengaktifkan di atas yang dapat dihidupkan sekarang akan menjadi langkah pertama yang baik, dan mungkin nanti setelah banyak peringatan menjadikannya perilaku default. Dengan asumsi perilaku default aman, memiliki fungsionalitas untuk mengelola ini (firewall->mengaktifkan port publik, ip) di docker-compose yml akan menjadi cara yang bagus untuk membuatnya diketahui apa yang sedang terjadi.

Saya memang menemukan opsi --iptables=false, namun, saya tidak ingin harus mengatur semua aturan sendiri. Satu-satunya hal yang saya keberatan adalah pengaturan sumber untuk aturan.

Meskipun saya belum memverifikasinya, saya menduga semua firewall yang didukung oleh buruh pelabuhan akan memiliki masalah yang sama.

arenetworking versio1.10

Komentar yang paling membantu

Masalah yang diangkat Ben adalah nyata dan mengejutkan (kombinasi yang buruk). Banyak admin, seperti saya, menggunakan firewall ufw yang sudah terbukti kebenarannya. Docker sedang melakukan dan mengakhiri ufw dan mengubah aturan iptables sedemikian rupa sehingga 1) menyebabkan ufw salah melaporkan status aturan pemfilteran paket saat ini, dan 2) mengekspos layanan yang tampaknya pribadi ke jaringan publik. Agar buruh pelabuhan tetap berada di komunitas sysadmin yang baik, pendekatan lain harus dirancang. Saat ini ada banyak admin di luar sana, yang, seperti Ben dan saya, secara tidak sengaja membuka port ke Internet yang lebih luas. Tidak seperti Ben dan saya sendiri, mereka belum mengetahuinya.

Semua 114 komentar

Catatan: Saya perhatikan di https://github.com/docker/docker/blob/master/vendor/src/github.com/docker/libnetwork/iptables/iptables.go bahkan tidak ada opsi untuk mengatur sumber , jadi itu hanya menggunakan default iptables untuk ip/perangkat sumber.

Ini tidak cukup #14041 karena masalah ini berbicara tentang port yang terbuka. Mengekspos port dimaksudkan untuk membuatnya dapat diakses publik, karena ini adalah cara Anda mengekspos layanan ke dunia luar. Jika Anda bekerja di lingkungan pengembangan, Anda dapat menonaktifkan akses ke port dari luar komputer Anda dengan firewall host, atau tidak mengekspos port dan mengakses layanan secara langsung, atau dari wadah lain di jaringan yang sama.

Saya akan merekomendasikan Anda menggunakan fitur jaringan buruh pelabuhan yang lebih baru untuk mengatur jaringan pribadi untuk layanan yang tidak ingin Anda buka sama sekali, lihat https://docs.docker.com/engine/userguide/networking/

Itulah yang saya pikirkan pertama kali; tetapi agak bingung, karena _exposing_ a port ( EXPOSE ), sebenarnya tidak melakukan apa-apa, tetapi _publishing_ a port ( -p / -P ) sebenarnya mengeksposnya di tuan rumah.

Jika Anda benar-benar berbicara tentang _publishing_, maka ini adalah seperti yang dirancang;

Dalam contoh Anda, wadah B dan C tidak boleh mempublikasikan port mereka, dan wadah A dapat berkomunikasi dengan mereka melalui Jaringan Docker, mis.

docker network create mynet

docker run -d --net=mynet --name=api api-image
docker run -d --net=mynet --name=db database-image
docker run -d --net=mynet --name=web -p 443:443 nginx

Ini hanya memublikasikan wadah "web" ke Host, Wadah web dapat mengakses wadah "API" dan "basis data" melalui namanya (yaitu http://api :80/, dan db:3306 (dengan asumsi MySQL))

@justincormack jadi saya rasa menggunakan jaringan pribadi tidak menyelesaikan masalah. Dalam kasus saya, saya menggunakan jaringan pribadi di antara wadah, dan mereka masih terbuka untuk umum karena firewall Host tidak dikonfigurasi untuk membatasi paparan ke jaringan pribadi.

@thaJeztah masalah masih bermuara pada dukungan firewall - tidak ada dukungan firewall di buruh pelabuhan untuk membatasinya ke jaringan tertentu. Anda mungkin masih dapat mengakses container tersebut dari sistem lain karena firewall tidak akan mencegah sistem lain mengakses port pada host.

Sekarang saya menjalankan ini melalui docker-compose; namun, ini tidak sepenuhnya merupakan masalah penulisan buruh pelabuhan karena fungsionalitas libnetwork memiliki kemampuan _no_ untuk membatasi jaringan dalam aturan firewall - aturan iptables tidak memiliki spesifikasi sumber jadi terlepas dari bagaimana seseorang mengonfigurasi jaringan selama seseorang bergantung pada buruh pelabuhan untuk membuat aturan firewall (yang mana yang harus karena lebih mungkin untuk membuatnya benar) maka ini menjadi masalah. Pertimbangkan hal berikut dalam file docker-compose.yml:

nginx:
    build: ./docker/nginx/.
    ports:
        - "127.0.0.1:8080:80"
        - "127.0.0.1:443:443"
    environment:
        DESTINATION_HOST: repose
    links:
        - repose
repose:
    build: ./docker/repose/.
    ports:
        - "127.0.0.1:80:8080"
    environment:
        DESTINATION_HOST: phoenix
        DESTINATION_PORT: 8888
    links:
        - phoenix
curryproxy:
    build: ./docker/curryproxy/.
    ports:
        - "127.0.0.1:8081:8081"
    external_links:
        - rse_rse_1
        - rse_rse_2
        - rse_rse_3
phoenix:
    build: .
    ports:
        - '127.0.0.1:88:8888'
    links:
        - curryproxy:curry
    external_links:
        - rse_rse_1:rse
        - rse_rse_2
        - rse_rse_3
        - rse_cache_1:cache
    volumes:
        - .:/home/phoenix

Di atas adalah kutipan dari salah satu proyek saya. Meskipun saya ingin dapat menguji semuanya secara lokal dari Host saya, saya tidak ingin orang lain dapat mengakses apa pun kecuali instance nginx.

Saya tidak yakin bagaimana ini diterjemahkan ke nomenklatur Anda ... mungkin ini adalah bagian dari aspek "penerbitan", dan kemampuan penerbitan perlu diperluas untuk melakukan apa yang saya katakan.

Jika ini dirancang, maka ini adalah model keamanan yang buruk karena Anda sekarang mengekspos semua pengembang ke risiko ekstrem saat berada di jaringan yang tidak dikenal (misalnya bepergian).

Seperti yang saya katakan, saya tidak mengharapkan default untuk segera berubah tetapi memiliki opsi akan menjadi langkah pertama yang baik.

Saya agak bingung, dapatkah Anda memberikan beberapa contoh eksternal tentang apa yang dapat Anda sambungkan? Layanan backend akan (secara default) berada di jaringan 172.17.0.0/16 , yang tidak akan dapat Anda akses secara eksternal. Saya tidak akan berpikir dulu karena Anda tidak akan memiliki rute ke yang ditentukan dari Host eksternal.

Ada potensi masalah jika IP eksternal Anda juga merupakan IP pribadi sehingga lalu lintas tidak akan terputus yang diarahkan ke jaringan internal (sedangkan seharusnya dari publik ke pribadi) - apakah itu masalahnya?

@justincormack jadi saya terutama menyiapkan proxy yang tepat sehingga beberapa layanan hanya dapat dipukul melalui proxy (nginx - penghentian ssl), yang kemudian memfilter melalui proxy otentikasi (beristirahat), dan akhirnya pergi ke layanan lain (phoenix). Saya tidak peduli jika semuanya terikat pada antarmuka 0.0.0.0; tetapi saya hanya ingin nginx dapat diakses secara eksternal (atau setidaknya bagian istirahat jika saya tidak memiliki nginx di sini). Solusi mudah, misalnya, adalah tidak harus menyetel "127.0.0.1" dalam konfigurasi, tetapi memiliki bagian firewall di mana mudah untuk menentukan bahwa untuk mengizinkan melalui firewall dengan konfigurasi dasar hanya jaringan buruh pelabuhan dan lokal antarmuka host (loopback) diaktifkan untuk berbicara - sesuatu seperti:

firewall:
    external:
        ports:
            - 80
            - 443

Sekarang situasinya dapat sedikit dikurangi dengan membatasi pemetaan jaringan pada _host_ ke 127.0.0.1 alih-alih peta default 0.0.0.0. Perhatikan bahwa inilah yang benar-benar menguranginya karena jika tidak, bridging akan meneruskan port Host ke jaringan buruh pelabuhan.

Dan ya, saya memang memverifikasi bahwa pembatasan itu berhasil; namun, itu masih menyisakan potensi kerentanan dan aturan firewall tidak cocok dengan apa yang sebenarnya sedang dilakukan.

Sebagai contoh lain, ada kerentanan Kernel Linux beberapa waktu lalu (kesulitan menemukannya saat ini) yang terkait dengan port yang ditandai di IPtables sebagai dibuka untuk digunakan oleh aplikasi, tetapi kemudian tidak benar-benar terhubung ke aplikasi - misalnya, berada di port host lokal tetapi bukan port IP publik. Ini berpotensi mengaturnya, dan akan menjadi praktik yang lebih baik untuk membatasi aturan IPtables ke jaringan yang diharapkan daripada membiarkannya terbuka untuk terhubung dari mana saja. Seperti yang saya katakan, setidaknya memiliki opsi untuk menentukan. Mereka kemungkinan telah memperbaiki masalah khusus itu tetapi mengapa membiarkan kemungkinan itu terbuka?

IOW, ini semua tentang keamanan.

@BenjamenMeyer jika Anda tidak ingin layanan lain dapat diakses, mengapa Anda mempublikasikan port mereka sama sekali? yaitu "127.0.0.1:8081:8081" tidak diperlukan jika hanya diakses melalui jaringan buruh pelabuhan (layanan lain terhubung langsung melalui jaringan buruh pelabuhan)

Satu masalah yang saya miliki terkait dengan yang satu ini adalah bahwa saya ingin mempublikasikan port, tetapi hanya mengizinkan alamat IP tertentu untuk mengaksesnya.

Misalnya, saya menjalankan lingkungan Jenkins dalam beberapa wadah. Node master "diterbitkan", tetapi saya harus membuat beberapa aturan iptables yang cukup rumit untuk menguncinya sehingga hanya 2 kantor yang kami miliki yang dapat mengaksesnya.

Apakah ada cara untuk mengatasi ini yang saat ini ada di Docker? Atau setidaknya praktik yang direkomendasikan? Saya telah melihat dalam dokumentasi bagaimana Anda dapat membatasi akses ke 1 alamat IP; tapi tidak beberapa. Masalah lain dengan ini adalah bahwa jika Anda memiliki server yang sudah memiliki konfigurasi iptables, Anda mungkin mengatur ulang semua aturan sebelum menerapkan aturan Anda (karenanya aturan berbelit-belit yang harus saya siapkan).

Saya memiliki masalah yang mirip dengan yang dinyatakan oleh @SeerUK. Ada pelanggaran ekspektasi yang menggelegar ketika aturan firewall yang sudah ada sebelumnya tidak berlaku untuk port kontainer yang diterbitkan. Perilaku yang diinginkan adalah sebagai berikut (setidaknya bagi saya)

  1. Upaya koneksi pengguna difilter berdasarkan konfigurasi INPUT, dll
  2. Penerusan lalu lintas kemudian terjadi seperti biasa berdasarkan aturan FORWARD yang ditambahkan buruh pelabuhan

Apakah ada cara ringkas untuk mencapai ini di iptables, atau tidak dengan mudah mengizinkan konstruksi seperti itu. Saya sangat terbatas dalam pengetahuan saya tentang iptables jadi bersabarlah. Saya baru-baru ini mengambil pengetahuan tentangnya ketika mencoba memahami interaksi buruh pelabuhan dengannya.

Apa yang sebenarnya saya gunakan untuk saat ini, karena saya benar-benar menjalankan wadah ini di server khusus yang cukup kuat, saya telah menyiapkan KVM VM yang menjalankan Docker, kemudian menggunakan beberapa aturan iptables standar untuk membatasi akses dari Host . VM memiliki antarmuka jaringannya sendiri yang hanya dapat diakses dari server, jadi saya harus menambahkan aturan untuk secara eksplisit mengizinkan akses ke port di iptables pada Host. Saya telah kehilangan sedikit kinerja, tetapi tidak banyak.

@thaJeztah Saya ingin dapat mengaksesnya dari sistem lokal, dan mengujinya dengan mudah. Misalnya, menyiapkan RESTful HTTP API yang memiliki titik akhir Kesehatan dan dapat menjalankan curl dengan andal dengan menggunakan localhost (Saya harus mendokumentasikan ini untuk orang lain dan memiliki alamat IP yang berubah tidak dapat diandalkan ). Dalam kebanyakan kasus untuk lingkungan dev saya, saya hanya ingin wadah berbicara satu sama lain, tetapi saya juga ingin dapat mengaksesnya dari Host.

Untuk kasus @SeerUK , dapat mengatur blok IP (5.5.0.0/16 - parameter yang valid untuk alamat sumber dalam aturan iptables) akan menjadi hal yang sangat baik. IPtables sudah memiliki kemampuan untuk melakukan pembatasan, tetapi buruh pelabuhan tidak memanfaatkannya.

@thaJeztah Saya menetapkan "127.0.0.1:8081:8081" secara eksplisit untuk menjauhkannya dari jaringan eksternal; Saya telah menemukan log di wadah buruh pelabuhan saya dari orang-orang yang mencoba membobol wadah melalui port yang terbuka.

Pekerjaan saya saat ini adalah mematikan wadah buruh pelabuhan sebelum saya berangkat hari itu karena saya tidak dapat memastikan lingkungan yang saya inginkan menjadi eksternal sebenarnya _is_ eksternal, atau bahwa lingkungan dibatasi dengan benar untuk tujuan keamanan.

@BenjamenMeyer salah satu cara untuk melakukan ini adalah menjalankan tes tersebut dalam sebuah wadah, misalnya

docker run --net -it --rm --net=mynetwork healthchecker 

Masalah yang diangkat Ben adalah nyata dan mengejutkan (kombinasi yang buruk). Banyak admin, seperti saya, menggunakan firewall ufw yang sudah terbukti kebenarannya. Docker sedang melakukan dan mengakhiri ufw dan mengubah aturan iptables sedemikian rupa sehingga 1) menyebabkan ufw salah melaporkan status aturan pemfilteran paket saat ini, dan 2) mengekspos layanan yang tampaknya pribadi ke jaringan publik. Agar buruh pelabuhan tetap berada di komunitas sysadmin yang baik, pendekatan lain harus dirancang. Saat ini ada banyak admin di luar sana, yang, seperti Ben dan saya, secara tidak sengaja membuka port ke Internet yang lebih luas. Tidak seperti Ben dan saya sendiri, mereka belum mengetahuinya.

@thaJeztah yang mengasumsikan bahwa saya melakukannya melalui baris perintah dan tidak menggunakan alat lain di mana saya hanya perlu mengatur alamat IP.

Misalnya, saya sedang mengerjakan API. Saya memiliki alat yang dapat saya gunakan untuk bekerja dengan API itu dalam produksi untuk mendukungnya; untuk pengembangan alat dan API, saya hanya ingin mengarahkan alat ke API dockerized. Alat ini tidak tahu apa-apa tentang buruh pelabuhan, juga seharusnya. Dan saya tidak perlu memasukkan alat ke buruh pelabuhan hanya untuk menggunakannya - mengarahkannya ke port yang hanya terbuka ke Host lokal sudah cukup.

@jcheroske Saya setuju, tapi saya tidak tahu bahwa ada solusi yang baik untuk aspek _that_. Untuk itu, ufw mungkin perlu dibuat lebih pintar untuk dapat mencari dan melaporkan aturan yang tidak terlibat dalam pembuatannya. Ada banyak perangkat lunak di luar sana yang dapat menyesuaikan aturan iptables dengan cara yang ufw (atau firewall AFAIK, dll) tidak akan tahu. Sebenarnya tidak ada solusi sederhana untuk memperbaikinya.

Yang mengatakan, akan lebih baik jika Docker dapat berintegrasi dengan mereka untuk membuang file konfigurasi yang sesuai untuk dapat mengaktifkan/menonaktifkannya, atau berintegrasi dengan alat-alat itu sehingga terhubung dan membuang informasi dengan tepat, mengingat ada solusi yang lebih baik Saya tidak berpikir aspek _that_ benar-benar akan terpecahkan. Di sini, ini lebih tentang membatasi cakupan aturan iptables yang dibuat untuk setidaknya meminimalkan potensi dampak dengan mengizinkan spesifikasi sumber (lo, eth0, 127.0.0.0/24, dll).

Jika Anda bersedia melakukannya, menggunakan iptables membuat ini benar-benar mungkin.

Ini adalah contoh yang dipangkas tentang bagaimana Anda dapat menggunakannya: https://Gist.github.com/SeerUK/b583cc6f048270e0ddc0105e4b36e480

Anda dapat melihat bahwa tepat di bagian bawah, 1.2.3.4 secara eksplisit diberikan akses ke port 8000 (yang diekspos oleh Docker), lalu apa pun ke port tersebut akan dihapus. Rantai PRE_DOCKER dimasukkan sebelum rantai DOCKER sehingga dipukul lebih dulu, artinya DROP menghentikan permintaan yang diblokir agar tidak pernah mencapai rantai DOCKER.

Agak menjengkelkan karena Docker tidak memiliki fungsi ini di dalamnya, tetapi ada kemungkinan untuk mengatasinya sekarang.

Alternatif lain adalah menggunakan firewall eksternal. Beberapa tempat seperti AWS dan Scaleway menawarkan hal-hal seperti grup keamanan tempat Anda dapat mengelola akses ke kotak Anda dari luar, dari sana setiap port berperilaku dengan cara yang sama.

Saya tidak pernah benar-benar berhasil menemukan cara untuk membuat ini bekerja dengan UFW. Meskipun untuk saat ini, saya senang menggunakan iptables sebagai solusi. Tampaknya bekerja dengan sangat baik untuk saya sejauh ini.

Jelas, ini bukan solusi yang bagus jika Anda telah membangun seperangkat aturan firewall yang cukup rumit di sekitar UFW. Padahal, itu membuat penggunaan hal-hal seperti iptables-persistent cukup mudah. Anda juga dapat menggunakan cara alternatif untuk mengizinkan akses ke cara ini yang tampak lebih "normal" di iptables.

@BenjamenMeyer apakah Anda pernah berpikir untuk menggunakan docker network ditentukan pengguna dengan opsi subnet & rentang ip dan menetapkan alamat ip statis untuk wadah & menggunakannya untuk pengembangan lokal sehingga Anda tidak harus bergantung pada ip statis virtual seperti 127.0.0.1 ? Itu akan menghindari kebutuhan untuk memiliki pemetaan port bersama-sama untuk kontainer-kontainer yang bersifat pribadi untuk sebuah host.

docker network create --subnet=30.1.0.0/16 --ip-range=30.1.0.0/24 mynetwork
docker run --net=mynetwork --ip=30.1.1.1 --name=myservice1 xxxx
docker run --net=mynetwork --ip=30.1.1.2 --name=myservice2 yyyy

Dengan pengaturan ini, myservice2 dapat mencapai myservice1 dengan nama myservice1 dan bahkan tidak perlu bergantung pada ip statis. Juga tuan rumah dapat mencapai ip statis dengan bebas tanpa perlu memiliki pemetaan port.

Juga dengan compose 1.7, Anda dapat menentukan alamat ip statis untuk wadah dan menentukan subnet dan rentang jaringan.

Saya memang menemukan solusi sederhana.

1) Edit /etc/default/docker: DOCKER_OPTS="--iptables=false"

2) Tambahkan aturan ufw: ufw allow to <private_ip> port <port>

Sangat sederhana sehingga benar-benar membuat saya bertanya-tanya mengapa opsi --iptables=false bukan default. Mengapa membuat situasi seperti itu ketika semua buruh pelabuhan harus mengatakan, "Hei, jika Anda menjalankan firewall, Anda harus melubanginya!" Apa yang saya lewatkan?

https://fralef.me/docker-and-iptables.html
http://blog.viktorpetersson.com/post/101707677489/the-dangers-of-ufw-docker

Saya tidak bisa membuat buruh pelabuhan berhenti memodifikasi iptables untuk menyelamatkan hidup saya. Mencoba memperbarui /etc/default/docker tetapi tidak berhasil di Ubuntu 16.04

@enzeart Coba /lib/systemd/system/docker.service .

@SeerUK Memberkati jiwamu

@enzeart untuk mengonfigurasi daemon yang berjalan pada host yang menggunakan systemd, sebaiknya tidak mengedit file docker.unit itu sendiri, tetapi menggunakan file "drop in". Dengan begitu, Anda tidak akan mengalami masalah saat memutakhirkan buruh pelabuhan (jika ada file docker.unit yang lebih baru). Lihat https://docs.docker.com/engine/admin/systemd/#custom -docker-daemon-options untuk info lebih lanjut.

Anda juga dapat menggunakan file konfigurasi daemon.json, lihat https://docs.docker.com/engine/reference/commandline/daemon/#daemon -configuration-file

@mavenugo Sudah ada jaringan buruh pelabuhan.

@jcheroske yang berfungsi, tetapi seperti yang saya catat itu berarti bahwa _end-user_ (saya) kemudian harus memastikan bahwa semua aturan iptables benar, yang tidak optimal dan hampir tidak mungkin terjadi seperti memiliki docker melakukannya secara otomatis, jadi masalah ini.

Hai, silakan naik. Saya pikir masalahnya juga. Rantai kontainer di Iptables harus mengikuti aturan utama dan tidak diekspos ke dunia secara default.

Saya benar-benar ingin melihat Docker (dan docker-compose) memiliki kemampuan untuk membuat daftar putih atau daftar hitam IP yang dapat mengakses port itu.

Ambil contoh:

nginx:
    ports:
      - "8000:8000"
    whitelist:
      - 10.6.20.2

Akan menyiratkan bahwa hanya IP sumber 10.6.20.2 yang dapat mengakses port 8000 pada host ini.

@StefanPanait Saya sangat menyukai ide itu. Itu juga bisa bekerja dengan sintaks yang mirip dengan volume dan daftar akses/tolak, seperti:

nginx:
  access:
  - "10.0.1.6:allow"
  - "deny"

Tentu saja masih harus memungkinkan hal-hal seperti komunikasi antar-kontainer.

Komunikasi antar-wadah

Meskipun saya kira cara yang tepat untuk melakukannya adalah dengan memisahkan jaringan buruh pelabuhan ... tetap saja, saya pikir dapat melakukan sesuatu seperti:

nginx: access: - "10.0.1.6:allow" - "webapi:allow" - "database:deny" - "deny"
Bisa berguna... pertanyaannya adalah, apakah cukup berguna untuk membenarkan implementasi sampai tingkat itu? Saya tidak tahu.

Saat ini, saya ingin melihat masalah asli diselesaikan, kemudian fitur seperti ini dapat ditambahkan jika tidak masuk akal untuk merancang resolusi untuk memulai (mungkin).

mengapa Anda tidak dapat melarang satu wadah untuk berbicara dengannya? Itu bisa sangat berguna untuk debugging

Itu untuk docker network disconnect ? Anda dapat memutuskan wadah dari jaringan untuk debugging, dan memasangnya kembali dengan docker network attach

Bagi mereka yang baru mengetahui bahwa banyak sekali port terbuka di server terbuka internet mereka, setelah menggunakan UFW, saya menggali dan menggali dan menemukan yang berikut:

Ubuntu 16.04 dengan UFW dan Docker menghadirkan tantangan baru. Saya melakukan semua langkah seperti yang ditunjukkan di sini: https://svenv.nl/unixandlinux/dockerufw TAPI saya TIDAK bisa mendapatkan buruh pelabuhan plus UFW untuk bekerja pada 16.04. Dengan kata lain, apa pun yang saya lakukan, semua port buruh pelabuhan menjadi terekspos secara global ke internet. Sampai saya menemukan ini: http://blog.samcater.com/how-to-set-docker-1-12-to-not-interfere-with-iptables-firewalld/
Saya harus membuat file: /etc/docker/daemon.json dan memasukkan yang berikut ini:

{
"iptables": salah
}

Saya kemudian mengeluarkan sudo service docker stop lalu sudo service docker start AKHIRNYA buruh pelabuhan hanya mengikuti aturan yang sesuai di UFW.

Data tambahan: https://chjdev.com/2016/06/08/docker-ufw/

@thaJeztah

mengapa Anda tidak dapat melarang satu wadah untuk berbicara dengannya? Itu bisa sangat berguna untuk debugging
Itu untuk pemutusan jaringan buruh pelabuhan? Anda dapat memutuskan wadah dari jaringan untuk debugging, dan memasangnya kembali dengan jaringan buruh pelabuhan

Dan bagaimana jika diinginkan untuk tetap memiliki konektivitas jaringan? Contoh: Menguji kegagalan Pemeriksaan Kesehatan dari server di Kontainer B untuk Kontainer A saat masih memiliki layanan yang disediakan oleh Kontainer C, D, dan E. Lebih mudah untuk hanya melarang Kontainer B untuk dibawa ke Kontainer A daripada menutup seluruh jaringan - Kontainer C mungkin juga bergantung pada akses ke Kontainer B untuk lulus Pemeriksaan Kesehatan.

Tetap saja, itu tidak tahan dengan "mari kita perbaiki masalah aslinya".

@gts24 penemuan menarik.

IMHO, seluruh masalahnya adalah Docker, seperti semua program lain, tidak boleh menyentuh firewall (iptables atau lainnya) sama sekali. Ketika saya menginstal (misalnya) Apache dan memintanya untuk mendengarkan di 0.0.0.0:80 itu keputusan saya untuk membuka port 80 di firewall atau tidak, di mana saya dapat menentukan aturan apa pun yang saya inginkan.

Alih-alih menciptakan kembali aturan firewall pada file konfigurasi buruh pelabuhan (dan/atau menulis), seluruh fitur PUBLISH harus dihentikan, dan fitur LISTEN dibuat untuk bekerja seperti semua program lain. Paling-paling, buruh pelabuhan dapat membuat layanan firewalld yang dinonaktifkan secara default untuk setiap port/wadah, pada sistem yang menggunakannya.

@gcscaglia set --iptables=false pada daemon dan Anda harus mendapatkannya

@thaJeztah Fitur itu tidak berguna karena Docker tidak menawarkan alternatif untuk mendapatkan aturan firewall yang diperlukan (atau kait skrip pemicu yang lebih spesifik dengan parameter yang relevan) dari daemon. Ini hampir tidak dapat digunakan jika Anda memiliki wadah statis dan tidak pernah mengubah apa pun tentangnya (misalnya port yang diterbitkan) tetapi untuk semua kasus lain Anda dapat melupakannya.

@thaJeztah persis seperti yang dikatakan taladar.

--iptables=false harus diganti namanya menjadi --networking=false karena bahkan jaringan container-to-container internal tidak berfungsi dengan itu dinonaktifkan. Opsi untuk membuat wadah mendengarkan pada beberapa kombinasi port/antarmuka tanpa membuat lubang pada aturan firewall masuk (yaitu LISTEN ) akan menyelesaikan semua ini, kompatibel ke belakang dan memungkinkan --iptables=true digunakan .

Dengan mode mendengarkan seperti itu, mereka yang ingin "hanya berfungsi" dapat tetap menggunakan PUBLISH , dan mereka yang menginginkan kontrol dapat menggunakan LISTEN .

@gcscaglia ok, jadi jika Anda ingin buruh pelabuhan menyiapkan aturan dasar dan menangani jaringan wadah-wadah tetapi tidak "menerbitkan". Anda dapat tetap mengaktifkan --iptables , tetapi _jangan_ gunakan -p / --publish . Anda harus dapat mengatur aturan IPTables secara manual untuk meneruskan port ke container. Kontainer sudah mendengarkan alamat IP pribadinya sendiri, dan port yang didengarkan oleh layanan di penampung Anda.

@thaJeztah Tidak, Anda tidak bisa. Karena Anda tidak tahu bahwa ada wadah yang baru saja dimulai dan membutuhkan aturan firewall. Anda tidak memiliki cara untuk memberi tahu siapa pun yang menggunakan API untuk meluncurkannya di port Host mana yang didengarkannya.

Contoh sederhana. Kami menggunakan wadah Docker untuk menjalankan pekerjaan Jenkins. Mereka mengekspos Port SSH mereka sehingga Docker dapat menghubungi mereka. Mereka dihancurkan segera setelah pekerjaan selesai. Docker tidak menawarkan cara apa pun untuk membuatnya bekerja dengan --iptables=false karena Anda tidak memiliki cara untuk memberi tahu Jenkins (menggunakan API Docker untuk meluncurkan wadah) port Host dan Anda bahkan tidak memiliki cara untuk memicu skrip untuk menyiapkan aturan firewall yang diperlukan.

Ide Anda hanya berfungsi untuk kasus penggunaan yang sangat sederhana dengan memiliki wadah permanen yang tidak pernah berubah yang diluncurkan secara manual. Bahkan --restart=always dalam wadah sederhana akan rusak dalam pengaturan ini kecuali wadah memiliki IP statis.

@taladar Saya membalas kasus penggunaan @gcscaglia , yang meminta fitur di mana buruh pelabuhan _not_ mengelola IPTables untuk membuka port, dan di mana mereka mengendalikan IPTables; yaitu, tidak ada wadah yang terbuka, kecuali jika dilakukan secara manual. Juga, dalam balasan saya, saya menjelaskan kepada _not_ gunakan --iptables=false , tetapi untuk tetap mengaktifkannya, tetapi jangan gunakan fitur -p / --publish (yang memberitahu buruh pelabuhan untuk membuat port yang dapat diakses melalui IPTables).

@thaJeztah Sementara Anda memiliki kasus penggunaan saya dengan benar, AFAIK solusi yang diusulkan tidak akan berfungsi untuk saya karena alasan yang sama itu tidak akan berfungsi untuk kasus taladar: Satu restart dari apa pun dan tiba-tiba aturan manual saya perlu diperbarui. Tidak ada pengait atau pemicu yang dapat saya gunakan untuk diberi tahu tentang restart sehingga saya dapat mengotomatiskan pembaruan seperti itu (belum lagi saya memang menciptakan kembali roda).

Saat ini satu-satunya solusi untuk kasus saya adalah memiliki firewall lain (yang tidak dapat disentuh buruh pelabuhan) di antara Host buruh pelabuhan dan semua jaringan eksternal. Tetapi jika Docker hanya akan melakukan semua yang sudah dilakukannya kecuali membuka port ke dunia, saya bisa menghilangkan firewall kedua sepenuhnya.

Saya kira Anda tidak dapat memiliki segalanya, tetapi itu pasti membuat frustrasi. Apakah menurut Anda layak untuk membuka permintaan fitur tentang ide LISTEN , atau tim Docker tidak akan tertarik dengan fitur seperti itu?

Apa yang akan dilakukan LISTEN ? Ada EXPOSE , yang memungkinkan Anda memberi anotasi pada port apa yang didengarkan oleh wadah. Untuk pemicu, Anda dapat mendengarkan buruh pelabuhan events .

Tidak mengatakan tidak ada ruang untuk perbaikan di sini (saya tahu ada yang sedang diperiksa), hanya ingin tahu apa yang Anda harapkan

Saat ini, seperti yang Anda katakan, semua layanan yang berjalan dalam wadah mengikat ke IP pribadi wadah (jika Anda tidak menggunakan --net=host atau serupa). Ini bagus dan diinginkan karena isolasi seperti itu antara Host dan kontainer adalah titik jual Docker.

Tetapi, saat ini, jika saya ingin aplikasi yang berjalan di luar wadah apa pun (baik itu di Host atau di tempat lain di jaringan) memiliki akses ke layanan yang berjalan di dalam wadah, saya perlu sarana untuk membuat layanan itu mendengarkan di salah satu antarmuka jaringan Host. Untuk mengatasi masalah ini tanpa mengekspos antarmuka Host apa pun ke wadah, Docker membuat fitur -p / --publish , yang:

  1. Membuat aturan iptables untuk meneruskan port yang dipilih pada antarmuka host yang dipilih ke port yang dipilih pada IP pribadi kontainer (Yang kita semua harapkan karena itulah yang kita minta)
  2. Memberi tahu iptables untuk mengizinkan siapa saja dari

Apa yang saya usulkan adalah fitur (bernama LISTEN atau lainnya) yang hanya melakukan

Adapun EXPOSE , AFAIK itu hanya metadata dalam gambar Docker sehingga daemon tahu apa yang harus dilakukan ketika pengguna menentukan -P (terbitkan semuanya). Mungkin saya salah tentang hal itu, dan port "terbuka" dapat diteruskan dengan cara yang tahan restart (tanpa akses ke seluruh dunia)?

--menyimpang dari topik--

IMHO OP dari masalah ini menanyakan dengan tepat mengapa -p melakukan "2" dan bagaimana menghentikan Docker dari melakukannya. Meskipun pengaturan tingkat daemon (selain menonaktifkan jaringan) dapat menyelesaikannya, untuk menjaga agar semuanya tetap kompatibel, yang terbaik adalah fitur baru (yaitu LISTEN atau nama lain).

Sementara banyak pengguna seperti ini "bekerja di luar kotak" efek, tidak ada sysadmin mengharapkan program selain iptables / firewalld mereka untuk berkeliling membuka port di firewall, apalagi dengan cara perangkat lunak manajemen firewall mereka tidak melaporkan.

Saya melihat ada tiga masalah utama:

  1. Cara Docker menerbitkan/mengekspos port melewati aturan firewall umum seperti UFW.
  2. Fakta di atas tampaknya tidak terdokumentasi dengan baik (benar-benar tidak terduga karena tidak ada layanan Linux lain yang saya ketahui tentang melewati aturan firewall itu sendiri).
  3. Tidak ada cara sederhana untuk mengadaptasi iptables ke cara Docker menerbitkan/mengekspos port atau cara yang diketahui orang tidak mudah untuk diotomatisasi dan tidak ada yang didokumentasikan.

Mungkin secara teknis tidak layak untuk mengimplementasikan port yang mengekspos pada tabel FILTER sehingga memperbaiki 1 tidak mungkin. Setidaknya ini harus mendapatkan peringatan besar di suatu tempat (perbaikan 2) tetapi idealnya 3 dapat diselesaikan dengan opsi baru seperti yang disarankan orang-orang di sini seperti allow atau deny yang akan menambahkan aturan firewall tambahan secara otomatis untuk mengizinkan atau menolak IP tertentu untuk port yang terbuka/diterbitkan.

Misalnya allow: "tcp:{your_trusted_ip}" untuk wadah bernama "elasticsearch" port penerbitan 9200 mungkin melakukan sesuatu seperti:

iptables -t mangle -N DOCKER-elasticsearch
iptables -t mangle -A DOCKER-elasticsearch -s {your_trusted_ip} -j RETURN
iptables -t mangle -A DOCKER-elasticsearch -j DROP
iptables -t mangle -I PREROUTING -p tcp --dport 9200 -j DOCKER-elasticsearch

Saya menemukan ini cukup berguna dari dokumen Docker: https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communicating -to-the-outside-world

Aturan penerusan Docker mengizinkan semua IP sumber eksternal secara default. Untuk mengizinkan hanya IP atau jaringan tertentu untuk mengakses wadah, masukkan aturan yang ditiadakan di bagian atas rantai filter DOCKER. Misalnya, untuk membatasi akses eksternal sehingga hanya IP sumber 8.8.8.8 yang dapat mengakses container, aturan berikut dapat ditambahkan:

$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

@jmimico ya saya pernah menemukan itu sebelumnya. Bagaimana Anda membatasi akses dari 2 atau lebih IP?

Apa yang begitu sulit tentang Docket hanya menambahkan opsi untuk menjalankan skrip Shell di tempat mana pun di mana sekarang ia membuat aturan iptables dengan semua informasi internal Docker yang diteruskan ke skrip sebagai parameter? Itu akan memungkinkan setiap orang untuk membuat aturan yang mereka butuhkan. Tambahkan beberapa cara untuk memicu eksekusi ulang skrip untuk wadah aktif yang dapat dipanggil orang setelah mereka melakukan iptables-restore atau menghapus rantai karena beberapa alasan lain dan Anda selesai.

Docker tidak perlu membuat ulang semua jenis skenario firewall pra-bangun seperti yang disarankan beberapa orang di sini, yang dapat dibangun di atas sistem seperti itu dengan set distribusi skrip kait. Paling-paling sesuatu seperti mengekspos hanya di localhost dan mengekspos secara global (seperti yang dilakukan Docker sekarang) mungkin masuk akal. IPTables memiliki terlalu banyak fleksibilitas bagi Docker untuk berharap dapat memodelkan semua skenario secara langsung dalam pengaturan.

Tiket ini tampaknya telah ada selamanya, perilaku saat ini membuat batas Docker tidak dapat digunakan (tampaknya menjadi cara standar untuk mengimplementasikan fitur dalam proyek ini, misalnya kurangnya GC bawaan yang tepat atau hampir tidak ada satu penyimpanan yang dapat digunakan, bebas bug kernel, dan berkinerja backend,...) dan ada solusi mudah untuk memungkinkan orang menerapkan solusi mereka sendiri yang sesuai dengan lingkungan mereka.

@StefanPanait Pertanyaan bagus. Taruhan saya adalah Anda perlu memanfaatkan penggunaan grup objek. Isi grup objek dengan IP daftar putih dan kemudian gunakan grup objek itu di baris pertama rantai DOCKER.

Contoh:
iptables -N docker-allow
iptables -A docker-allow -s 1.1.1.1 -j MENERIMA
iptables -A docker-allow -s 2.2.2.2 -j TERIMA
iptables -A docker-allow -s 3.3.3.3 -j MENERIMA
iptables -A docker-allow -j DROP

iptables -I DOCKER -i ext_if -j docker-allow

Bukankah aturan yang ditambahkan ke rantai DOCKER pernah dihancurkan oleh hal-hal seperti daemon restart? Saya pikir itu masalah dengan solusi manual adalah bahwa mereka sulit untuk dilakukan dengan benar sehingga ada kasus yang kuat untuk lebih mendukung kasus umum (memblokir/mengizinkan IP individu) secara lebih langsung.

Mungkin sebuah plugin akan menjadi tempat yang tepat untuk mendukung ini? Misalnya, mungkin plugin "ufw" dapat menambahkan aturan dengan cara yang kompatibel dengan ufw sehingga pengguna dapat mengelola firewall secara efektif dengan rantai alat firewall reguler mereka dan layanan buruh pelabuhan akan berperilaku lebih seperti layanan host normal.

Bukankah aturan yang ditambahkan ke rantai DOCKER pernah dihancurkan oleh hal-hal seperti daemon restart? Saya pikir itu masalah dengan solusi manual adalah bahwa mereka sulit dilakukan dengan benar sehingga ada kasus yang kuat untuk lebih mendukung kasus umum (memblokir/mengizinkan IP individu) secara lebih langsung.

Menambahkan aturan menjatuhkan ke rantai DOCKER-USER tampaknya berfungsi lebih baik dalam membuatnya terus-menerus di seluruh restart buruh pelabuhan.

Dengan Docker v.17.06 ada rantai iptables baru yang disebut DOCKER-USER. Yang ini untuk aturan khusus Anda, lihat jawaban saya di serverfault: https://serverfault.com/questions/704643/steps-for-limiting-outside-connections-to-docker-container-with-iptables/886257#886257

Saat saya berkomentar di SF, saya rindu mengapa rantai DOCKER-USER ini berbeda dari rantai yang ditambahkan pengguna lainnya .. Tidak memiliki filter yang diterapkan sebelumnya dan menyaring semua lalu lintas dan bukan hanya lalu lintas yang ditentukan oleh wadah buruh pelabuhan jadi Anda masih harus menentukan nama antarmuka sendiri dan masih rentan terhadap ahli non-iptables membuat kesalahan besar.

Di sisi lain itu masih berlaku dengan mentalitas "Docker adalah satu-satunya pengguna iptables" yang menyebalkan bagi orang-orang yang ingin menggunakan iptables untuk lebih dari sekadar Docker. Jadi itu buruk untuk seluruh jajaran pengguna potensial selain mungkin orang-orang yang mendedikasikan seluruh host hanya untuk Docker.

OK, jadi menggunakan DOCKER-USER memecahkan masalah urutan penyisipan dengan memastikan bahwa itu selalu datang dalam rantai sebelum aturan terkait Docker lainnya. Namun, itu tidak membuat daftar putih lalu lintas ke wadah dengan nomor port lebih mudah karena pada titik ini --dport adalah port layanan di dalam wadah buruh pelabuhan, bukan port yang terbuka. Contoh:

Publikasikan port 9900 untuk mengekspos layanan buruh pelabuhan yang mendengarkan secara internal pada 9000.

$ sudo iptables -A DOCKER-USER -m limit --limit 20/min -j LOG --log-prefix "IPTables: "
$ docker run --rm -it -p '192.168.56.101:9900:9000' alpine nc -l 9000

Dari komputer lain di jaringan:

$ telnet 192.168.56.101 9900

Apa yang dicatat:

IPTables: IN=enp0s8 OUT=docker0 MAC=08:00:27:b6:8d:d6:0a:00:27:00:00:04:08:00 SRC=192.168.56.1 DST=172.17.0.2 LEN=52 TOS=0x00 PREC=0x00 TTL=127 ID=14127 DF PROTO=TCP SPT=51208 DPT=9000 WINDOW=64240 RES=0x00 SYN URGP=0
IPTables: IN=docker0 OUT=enp0s8 PHYSIN=veth05ba007 MAC=02:42:0f:f9:76:4c:02:42:ac:11:00:02:08:00 SRC=172.17.0.2 DST=192.168.56.1 LEN=40 TOS=0x00 PREC=0x00 TTL=63 ID=23041 DF PROTO=TCP SPT=9000 DPT=51208 WINDOW=0 RES=0x00 ACK RST URGP=0

Jadi seperti yang Anda lihat saat ini tidak ada peluang untuk memfilter lalu lintas ke port 9900. Tentu, saya dapat memfilter lalu lintas ke 9000 tetapi ini menjadi masalah karena port internal dapat secara tidak sengaja tumpang tindih antara beberapa wadah atau bahkan layanan yang berjalan di host. Ini adalah salah satu nilai jual Docker yang hebat bahwa Anda dapat menjalankan banyak layanan pada satu host dan tidak khawatir tentang konflik port. Jadi, banyak container didesain untuk hanya mendengarkan pada port dan pengguna dapat menggunakan opsi --publish untuk mengubah port mana yang terbuka pada antarmuka mana:

$ docker run -d -p 7777:6379 --name data1 redis
$ docker run -d -p 8888:6379 --name data2 redis

Namun, saya tidak dapat menggunakan DOCKER-USER (tolong perbaiki saya jika saya salah) untuk memengaruhi lalu lintas ke data1 tanpa juga memengaruhi lalu lintas ke data2 kecuali saya menggunakan semacam introspeksi untuk menemukan IP wadah tujuan yang bersifat sementara yang membawa Anda kembali ke titik awal dalam menemukan cara sederhana dan andal untuk mem-firewall layanan yang diterbitkan tanpa skrip dan introspeksi.

Untuk lebih jelasnya, ini TIDAK berfungsi:

$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 7777 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 8888 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 7777 -j DROP
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 8888 -j DROP

Ini berhasil, tetapi hasilnya adalah kedua layanan tersebut terkena kedua CIDR yang masuk daftar putih:

$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 6379 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 6379 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 6379 -j DROP

Jadi sepertinya DOCKER-USER hanya berguna untuk mengekspos semua port ke IP tertentu tetapi tidak mengekspos port tertentu ke IP tertentu kecuali Anda tidak keberatan menulis aturan iptables Anda untuk merujuk nomor port internal dan tidak memiliki banyak wadah menggunakan yang sama nomor port internal. Semua orang tampaknya kehilangan poin-poin ini dan berjalan dengan DOCKER-USER sebagai solusi dan saya pikir ini layak mendapatkan solusi baru yang lebih baik.

@SeerUK
Solusi yang diposting di https://Gist.github.com/SeerUK/b583cc6f048270e0ddc0105e4b36e480 tidak berfungsi untuk saya. Bisakah Anda membantu?

kesalahan docker adalah menggunakan iptables (firewall sistem) untuk melakukan perutean aplikasi. Ini akan menciptakan masalah dan kekacauan selamanya. Ubah iptables itu sangat berbahaya. Untuk menambahkan fungsi ini tertanam di buruh pelabuhan tidak begitu mahal. Selain itu bisa juga status konkuren tidak konsisten jika Anda menjalankan buruh pelabuhan secara bersamaan .

Tampaknya iptables memiliki perilaku aneh jika Anda mengubah iptables saat buruh pelabuhan sedang berjalan. Jika Anda menghentikan buruh pelabuhan, atur iptables dan restart buruh pelabuhan semua berfungsi seperti yang diperkirakan. Kekhawatiran saya adalah ... jika saya harus mengubah iptables dalam produksi?

Tampaknya iptables memiliki perilaku aneh jika Anda mengubah iptables saat buruh pelabuhan sedang berjalan.

iptables adalah iptables, tidak peduli apakah buruh pelabuhan berjalan atau tidak..

Lebih baik jika Anda melakukan banyak tes sebelumnya ... untuk memberi tahu iptables adalah iptables hanyalah sebuah tautologi. Itu saran saya :)

Saya pikir maksudnya adalah bahwa iptables tidak berperilaku berbeda ketika Docker berjalan seperti yang disarankan komentar Anda. Ini jelas merupakan masalah Docker dengan cara mereka menggunakan iptables seolah-olah tidak ada orang lain yang membutuhkannya di sistem yang sama.

Saya tidak mengerti mengapa DOCKER-USER tidak menyelesaikan ini.
Anda menggunakan iptables untuk memfilter sesuka Anda: port sumber, port target, addr sumber, lalu lintas non-lokal, dll.

Inti dari DOCKER-USER adalah ia menjalankan aturan apa pun yang ingin dijalankan pengguna sebelum aturan buruh pelabuhan dijalankan, ini memungkinkan Anda untuk melakukan apa pun yang Anda inginkan dengan lalu lintas sebelum mencapai buruh pelabuhan.

@ cpuguy83 masalah intinya adalah buruh pelabuhan membuka port ke jaringan publik - di luar sistem - tanpa pemberitahuan karena tidak mengikat port yang terbuka ke antarmuka jaringan (seperti eth0 atau lo) atau IP tertentu (fe 127.0.0.1). 0.1, 172.16.1.1); aturan yang diperkenalkan oleh Docker juga tidak muncul di alat manajemen iptables seperti UFW - sehingga pengguna mungkin tidak menyadari bahwa berbagai wadah buruh pelabuhan dapat diakses dari sistem mana pun di jaringan, bukan hanya host lokal mereka.

DOCKER-USER tidak dapat menyelesaikannya karena juga tidak mengikat jaringan buruh pelabuhan ke antarmuka jaringan tertentu atau IP tertentu (fe 127.0.0.1).

Sesuai permintaan awal saya:
1.Docker harus mengikat dirinya sendiri ke IP tertentu - berdasarkan konfigurasi Jaringan Docker - dan kemudian mengizinkan pengguna untuk menambahkan aturan untuk mengekspos container di luar sistem (menggunakan perkakas pilihan mereka); secara default wadah tidak boleh diekspos di luar sistem.

  1. Itu tidak dapat dilakukan tanpa masa transisi karena setidaknya beberapa orang mengandalkan perilaku historis.

IMHO, seluruh masalahnya adalah Docker, seperti semua program lain, tidak boleh menyentuh firewall (iptables atau lainnya) sama sekali. Ketika saya menginstal (misalnya) apache dan memintanya untuk mendengarkan pada 0.0.0.0:80 itu keputusan saya untuk membuka port 80 di firewall atau tidak, di mana saya dapat menentukan aturan apa pun yang saya inginkan.
Alih-alih menemukan kembali aturan firewall pada file konfigurasi buruh pelabuhan (dan/atau menulis), seluruh fitur PUBLISH harus dihentikan, dan fitur DENGARKAN baru dibuat untuk bekerja seperti semua program lain. Paling-paling, buruh pelabuhan dapat membuat layanan firewalld yang dinonaktifkan secara default untuk setiap port/wadah, pada sistem yang menggunakannya.

Bagus sekali @gcscaglia ! Yang lebih membingungkan, ada sedikit atau tidak ada yang menyebutkan semua ini di https://docs.docker.com/engine/reference/run/#expose -incoming-ports , yang menurut saya adalah tempat sebagian besar dari mereka yang peduli untuk mencari sedikit dokumentasi untuk melengkapi pembelajaran dengan contoh berakhir di. Seharusnya ada kotak merah terang di suatu tempat yang menjelaskan risiko Docker mengesampingkan aturan iptables yang sudah ada sebelumnya.

Jika Anda tidak ingin buruh pelabuhan mengelola iptables, maka setel --iptables-=false
Jika Anda hanya ingin buruh pelabuhan membuka port pada antarmuka tertentu, Anda juga dapat mengaturnya di daemon config.

@BenjamenMeyer
Anda dapat memblokir semua lalu lintas di DOCKER-USER dan hanya membiarkan apa yang Anda inginkan.

Anda dapat memblokir semua lalu lintas di DOCKER-USER dan hanya membiarkan apa yang Anda inginkan.

@cpuguy83 Tolong beri tahu saya jika ada yang saya katakan di sini salah:

$ docker run -d -p 7777:6379 --name data1 redis
$ docker run -d -p 8888:6379 --name data2 redis

Namun, saya tidak dapat menggunakan DOCKER-USER (tolong perbaiki saya jika saya salah) untuk memengaruhi lalu lintas ke data1 tanpa juga memengaruhi lalu lintas ke data2 kecuali saya menggunakan semacam introspeksi untuk menemukan IP wadah tujuan yang bersifat sementara yang membawa Anda kembali ke titik awal dalam menemukan cara sederhana dan andal untuk mem-firewall layanan yang diterbitkan tanpa skrip dan introspeksi.

Untuk lebih jelasnya, ini TIDAK berfungsi:

$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 7777 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 8888 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 7777 -j DROP
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 8888 -j DROP

Ini berhasil, tetapi hasilnya adalah kedua layanan tersebut terkena kedua CIDR yang masuk daftar putih:

$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 192.168.56.0/24 --dport 6379 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp -s 10.0.24.0/24 --dport 6379 -j RETURN
$ sudo iptables -A DOCKER-USER -p tcp -m tcp --dport 6379 -j DROP

Jadi tidak ada cara untuk mengontrol lalu lintas ke/dari wadah data1 secara independen dari wadah data2 menggunakan DOCKER-USER . Bagi saya ini membuat DOCKER-USER tidak banyak solusi.

@colinmollenhour

Jika Anda memiliki aturan drop generik di DOCKER-USER , apa bedanya ini dengan jika docker ditambahkan vs aturan lompatan utama yang ditambahkan sebelumnya?

@ cpuguy83 poin saya tidak bertentangan dengan override per-se. Apa yang saya katakan adalah bahwa memiliki Docker menimpa aturan iptables yang sudah ada sebelumnya harus menjadi fitur opt-in, bukan fitur opt-out.

Dan bahkan sebagai opt-out - yang seharusnya tidak - itu harus didokumentasikan dengan sangat baik karena benar-benar tidak terduga dan cukup kontra-intuitif untuk di-debug. Terutama mengingat berapa banyak yang menggunakan ufw . Saya tahu tidak ada perangkat lunak lain yang melakukan hal seperti ini tanpa peringatan yang sangat eksplisit dan saya pribadi akan menjauhi perangkat lunak tersebut.

Selain itu, ini diperburuk oleh fakta bahwa sebagian besar pengguna Docker - setidaknya menurut pengalaman saya - mulai menggunakannya di lingkungan di mana infrastruktur jaringan tambahan menutupi masalah, memperkuat asumsi bahwa mesin dikonfigurasi seperti yang mereka yakini.

Saya harap Docker akan pindah ke pendekatan LISTEN-only, seperti yang dicontohkan oleh @gcscaglia .

Jika Anda memiliki aturan drop generik di DOCKER-USER, apa bedanya dengan jika docker ditambahkan vs aturan lompatan utama yang ditambahkan sebelumnya?

Saya rasa saya tidak mengerti pertanyaan Anda ... Harap abaikan komentar saya 22 Apr 2017 karena itu hanya berkaitan dengan kegigihan yang memang dipecahkan oleh DOCKER-USER. Masalah yang saya tunjukkan bukanlah tentang kegigihan.

@taladar Apa yang Anda

@jacoscaz

Pertama, saya pikir semua pengelola setuju bahwa perilaku yang ada tidak ideal. Sayangnya perilaku tersebut sudah ada sejak dulu. Mengubah default untuk sesuatu yang digunakan oleh jutaan orang bukanlah sesuatu yang bisa kita lakukan di sini. Ini adalah salah satu alasan mengapa kami menambahkan DOCKER-USER sehingga setidaknya orang dapat memasukkan aturan apa pun yang mereka butuhkan.

Namun kami tidak dapat menyiasati kebutuhan untuk menggunakan iptables (atau ebpf, atau solusi bawaan lainnya) DAN menyediakan fungsionalitas yang disediakan oleh -p ... sebaliknya, jika Anda ingin mencegah orang membuat lubang di firewall, larang mereka menggunakan -p .

Untuk rekap, Anda dapat:

  1. Beri tahu buruh pelabuhan untuk (secara default) mengikat ke alamat tertentu (alamat default tentu saja 0.0.0.0 , atau semua antarmuka)... namun ini tidak akan mencegah seseorang secara manual menentukan alamat di -p spesifikasi (misalnya -p 1.2.3.4:80:80 )
  2. Suntikkan aturan khusus ke DOCKER-USER , termasuk tolak semua
  3. Nonaktifkan manajemen iptables dengan --iptables=false

Apakah ada hal lain yang dapat Anda sarankan yang tidak termasuk melanggar pengguna yang ada?

@ cpuguy83 saya mengerti itu. Saya tidak menganjurkan agar perubahan seperti itu terjadi secara drastis dari satu versi ke versi lainnya. Saya pikir itu akan menjadi perubahan yang baik untuk merencanakan selama beberapa versi. Saya juga tidak berpikir Docker harus berhenti menggunakan iptables sepenuhnya. Penerusan berbeda dari mengizinkan dan sejauh yang saya mengerti Docker harus dapat meneruskan secara default tanpa mengizinkan akses ke siapa pun di mana saja secara default.

Sejauh hal-hal yang dapat dilakukan sekarang, dokumentasi tambahan tentang ini harus menjadi yang pertama dan terpenting. Manakah saluran yang paling tepat untuk meningkatkan ini dengan pengelola docker.com?

Dengan tidak adanya minat di pihak mereka, menjaga percakapan ini tetap hidup mungkin adalah cara terbaik untuk memaksimalkan kemungkinan perilaku ini menjadi lebih dikenal secara luas.

Saya setuju dengan panggilan untuk menambahkan dokumentasi tambahan untuk fungsi ini. Sejauh yang saya tahu itu hanya disebutkan di https://docs.docker.com/network/iptables/. Saya baru mengetahui masalah ini setelah mencoba mencari tahu mengapa layanan yang saya batasi tersedia untuk IP tertentu melalui firewall tersedia untuk umum. Perilaku ini benar-benar tidak terduga bagi saya karena bertentangan dengan setiap layanan jaringan lain yang pernah saya tangani.

Saya mengerti bahwa ada solusi, tetapi saya yakin ini harus dilihat untuk perubahan jangka panjang pada fungsi Docker. Saya suka ide untuk mengaturnya ke DENGARKAN pada port, dan mengizinkan aturan yang ditentukan pengguna untuk membangun di atasnya.

Seperti yang disarankan, saya menambahkan aturan DROP ke DOCKER-USER untuk mencegah wadah terpapar ke luar secara tidak sengaja (yang secara mengkhawatirkan, memang terjadi).

Namun, saya sekarang memiliki satu layanan yang ingin saya ekspos. Tetapi seperti yang telah dijelaskan oleh @colinmollenhour , karena NAT terjadi sebelum pemfilteran, saya hanya dapat memfilter pada ip buruh pelabuhan (yang tidak diperbaiki) dan nomor port internal (yang mungkin sama untuk beberapa wadah).

Jadi bagaimana saya bisa mengekspos layanan yang satu ini?

@SystemParadox itulah salah satu dari banyak alasan mengapa DOCKER-USER bukan perbaikan nyata untuk masalah tersebut.

@cpuguy83
Saya menyukai solusi DENGARKAN yang diusulkan, dan tidak pernah menganjurkan perubahan putus-putus dari satu rilis ke rilis lainnya; melainkan menganjurkan membuat perubahan pada serangkaian versi dengan pemberitahuan yang sesuai akan keluar b/c saya menyadari bahwa banyak orang menggunakan Docker dan memiliki perubahan yang melanggar dari satu versi ke versi lain akan merugikan semua.

Saya juga setuju bahwa memperbarui dokumentasi Docker mengenai -p dan EXPOSE, dll harus menjadi prioritas yang dilakukan segera setidaknya untuk menarik kesadaran akan masalah ini. Dalam pengalaman saya, kebanyakan orang yang menggunakan Docker bukan ahli firewall sehingga mereka mempercayai Docker untuk melakukan apa yang mereka harapkan, yang tidak ada dalam desain saat ini.

Lebih lanjut, solusi rekap di https://github.com/moby/moby/issues/22054#issuecomment -425580301 juga tidak berfungsi. Mengapa? Saya tidak menjalankan Docker secara langsung, saya menjalankan Docker Compose - berdasarkan YAML; Alamat IP bersifat dinamis (dikontrol oleh Docker) dan sering kali saya menggunakan beberapa layanan dalam Jaringan Docker yang sama yang perlu berinteraksi satu sama lain. Jadi penggunaan -p dan penggunaan pengikatan alamat (opsi 1 dalam rekap) bukan solusi. DOCKER-USER tidak benar-benar menyelesaikan apa pun seperti yang ditunjukkan orang lain (opsi 2 dalam rekap) dan menonaktifkan Tabel IP sepenuhnya (opsi 3 dalam rekap) juga tidak membantu apa pun b/c sekarang semuanya rusak (IP dinamis jadi sulit untuk membuat skrip solusi; jaringan antar-wadah rusak b/c Docker bergantung pada IPTables untuk berpindah di antara wadah; dll).

Sekali lagi, tidak ada panggilan di utas ini untuk perubahan putus-putus antara dua versi; tetapi panggilan untuk pendekatan bertahap terencana yang memungkinkan orang untuk bermigrasi dengan tepat.

Sebagai solusinya, Anda dapat mengakses port tujuan asli menggunakan -m conntrack --ctorigdstport .

Jadi dalam kasus saya, saya memiliki yang berikut:

-A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow docker out
-A DOCKER-USER -s 172.17.0.0/16 -j ACCEPT
# Allow access to docker service mapped to host 8702 (the service is actually listening on port 8088 in the container)
-A DOCKER-USER -p tcp -m conntrack --ctorigdstport 8702 -j ACCEPT
# Prevent access to docker from outside
-A DOCKER-USER -j DROP

@SystemParadox

Hore untuk solusi iptables yang benar! 🍻

Saya belum pernah mendengar tentang --ctorigdstport tetapi saya rasa itu karena saya belum membaca dan mencoba setiap ekstensi iptables yang mungkin dan Anda yang pertama menyebutkannya dalam konteks ini sepengetahuan saya.

Saya menguji dan ini memang berhasil:

$ docker run -d -p 7777:6379 --name data1 redis
$ docker run -d -p 8888:6379 --name data2 redis
$ sudo iptables -N DOCKER-USER-redis1
$ sudo iptables -A DOCKER-USER-redis1 -s 192.168.56.0/24 -p tcp -m tcp -j RETURN
$ sudo iptables -A DOCKER-USER-redis1 -j REJECT --reject-with icmp-port-unreachable
$ sudo iptables -N DOCKER-USER-redis2
$ sudo iptables -A DOCKER-USER-redis2 -s 10.0.24.0/24 -p tcp -m tcp -j RETURN
$ sudo iptables -A DOCKER-USER-redis2 -j REJECT --reject-with icmp-port-unreachable
$ sudo iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 7777 -j DOCKER-USER-redis1
$ sudo iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 8888 -j DOCKER-USER-redis2

Saya pikir contoh seperti ini termasuk dalam dokumen karena mungkin mencakup apa yang dicari oleh 99% pengguna: kemampuan untuk mengekspos port menggunakan -p tetapi masih dapat mengontrol lalu lintas ke mereka menggunakan filter umum seperti -s .

Saya membuat permintaan untuk memperbarui dokumentasi Docker tentang iptables.

https://github.com/docker/docker.github.io/issues/8087

Solusi yang tercantum di sana di https://unrouted.io/2017/08/15/docker-firewall/
tampaknya menjadi sesuatu yang serupa, membuat rantai iptables tambahan yang disebut FILTER
ke mana rantai INPUT dan DOCKER-USER melompat.

@SystemParadox @colinmollenhour Setelah menguji --ctorigdstport Saya dapat mengonfirmasi bahwa itu berfungsi, tetapi dengan sedikit peringatan.

Dalam kasus saya, saya memiliki aplikasi PHP dockerized di Apache yang mendengarkan pada port 80. Aturan saya yang hanya mengizinkan 1.2.3.4 adalah sebagai berikut:

-A DOCKER-USER -s 1.2.3.4/32 -i eth0 -p tcp -m conntrack --ctorigdstport 80 -j ACCEPT
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 -j DROP

Jadi aturan menjatuhkan saya sedikit lebih spesifik daripada Anda, hanya menjatuhkan paket yang mengenai server web saya — atau begitulah menurut saya. Bahkan, itu menjatuhkan paket yang diarahkan ke server web saya serta paket yang kembali dengan tanggapan dari permintaan yang dibuat oleh aplikasi PHP ke server pihak ketiga.

Hal ini disebabkan fakta bahwa --ctorigdstport tidak cocok dengan port tujuan pada paket yang difilter, tetapi pada paket yang memulai koneksi. Jadi, tanggapan terhadap permintaan yang keluar dari Docker ke server lain akan memiliki SPT=80 dan juga akan cocok dengan --ctorigdstport 80 .

Jika ada yang ingin memiliki kontrol yang lebih ketat dalam aturan DROP, --ctdir juga harus ditambahkan:

-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j DROP

Faktanya, semua aturan yang mengizinkan koneksi juga harus memiliki --ctdir ditambahkan untuk mengekspresikan artinya secara tepat:

-A DOCKER-USER -s 1.2.3.4/32 -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j ACCEPT

@jest wow itu sangat penting untuk diketahui! Saya tidak menyadari itu bisa cocok dengan paket ke arah lain. Masuk akal ketika Anda memikirkannya, karena cocok dengan keadaan seluruh koneksi, tetapi mudah untuk dilewatkan saat membaca dokumen.

@SystemParadox ya, saya tidak punya kesempatan untuk memberi tahu diri saya melalui dokumen dan terkejut dengan permintaan dari Docker yang menunggu tanggapan. :)

Saya terus berputar-putar dengan alasan membutuhkan --ctdir ORIGINAL . Di satu sisi, penjelasan oleh @jest sangat masuk akal, dan di sisi lain saya biasanya tidak pernah berurusan dengan paket balasan jadi mengapa harus berbeda di sini?

Saya pikir perbedaannya adalah saya memiliki -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT sebagai aturan pertama, jadi aturan saya yang lain tidak pernah melihat paket balasan. Dalam hal ini, saya pikir --ctdir ORIGINAL tidak sepenuhnya diperlukan, meskipun mungkin akan lebih aman untuk memasukkannya.

@jest , apakah Anda setuju dengan ini? Agaknya Anda tidak memiliki aturan ESTABLISHED,RELATED -j ACCEPT , itulah mengapa ini membuat perbedaan bagi Anda?

@jest Posting Anda sangat membantu, terima kasih.

Apakah pendekatan Anda hanya diperlukan untuk hal-hal yang dikelola oleh buruh pelabuhan, atau untuk semuanya? Misalnya, port ssh saya (22) tidak ada hubungannya dengan buruh pelabuhan. Apakah saya perlu menggunakan -m tcp --dport 22 seperti biasa, atau haruskah saya menggunakan -m conntrack --ctorigdstport 22 --ctdir ORIGINAL ?

Saya berasumsi pendekatan Anda hanya diperlukan untuk lalu lintas yang dikelola buruh pelabuhan, karena paket-paket itu mengalami mangling/natting sebelum sampai ke saya di tabel filter. TAPI, saya baru mengenal iptables jadi saya ingin memastikan dari seseorang yang tahu lebih banyak dari saya!

@lonix1 Aturan ditambahkan oleh buruh pelabuhan ke rantai DOCKER hanya jika Anda mengekspos port, dan mungkin hanya ketika wadah sedang berjalan. Jika tidak satu pun dari wadah Anda yang mengekspos port 22, Anda seharusnya memiliki aturan firewall yang berfungsi tanpa dimodifikasi.

@SystemParadox Sudah beberapa waktu dan saya tidak memiliki akses ke server itu untuk memeriksa, tetapi jika saya ingat dengan benar, ada aturan ESTABLISHED,RELATED (dikelola oleh UFW, dalam rantai ufw-before-input ). Namun, dalam kasus saya, mereka tidak akan cocok pada paket pertama (SYN) koneksi yang dibuat dari buruh pelabuhan ke host Internet pada port 80. Dan akan dijatuhkan oleh aturan yang sesuai di DOCKER-USER ketika tidak ada --ctdir .

@Ionix1 , paket untuk layanan di host hanya melalui INPUT, sedangkan paket untuk layanan buruh pelabuhan hanya melalui FORWARD dan DOCKER-USER.

Misalnya, dengan IP eksternal 10.0.0.1 dan dua kontainer dengan -p 4000:80 dan -p 4001:80 , Anda akan melihat paket dengan properti berikut:

INPUT:
dst 10.0.0.1 dport 80 ctorigdst 10.0.0.1 ctorigdstport 80
FORWARD/DOCKER-USER:
dst 172.17.0.5 dport 80 ctorigdst 10.0.0.1 ctorigdstport 4000
dst 172.17.0.6 dport 80 ctorigdst 10.0.0.1 ctorigdstport 4001

Jadi Anda dapat menggunakan --dport 80 untuk aturan INPUT, karena aturan tersebut berada dalam rantai yang benar-benar terpisah. Seperti yang Anda lihat, --ctorigdstport 80 masih akan cocok, tetapi kecuali Anda juga merusak input karena alasan tertentu, saya mungkin tidak akan melakukannya.

Anda mungkin juga memperhatikan bahwa Anda sebenarnya dapat menggunakan --dport 80 dengan --dst 172.17.0.5 untuk memfilter paket untuk wadah buruh pelabuhan tertentu, tetapi IP itu tidak dapat diprediksi, itulah sebabnya kami menggunakan --ctorigdstport .

Pada akhirnya Anda perlu menyadari paket apa yang mungkin cocok dengan aturan tertentu, tergantung pada rantai tempat Anda berada, apa tujuannya, dan apakah ada gangguan yang terjadi.

@jest terima kasih, itu sepertinya mengkonfirmasi pemikiran saya.

Jadi, saya perlu sedikit arahan... untuk beralih dari UFW ke iptables...
-apakah saya hanya mematikan UFW melalui "ufw disable"?
-apakah saya membuat file .sh saya sendiri, atau apakah ada yang sudah ada (saya Ubuntu di DigitalOcean)?
-saya hanya perlu memberi tahu Docker "--iptables=false"? (itu untuk Docker?)
-DOCKER-USER sudah dibuat dan dirantai oleh Docker?

@fredjohnston Anda dapat terus menggunakan UFW jika Anda mau. Profil disimpan di /etc/ufw . Masalahnya di sini adalah bahwa Docker tidak akan muncul karena tidak ada profil aplikasi yang terdaftar di /etc/ufw/applications.d (sama untuk alat firewall lain dan konfigurasinya).

Menonaktifkan IPTables di Docker berarti Anda tidak akan memiliki banyak jaringan di Docker, hanya alamat IP dan wadah yang tidak akan dapat berbicara satu sama lain. DOCKER_USER adalah peretasan untuk memberi Anda kendali, tetapi sebenarnya tidak menyelesaikan masalah - yang sebenarnya tentang tidak membuat wadah Docker publik di jaringan secara default, tetapi dikunci ke alamat IP wadah.

Untuk saat ini, saya menyarankan Anda untuk terus menggunakan alat Firewall apa pun yang paling nyaman bagi Anda (ufw, dll) tetapi ketahuilah bahwa Docker Containers akan menjadi publik di jaringan Anda.

Karena saya di sini dengan cara apa pun - saya sebenarnya mengalami masalah terkait sekarang di mana ini juga merupakan masalah pada platform selain Linux. Pertimbangkan hal berikut:

  • Proyek A memiliki dua wadah, satu untuk database dan satu untuk aplikasi.
  • Proyek B memiliki dua wadah, satu untuk database dan satu untuk aplikasi.
  • Kedua proyek diisolasi satu sama lain (repositori sumber terpisah, konfigurasi, dll)
  • Kedua proyek dikelola di bawah Docker Compose
  • Kedua proyek mengekspos Port Database mereka untuk tujuan pengembangan lokal
  • Kedua proyek menggunakan server database yang sama (postgres, mysql, dll)

Sekarang anggaplah Anda ingin menjalankan kedua proyek secara lokal - misalnya untuk bekerja di pustaka bersama yang digunakan kedua proyek sehingga Anda dapat dengan mudah menariknya ke dalam kode mereka untuk pengujian.

Di bawah desain interaksi firewall saat ini - dan apa yang sebagian mengarah ke masalah di atas tentang mengekspos wadah ke jaringan publik tanpa sepengetahuan pengguna - basis data buruh pelabuhan dari kedua proyek tidak dapat dijalankan pada saat yang sama karena mereka akan bersaing untuk port terbuka untuk database. Sama jika Anda ingin mengekspos kedua port aplikasi mereka dan keduanya menggunakan port yang sama untuk server aplikasi - umum karena API dan aplikasi berbasis HTTP sangat umum sekarang terutama di aplikasi berorientasi cloud.

Tentu Anda dapat meretas cara Anda untuk mengatur keduanya di bawah satu wadah DB; tetapi Anda tidak mengisolasinya sesuai desain proyek Anda, dan harus lebih berhati-hati tentang konfigurasi, dll.

Dalam solusi yang tepat di sini ada dua:

  1. Kontainer hanya akan terikat ke IP mereka dan port terbuka mereka akan terikat ke IP mereka sendiri dalam Jaringan Docker masing-masing, bukan pada sistem yang cocok dengan semua IP ( 0.0.0.0 , :: ).
  2. Docker juga tidak akan secara terbuka mengekspos rute ke Jaringan Docker dari sistem secara default. Jaringan Docker dapat digunakan untuk membangun koneksi antar-jaringan (jaringan buruh pelabuhan ke jaringan buruh pelabuhan) seperti yang dirancang saat ini, dan kemudian juga mengizinkan koneksi host lokal secara default.
  3. Pengguna kemudian akan siap untuk menambahkan aturan firewall yang sesuai untuk mengekspos kontainer ke dunia luar kapan dan jika diinginkan - misalnya, dengan meneruskan port port 443 ke port 443 dari kontainer pilihan mereka.

Sekali lagi, ini dapat dilakukan secara bertahap:

  • Rilis 1: Terapkan Langkah 1 dan 2; tetapi tambahkan juga perutean non-localhost (sementara) dengan peringatan. Perilaku saat ini dari first-come-first-serve untuk mendapatkan pelabuhan dipertahankan; dan peringatan tentang perilaku ini akan pergi dikeluarkan.
  • Rilis 1+N: Hapus peringatan, dan batalkan perutean non-localhost. Memerlukan Langkah 3 untuk pengguna yang ingin Docker mengekspos port dari sistem dan pastikan ini didokumentasikan dengan baik.

DOCKER_USER adalah peretasan untuk memberi Anda kendali, tetapi benar-benar tidak menyelesaikan masalah - yang sebenarnya tentang tidak membuat wadah Docker publik di jaringan secara default, tetapi dikunci ke alamat IP wadah.

Untuk saat ini, saya menyarankan Anda untuk terus menggunakan alat Firewall apa pun yang paling nyaman bagi Anda (ufw, dll) tetapi ketahuilah bahwa Docker Containers akan menjadi publik di jaringan Anda.

Ada permintaan pembaruan dokumen di sini https://github.com/docker/docker.github.io/pull/8357 untuk membuat konfigurasi statis iptables bolt-on tapi saya tidak yakin dengan statusnya.

Sunting: Saya perhatikan bahwa Anda telah salah memahami arti dari DOCKER-USER. Ini tidak digunakan untuk "membuat wadah terkunci ke alamat IP wadah" tetapi untuk memfilter akses ke wadah dengan aturan iptables.

@aki-k per DOCKER_USER Saya sadar DOCKER_USER tidak mengunci wadah terhadap Alamat IP dan tidak pernah mengklaim itu. DOCKER_USER hanya menyerahkan masalah keamanan kepada pengguna untuk dikelola - artinya pengguna harus tahu cara memanipulasi firewall mereka untuk memastikan mereka benar-benar memiliki lingkungan yang aman. Menjadikannya sebagai masalah pengguna sama-sama tidak dapat diterima karena sebagian besar pengguna tidak tahu cara mengelola firewall mereka - aturan firewall itu sulit, dan bahkan kita yang tahu sedikit tentang menulis aturan firewall masih sering salah.

Permintaan saya - dan intinya - dalam masalah ini adalah bahwa Docker harus aman secara default dan tidak mengekspos wadah ke dunia luar tanpa sepengetahuan pengguna atau intervensi eksplisit untuk melakukannya. Dan per komentar terakhir saya (https://github.com/moby/moby/issues/22054#issuecomment-552951146) melakukannya juga akan memiliki beberapa manfaat teknis lainnya juga.

Permintaan saya - dan intinya - dalam masalah ini adalah bahwa Docker harus aman secara default dan tidak mengekspos wadah ke dunia luar tanpa sepengetahuan pengguna atau intervensi eksplisit untuk melakukannya.

Laporan masalah paling awal yang saya temukan tentang ini adalah dari 18 Maret 2014:

https://github.com/moby/moby/issues/4737

Ini mungkin keputusan desain yang tidak ingin mereka ubah dan coba perbaiki dengan rantai iptables DOCKER-USER. Anda dapat menggunakan opsi -p untuk menjalankan buruh pelabuhan untuk mempublikasikan port hanya ke Host buruh pelabuhan (-p 127.0.0.1:port:port) tetapi itu juga tidak menyelesaikan masalah.

Mari kita menjadi jelas, Docker Apakah aman secara default. Anda harus memberi tahu Docker untuk melakukan penerusan porta.

Adapun layanan yang perlu berkomunikasi satu sama lain, Anda harus menggunakan jaringan ( docker network ) untuk membatasi akses, bukan penerusan porta.

Mari kita perjelas, Docker _Is_ aman secara default. Anda harus memberi tahu Docker untuk melakukan penerusan porta.

Tolong jangan abaikan masalah faktual dengan buruh pelabuhan yang menjalankan perlindungan iptables Anda yang sudah ada. Saya yakin Anda telah melihat banyak laporan masalah yang membahas hal ini.

Mari kita perjelas, Docker _Is_ aman secara default. Anda harus memberi tahu Docker untuk melakukan penerusan porta.

Adapun layanan yang perlu berkomunikasi satu sama lain, Anda harus menggunakan jaringan ( docker network ) untuk membatasi akses, bukan penerusan porta.

Mari kita perjelas - Docker aman sampai Anda ingin mengaksesnya di luar jaringan buruh pelabuhan. Setelah Anda ingin mengaksesnya bahkan dari host lokal (127.0.0.1) maka Docker tidak aman secara default karena mengikat terhadap 0.0.0.0 dan mengekspos wadah dari sistem - melewati apa pun yang dilakukan pengguna untuk mengamankan sistem mereka, tanpa muncul dalam perkakas selain penggunaan langsung iptables . DOCKER_USER tidak dan tidak akan pernah menjadi solusi yang tepat karena mengharuskan pengguna mengetahui terlalu banyak tentang sistem firewall yang mendasarinya (iptables di Linux, apa pun yang digunakan Mac, dan Windows Firewall di Windows). Itu masih perlu diamankan secara default. Ada cara yang sangat mudah untuk melakukannya seperti yang saya uraikan sebelumnya di https://github.com/moby/moby/issues/22054#issuecomment -552951146 dan telah memanggil beberapa kali selama masalah ini (meskipun mungkin tidak sejelas itu komentar).

Perhatikan juga bahwa dokumentasi untuk mengekspos port juga tidak menyebutkan masalah keamanan ini, tidak mengacu pada bagaimana Docker berinteraksi dengan firewall sistem saat mengekspos port - sehingga mengurangi keamanan pada sistem yang telah dirancang untuk aman hingga Docker digunakan .

Mari kita perjelas, Docker _Is_ aman secara default. Anda harus memberi tahu Docker untuk melakukan penerusan porta.
Adapun layanan yang perlu berkomunikasi satu sama lain, Anda harus menggunakan jaringan ( docker network ) untuk membatasi akses, bukan penerusan porta.

Mari kita perjelas - Docker aman sampai Anda ingin mengaksesnya di luar jaringan buruh pelabuhan. Setelah Anda ingin mengaksesnya bahkan dari host lokal (127.0.0.1) maka Docker _not_ aman secara default karena mengikat terhadap 0.0.0.0 [...]

Tepatnya, Docker tidak mengikat ke 0.0.0.0. Itulah harapan (wajar) pengguna: yang menetapkan --publish pada CLI, karenanya beroperasi di ruang pengguna, memulai semacam daemon proxy yang mendengarkan pada port yang ditentukan, menerima koneksi masuk dan mendorong bolak-balik semua paket antara Docker dan dunia luar.

Tetapi sebaliknya, Docker menyuntikkan aturan DNAT/masquarading ajaib ke dalam firewall untuk menulis ulang alamat pada paket, sehingga secara acak melanggar sistem aturan yang sudah diinstal sebelumnya.

Menurut pendapat saya, tingkat abstraksi yang kacau di sini adalah yang paling mengecewakan dan membingungkan pengguna. Saya tidak tahu skenario apa yang dipertimbangkan oleh tim Docker ketika merancang mesin --publish kami lihat di sini, saya tidak melihat ada yang membenarkan keputusan (mungkin selain alasan kinerja).

Mari kita perjelas, Docker Aman secara default. Anda harus memberi tahu Docker untuk melakukan penerusan porta.

... yang merupakan salah satu fitur Docker yang paling banyak digunakan. Secara efektif, Anda baru saja menyatakan bahwa penggantian tidak berdokumen dari aturan firewall yang sudah ada sebelumnya dalam salah satu fitur Docker yang paling sering digunakan membuat Docker _secure secara default_.

Yah, apa pun yang cocok untuk Anda, saya kira. Karena tidak berhasil untuk saya, saya akan mulai mencari platform wadah alternatif. Masalah keamanan dapat diperbaiki tetapi mengabaikan ekspektasi keamanan yang wajar adalah hal yang berbeda.

Mari kita menilai situasi seperti sekarang ini:

Secara default, tidak ada port yang terbuka. Anda harus memberi tahu Docker untuk mengekspos port.
Di masa lalu Docker akan mengatur iptables sedemikian rupa sehingga apa pun yang tahu cara merutekan ke jaringan jembatan dapat mengakses IP wadah (dengan menetapkan kebijakan penerusan ke "terima"), tetapi ini tidak lagi benar.

Saya telah melihat beberapa orang mengatakan mereka menggunakan -p untuk mengekspos layanan satu sama lain, yang seharusnya tidak diperlukan.
Pada jaringan default Anda dapat menggunakan --link untuk menyambungkan layanan bersama-sama, wadah tersedia melalui DNS.
Pada jaringan non-default (jaringan yang ditentukan pengguna), container juga dapat saling mengakses dengan DNS, termasuk menyiapkan alias melalui --link , atau bahkan ke jaringan dengan alias tertentu.

Sepertinya banyak kasus benar-benar Anda hanya ingin terhubung ke layanan dari klien, dalam hal ini disarankan untuk menggunakan wadah lain dengan akses ke layanan yang ingin Anda sambungkan daripada mengekspos port.

-p dirancang khusus untuk ingress, seperti membiarkan hal-hal eksternal mengakses layanan ini.
Default untuk -p memang mengizinkan lalu lintas dari mana saja. Anda dapat mengubah ini dengan secara manual menentukan alamat yang akan diizinkan baik per -p atau sebagai pengaturan lebar daemon.
Karena -p menggunakan iptables, rantai DOCKER-USER dibuat sehingga pengguna dapat menambahkan aturan filter mereka sendiri sebelum mencapai wadah.

Karena -p dirancang untuk ingress, saya pikir masuk akal untuk mengekspos lalu lintas seperti itu. Saya merasa sangat disayangkan bahwa aturan Docker dimasukkan di bagian atas tabel filter, namun mengubah ini akan menjadi perubahan besar bagi sekelompok besar pengguna yang DO menginginkan perilaku ini.

Ada beberapa alternatif lain untuk -p :

  1. Jangan gunakan -p , sambungkan ke IP wadah secara langsung. Ini membutuhkan sedikit kerja ekstra karena Anda harus mencari IP, tetapi data ini tersedia dari API. Anda juga harus memastikan kebijakan penerusan pada firewall memungkinkan ini (dengan asumsi Anda terhubung dari Host yang berbeda, Host yang sama seharusnya baik-baik saja)
  2. Gunakan jaringan macvlan atau ipvlan untuk layanan yang Anda inginkan agar dapat diakses dari jaringan host (yaitu ingress). Opsi jaringan ini memberi wadah IP langsung dari antarmuka jaringan host (Anda memilih antarmuka mana yang terikat).
  3. Gunakan --net=host , ini menjalankan layanan di namespace jaringan host yang memberikan akses layanan ke infra jaringan yang sudah ada di host.

Anda mengatakan "jadikan ini aman secara default", tetapi mengekspos port menurut definisi adalah tindakan yang berpotensi tidak aman. Tampaknya juga ada beberapa gagasan bahwa mengekspos ke localhost saja aman, tetapi tidak karena apa pun yang berjalan di Host dapat mengakses localhost (termasuk javascript di browser jika itu adalah desktop).

Kasus penggunaan apa yang Anda coba selesaikan dengan menggunakan -p ?
Apakah Anda memiliki beberapa pemikiran tentang perubahan aktual yang ingin Anda lihat?

Saya baik-baik saja mengubah sesuatu untuk menjadikannya lebih baik untuk alur kerja Anda, tetapi ada banyak kasus penggunaan yang berbeda di sini dan satu ukuran tidak pernah cocok untuk semua (lihat keluhan tentang -p ).

@ cpuguy83 itu semua baik-baik saja dan keren, tetapi tidak mengubah apa pun dalam permintaan ini.

Orang-orang menggunakan buruh pelabuhan dan ingin terhubung ke aplikasi yang berjalan di bawah buruh pelabuhan dari sistem lokal mereka - ini adalah kasus penggunaan yang sangat umum untuk pengembang terutama ketika mencoba mendiagnosis sesuatu atau menulis layanan yang tidak berada di bawah buruh pelabuhan tetapi perlu terhubung ke layanan yang dihosting di buruh pelabuhan (untuk mengisi lingkungan dev). Berkembang di bawah Docker tidak selalu merupakan pengalaman yang baik, menyenangkan, atau bermanfaat, seperti yang dikatakan:

disarankan untuk menggunakan wadah lain dengan akses ke layanan yang ingin Anda sambungkan daripada membuka port.

Apakah hanya no-go. Tidak semua alat ramah Docker, juga tidak harus demikian. Pengguna tidak harus sepenuhnya berada di bawah Docker untuk memanfaatkan layanan yang berjalan di bawah Docker. Bahkan kemudian, jika Docker digunakan untuk mengoperasikan server, administrator tidak dapat dengan mudah mengontrolnya melalui konfigurasi firewall dan fungsionalitas Expose Port namun diatur (baris perintah, Dockerfile, Docker Compose Config) benar-benar rusak.

Selanjutnya, orang-orang menggunakan Docker Compose untuk mengelola sebagian besar lingkungan, dan menentukan melalui docker-compose.yml atau Dockerfile bahwa port perlu diekspos sehingga mereka dapat mengaksesnya secara lokal. Oleh karena itu mengatakan parameter use the -p tidak benar karena mereka tidak pernah berinteraksi dengan perintah buruh pelabuhan secara langsung sedemikian rupa sehingga itu akan berfungsi.

Mengekspos port tidak berarti keamanan harus dilanggar. Saya telah menguraikan bagaimana Anda dapat mengekspos port ke sistem lokal tanpa merusak keamanan ( https://github.com/moby/moby/issues/22054#issuecomment-552951146 ) dan itu akan membuat manajemen eksposur eksternal (mati sistem) di tangan pengguna dengan cara yang dapat mereka kontrol dengan mudah dengan perkakas yang ada.

Larutan:

  • Gunakan Jaringan Docker
  • Mengekspos Port di Jaringan Docker saja dan host lokal
  • Berhenti mengikat port pada 0.0.0.0 - atau lakukan secara efektif
  • Mengharuskan pengguna untuk menggunakan alat firewall mereka sendiri untuk mengekspos sistem port off (ufw, firewalld, dll)
  • Sediakan integrasi untuk firewall umum untuk mempermudah ini

Dengan kata lain, alih-alih mengakses layanan dalam wadah buruh pelabuhan melalui 127.0.0.1:<port> memerlukan <docker container ip>:<service port> bahkan dari Host lokal. Jika orang ingin mengekspos layanan dari sistem, mereka dapat menambahkan aturan firewall melalui perkakas mereka (ufw, dll) untuk meneruskan port dari port yang diberikan ke <docker container ip>:<service port> .

Atau, ikuti pendekatan Kubernetes dengan desain Proxy mereka, secara efektif melakukan seperti yang disarankan @jest di https://github.com/moby/moby/issues/22054#issuecomment -554665865. Sekali lagi, ini masih perlu sistem lokal hanya sampai pengguna dengan sengaja mengeksposnya ke jaringan luar.

Masalah terbesar di sini adalah bahwa Docker mengkompromikan integritas firewall untuk menyediakan layanannya, melakukannya tanpa memberi tahu pengguna sama sekali, dan tanpa mengintegrasikan ke dalam perangkat pengguna sehingga pengguna tidak mengetahuinya atau tidak dapat mengontrolnya.

Saya menyadari ada banyak sekali antarmuka firewall di pasaran - bahkan dengan iptables ada firewalld, ufw, dan selusin lainnya. Saya tidak benar-benar mengharapkan Docker untuk berintegrasi dengan mereka (meskipun itu akan menyenangkan), tetapi saya berharap Docker bekerja dengan cara yang tidak mem-bypass mereka atau merusak keamanan apa pun yang dilakukan pengguna.

Sebagai kasus uji dasar:

  • Siapkan server berbasis Debian (Debian, Ubuntu)
  • Instal ufw, OpenSSH Server
  • jalankan ufw allow OpenSSH
  • jalankan ufw enable

Pada titik ini Anda memiliki server yang cukup aman; satu-satunya lalu lintas yang diizinkan masuk adalah (a) terkait dengan lalu lintas keluar atau (b) lalu lintas Server SSH.

Sekarang, mulai wadah buruh pelabuhan dengan port terbuka.

Solusi yang dapat diterima akan memenuhi hal berikut:

  • Port tidak boleh diakses dari komputer lain; firewall harus terus memblokirnya dari sistem luar.
  • Port harus dapat diakses dari komputer lokal (localhost).
  • Beberapa kontainer buruh pelabuhan harus dapat mengekspos port yang sama dan semuanya berfungsi; semua kontainer dengan port terbuka harus dapat diakses dari sistem lokal saja.
  • Pengguna tidak perlu mengetahui detail konfigurasi firewall mereka untuk mewujudkannya.

Coba hal yang sama untuk sistem berbasis CentOS/Fedora/RHEL dengan firewalld .

@cpuguy83 IMO orang mengharapkan -p untuk bekerja pada tingkat aplikasi. Yaitu, jika saya -p 80:80 , saya mengharapkan perilaku seolah-olah aplikasi yang terikat ke port 80 dalam wadah sedang berjalan di Host.

VirtualBox atau SSH model port forwarding sedemikian rupa, sehingga orang menganggap hal yang sama dalam kasus Docker.

Untuk menggunakan paralel harapan yang lebih luas: dari sudut pandang pengguna, ini harus berfungsi sebagai volume yang terikat host. Anda cukup menunjuk ke direktori host, dan "sebagai ajaib" itu terlihat di dalam wadah; modifikasi apa pun yang dilakukan pada sistem file dari sisi lain berfungsi sama, termasuk izin, kuota, dll.

Mempersempit masalah -p ke kasus firewall: di dunia normal pengguna mengharapkan bahwa aplikasi terikat 0.0.0.0:80 dapat dilihat oleh dunia luar. Jika pengguna ingin membatasi akses, ia diinstruksikan dalam banyak panduan untuk menggunakan firewall dan menyiapkan aturan di rantai INPUT :

-P INPUT DROP
-A INPUT -s 1.2.3.4/32 -p tcp --dst-port 80 -j ACCEPT

atau gunakan alat seperti UFW:

ufw enable
ufw allow http

Tetapi dengan buruh pelabuhan, pengguna harus dapat membuat aturan seperti itu secara tiba-tiba:

-A DOCKER-USER -s 1.2.3.4/32 -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j ACCEPT
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j DROP

Tolong, tunjukkan satu panduan komprehensif untuk pengguna rata-rata tentang cara menyelesaikan skenario umum seperti itu dengan Docker.

Dan misalnya rata-rata pengembang — kepada siapa Anda telah menjual seluruh konsep "penampungan aplikasi" — konsekuensi dari membuka port tidak dapat diprediksi.

Hari-hari ini saya tidak mengekspos port karena kurangnya pengetahuan saya, dan menggunakan layanan seperti Traefik sebagai gantinya. Mungkin --expose juga tidak boleh diusulkan sebagai tujuan umum dalam dokumen CLI, karena IMO tidak ada gunanya bagi pengguna biasa.

Atau, berikan kepada siapa pun yang tidak memiliki pengetahuan mendalam tentang alat-alat ini dengan laptop Linux, seperti Dell atau Lenovo, dan saksikan bagaimana upaya bonafide mereka dalam menyetel firewall mereka dengan benar sama sekali tidak ada bedanya ketika seseorang berhasil mengakses database lokal mereka saat minum kopi di Starbucks.

Masalah persis ini menyebabkan kerentanan sistem bagi kami yang saya temukan selama akhir pekan. Per @jacoscaz , saya baru saja dapat memanfaatkan database lokal pengembang lain karena memiliki port yang diterbitkan. Akan sangat bagus jika Anda semua bisa memasukkan ini dalam dokumentasi intro sehingga orang lain tidak melakukan hal yang sama. Kami membutuhkan layanan non-containerized untuk terhubung ke container tanpa semua orang di jaringan mendapatkan akses, jadi jaringan Docker tidak mungkin. Kedengarannya seperti pilihan terbaik untuk saat ini adalah menghubungkan ke IP kontainer lokal, kecuali ada yang punya ide yang lebih baik.

@dentonmwood Kedengarannya persis seperti yang harus Anda lakukan. Seperti yang saya sebutkan di atas, Anda bahkan dapat mengatur layanan untuk dijalankan menggunakan macvlan atau ipvlan yang akan memberikannya IP langsung di jaringan normal Anda.

@BenjamenMeyer @jest @jacoscaz

Terima kasih atas tanggapan tambahannya.

Saya setuju bahwa pengetahuan kami meminta pengguna untuk berpose dalam hal ini tidak bagus. Saat ini kami menempatkan tanggung jawab pada pengguna (baik itu sysadmin atau pengembang) untuk memahami apa yang dilakukan -p dan untuk mengambil tindakan pencegahan yang tepat untuk memastikan layanan hanya diekspos kepada siapa yang menurut mereka terpapar. Kami mengambil langkah lebih jauh bahkan dengan mengharapkan pengembang yang sering tidak memiliki alasan untuk mengetahui iptables untuk masuk dan memperbaikinya untuk lingkungan mereka sendiri (melalui DOCKER-USER ).
Kami pada dasarnya berada dalam situasi ini karena takut melanggar kompatibilitas.

Saya memiliki beberapa ide yang belum sempat saya pikirkan sepenuhnya, tetapi pada dasarnya akan mengubah perilaku -p berdasarkan versi API klien dan menangani ingress secara terpisah. Masih merupakan perubahan besar yang membuat saya khawatir, tetapi setidaknya perilaku lama dipertahankan dalam versi API yang lebih lama.

Saya memang berpikir bahwa kami dapat melakukan proxy lokal (ala kubectl proxy ) untuk kasus penggunaan akses lokal, namun ini sekali lagi menempatkan tanggung jawab pada pengembang untuk mengetahui dan memahami lebih dari yang seharusnya mereka perlukan. .

Pikiran?

Saya pikir memperkenalkan proxy adalah langkah ke arah yang baik.

Saya mengakui bahwa "penerusan port" adalah tanggung jawab bersama antara wadah dan orkestra, serupa dalam semangat dengan mode Swarm. Tetapi integrasi host minimal selalu diperlukan dan ketika memberikan opsi seperti -p kepada pengguna (non-ahli), solusi yang diusulkan harus dapat dipahami oleh orang tersebut.

Karena konsekuensi -p terhadap lingkungan tidak ditentukan (setidaknya pada tingkat CLI, saya pikir), ada kemungkinan untuk memperkenalkan konfigurasi yang ramah pengguna dari cara kerjanya.

Misalnya, saat ini ada iptables di /etc/docker/daemon.json yang menentukan apakah akan memanipulasi DOCKER atau tidak. Konfigurasi dapat diperluas dengan entri lain, sehingga kombinasi seperti iptables==true && expose_with_network_proxy==true akan mengaktifkan perilaku seperti proxy.

Ini umumnya aman untuk instalasi baru, seperti yang lebih memilih overlay2 daripada aufs beberapa waktu lalu (jika saya ingat dengan benar). Dan mudah digunakan, karena pemutakhiran tidak menyentuh file konfigurasi yang ada, tetapi pemasangan baru dapat dilakukan secara gratis.

Kami pada dasarnya berada dalam situasi ini karena takut melanggar kompatibilitas.

Saya benar-benar ingin menekankan fakta bahwa beratnya masalah ini, setidaknya di mata saya, lebih berkaitan dengan kurangnya dokumentasi daripada dengan dasar-dasar teknis saat ini -p . Ya, saya tidak percaya bahwa mekanisme saat ini dapat dikatakan _secure_, tetapi kelemahan keamanan dapat diperbaiki dan saya tidak dalam posisi untuk mengkritik alasan yang mengarah pada skenario saat ini. Bagaimanapun, tinjauan ke belakang selalu 20/20, dan saya mengagumi komitmen terhadap kompatibilitas ke belakang dan kesediaan untuk menghadapi tantangan teknis yang ditimbulkan oleh komitmen tersebut.

Apa yang saya tidak mengerti adalah mengapa masih tidak ada kotak merah terang, besar, di seluruh dokumentasi Docker yang secara eksplisit memperingatkan efek samping dari penggunaan -p . Seandainya saya menemukan peringatan seperti itu, saya tidak berpikir saya akan berada di sini sejak awal.

Pikiran?

Opsi proxy terdengar masuk akal. Plus, saya menyukai gagasan untuk dapat mengekspos dan menghapus port kapan pun diperlukan daripada terikat untuk melakukannya saat meluncurkan docker run .

@BenjamenMeyer @jest @jacoscaz

Terima kasih atas tanggapan tambahannya.

Terima kasih untuk akhirnya melihat ini lebih dekat.

Saya setuju bahwa pengetahuan kami meminta pengguna untuk berpose dalam hal ini tidak bagus. Saat ini kami menempatkan tanggung jawab pada pengguna (baik itu sysadmin atau pengembang) untuk memahami apa yang dilakukan -p dan untuk mengambil tindakan pencegahan yang tepat untuk memastikan layanan hanya diekspos kepada siapa yang menurut mereka terpapar. Kami mengambil langkah lebih jauh bahkan dengan mengharapkan pengembang yang sering tidak memiliki alasan untuk mengetahui iptables untuk masuk dan memperbaikinya untuk lingkungan mereka sendiri (melalui DOCKER-USER ).
Kami pada dasarnya berada dalam situasi ini karena takut melanggar kompatibilitas.

Saya memiliki beberapa ide yang belum sempat saya pikirkan sepenuhnya, tetapi pada dasarnya akan mengubah perilaku -p berdasarkan versi API klien dan menangani ingress secara terpisah. Masih merupakan perubahan besar yang membuat saya khawatir, tetapi setidaknya perilaku lama dipertahankan dalam versi API yang lebih lama.

Pikiran?

  1. Mulailah dengan memperbarui dokumentasi sehingga pengguna mengetahui efek EXPOSE dari semua metode (-p, Dockerfile, docker-compose.yml). Banyak yang bisa dilakukan dengan cepat. Ini juga dapat membantu mendapatkan perhatian tentang masalah ini untuk mendapatkan lebih banyak orang yang menawarkan saran/keahlian dalam menemukan solusi yang baik dan membantu menjawab jika ada keinginan komunitas untuk kompatibilitas ke belakang juga.
  2. Rencanakan metode untuk berpindah dari tempat Docker sekarang ke tempat yang dibutuhkan Docker. Ini dapat mencakup perubahan yang melanggar di beberapa titik.

Saya pikir beratnya situasi tentu memungkinkan perubahan besar untuk memperbaikinya; hanya tidak melakukannya tanpa memberitahu orang-orang. Tetapkan garis waktu (6 bulan? 12 bulan?) di mana perubahan itu banyak dibahas, dll dan Anda mempersiapkan komunitas; kemudian dalam versi "utama" buat perubahan. Berdasarkan skema versi Anda, sepertinya set pertama adalah tahun (19); mengingat kita berada di akhir 2019, gunakan sisa tahun 2019 dan kemudian 2020 untuk mencari solusi dan mengiklankannya; memperkenalkannya sebagai fitur opsional sekitar tahun 2020 dan kemudian mempromosikannya ke tempat pertama/penggunaan default pada tahun 2021.

Versi Dockerfile dan Versi Skema Penulisan Docker mungkin merupakan alat yang baik juga sejauh mengatur perilaku default, tetapi saya tidak akan memblokir versi yang lebih lama untuk dapat memanfaatkannya, dan akan memberikan peringatan keras tentang perlunya memperbarui dalam kasus seperti itu juga.

Bagaimanapun itu diluncurkan, saya pikir Anda akan menemukan komunitas secara keseluruhan jauh lebih mendukung perubahan seperti itu jika mereka mengerti mengapa dan apa yang terjadi dan tidak merasa seperti mereka dibutakan olehnya.

Saya memang berpikir bahwa kami dapat melakukan proxy lokal (ala kubectl proxy ) untuk kasus penggunaan akses lokal, namun ini sekali lagi menempatkan tanggung jawab pada pengembang untuk mengetahui dan memahami lebih dari yang seharusnya mereka perlukan. .

Saya menyukai ide proxy, dan saran @jest tentang cara mengaktifkannya mungkin juga merupakan metode yang bagus untuk melakukan migrasi.

Sejujurnya, kebanyakan orang yang ingin mengeksposnya dari sistem akan atau harus terbiasa dengan firewall sampai tingkat tertentu, bahkan jika itu hanya cara mengkonfigurasi UFW atau firewalld untuk melakukannya. Jadi jika solusinya hanya membuatnya tersedia untuk host lokal, maka saya pikir itu dapat diterima bagi orang-orang untuk mempelajari cara menggunakan alat firewall mereka untuk melakukan port forward melalui firewall.

Saya pikir penting bahwa fungsionalitas seperti itu dilakukan melalui alat firewall yang telah diputuskan pengguna untuk digunakan karena akan membuat semuanya terlihat oleh mereka. Fungsionalitas seperti itu tidak boleh melewati perkakas mereka. Saya juga menyadari bahwa ada begitu banyak alat firewall di luar sana sehingga tidak masuk akal bagi Docker untuk berintegrasi dengan semuanya. Jadi saya akan menyarankan untuk mengambil rute dokumentasi dan menyoroti bagaimana melakukannya dengan beberapa yang populer untuk memulai, dan biarkan komunitas menambahkan lebih banyak dan memperbaruinya.

Saya menyukai ide proxy, dan saran @jest tentang cara mengaktifkannya mungkin juga merupakan metode yang bagus untuk melakukan migrasi.

Sejujurnya, kebanyakan orang yang ingin mengeksposnya dari sistem akan atau harus terbiasa dengan firewall sampai tingkat tertentu, bahkan jika itu hanya cara mengkonfigurasi UFW atau firewalld untuk melakukannya. Jadi jika solusinya hanya membuatnya tersedia untuk host lokal, maka saya pikir itu dapat diterima bagi orang-orang untuk mempelajari cara menggunakan alat firewall mereka untuk melakukan port forward melalui firewall.

Saya menggemakan ini. Dengan solusi proxy, saya pikir akan layak untuk menghasilkan sesuatu yang memungkinkan pengguna untuk mengikat proxy ke kombinasi antarmuka dan port apa pun yang mereka inginkan. Namun, jika dipaksa untuk berkompromi atas nama kompatibilitas mundur (yang saya dukung!) atau alasan lain apa pun, prioritas harus diberikan agar sesuai dengan ekspektasi keamanan yang wajar, bahkan dengan biaya pendelegasian paparan di luar sistem kepada pengguna.

Lebih jauh ke komentar saya, proxy sebenarnya dapat beroperasi dengan cara yang berbeda tergantung pada alat firewall yang tersedia. Jika alat konfigurasi firewall yang didukung terdeteksi, proxy dapat menggunakannya untuk menetapkan aturan penerusan yang sesuai. Kehadiran alat tersebut dapat ditambahkan sebagai persyaratan untuk lingkungan produksi. Jika alat seperti itu tidak tersedia, proxy akan secara default memunculkan server proxy tingkat aplikasi.

Docker melewati firewall macOS sama seperti di Linux.

Di mesin pengembangan saya (Desktop Docker untuk Mac) saya menambahkan "ip": "127.0.0.1" ke konfigurasi daemon Docker. Dengan cara ini, basis data pengembangan, dll. Secara default, hanya dapat diakses dari localhost. Untuk kasus langka yang saya perlukan untuk membuat aplikasi terlihat oleh orang lain, saya dapat mempublikasikannya secara eksplisit dengan -p 0.0.0.0:8080:8080 .

Sunting: Tampaknya Docker Compose masih mengikat ke 0.0.0.0 secara default, terlepas dari konfigurasi daemon Docker. Jadi trik ini hanya berfungsi saat menjalankan Docker dari baris perintah. Lagi pula karena file Compose sering dibagikan dengan rekan tim yang mungkin memiliki konfigurasi sistem yang berbeda, lebih baik tambahkan 127.0.0.1 secara eksplisit ke file Compose.

@luontola Sungguh solusi yang elegan.

Sunting: Apa yang saya juga pikirkan mungkin adalah cara untuk memiliki daftar izinkan/blokir alamat yang dapat didefinisikan misalnya penulisan Docker yang kemudian akan secara otomatis ditambahkan ke rantai iptables DOCKER-USER.

Daisy oopsie kecil yang menyoroti pentingnya masalah ini: https://github.com/docker/for-linux/issues/810 (ringkasan: DOCKER-USER telah dihapus sehingga bahkan jika Anda mengonfigurasi iptables untuk memblokir akses eksternal buruh pelabuhan, itu akan mengabaikan konfigurasi tambahan itu dan mengekspos semua wadah)

@danhallin komentar seperti milik Anda benar-benar dapat menyelamatkan hari dalam beberapa situasi. Terima kasih sudah berbagi.

Hmm bacaan yang menarik!

Saya menjalankan Mac OS X dan juga memiliki firewall lokal bernama LittleSnitch. Itu baru saja muncul dialog menanyakan apakah itu OK untuk 185.156.177.252 untuk terhubung ke proses com.docker.backend. Saya mengklik tolak.

Saya bertanya-tanya bagaimana itu bisa membuka port forward di router saya, tetapi saya baru menyadari bahwa ini tentu saja dilakukan melalui UPnP! Semua router mendukung ini.

Yang saya herankan sekarang adalah alasannya. Mengapa sesuatu dari 185.156.177.252 mencoba terhubung dari luar? Jika proses Docker lokal saya membutuhkan sesuatu, ia harus menelepon ke rumah dari dalam, bukan membuka port di luar.

@ cpuguy83 itu semua baik-baik saja dan keren, tetapi tidak mengubah apa pun dalam permintaan ini.

Orang-orang menggunakan buruh pelabuhan dan ingin terhubung ke aplikasi yang berjalan di bawah buruh pelabuhan dari sistem lokal mereka - ini adalah kasus penggunaan yang sangat umum untuk pengembang terutama ketika mencoba mendiagnosis sesuatu atau menulis layanan yang tidak berada di bawah buruh pelabuhan tetapi perlu terhubung ke layanan yang dihosting di buruh pelabuhan (untuk mengisi lingkungan dev). Berkembang di bawah Docker tidak selalu merupakan pengalaman yang baik, menyenangkan, atau bermanfaat, seperti yang dikatakan:

disarankan untuk menggunakan wadah lain dengan akses ke layanan yang ingin Anda sambungkan daripada membuka port.

Apakah hanya no-go. Tidak semua alat ramah Docker, juga tidak harus demikian. Pengguna tidak harus sepenuhnya berada di bawah Docker untuk memanfaatkan layanan yang berjalan di bawah Docker. Bahkan kemudian, jika Docker digunakan untuk mengoperasikan server, administrator tidak dapat dengan mudah mengontrolnya melalui konfigurasi firewall dan fungsionalitas Expose Port namun diatur (baris perintah, Dockerfile, Docker Compose Config) benar-benar rusak.

Selanjutnya, orang-orang menggunakan Docker Compose untuk mengelola sebagian besar lingkungan, dan menentukan melalui docker-compose.yml atau Dockerfile bahwa port perlu diekspos sehingga mereka dapat mengaksesnya secara lokal. Oleh karena itu mengatakan parameter use the -p tidak benar karena mereka tidak pernah berinteraksi dengan perintah buruh pelabuhan secara langsung sedemikian rupa sehingga itu akan berfungsi.

Mengekspos port tidak berarti keamanan harus dilanggar. Saya telah menguraikan bagaimana Anda dapat mengekspos port ke sistem lokal tanpa merusak keamanan ( #22054 (komentar) ) dan itu akan menempatkan manajemen eksposur eksternal (di luar sistem) di tangan pengguna dengan cara yang dapat mereka lakukan dengan mudah kontrol dengan alat yang ada.

Larutan:

* Use Docker Network

* Expose the Ports on the Docker Network alone and local host

* Stop binding the port on 0.0.0.0 - or effectively doing so

* Require users to use their own firewall tooling to expose the port off system (ufw, firewalld, etc)

* Provide integrations for common firewalls to make this easy

Dengan kata lain, alih-alih mengakses layanan dalam wadah buruh pelabuhan melalui 127.0.0.1:<port> memerlukan <docker container ip>:<service port> bahkan dari host lokal. Jika orang ingin mengekspos layanan dari sistem, mereka dapat menambahkan aturan firewall melalui perkakas mereka (ufw, dll) untuk meneruskan port dari port yang diberikan ke <docker container ip>:<service port> .

Atau, ikuti pendekatan Kubernetes dengan desain Proxy mereka, secara efektif melakukan seperti yang disarankan @jest di #22054 (komentar) . Sekali lagi, ini masih perlu sistem lokal hanya sampai pengguna dengan sengaja mengeksposnya ke jaringan luar.

Masalah terbesar di sini adalah bahwa Docker mengkompromikan integritas firewall untuk menyediakan layanannya, melakukannya tanpa memberi tahu pengguna sama sekali, dan tanpa mengintegrasikan ke dalam perangkat pengguna sehingga pengguna tidak mengetahuinya atau tidak dapat mengontrolnya.

Saya menyadari ada banyak sekali antarmuka firewall di pasaran - bahkan dengan iptables ada firewalld, ufw, dan selusin lainnya. Saya tidak benar-benar mengharapkan Docker untuk berintegrasi dengan mereka (meskipun itu akan menyenangkan), tetapi saya berharap Docker bekerja dengan cara yang tidak mem-bypass mereka atau merusak keamanan apa pun yang dilakukan pengguna.

Sebagai kasus uji dasar:

* Setup a Debian-based server (Debian, Ubuntu)

* Install ufw, OpenSSH Server

* run `ufw allow OpenSSH`

* run `ufw enable`

Pada titik ini Anda memiliki server yang cukup aman; satu-satunya lalu lintas yang diizinkan masuk adalah (a) terkait dengan lalu lintas keluar atau (b) lalu lintas Server SSH.

Sekarang, mulai wadah buruh pelabuhan dengan port terbuka.

Solusi yang dapat diterima akan memenuhi hal berikut:

* The port should not be accessible from another computer; the firewall should continue to block it from outside systems.

* The port should be accessible from the local computer (localhost).

* Multiple docker containers should be able to expose the same port and have everything work; all containers with an exposed port should be accessible from the local system only.

* The user should not have to know about their firewall configuration details to make this happen.

Coba hal yang sama untuk sistem berbasis CentOS/Fedora/RHEL dengan firewalld .

Saya menemukan masalah ini ketika saya mencoba mencari tahu apakah ada cara untuk mengonfigurasi buruh pelabuhan agar tidak melewati aturan input firewall saya setiap kali port diterbitkan. Komentar di atas berfungsi dengan baik untuk menjelaskan semuanya dan juga pendekatan IMO yang lebih disukai.

Kemarin, saya menemukan masalah ini secara tidak sengaja. Saya telah menghabiskan waktu berminggu-minggu dengan cermat menyesuaikan aturan firewall iptables saya untuk VPS saya. Saya sudah mencoba untuk berhati-hati dan membatasi. Filter Input & Output diatur ke drop secara default. Saya secara eksplisit mengizinkan lalu lintas tertentu, dan memblokir yang lainnya. Lalu lintas dicatat, dan saya telah menguji dan memantau.

Saya tahu Docker membuat perubahannya sendiri pada rantai Forward dan tabel NAT.. Jadi saya _sangat_ berhati-hati untuk menghormati perubahan itu selama proses saya. Juga, semua wadah saya dilampirkan ke jaringan yang ditentukan pengguna. Jaringan host default tidak pernah digunakan. Dokumentasi resmi memberitahu kita untuk tidak melakukannya.

Kejutan pertama saya adalah bahwa Proxy Nginx saya yang kemas dapat diakses ke seluruh Internet. Saya memiliki opsi dalam aturan firewall saya untuk mengizinkan lalu lintas web masuk dari dunia. Tapi saya belum mengaktifkan fitur itu. Tidak ada di iptables saya yang jelas bahwa HTTP 80/443 diizinkan.

Beberapa aplikasi web saya mengandalkan database seperti MySQL. Awalnya saya _not_ menggunakan opsi -p di Docker Compose. Saya tahu itu tidak perlu, karena aplikasi web saya dan server db berbagi jaringan Docker yang sama yang ditentukan pengguna. Tapi sebagai mantan DBA, saya selalu memikirkan backup. Jadi saya mengaktifkan opsi -p untuk memungkinkan pekerjaan cron dan alat pencadangan host saya mengambil cadangan tepat waktu. Saya telah menulis firewall lain _option_ untuk mengizinkan akses SQL eksternal. Tapi sekali lagi, belum-belum diaktifkan itu.

Setelah keterkejutan saya di Nginx, saya dengan bijak memutuskan untuk memeriksa ulang apakah MySQL tidak terekspos juga. Saya mencoba menghubungkan (dari laptop saya) ke database MySQL di VPS jarak jauh saya. Dan lagi-lagi kaget saat berhasil langsung connect.

Tidak ada yang saya katakan belum dibahas panjang lebar di posting sebelumnya. Terima kasih banyak kepada @BenjamenMeyer @jest @jacoscaz atas penyelidikan dan saran mereka yang bermanfaat. Tetapi bagi mereka yang menanyakan kasus penggunaan dan pengalaman modern? Di sini Anda memilikinya. Lebih dari 4 tahun setelah utas ini dimulai, orang-orang seperti saya masih menghadapi perilaku ini. Dan masih pergi dengan perasaan kaget.

Ya, ada banyak solusi. Saya akan segera mengejar beberapa. Tetapi untuk menerapkannya, Anda harus benar - benar

Tetapi "perilaku bypass firewall" ini tidak disebutkan dengan jelas, diperingatkan dengan keras, dan didokumentasikan secara lebih luas. Dalam hal keamanan jaringan, kejutan bukanlah hal yang baik.

Ingin membagikan solusi saya untuk masalah ini jika orang lain menganggapnya berguna. Menggunakan iptables & ipset. Diuji pada Ubuntu, CentOS 7 & RHEL 7. ipset digunakan karena IP "tepercaya" tidak selalu dalam rentang IP yang sama (perbaiki batasan iptables).
Ia bekerja dengan Docker normal, dan Docker Swarm (alias SwarmKit).
Ini memastikan Anda aman secara default, hanya mengizinkan IP yang Anda tentukan untuk dapat terhubung ke port OS & port Docker (menggunakan iptables dan ipset) yang Anda tentukan harus terbuka. Juga memiliki opsi untuk membuat port OS atau port Docker "publik" (terbuka untuk semua IP)

Ansible tidak diperlukan, tetapi membuatnya lebih mudah.. Peran yang memungkinkan: https://github.com/ryandaniels/ansible-role-iptables-docker
Langkah-langkah manual untuk CentOS/RHEL:
https://github.com/ryandaniels/ansible-role-iptables-docker#manual -commands-centosrhel
Dan Ubuntu 18.04/20.04:
https://github.com/ryandaniels/ansible-role-iptables-docker#manual -commands-ubuntu-2004

Anda harus menginstal/mengonfigurasi ipset selain iptables (lihat tautan di atas jika mengalami masalah).
Contoh konfigurasi iptables (dengan ssh port 22 terbuka untuk semua orang):

*filter
:DOCKER-USER - [0:0]
:FILTERS - [0:0]
#Can't flush INPUT. wipes out docker swarm encrypted overlay rules
#-F INPUT
#Use ansible or run manually once instead to add -I INPUT -j FILTERS
#-I INPUT -j FILTERS
-A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
-A DOCKER-USER -i docker_gwbridge -j RETURN
-A DOCKER-USER -s 172.18.0.0/16 -j RETURN
-A DOCKER-USER -i docker0 -j RETURN
-A DOCKER-USER -s 172.17.0.0/16 -j RETURN
#Below Docker ports open to everyone if uncommented
#-A DOCKER-USER -p tcp -m tcp -m multiport --dports 8000,8001 -j RETURN
#-A DOCKER-USER -p udp -m udp -m multiport --dports 9000,9001 -j RETURN
-A DOCKER-USER -m set ! --match-set ip_allow src -j DROP
-A DOCKER-USER -j RETURN
-F FILTERS
#Because Docker Swarm encrypted overlay network just appends rules to INPUT
-A FILTERS -p udp -m policy --dir in --pol ipsec -m udp --dport 4789 -m set --match-set ip_allow src -j RETURN
-A FILTERS -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FILTERS -p icmp -j ACCEPT
-A FILTERS -i lo -j ACCEPT
#Below OS ports open to everyone if uncommented
-A FILTERS -p tcp -m state --state NEW -m tcp -m multiport --dports 22 -j ACCEPT
#-A FILTERS -p udp -m udp -m multiport --dports 53,123 -j ACCEPT
-A FILTERS -m set ! --match-set ip_allow src -j DROP
-A FILTERS -j RETURN
COMMIT
Apakah halaman ini membantu?
0 / 5 - 0 peringkat