คำขอมาถึงโดยมีที่อยู่ IP ของทันเนลและออกจากคอนเทนเนอร์เดิมโดยมีที่อยู่ของบริการข้างเคียง ระหว่างสองช่วงเวลานั้น DNAT เขียนปลายทางใหม่ และแพ็กเก็ตก็ไม่ใช่ข้อมูลขาเข้าของคอนเทนเนอร์ VPN อีกต่อไป ตอนนี้มันคือทราฟฟิกที่ถูกส่งต่อ ซึ่งตัดสินด้วยกฎอีกชุดหนึ่ง การเปลี่ยนแปลงนี้อธิบายว่าทำไมกฎไฟร์วอลล์ที่ดูถูกต้องสำหรับที่อยู่ทันเนลจึงไม่มีผลกับการเชื่อมต่อที่แปลแล้ว

ติดตามแพ็กเก็ตหลังการแปล

ใช้พูลไคลเอนต์ 10.90.0.0/24 และที่อยู่ทันเนล 10.90.0.1 คอนเทนเนอร์สองตัวอยู่บนบริดจ์เดียว: 192.0.2.2 รัน VPN และ 192.0.2.3 รันแอปพลิเคชัน ไคลเอนต์เชื่อมต่อกับ 10.90.0.1:8080 และกฎ DNAT ในเนมสเปซของคอนเทนเนอร์ VPN เขียนที่อยู่นั้นใหม่เป็นที่อยู่และพอร์ตจริงของแอปพลิเคชัน จากนั้นเส้นทางหนึ่งส่งแพ็กเก็ตข้ามบริดจ์ ที่อยู่เหล่านี้เป็นเพียงตัวอย่าง ไม่ใช่สูตรการติดตั้ง

พอร์ตที่แอปพลิเคชันฟังจริงอาจแตกต่างจากพอร์ตใด ๆ ที่เผยแพร่บนโฮสต์ อ่านตัวรับฟังภายในคอนเทนเนอร์แทนที่จะสมมติว่าตัวเลขทั้งสองตรงกัน

สิทธิ์เป็นของเส้นทางการส่งต่อ

คอนเทนเนอร์ VPN ต้องการการส่งต่อ IP และการตัดสินใจส่งต่อที่จำกัดเฉพาะพูลไคลเอนต์ ที่อยู่ของแอปพลิเคชัน และพอร์ตที่ตั้งใจไว้ การตอบกลับที่สร้างแล้วต้องมีสิทธิ์ของตัวเอง กฎที่ตรงกับที่อยู่ทันเนลเดิมจะไม่ตรงหลัง DNAT เพราะปลายทางเปลี่ยนไปแล้ว สิทธิ์ INPUT เป็นตะขอที่ผิดสำหรับทราฟฟิกที่ไม่ได้ส่งถึงโฮสต์นี้อีกต่อไป

รักษาขอบเขตให้แคบ: ช่วงต้นทางหนึ่ง ปลายทางหนึ่ง และบริการหนึ่ง กฎการส่งต่อที่ผ่อนปรนเขียนง่ายกว่าและป้องกันตัวได้ยากกว่ามากในภายหลัง

docker exec vpn-container ip route get 192.0.2.3
docker exec vpn-container iptables -t nat -S
docker exec vpn-container iptables -S FORWARD

เชนของ Docker ไม่ใช่เชนของคอนเทนเนอร์คุณ

กฎภายในเนมสเปซของคอนเทนเนอร์ไม่ใช่กฎของโฮสต์ Docker เมื่อทราฟฟิกข้ามจากอินเทอร์เฟซของทันเนลไปยังบริดจ์ ไฟร์วอลล์ของบริดจ์บนโฮสต์อาจตัดสินใจต่างออกไป ด้วยแบ็กเอนด์ iptables ของ Docker เชนการส่งต่อที่อธิบายไว้ในเอกสารและจุดจับคู่หลัง DNAT คือที่ที่การตัดสินใจนั้นปรากฏ

เอกสารอ้างอิงไฟร์วอลล์ของ Docker อธิบายเชนเหล่านั้นและการจับคู่หลัง DNAT อย่าแก้ไขการยอมรับที่ขาดหายด้วยการปิดการจัดการไฟร์วอลล์ของ Docker หรือทำให้ทุกเชนผ่อนปรน เพราะนั่นจะลบขอบเขตที่คุณพยายามใช้

ทำให้เส้นทางกลับเป็นการเลือกที่ตั้งใจ

หากเก็บที่อยู่ต้นทางไว้ แอปพลิเคชันจะเห็น 10.90.0.x และ ต้องส่งการตอบกลับกลับผ่านคอนเทนเนอร์ VPN. มิฉะนั้นเกตเวย์ Docker ปกติของมันจะส่งไปยังโฮสต์ซึ่งไม่ได้เป็นเจ้าของทันเนล ทางเลือกคือการแปลต้นทางแบบแคบที่คอนเทนเนอร์ VPN ซึ่งทำให้การตอบกลับง่ายขึ้นแต่ซ่อนไคลเอนต์จากแอปพลิเคชัน เลือกอย่างตั้งใจและจดไว้ว่าเลือกแบบไหน

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

เก็บกฎไว้ในการกำหนดค่าเริ่มต้นที่รองรับของคอนเทนเนอร์ เพราะการแก้ไขแบบอินเทอร์แอกทีฟจะหายไปเมื่อสร้างใหม่ การเผยแพร่พอร์ตบนโฮสต์เป็นเส้นทางการเปิดเผยอีกแบบ และไม่จำเป็นเพียงเพราะบริการเข้าถึงได้ผ่านทันเนล

บทความที่เกี่ยวข้อง