เมื่อเร็ว ๆ นี้ ฉันได้เริ่มย้ายเว็บเซิร์ฟเวอร์ที่มีแอพต่าง ๆ ไปยังเซิร์ฟเวอร์ใหม่และรวมทุก ๆ
แอพในคอนเทนเนอร์นักเทียบท่า การตั้งค่าปัจจุบันของฉันประกอบด้วย nginx สำหรับเซิร์ฟเวอร์พร็อกซีย้อนกลับและฐานข้อมูล
ทำงานบนเซิร์ฟเวอร์เองและเว็บแอปพลิเคชันทั้งหมดทำงานในคอนเทนเนอร์นักเทียบท่าของตนเอง
ตอนนี้ฉันกำลังพยายามรักษาความปลอดภัยของเว็บเซิร์ฟเวอร์โดยใช้ iptables เหมือนที่ฉันทำเมื่อหลายปีก่อน ฉัน
ต้องเป็นไปตามเงื่อนไขดังต่อไปนี้:
- ไฟร์วอลล์ปกติสำหรับบริการที่ไม่ใช่นักเทียบท่าควรยังคงใช้งานได้ (นโยบายเริ่มต้นที่จะปล่อยสำหรับทั้งอินพุตและเอาต์พุต เข้าถึงได้เฉพาะพอร์ตที่มีชื่ออย่างชัดเจนเท่านั้น)
- ตู้คอนเทนเนอร์ (มีข้อยกเว้น - ดูด้านล่าง) ต้องไม่สามารถเข้าถึงได้จากโลก
- คอนเทนเนอร์ต้องสามารถเข้าถึงโฮสต์โดยใช้ "docker.host.internal" เพื่อเข้าถึงเซิร์ฟเวอร์ฐานข้อมูล
- คอนเทนเนอร์ต้องสามารถเข้าถึงบริการของคอนเทนเนอร์อื่นได้โดยใช้ชื่อโดเมนสาธารณะ (พร็อกซี)
- คอนเทนเนอร์เดียวควรมี 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
ขอบคุณมากล่วงหน้า!