SSH ผ่านรีเลย์สตรีมของ NGINX โดยไม่ทำให้พัง
ส่วนหัว PROXY คือข้อความถึงผู้รับที่คาดหวังมัน และระเบียน DNS ที่ผ่านพร็อกซีไม่ใช่รีเลย์ TCP จงแก้ไขขอบและต้นน้ำแยกจากกัน
SSH สาธารณะผ่านรีเลย์ล้มเหลวที่สองขอบเขตที่ไม่เกี่ยวข้องกัน และการแก้ไขจุดหนึ่งมักเผยให้เห็นอีกจุดหนึ่ง ขอบอาจส่งคืนการตอบสนอง HTTP แทนการขนส่งสตรีม หรือรีเลย์เติมส่วนหัวที่แบ็กเอนด์ไม่เคยตกลงที่จะอ่านไว้ข้างหน้า สามเงื่อนไขตัดสินว่าคุณกำลังดูอันไหน: ระเบียนสาธารณะชี้ไปที่ใดจริง ๆ บล็อกสตรีมส่งอะไรขึ้นต้นน้ำ และไคลเอนต์ SSH ตรวจสอบชื่อใด จัดการตามลำดับนั้น
สองขอบเขต สองอาการ
ความล้มเหลวที่ขอบดูเหมือนหน้าแสดงสถานะ HTTP มาถึงที่ที่แบนเนอร์ SSH ควรอยู่ การเชื่อมต่อเสร็จสิ้นในระดับ TCP และไบต์แรกเป็นข้อความของเว็บเซิร์ฟเวอร์ นั่นคือความไม่ตรงกันของโปรโตคอล ไม่ใช่แพ็กเก็ตที่หายไป มันยังบอกคุณว่าขอบจงใจให้บริการอย่างอื่นสำหรับชื่อนั้น
ความล้มเหลวที่ต้นน้ำดูแตกต่างออกไป การเชื่อมต่อไปถึง sshd, sshd อ่านไบต์ที่ไม่ใช่การแลกเปลี่ยนข้อมูลระบุตัวตนที่คาดไว้ และเซสชันก็ตายหรือค้างโดยไม่เคยเสนอคีย์
สองอย่างนี้สับสนได้ง่ายเพราะทั้งคู่ทำให้ไคลเอนต์เชื่อมต่อแล้วล้มเหลว การตอบสนองโปรโตคอลแรกที่คุณได้รับคือสิ่งที่แยกความแตกต่าง จึงควรอยู่ในตั๋ว
ส่วนหัว PROXY คือข้อความ ไม่ใช่สวิตช์
ในโมดูลสตรีม proxy_protocol on สั่งให้ NGINX เขียนส่วนหัวโปรโตคอล PROXY ไปยังต้นน้ำก่อนเพย์โหลด มันไม่ได้เปิดใช้พร็อกซี TCP และไม่เกี่ยวข้องกับการเข้ารหัส SSH เลย เป็นบันทึกที่ส่งถึงผู้รับ หากผู้รับอ่านไม่ได้ มันก็กลายเป็นขยะที่จุดเริ่มต้นของสตรีม
บริการที่รับต้องบริโภคส่วนหัวนั้นอย่างจงใจ sshd ปกติคาดหวังการแลกเปลี่ยนข้อมูลระบุตัวตน SSH เป็นไบต์แรกของการเชื่อมต่อ ดังนั้นคำนำที่ไม่คาดคิดจึงทำให้การจับมือพังในลักษณะที่ดูเหมือนเซิร์ฟเวอร์เสียหาย
stream {
server {
listen 2222;
proxy_pass 10.77.0.20:22;
}
}
ชิ้นส่วนนั้นคือรีเลย์ที่ใช้งานได้ทั้งหมดสำหรับแบ็กเอนด์ที่เข้าถึงได้ผ่าน VPN ไม่มีคำสั่ง PROXY ปรากฏเพราะผู้รับไม่พูดโปรโตคอลนั้น และการไม่มีอยู่คือการตัดสินใจ ไม่ใช่การละเว้น
แยกทั้งสองทิศทางด้วย การตั้งค่า proxy_protocol บนบรรทัด listen หมายความว่า NGINX คาดว่าไคลเอนต์ของตัวเองจะส่งส่วนหัวก่อน การเปิดใช้กับไคลเอนต์ SSH ทั่วไปให้ผลตรงกันข้ามกับปัญหาที่ผู้คนมักพยายามแก้
ชื่อโฮสต์สาธารณะไปถึงอะไรจริง ๆ
หน้า HTTP 400 ในเซสชัน SSH คือหลักฐานเกี่ยวกับขอบ มีบางอย่างในเส้นทางที่พูด HTTP และงานใด ๆ กับคีย์หรือบัญชีที่แบ็กเอนด์ก็ไม่เปลี่ยนสิ่งนั้น หยุดแก้ไขแบ็กเอนด์จนกว่าขอบจะชัดเจน
ระเบียนที่ผ่านพร็อกซีทั่วไปของ Cloudflare ขนส่งทราฟฟิก HTTP และ HTTPS ที่รองรับบนพอร์ตที่กำหนด การเปิดพร็อกซีสำหรับชื่อโฮสต์ไม่ได้สร้างรีเลย์ TCP ทั่วไป และการย้าย SSH ไปยังพอร์ต 443 ก็ไม่ได้ทำให้เป็น HTTPS
มีสองทิศทางที่เป็นไปได้ ระเบียน DNS เท่านั้นสามารถชี้ไปยังรีเลย์ TCP ของคุณเอง ซึ่งวางการตัดสินใจเรื่องการเปิดเผยไว้ในมือคุณ หรือใช้ผลิตภัณฑ์ที่บันทึกการขนส่ง SSH ไว้อย่างชัดเจน พร้อมการกำหนดค่าต้นทาง ไคลเอนต์ และการเข้าถึงของตัวเอง
ไม่ว่าคุณจะเลือกอะไร รีเลย์ยังต้องมีเส้นทาง VPN ไปยังแบ็กเอนด์ การเชื่อมต่อที่ได้รับอนุญาต และเส้นทางกลับ เส้นทางไม่ใช่ทางเลือกเพราะฝั่งสาธารณะทำงาน
รักษาตัวตนของ SSH ให้คงที่ด้วยนามแฝง
ผู้ใช้มักต้องการพิมพ์ชื่อโฮสต์เดิมต่อไป นามแฝงในการกำหนดค่า SSH ทำได้โดยไม่ต้องเปลี่ยนอะไรในรีเลย์ และเก็บการเปลี่ยนแปลงไว้ฝั่งไคลเอนต์ซึ่งเป็นที่ที่มันควรอยู่
Host git.example.com
HostName ssh-entry.example.net
Port 2222
User git
HostKeyAlias git.example.com
หากไม่มี HostKeyAlias OpenSSH จะค้นหาคีย์โฮสต์ภายใต้ชื่อที่เชื่อมต่อ ดังนั้นรายการจึงเคลื่อนย้ายและผู้ใช้ทุกคนเห็นคำเตือนเรื่องคีย์ที่เปลี่ยนไปในการใช้งานครั้งแรก การตั้งนามแฝงทำให้รายการ known-hosts คงที่ในขณะที่การเชื่อมต่อยังไปยังรีเลย์
นามแฝงนี้ใช้กับรีโมตที่อิง SSH เท่านั้น URL ของ Git แบบ HTTPS ไม่ได้ปรึกษามัน และ URL รีโมตทั่วไปต้องตรงกับการขนส่งที่คุณจัดเตรียมไว้จริง
สิ่งที่คุณไม่ควรทำคือปิดการตรวจสอบคีย์โฮสต์เพื่อให้คำเตือนหายไป นั่นเป็นการถอดการป้องกันที่การซ่อมการส่งต่อไม่เคยขอให้แตะ และเปลี่ยนความรำคาญด้านรูปลักษณ์ให้เป็นการเปิดเผยจริง
ตรวจสอบแต่ละฮ็อปแยกกัน
ทดสอบตัวรับฟังสาธารณะตามลำพัง จากนั้นทดสอบการเชื่อมต่อจากรีเลย์ไปยังแบ็กเอนด์จากโฮสต์รีเลย์ และหลังจากนั้นจึงทดสอบไคลเอนต์ตั้งแต่ต้นจนจบ การทดสอบทั้งสามนั้นแต่ละอันตัดชั้นที่แตกต่างกันออกไป การข้ามหนึ่งหมายความว่าผลลัพธ์ที่เหลืออีกสองไม่สามารถตีความได้ สามการสังเกต สามตำแหน่งที่ความล้มเหลวสามารถอาศัยอยู่
เก็บที่อยู่ปลายทาง พอร์ต และไบต์โปรโตคอลแรกไว้กับผลลัพธ์แต่ละรายการ สามสิ่งนั้นแยกข้อผิดพลาดที่ขอบออกจากปัญหาเส้นทาง VPN และจากความล้มเหลวในการพิสูจน์ตัวตน SSH และนั่นคือความแตกต่างระหว่างการซ่อมกับการเดา
สุดท้าย จัดทำเอกสารการเปิดเผยที่ตั้งใจไว้ รีเลย์ TCP ที่ขนส่ง SSH ไปยังแบ็กเอนด์ส่วนตัวคือการเปิดช่องโดยเจตนาในขอบเขตสาธารณะ และสมควรได้รับการทบทวนเช่นเดียวกับบริการขาเข้าอื่น ๆ