Score:0

Iptables และนักเทียบท่า - ปิดใช้งานการเข้าถึงระยะไกลไปยังคอนเทนเนอร์ในขณะที่ยังคงรักษาโฮสต์และการสื่อสารคอนเทนเนอร์ผ่านพร็อกซี

ธง us

เมื่อเร็ว ๆ นี้ ฉันได้เริ่มย้ายเว็บเซิร์ฟเวอร์ที่มีแอพต่าง ๆ ไปยังเซิร์ฟเวอร์ใหม่และรวมทุก ๆ แอพในคอนเทนเนอร์นักเทียบท่า การตั้งค่าปัจจุบันของฉันประกอบด้วย nginx สำหรับเซิร์ฟเวอร์พร็อกซีย้อนกลับและฐานข้อมูล ทำงานบนเซิร์ฟเวอร์เองและเว็บแอปพลิเคชันทั้งหมดทำงานในคอนเทนเนอร์นักเทียบท่าของตนเอง

ตอนนี้ฉันกำลังพยายามรักษาความปลอดภัยของเว็บเซิร์ฟเวอร์โดยใช้ iptables เหมือนที่ฉันทำเมื่อหลายปีก่อน ฉัน ต้องเป็นไปตามเงื่อนไขดังต่อไปนี้:

  1. ไฟร์วอลล์ปกติสำหรับบริการที่ไม่ใช่นักเทียบท่าควรยังคงใช้งานได้ (นโยบายเริ่มต้นที่จะปล่อยสำหรับทั้งอินพุตและเอาต์พุต เข้าถึงได้เฉพาะพอร์ตที่มีชื่ออย่างชัดเจนเท่านั้น)
  2. ตู้คอนเทนเนอร์ (มีข้อยกเว้น - ดูด้านล่าง) ต้องไม่สามารถเข้าถึงได้จากโลก
  3. คอนเทนเนอร์ต้องสามารถเข้าถึงโฮสต์โดยใช้ "docker.host.internal" เพื่อเข้าถึงเซิร์ฟเวอร์ฐานข้อมูล
  4. คอนเทนเนอร์ต้องสามารถเข้าถึงบริการของคอนเทนเนอร์อื่นได้โดยใช้ชื่อโดเมนสาธารณะ (พร็อกซี)
  5. คอนเทนเนอร์เดียวควรมี 22 พอร์ตที่เข้าถึงได้โดยตรงจากโลก (git)

จนถึงตอนนี้ ฉันสามารถตอบสนองความต้องการสามข้อแรกเท่านั้น การตั้งค่า iptables อย่างง่ายของฉัน ซึ่งฉันนำมาใช้ สภาพแวดล้อมที่ไม่ใช่นักเทียบท่าก่อนหน้ามีลักษณะดังนี้:

# นโยบายเริ่มต้นที่จะยกเลิก

-P อินพุตลดลง
-P ไปข้างหน้าลดลง
-P เอาท์พุทลดลง

# อนุญาตการท่องอินเทอร์เน็ต, NTP, DNS
-A OUTPUT -p tcp -m tcp --dport 80 -j ยอมรับ
-A OUTPUT -p tcp -m tcp --dport 443 -j ยอมรับ
-A INPUT -p tcp -m tcp --sport 80 -m state --state ที่เกี่ยวข้อง,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --sport 443 -m state --สถานะที่เกี่ยวข้อง ก่อตั้ง -j ยอมรับ
-A อินพุต -p udp -m udp --sport 53 -j ยอมรับ
-A อินพุต -p tcp -m tcp --sport 53 -j ยอมรับ
-A OUTPUT -p udp -m udp --dport 53 -j ยอมรับ
-A OUTPUT -p tcp -m tcp --dport 53 -j ยอมรับ
-A อินพุต -p udp -m udp --dport 123 -j ยอมรับ
-A OUTPUT -p udp -m udp --sport 123 -j ยอมรับ

# บริการอนุญาต - เว็บเซิร์ฟเวอร์, เซิร์ฟเวอร์ SSH บนพอร์ต 16 (ฉันรู้ว่ามันไม่ใช่มาตรฐาน แต่ฉันคุ้นเคย) และ SSH บนพอร์ต 22 สำหรับการเข้าถึงคอมไพล์
-อินพุต -p tcp -m tcp --dport 22 -j ยอมรับ
-อินพุต -p tcp -m tcp --dport 16 -j ยอมรับ
-อินพุต -p tcp -m tcp --dport 80 -j ยอมรับ
-อินพุต -p tcp -m tcp --dport 443 -j ยอมรับ
-A OUTPUT -p tcp -m tcp --sport 22 -m state --state ที่เกี่ยวข้อง ก่อตั้ง -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 16 -m state --สถานะที่เกี่ยวข้อง ก่อตั้ง -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 80 -m state --state ที่เกี่ยวข้อง ก่อตั้ง -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 443 -m state --สถานะที่เกี่ยวข้อง ก่อตั้ง -j ยอมรับ

# อนุญาตการสื่อสารในท้องถิ่นทั้งหมด
-A อินพุต -i lo -j ยอมรับ
-A OUTPUT -o lo -j ยอมรับ

