İptables ile liman işçisi konteynırının dış bağlantılarını sınırlamak için adımlar?


20

Amacım, docker kapsayıcılarına erişimi sadece birkaç genel IP adresine sınırlamak. Hedefime ulaşmak için basit, tekrarlanabilir bir süreç var mı? Docker'ın varsayılan seçeneklerini kullanırken sadece iptables temellerini anlayarak çok zor buluyorum.

Bir kapsayıcı çalıştırmak, genel İnternet tarafından görünür hale getirmek istiyorum, ancak yalnızca belirli ana bilgisayarlardan bağlantılara izin vermek istiyorum. Varsayılan bir INPUT ilkesini reddetme kuralını ayarlamak ve sonra yalnızca benim ana bilgisayar bağlantılarına izin bekliyoruz. Ancak Docker'ın NAT kuralları ve zincirleri engel olur ve INPUT kurallarım göz ardı edilir.

Birisi aşağıdaki varsayımlar göz önüne alındığında hedefime nasıl ulaşılacağına dair bir örnek verebilir mi?

  • Eth0 hakkında halka açık IP 80.80.80.80
  • Eth1 üzerinde özel IP 192.168.1.10
  • docker run -d -p 3306:3306 mysql
  • Ana bilgisayar 4.4.4.4 ve 8.8.8.8 dışındaki ana bilgisayar / kap 3306 ile tüm bağlantıyı engelle

Kapsayıcıyı yalnızca yerel ip adresine bağlamaktan mutluyum, ancak iptables yönlendirme kurallarının düzgün bir şekilde docker işleminden ve ana bilgisayar yeniden başlatıldığından nasıl kurulacağı konusunda talimatlara ihtiyacım var.

Teşekkürler!

Yanıtlar:


15

Liman işçisinin güvenlik duvarı kurallarıyla çalışırken akılda tutulması gereken iki şey:

  1. Kurallarınızın docker tarafından gizlenmesini önlemek için DOCKER-USERzinciri kullanın
  2. Docker PREROUTING, nattablonun zincirindeki port eşlemesini yapar . Bu daha önce olur filterkurallar, bu nedenle --destve --dportkabın iç IP ve port göreceksiniz. Orijinal hedefe erişmek için tuşunu kullanabilirsiniz -m conntrack --ctorigdstport.

Örneğin:

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

NOT: Olmadan --ctdir ORIGINAL, bu aynı zamanda kapsayıcıdan başka bir sunucuda 3306 numaralı bağlantı noktasına bağlantı için geri gelen yanıt paketleriyle de eşleşir, ki bu kesinlikle istediğiniz şey değildir! Benim gibi ilk kuralınız ise buna kesinlikle ihtiyacınız yok -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, çünkü tüm cevap paketleri ile ilgilenecek, ancak yine de kullanmak daha güvenli --ctdir ORIGINALolacaktır.


Bu , aşağıdakileri içerecek şekilde düzenlenmeli --ctdirmi? Ben kullanım-m conntrack --ctstate NEW --ctorigdstport 3306 --ctdir ORIGINAL
LoNiX

@Ionix, evet olmalı, ancak neden sadece kafa karıştırıcı olduğunu anladım. Biraz açıklama ekledim.
SystemParadox

1
Varsayılan DOCKER-USERtablonun girdiyi içerdiğine dikkat edin: -A DOCKER-USER -j RETURNkullanırsanız yukarıdakilerden önce çalışır -A. Bir çözüm, kuralları ters sırayla eklemek -I.
BMitch

@BMitch Veya daha da iyisi , tüm kuralları yeni bir FILTERSzincire -Iekleyin ve yeni kurallar ekleyin (söylediğiniz gibi), atlamak için: -I INPUT -j FILTERSve-I DOCKER-USER -i eth0 -j FILTERS
lonix

@BMitch Ancak, sunucumu yeni kontrol ettim ve iade kuralı orada değil, belki de en son docker sürümü artık eklemiyor? -ISadece güvenli olmak için kullanmak için iyi bir fikir .
lonix

8

Docker v.17.06 ile DOCKER-USER adlı yeni bir iptables zinciri var. Bu, özel kurallarınız içindir: https://docs.docker.com/network/iptables/

Zincir DOCKER'ın aksine, bina / başlangıç ​​konteynerlerinde sıfırlanmaz. Bu nedenle, docker'ı kurmadan ve kapları başlatmadan önce sunucuyu sağlamak için iptables config / script'inize şu satırları ekleyebilirsiniz:

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

Artık MySQL için bağlantı noktası, docker'ın dünya için bağlantı noktasını açtığını düşünürken harici erişimden (eth0) engellendi. (Bu kurallar, harici arayüzünüzün eth0 olduğunu varsayar.)

