OpenVPN ใน Docker: สัญญาการทำงานที่ไคลเอนต์ขนาดเล็กต้องการ
อิมเมจที่ตรวจสอบแล้ว โปรไฟล์ที่ป้องกันหนึ่งชุด การเข้าถึง TUN และ NET_ADMIN คอนเทนเนอร์ได้อะไร สิ่งใดไม่ควรได้ และจะพิสูจน์ได้อย่างไรว่าอุโมงค์ทำงาน
ใส่ไคลเอนต์ VPN ลงในคอนเทนเนอร์ แล้วคุณจะได้เนมสเปซหนึ่งอันที่มีอุโมงค์อยู่ข้างใน ไม่ใช่โฮสต์ที่กำหนดเส้นทางทราฟฟิกทั้งหมดผ่าน VPN ทั้งสองอย่างเป็นโครงการแยกกัน และการปฏิบัติต่อมันเป็นสิ่งเดียวกันก็คือวิธีที่คอนเทนเนอร์กลายเป็นมีสิทธิพิเศษโดยไม่ตั้งใจ คู่มือนี้ครอบคลุมเฉพาะอย่างแรก: อิมเมจที่ตรวจสอบแล้วหนึ่งชุด โปรไฟล์ที่ป้องกันหนึ่งชุด และโปรเซสไคลเอนต์ที่จำกัดอยู่ในเนมสเปซเครือข่ายของตัวเอง
เริ่มจากอาร์ติแฟกต์ที่ใครบางคนอนุมัติแล้ว ขั้นตอนด้านล่างสมมติว่าอิมเมจมีไฟล์เรียกทำงาน openvpn และโปรไฟล์ไคลเอนต์ที่สมบูรณ์ ซึ่งใบรับรองและวัสดุกุญแจได้รับการแก้ไขแล้วภายในเมานต์ พวกเขาไม่ได้สร้างซอฟต์แวร์ ไม่ได้ออกข้อมูลรับรอง และไม่ครอบคลุมรันไทม์ที่ไม่มี root หรือคอนเทนเนอร์ Windows แบบเนทีฟ ซึ่งแต่ละอย่างเปลี่ยนคำตอบ
คอนเทนเนอร์ได้อะไรและไม่ได้อะไร
เก็บโปรไฟล์และทุกอย่างที่อ้างถึงไว้ในไดเรกทอรีโลคัลที่มีสิทธิ์จำกัด เมานต์แบบอ่านอย่างเดียว เส้นทางสัมพัทธ์ภายในโปรไฟล์ต้องแก้ไขได้ภายในเมานต์นั้น นี่คือรายละเอียดที่คนมักมองข้ามเมื่อใบรับรองอยู่เหนือโปรไฟล์ขึ้นไปหนึ่งไดเรกทอรีและคอนเทนเนอร์ไม่เคยเห็นมัน
services:
vpn:
image: ${VPN_CLIENT_IMAGE:?set the reviewed image reference}
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./vpn:/vpn:ro
working_dir: /vpn
entrypoint: ["openvpn"]
command: ["--config", "/vpn/client.ovpn"]
ไฟล์นั้นให้สามสิ่งและไม่ขออะไรอื่น ควรปักหมุดการอ้างอิงอิมเมจด้วย digest หากนโยบายการติดตั้งใช้งานของคุณกำหนดเช่นนั้น และโปรไฟล์ควรเป็นชุดที่ตรวจสอบแล้ว ไม่ใช่สำเนาที่ใครแก้ไขในที่บนโฮสต์
อ่านอย่างเดียวในที่นี้หมายความว่าคอนเทนเนอร์แก้ไขไฟล์บนโฮสต์ของคุณไม่ได้ ไม่ได้หมายความว่าคอนเทนเนอร์อ่านคีย์ส่วนตัวที่คุณเมานต์ไม่ได้ นั่นคือจุดประสงค์ทั้งหมดของการเมานต์ และนั่นคือเหตุผลที่สิทธิ์ไฟล์ ความเป็นเจ้าของ และวิธีที่ความลับไปถึงโฮสต์ยังคงสำคัญ อย่าส่งรหัสผ่านบนบรรทัดคำสั่งและอย่าอบไว้ในเลเยอร์อิมเมจ เพราะทั้งสองอย่างหลงเหลืออยู่ในที่ที่คุณทำความสะอาดภายหลังไม่ได้
ความสามารถ entrypoint และกับดักระหว่างกัน
ต้องมีการตั้งค่าสองอย่างและทำงานที่ไม่เกี่ยวข้องกัน NET_ADMIN อนุญาตให้จัดการอินเทอร์เฟซและเส้นทางภายในเนมสเปซของคอนเทนเนอร์ รายการอุปกรณ์ /dev/net/tun อนุญาตให้โปรเซสเปิดอุปกรณ์อุโมงค์ได้เลย การให้อย่างใดอย่างหนึ่งโดยไม่มีอีกอย่างทำให้เกิดความล้มเหลวชัดเจน ซึ่งสะดวก: อุปกรณ์ TUN ที่หายไปล้มเหลวตอนเปิด ในขณะที่ความสามารถที่หายไปล้มเหลวเมื่อไคลเอนต์พยายามกำหนดค่าอินเทอร์เฟซ
ทั้งสองอย่างไม่ได้ทำให้ privileged: true ชอบธรรม คอนเทนเนอร์ที่มีสิทธิพิเศษได้ความสามารถทั้งหมดบวกการเข้าถึงอุปกรณ์ ซึ่งเป็นการให้ที่ใหญ่กว่าที่ภาระงานนี้ต้องการมาก เอกสารอ้างอิงสิทธิพิเศษและความสามารถของรันไทม์ อธิบายว่าการให้นั้นไปไกลแค่ไหน หาก chart หรือโพสต์บล็อกขอสิ่งนี้ ให้ตรวจสอบก่อนว่าข้อกำหนดคือเส้นทางอุปกรณ์ที่หายไปหรือความสามารถที่หายไป
การเขียนทับ entrypoint คือส่วนที่กัด การเรียก openvpn โดยตรงถูกต้องสำหรับอิมเมจธรรมดาและผิดสำหรับอิมเมจผลิตภัณฑ์ใด ๆ ที่สคริปต์เริ่มต้นเตรียมกฎไฟร์วอลล์ ไฟล์ตัวแก้ไข หรือข้อมูลรับรองก่อนเรียกใช้ดีมอน การเขียนทับสคริปต์นั้นข้ามการเตรียมการและทำให้คุณต้องดีบักอุโมงค์ที่ขึ้นมาในเนมสเปซที่กำหนดค่าไว้ครึ่งเดียว
รันไคลเอนต์ในเบื้องหน้าและปล่อยให้เป็นโปรเซสหลักของคอนเทนเนอร์ โปรเซสที่กลายเป็นดีมอนจะออกทันที คอนเทนเนอร์รีสตาร์ตเป็นลูป และบันทึกที่คุณต้องการก็กระจัดกระจายไปตามการรีสตาร์ตที่ดูเหมือนกันทั้งหมด
ตรวจสอบจากภายในเนมสเปซ ไม่ใช่จากโฮสต์
ยกสแตกขึ้น ยืนยันในบันทึกว่าไคลเอนต์เข้าสู่สถานะเชื่อมต่อแล้ว จากนั้นตรวจสอบเนมสเปซที่ถืออุโมงค์จริง ๆ
docker compose up -d
docker compose logs --tail 40 vpn
docker compose exec vpn ip -br addr
docker compose exec vpn ip route
รายการที่อยู่ควรแสดงอินเทอร์เฟซอุโมงค์ที่มีที่อยู่จากพูล และตารางเส้นทางควรแสดงปลายทางที่ถูกพุชชี้มาที่มัน หากไม่มีอินเทอร์เฟซ ไคลเอนต์ไม่เคยไปถึงจุดที่สร้างมัน หากมีแต่ไม่มีเส้นทางใดใช้มัน ที่ต้องดูคือ push หรือตัวเลือกเส้นทาง
จากนั้นทดสอบปลายทางที่คุณสนใจ จากเนมสเปซที่ควรใช้อุโมงค์ ด้วยแอปพลิเคชันไม่ใช่แค่ ping การแก้ชื่อเป็นความล้มเหลวแยกที่ควรทดสอบอย่างชัดเจน: ที่อยู่ DNS ที่ถูกพุชไม่ได้อัปเดตตัวแก้ไขของคอนเทนเนอร์ด้วยตัวเอง และไคลเอนต์เดี่ยวที่เพิกเฉยต่อ push จะแก้ชื่อผ่านสิ่งที่อิมเมจกำหนดค่าไว้
สถานะตัดการเชื่อมต่อเป็นส่วนหนึ่งของสัญญา
พฤติกรรมการเชื่อมต่อใหม่ต้องมีการตรวจสอบของตัวเอง เพราะนโยบายรีสตาร์ตพิสูจน์ว่าโปรเซสรีสตาร์ตและไม่ได้บอกอะไรเกี่ยวกับสิ่งที่ทราฟฟิกทำในระหว่างนั้น หยุดอุโมงค์ ลองปลายทางที่ตั้งใจ และสังเกตว่าการเชื่อมต่อถูกปฏิเสธ ค้าง หรือสำเร็จอย่างเงียบ ๆ ผ่านเส้นทางปกติของคอนเทนเนอร์ ผลลัพธ์สุดท้ายคือสิ่งที่สำคัญ และมองไม่เห็นในบันทึกที่สุขภาพดี
หากภาระงานต้องไม่ใช้เส้นทางปกติเลย ให้ออกแบบอย่างชัดเจนด้วยกฎไฟร์วอลล์และสัญญาณความพร้อมภายในเนมสเปซ Kill switch คือแนวนโยบายที่คุณเขียนและทดสอบ ไม่ใช่คุณสมบัติที่ได้รับมาถ่ายทอดจากการรันไคลเอนต์ในคอนเทนเนอร์
สุดท้าย จำขอบเขตไว้: เส้นทางเหล่านี้อยู่ในเนมสเปซของคอนเทนเนอร์และไม่แทนที่ตารางเส้นทางของโฮสต์ กฎการส่งต่อ การแปล และไฟร์วอลล์ของ Docker ยังคงเป็นส่วนหนึ่งของเส้นทางภายนอก และพอร์ตที่เผยแพร่ไม่ใช่อินเทอร์เฟซ VPN