#อนุญาตให้ปิง
-A ส่งต่อ -p icmp -j ยอมรับ
-A อินพุต -p icmp -j ยอมรับ
-A OUTPUT -p icmp -j ยอมรับ

ฉันไม่ได้อ้างว่านี่เป็นวิธีที่ดีที่สุดในการทำสิ่งต่างๆ แต่ควรจะปลอดภัยพอสมควรและได้ผลกับฉันมาหลายปีแล้ว

ตอนนี้ถึงสิ่งที่ฉันไม่เข้าใจดี หากฉันใช้สิ่งนี้กับการกำหนดค่านักเทียบท่าใหม่ การเข้าถึงโฮสต์โดยใช้นามแฝง "docker.host.internal" จะหยุดลง เพื่ออนุญาตให้ ฉันใช้:

iptables -A อินพุต -i br-+ -j ยอมรับ
iptables -A OUTPUT -o br-+ -j ยอมรับ

ฉันเคยเห็น -i นักเทียบท่า 0 ถูกใช้ แต่ไม่ได้ผลสำหรับฉันเพราะทุกคอนเทนเนอร์นักเทียบท่ามีของตัวเอง br-* อินเทอร์เฟซในการตั้งค่าของฉันซึ่งใช้เพื่อเข้าถึงโฮสต์ สิ่งนี้ได้ผล จนถึงตอนนี้ดีมาก

ตอนนี้ฉันสังเกตเห็นว่าพอร์ตที่เผยแพร่นักเทียบท่าทั้งหมด (ฉันใช้ 80XX สำหรับบริการเว็บและมากกว่าโดเมนที่ถูกต้องของพร็อกซีไปยังพอร์ตเหล่านั้นผ่านพร็อกซี nginx) สามารถมองเห็นได้จากทั่วโลก ฉันไม่ต้องการสิ่งนั้นอย่างแน่นอน ดังนั้นหลังจากการค้นหา ฉันจึงเพิ่มสิ่งนี้:

iptables -I DOCKER-USER -i venet0 -j DROP

(เวเน่0 เป็นชื่อของอินเทอร์เฟซเครือข่ายของฉัน แทนที่จะเป็น eth0)

สิ่งนี้ทำงานได้ดี แต่ผิดเงื่อนไข 4 และ 5 - คอนเทนเนอร์ไม่สามารถเข้าถึงซึ่งกันและกันในที่อยู่โดเมนสาธารณะและฉันไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ git ผ่านพอร์ต 22 (ที่ฉันคาดไว้).

โดยการสื่อสารในที่อยู่ที่เป็นสาธารณสมบัติ ฉันหมายถึงสิ่งต่อไปนี้:

ฉันมีเซิร์ฟเวอร์ CI ของโดรนที่ทำงานในคอนเทนเนอร์เดียว โดยเปิดเผยพอร์ต 8001 ให้กับเจ้าบ้าน ฉันมีพรอกซี nginx ที่ส่งผ่านที่อยู่ https://ci.example.com มายังท่าเรือแห่งนี้ เช่นเดียวกับคอนเทนเนอร์ Gitea ของฉันที่เปิดเผยพอร์ต 8002 และวางจำหน่ายใน https://git.example.com.

โดรนต้องตรวจสอบสิทธิ์ผ่าน OAuth กับเซิร์ฟเวอร์ Gitea ในการทำเช่นนั้นจะต้องสามารถเข้าถึงได้ผ่านทาง https://git.example.com:443 ที่อยู่ไม่ใช่นักเทียบท่าภายใน http://gitea_container_name:8002. ฉันมีกรณีการใช้งานอื่น ๆ อีกหลายกรณีที่จำเป็นต้องเป็นไปได้ แต่กรณีนี้อธิบายได้ดีที่สุด

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

# พยายามเปิดใช้งานพอร์ตเฉพาะสำหรับคอนเทนเนอร์ gitea ไม่มีผล
iptables -I DOCKER-USER -i venet0 -p tcp --sport 8002 -j ยอมรับ

#ลองใช้คำแนะนำนี้ไม่มีผล
iptables -I DOCKER-USER -i venet0 -p tcp -m conntrack --ctorigdstport 443 --ctdir ORIGINAL -j ยอมรับ

# ไม่มีผล แต่ฉันสงสัยว่าสิ่งนี้จะไม่ทำงานเพราะฉันไม่คิดว่า 443 คือสิ่งที่มากับเครือข่ายนี้
iptables -I DOCKER-USER -i venet0 -p tcp --dport 443 -j ยอมรับ

# ไม่มีผลอะไร
iptables -A INPUT -i นักเทียบท่า 0 -j ยอมรับ

การตั้งค่าเช่นนี้เป็นไปได้หรือไม่? คนที่เชี่ยวชาญในโลกนักเทียบท่าและไฟร์วอลล์สามารถชี้ให้ฉันไปในทิศทางที่ถูกต้องได้หรือไม่?

การตั้งค่าของฉัน:

  • เดเบียน 11
  • iptables v1.8.7 (nf_tables)
  • นักเทียบท่า 20.10.5

ขอบคุณมากล่วงหน้า!

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา