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

พอร์ตเดียวที่ปิดไม่ได้

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

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

อินพุต การส่งต่อ และ NAT ตอบคำถามต่างกัน

ทราฟฟิกอินพุตมีปลายทางเป็นโฮสต์เอง จึงเป็นที่อยู่ของตัวรับฟัง VPN และเส้นทางบริหารจัดการ ทราฟฟิกส่งต่อผ่านโฮสต์ และไคลเอนต์อุโมงค์ต้องการมันพร้อมกับ net.ipv4.ip_forward=1 การกำหนดค่าคลาสสิกที่พังครึ่งหนึ่งอนุญาตการไหลขาออกแต่ลืมทิศทางขากลับ ไคลเอนต์จึงจบแฮนด์เชกแล้วไม่มีอะไรโหลด กฎ conntrack สำหรับทราฟฟิกที่สร้างแล้วและเกี่ยวข้องครอบคลุมทิศทางนั้น

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

IPv6 คืออีกนโยบายหนึ่ง ไม่ใช่ความคิดภายหลัง โฮสต์ที่มีเชน IPv4 เข้มงวดและนโยบายเปิดบน ip6tables ยังไม่ได้ปิดอะไรเลย บริการยังเข้าถึงได้ผ่านอีกตระกูลหนึ่ง จะสะท้อนชุดกฎด้วย ip6tables หรือปิด IPv6 บนอินเทอร์เฟซสาธารณะอย่างตั้งใจ และจดไว้ว่าเลือกอย่างไหน

ฐานที่อ่านจบได้ในครั้งเดียว

เริ่มจากการปฏิเสธ แล้วเพิ่มเฉพาะสิ่งที่โฮสต์ต้องการ ก่อนอื่น loopback และคำตอบ จากนั้นเส้นทางบริหารจัดการ จากนั้นตัวรับฟังอุโมงค์ จากนั้นนโยบายส่งต่อสำหรับไคลเอนต์:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -m conntrack --ctstate NEW -j ACCEPT
sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

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

ปิดพอร์ตสุดท้ายโดยไม่เสียโฮสต์

มีการออกแบบที่มีกับดัก หาก SSH มีอยู่เฉพาะผ่านอุโมงค์ บริการ VPN ที่ล้มเหลวจะพา SSH ไปด้วย และทางกลับอาจเหลือเพียงคอนโซลที่คุณไม่เคยเปิด ก่อนปิดพอร์ตสาธารณะสุดท้าย ให้ยืนยันว่าคอนโซลนั้นมีอยู่และคุณใช้มันได้จริง หรือเก็บเส้นทางบริหารจัดการแคบ ๆ หนึ่งเส้นทางที่ไม่ขึ้นกับอุโมงค์: SSH จากที่อยู่คงที่ ใช้กุญแจเท่านั้น ปิดการยืนยันด้วยรหัสผ่าน

ใช้การเปลี่ยนแปลงจากเซสชันที่สร้างไว้แล้ว ไม่ใช่ผ่านการเชื่อมต่อที่คุณกำลังจะกรอง ตั้งเวลาย้อนกลับเพื่อให้ข้อผิดพลาดหมดอายุแทนที่จะกลายเป็นถาวร เช่น งาน systemd-run --on-active=10min ที่คืนค่าชุดกฎก่อนหน้า และเปิดเซสชัน SSH ที่สองค้างไว้ขณะทดสอบเซสชันแรก จากนั้นตรวจสอบว่างานย้อนกลับทำงานจริง เพราะการกู้คืนที่ไม่ได้ทดสอบก็เท่ากับไม่มีการกู้คืน

ตรวจเส้นทาง ไม่ใช่สคริปต์

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

iptables -S
iptables -t nat -S
ss -lntup
ip -4 addr show

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

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

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