Iptables ตั้งค่ากฎเพื่อให้คอนเทนเนอร์นักเทียบท่าสามารถเข้าถึงบริการบนโฮสต์ IP


18

ฉันมีปัญหาในการเข้าถึงโฮสต์ private interface (ip) จาก container docker ฉันค่อนข้างแน่ใจว่าเกี่ยวข้องกับกฎ Iptables ของฉัน (หรืออาจกำหนดเส้นทาง) เมื่อฉันเพิ่มการ--net=hostตั้งค่าสถานะdocker runทุกอย่างทำงานตามที่คาดไว้ ในทำนองเดียวกันเมื่อฉันระบุว่านโยบายการป้อนข้อมูลกำลังติดตามเสรีนิยม-P INPUT ACCEPTสิ่งต่าง ๆ ก็ทำงานได้ตามที่ฉันคาดหวัง อย่างไรก็ตามสิ่งเหล่านี้เป็นตัวเลือกที่ไม่พึงประสงค์และไม่ปลอดภัยที่ฉันต้องการหลีกเลี่ยง

เนื่องจากมันไม่ได้เฉพาะเจาะจงกับบริการของฉัน (DNS) ฉันได้แยกสิ่งนั้นออกจากปัญหาเนื่องจากการค้นหาสิ่งนั้นร่วมกับนักเทียบท่าให้ผลในพื้นที่ปัญหาที่แตกต่างกัน (เป็นที่นิยม) เพิ่มเสียงให้กับผลการค้นหา

การเชื่อมโยงคอนเทนเนอร์ Docker นั้นไม่ใช่ตัวเลือกที่ใช้งานได้เนื่องจากคอนเทนเนอร์บางตัวจำเป็นต้องรันด้วยตัวเลือก --net = host เพื่อป้องกันการเชื่อมโยงและฉันต้องการสร้างสถานการณ์ที่สอดคล้องกันหากเป็นไปได้

ฉันมีกฎ Iptables ต่อไปนี้ การรวมกันของ CoreOS, Digital Ocean และ Docker ฉันถือว่า

-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT

อินเตอร์เฟสโฮสต์ของฉัน (เกี่ยวข้อง):

3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 10.129.112.210/16 brd 10.129.255.255 scope global eth1
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever

และฉันเรียกใช้คอนเทนเนอร์นักเทียบท่า:

$ docker run --rm -it --dns=10.129.112.210 debian:jessie # Specifying the DNS is so that the public DNS servers aren't used.

ณ จุดนี้ฉันต้องการที่จะสามารถใช้บริการในท้องถิ่นที่ถูกผูกไว้กับ 10.129.112.210:53 ดังนั้นสิ่งต่อไปนี้ควรตอบกลับ:

$ ping google.com
^C
$ ping user.skydns.local
^C

เมื่อฉันเรียกใช้คำสั่งเดียวกันจากโฮสต์ของฉัน:

$ ping photo.skydns.localPING photo.skydns.local (10.129.112.206) 56(84) bytes of data.
64 bytes from 10.129.112.206: icmp_seq=1 ttl=64 time=0.790 ms
^C

resolv.conf ของฉัน

$ cat /etc/resolv.conf
nameserver 10.129.112.210
nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 8.8.4.4

จุดที่นี่ไม่ได้เข้าถึงโฮสต์สาธารณะ แต่เป็นโฮสต์ภายในโดยใช้บริการ DNS ท้องถิ่นที่มีอยู่ในโฮสต์ (ผ่านอินสแตนซ์นักเทียบท่าอื่น)

เพื่อแสดงให้เห็นถึงมันยิ่งขึ้นไป (ทักษะการออกแบบงานศิลปะ ascii ของฉันทำได้ดีกว่า iptables ของฉันดังนั้นควรจะพูดได้เพียงพอ ณ จุดนี้):

 ______________________________________________