Sonunda, iptables'ı temizlemeniz gerekecek, önce yaptığım gibi bağlantı noktasını kilitlemeye çalışırken çok fazla uğraştıysanız, önce docker hizmetini yeniden başlatın.


Neden bu DOCKER-USER tablosunun diğer kullanıcı tarafından eklenen herhangi bir tablodan farklı olduğunu özlüyorum .. Önceden uygulanmış bir filtre yok, bu yüzden hala arayüz adlarını kendiniz belirtmeniz gerekiyor. Bir "MY-CHAIN" oluşturup FORWARD zincirine yerleştirirseniz, aynı sonuç elde edilir, değil mi?
ColinM

Evet, bu bir fark yaratır, çünkü Docker DOCKER-USER zincirini FORWARD zincirine ekler: -A FORWARD -j DOCKER-USER -A FORWARD -j DOCKER-ISOLATION Bu nedenle özel talimatlar DOCKER zincirinden önce yürütülür.
ck1

Kullanmak eğer Not --dportDOCKER-KULLANICI içinde bu aynı olmalıdır konteyner hizmetinin IP değil maruz portu. Bunlar genellikle eşleşir, ancak her zaman değil ve bu diğer hizmetlerle kolayca çakışabilir, bu yüzden hala bu DOCKER-USER çözümünün yarı pişmiş olduğunu iddia ediyorum.
ColinM

4

GÜNCELLEME : 2015 yılında geçerli olmakla birlikte, bu çözüm artık bunu yapmanın doğru yolu değildir.

Yanıt Docker'in https://docs.docker.com/articles/networking/#the-world adresindeki belgelerinde var gibi görünüyor.

Docker'ın iletme kuralları varsayılan olarak tüm harici kaynak IP'lerine izin verir. Yalnızca belirli bir IP veya ağın kaplara erişmesine izin vermek için, DOCKER filtre zincirinin üstüne reddedilen bir kural ekleyin. Örneğin, dış erişimi yalnızca kapsayıcı IP 8.8.8.8'in kapsayıcılara erişebileceği şekilde kısıtlamak için aşağıdaki kural eklenebilir:iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

Yaptığım şey şuydu:

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

--iptablesVeya --iccseçeneklerine dokunmadım .


1
Bunu yaparsanız iptables -vnL DOCKER, hedef bağlantı noktaları kap içindeki tüm bağlantı noktalarıdır. O hakkı alırsanız, yukarıdaki aracı kurallar yalnızca noktasını etkili olacağına dikkat 3306kapsayıcı içindeki - Eğer olsaydı, olduğu -p 12345:3306Kapsayıcınızın, olur Kuralınızın hala biri (yani erişim kilitlemek için gerekli --dport 12345çalışma olmaz) çünkü DOCKER zincirinin ACCEPT kuralları NAT sonrasıdır.
Sunside

Bu doğru, kuralların kaplar içindeki bağlantı noktaları ile ilgili olması gerekir.
GGGforce

1
Hum, ters proxy yapmak için dahili bir NGINX (örneğin Zabbix, özel bir yük dengeleyici, vb.) Kullanan birden çok kapsayıcı çalıştırırsanız, bu çok çirkin olur, çünkü kabın IP'sini önceden bilmenizi gerektirir. Hala gerektirmeyen bu sorun için bir çözüm arıyorum --iptables=false, çünkü bu hepsinin en kötü seçim gibi görünüyor.
Sunside

Teşekkür ederim! Saatlerce arama yaptıktan sonra sorunumu çözdünüz. Şimdi nihayet yumuşak dünyayı tüm dünyaya maruz bırakmadan MySQL'i sadece ev IP adresime hapsedebiliyorum.
Matt Cavanagh

1
DOCKER zincirinin kullanıcı tarafından doğrudan manipüle edilmesi beklenmemektedir! Bunun için DOCKER-USER zincirini kullanın. Kabul edilen cevabı kontrol edin.
Paul-Sebastian Manole

3

GÜNCELLEME: Bu cevap hala geçerli olsa da, @SystemParadox DOCKER-USERile birlikte kullanmanın yanıtı --ctorigdstportdaha iyidir.

Yeniden başlatmalar arasında iyi bir şekilde devam eden ve dahili port yerine açık portu etkilemenize izin veren bir çözüm .

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

Ortam değişkenlerini kullanarak veya etcd (veya her ikisi) ile dinamik olarak iptables sizin için otomatik olarak yönetmek için bu yöntemi kullanan bir Docker görüntü inşa ettik:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.