คอนเทนเนอร์ Windows กับ VPN: ทำไมเครือข่ายภายในเครื่องจึงพัง
คอนเทนเนอร์ Windows ใช้ตารางเส้นทางของโฮสต์ ดังนั้น VPN ที่บล็อกซับเน็ตภายในจึงพาเพรฟิกซ์ของคอนเทนเนอร์ไปด้วย โหมด Linux ใช้เส้นทางอื่น
บนแล็ปท็อปเครื่องเดียว เมื่อเชื่อมต่อไคลเอนต์ VPN หนึ่งตัว คอนเทนเนอร์ Linux ยังคงสื่อสารกันได้ แต่คอนเทนเนอร์ Windows หยุดทำงาน สิ่งที่เปลี่ยนแปลงไม่ใช่อิมเมจ แต่เป็นเส้นทางที่แพ็กเก็ตไหลเข้าสู่โฮสต์ คอนเทนเนอร์ Windows บนเครือข่ายเริ่มต้นยืมตารางเส้นทางและการแปลที่อยู่ของโฮสต์ นโยบายที่เปลี่ยนเส้นทางของโฮสต์จึงเปลี่ยนคอนเทนเนอร์ด้วย ตรวจสอบเรื่องนี้ด้วยการค้นหาเส้นทางก่อนติดตั้งอะไรใหม่
แพ็กเก็ตของคอนเทนเนอร์ Windows เข้าสู่โฮสต์ตรงไหน
คอนเทนเนอร์บนเครือข่ายเริ่มต้น nat ได้รับที่อยู่จากเพรฟิกซ์ของบริการ Host Networking Service ซึ่งมักอยู่ภายใน 172.16.0.0/12 และเข้าถึงโฮสต์ผ่านอะแดปเตอร์เสมือน โฮสต์เป็นเจ้าของเส้นทางของเพรฟิกซ์นั้นและแปลทราฟฟิกไปยังอะแดปเตอร์ที่ใช้งานอยู่ ไม่มีเครื่องเสมือนแยกต่างหากอยู่กลางเส้นทางนั้น
การออกแบบนี้เองทำให้ความล้มเหลวเป็นเรื่องเชิงกลไก เมื่อคอนเทนเนอร์ส่งแพ็กเก็ต โฮสต์จะค้นหาเส้นทางสำหรับเพรฟิกซ์ของคอนเทนเนอร์ เส้นทางใดชนะ แพ็กเก็ตก็ไปทางนั้น และคอนเทนเนอร์ไม่มีสิทธิ์ตัดสินใจ
ไคลเอนต์ VPN เปลี่ยนอะไรในเส้นทางนั้น
ไคลเอนต์องค์กรมักติดตั้งชุดเส้นทางจำนวนมากและตัวกรองที่ปฏิเสธการเข้าถึงซับเน็ตภายในขณะที่อุโมงค์ทำงาน เจตนาคือการป้องกัน เครือข่ายภายในที่ถูกบุกรุกไม่ควรเข้าถึงเครื่องที่ได้รับการป้องกัน ผลข้างเคียงคือเส้นทางของโฮสต์ไปยังเพรฟิกซ์ของคอนเทนเนอร์ไม่ใช่เครือข่าย NAT ภายในอีกต่อไป
แทนที่จะเป็นเช่นนั้น การค้นหากลับตรงกับอุโมงค์ และแพ็กเก็ตถูกส่งต่อให้เกตเวย์ซึ่งไม่เคยได้ยินที่อยู่คอนเทนเนอร์นั้นเลย Ping ล้มเหลว แอปพลิเคชันหมดเวลา และคอนเทนเนอร์ดูเสียหายขณะที่ไอคอน VPN สว่าง ดูตารางของโฮสต์ขณะเชื่อมต่อแล้วจะเห็นเส้นทางที่แข่งขันกัน
| Container mode | Outbound path | Typical result behind the VPN |
|---|---|---|
| Windows, default nat | Host routes and translates container traffic | Container prefix follows the tunnel and fails |
| Windows, transparent | Container sits on the physical link | Depends on the local subnet being allowed |
| Linux engine on Docker Desktop | VM egress proxied by a host process | Often keeps working |
ทำไมคอนเทนเนอร์ Linux จึงทำงานต่างออกไป
เอนจินของ Linux รันคอนเทนเนอร์ภายในเครื่องเสมือนขนาดเบา และการเชื่อมต่อขาออกจากเครื่องนั้นเปิดโดยพร็อกซีฝั่งโฮสต์ในนามของคอนเทนเนอร์ โฮสต์เป็นผู้เปิดซ็อกเก็ต กฎของ VPN เกี่ยวกับเพรฟิกซ์ของคอนเทนเนอร์จึงไม่ใช้กับมันในลักษณะเดียวกัน และภาระงานยังคงเข้าถึงเครือข่ายได้
ความต่างนี้ยังอธิบายด้วยว่าทำไมสูตรสำเร็จของ Linux จึงยกมาใช้ไม่ได้ คอนเทนเนอร์ Linux ที่ต้องการอุโมงค์ของตัวเองจะได้อุปกรณ์ TUN พร้อมความสามารถ NET_ADMIN คอนเทนเนอร์ Windows ไม่เปิดเผยอินเทอร์เฟซเป็นอุปกรณ์ ดังนั้นรูปแบบนั้นจึงไม่มีสิ่งที่เทียบเท่าในฝั่งนั้น
พิสูจน์เส้นทาง แล้วจึงเลือกการออกแบบ
เก็บหลักฐานจากโฮสต์ ไม่ใช่จากคอนเทนเนอร์ เพราะโฮสต์เป็นผู้ค้นหา:
docker network inspect nat --format "{{range .IPAM.Config}}{{.Subnet}}{{end}}"
route print -4
Get-NetRoute -AddressFamily IPv4 | Where-Object DestinationPrefix -like "172.16.*"
รันผลลัพธ์เส้นทางหนึ่งครั้งก่อนที่ VPN จะเชื่อมต่อ และอีกครั้งหลังจากนั้น หากในผลลัพธ์ครั้งที่สองเพรฟิกซ์ของคอนเทนเนอร์ชี้ไปที่อะแดปเตอร์ของอุโมงค์ การวินิจฉัยก็เสร็จสมบูรณ์ และการรีสตาร์ตคอนเทนเนอร์จะไม่ช่วย
ทางเลือกแรกคือการตัดสินใจเชิงนโยบาย ถามเจ้าของเครือข่ายว่าอนุญาตให้อุปกรณ์นี้เข้าถึง LAN ภายในได้หรือไม่ ไคลเอนต์องค์กรหลายตัวเปิดให้ตั้งค่านี้ได้ แต่ก็ทำให้ขอบเขตที่ตั้งใจไว้อ่อนแอลง ขอเป็นข้อยกเว้นที่บันทึกไว้เป็นลายลักษณ์อักษรพร้อมผู้รับผิดชอบและวันที่ทบทวน สวิตช์รายอุปกรณ์ที่ไม่มีใครกลับไปทบทวนคือวิธีที่แนวนโยบายป้องกันหายไปอย่างเงียบ ๆ
ในจุดที่ต้องรักษานโยบายไว้ ให้ย้ายภาระงานแทนการฝืนเส้นทาง เครือข่ายโปร่งใสที่มีซับเน็ตและเกตเวย์ชัดเจนจะวางคอนเทนเนอร์บนลิงก์ภายใน ภาระงาน Linux ทำงานอยู่หลังพร็อกซีของเครื่องเสมือน และ เครื่องเสมือนแยกต่างหากที่มีไคลเอนต์ของตัวเอง ยังคงรักษานโยบายของตัวเอง เลือกสักทางอย่างตั้งใจและทดสอบจากภายในคอนเทนเนอร์ เพราะคำขอของผู้ใช้เกิดขึ้นที่นั่น