|  __________________________           Host   |
| |   Docker DNS container   |                 |
|  ``````````````````````|```                  |
|                        |                     |
|     ,----------,---( private n. interface )  |
|     |          |                             |
|     |          |   ( public  n. interface )---
|     |          |                             |
|     |          |   ( loopbck n. interface )  |
|     |          |                             |
|     |          |                             |
|     |        __|_______________________      |
|     |       | Docker service container |     |
|     |        ``````````````````````````      |
|     |                                        |
|     |                                        |
| [ Local host service using DNS. ]            |
|                                              |
|______________________________________________|

  private (host) network interface: eth1 (10.129.0.0/16)
  Docker network interface: docker0 (172.17.0.0/16)

ฉันค้นหาอ่านและใช้ตัวอย่างการกำหนดค่า Iptables ที่แตกต่างกันแล้ว แต่ฉันรู้กฎกฎขั้นสูง "ขั้นสูง" น้อยเกินไปที่จะเข้าใจสิ่งที่เกิดขึ้นและเพื่อให้ได้ผลลัพธ์ตามที่ต้องการ

ผลลัพธ์ของiptables -t nat -nL:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Chain DOCKER (2 references)
target     prot opt source               destination

ผลลัพธ์ของcat /proc/sys/net/ipv4/ip_forward:

1

คุณสามารถโพสต์การส่งออกของiptables -t nat -nL? คุณทำการวิเคราะห์แพ็กเก็ตหรือไม่ทำการ ping จาก container container และใช้ tcpdump เพื่อดักจับแพ็กเก็ตบนโฮสต์
แดเนียลที

แน่นอนขอบคุณที่ช่วยเหลือจนถึงตอนนี้: pastebin.com/TAaT73nk (ไม่พอดีกับความคิดเห็น .. ) - แก้ไข -> อัปเดตลิงก์ไปยัง pastebin ที่ไม่หมดอายุ
Dynom

บางทีฉันอาจไม่เข้าใจปัญหาของคุณอย่างถูกต้อง แต่ฉันไม่เห็นกฎใด ๆ เพื่ออนุญาตการสืบค้น DNS ในโฮสต์ ยังเปิดใช้งาน ip_forward หรือไม่
Laurentiu Roescu

สวัสดี @ LaurentiuRoescu $ cat /proc/sys/net/ipv4/ip_forward -> 1และ-A INPUT -i eth1 -j ACCEPTยอมรับการเชื่อมต่อทั้งหมดบนอินเทอร์เฟซส่วนตัว กฎอะไรที่คุณขาดหายไป?
Dynom

2
ฉันคิดว่าแพ็กเก็ตจาก container มาจากอินเตอร์เฟส docker0 ไม่ใช่ eth1 ลอง-A INPUT -i docker0 -j ACCEPT
Laurentiu Roescu

คำตอบ:


14

คอนเทนเนอร์สื่อสารกับโฮสต์โดยใช้docker0อินเตอร์เฟส วิธีอนุญาตให้เพิ่มทราฟฟิกจากคอนเทนเนอร์:

-A INPUT -i docker0 -j ACCEPT

2
Dynom iptables -A INPUT -j LOGบทเรียนที่คุณอาจต้องการที่จะออกไปจากนี้คือการเข้าสู่ระบบสังกัดทั้งหมดของคุณจะเป็นประโยชน์ด้วยเช่น การประทับIN=docker0จะมีประโยชน์มากในการกำหนดว่าต้องใช้กฎใด ไม่ต้องละทิ้งงานของลอเรนติซึ่งยอดเยี่ยม - +1 จากฉัน!
MadHatter สนับสนุนโมนิกา

5
สำหรับผู้ที่ใช้ UFW นี่คือสิ่งที่ฉันทำเพื่อให้การสื่อสารทั้งหมดจาก Docker container เป็นเจ้าภาพ: ufw อนุญาตให้ใช้ใน docker0
Ali Ok

0

ฉันได้พบกับสถานการณ์ที่คล้ายกันมาก แต่การเพิ่ม-A INPUT -i docker0 -j ACCEPTจะเปิดการเข้าถึงทั้งหมดผ่านส่วนต่อประสาน eth0 ของตัวเชื่อมต่อโฮสต์ไปยังคอนเทนเนอร์ซึ่งไม่ใช่สิ่งที่ฉันตั้งใจไว้อย่างแน่นอน

และเนื่องจากฉันสังเกตเห็นว่าคอนเทนเนอร์ของฉันเพิ่งเข้าถึงได้ จำกัด (พูดเพียงพอร์ต 22) ไปยังโฮสต์อินเตอร์เฟสแทนการปิดตัวเองโดยสิ้นเชิงจากเครือข่ายโฮสต์ฉันจึงตรวจสอบกฎ iptables ของฉันและพบกฎในห่วงโซ่ IN_public_allow ซึ่งควรรับผิดชอบเรื่องนี้ -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPTกฎคือ ดังนั้นฉันจึงเพิ่มกฎที่คล้ายกันเพื่อให้คอนเทนเนอร์ของฉันเข้าถึงพอร์ตโฮสต์อื่นที่ต้องการซึ่งฉันคิดว่าอาจเป็นวิธีที่แม่นยำยิ่งขึ้นในการเปิดการเข้าถึงเครือข่ายโฮสต์ไปยังคอนเทนเนอร์


-i docker0ควรตรวจสอบให้แน่ใจว่าสิ่งนี้จะไม่ส่งผลกระทบต่อการจราจรที่ไม่ได้มาถึงผ่านเครือข่าย docker0 ไวยากรณ์ของคุณไม่ชัดเจน บางทีคุณกำลังบอกว่าเปิดใช้งานการเข้าถึงขาออกจากโฮสต์นักเทียบท่าผ่าน eth0 ซึ่งอาจเป็นจริง ฉันยอมรับว่ากฎที่กำหนดเป้าหมายเพิ่มเติมสามารถเปิดได้มากเท่าที่คุณต้องการ
mc0e
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.