HAProxy 302 ไปยังแอปส่วนตัว: ใครเปิดการกระโดดครั้งที่สอง?
การเปลี่ยนเส้นทางคืนการเชื่อมต่อที่สองให้เบราว์เซอร์ ส่งคำขอไปยังแบ็กเอนด์แทน แล้วแก้ไขการเปลี่ยนเส้นทางแบบสัมบูรณ์และคุกกี้ของแอปเอง
มีคนชี้โฮสต์ HAProxy สาธารณะไปยังแอปภายในองค์กร แล้วถามว่าทำไมเบราว์เซอร์จึงตามไปไม่ได้ พร็อกซีเข้าถึงแอปผ่าน VPN ของตัวเอง การเปลี่ยนเส้นทางส่งคืนส่วนหัว Location แล้วเบราว์เซอร์ก็พยายามเข้าถึงที่อยู่ที่อยู่ภายในอุโมงค์เท่านั้น จากภายนอกหน้าเว็บก็แค่ค้างอยู่ การตัดสินใจอยู่ที่ว่าฝ่ายใดเปิดการเชื่อมต่อที่สอง และนั่นคือสิ่งที่แยกการเปลี่ยนเส้นทางออกจากแบ็กเอนด์
สองเส้นทางที่ดูคล้ายกันในการกำหนดค่า
การเปลี่ยนเส้นทางจบการแลกเปลี่ยนด้วยการตอบกลับ ไคลเอนต์อ่าน Location แล้วเริ่มคำขอใหม่จากที่ที่ไคลเอนต์อยู่ ซึ่งเป็นเครือข่ายที่คุณไม่เคยควบคุม พร็อกซีไม่เกี่ยวข้องอีกต่อไป ทุกสิ่งหลังจากนั้นขึ้นอยู่กับ DNS เส้นทาง และความเชื่อถือของไคลเอนต์เอง ผลลัพธ์จึงแตกต่างกันไปตามตำแหน่งที่ผู้ใช้เปิดเบราว์เซอร์:
GET /app client -> proxy
302 Location proxy -> client (http://10.40.0.20:8080/)
GET /app client -> 10.40.0.20:8080 client network, no route
แบ็กเอนด์ของพร็อกซีเก็บขาที่สองไว้ฝั่งเซิร์ฟเวอร์ พร็อกซีเปิดมันผ่านเส้นทางที่มีอยู่แล้ว และไคลเอนต์ยังคงคุยกับชื่อสาธารณะชื่อเดียว ถ้าอุโมงค์หลุด ไคลเอนต์จะได้รับข้อผิดพลาดแทน URL ที่ตามไปไม่ได้ ความแตกต่างนี้ยังทำให้ความล้มเหลวตรวจสอบได้ เพราะข้อผิดพลาดปรากฏที่เดียวกับที่บันทึกอยู่:
GET /app client -> proxy
GET /app proxy -> 10.40.0.20:8080 over the VPN
response proxy -> client
เอกสารการเปลี่ยนเส้นทางของ HAProxy ลากเส้นแบ่งนี้ไว้พอดี: การตอบไคลเอนต์ด้วยการเปลี่ยนเส้นทางเป็นการกระทำที่ต่างจากการส่งต่อคำขอไปยังแบ็กเอนด์ ไดเรกทีฟทั้งสองอยู่ห่างกันไม่กี่บรรทัดในไฟล์กำหนดค่าและทำงานไม่เหมือนกันเลย ตัวหนึ่งจบคำขอ อีกตัวเริ่มคำขอที่สองซึ่งพร็อกซีเป็นเจ้าของ
สิ่งที่เบราว์เซอร์ต้องการแต่ VPN ของเซิร์ฟเวอร์ไม่ได้ให้
คำขอของเบราว์เซอร์เองต้องการสี่สิ่งที่อาจไม่มี: คำตอบ DNS สำหรับชื่อส่วนตัว เส้นทางไปยังที่อยู่นั้น สิทธิ์ในการเข้าถึงบริการที่รับฟัง และความเชื่อถือในใบรับรองที่บริการนั้นนำเสนอ โฮสต์พร็อกซีมีครบทั้งสี่ผ่านอุโมงค์ของมัน ไม่มีสิ่งใดส่งต่อไปยังไคลเอนต์ที่ไม่เคยอยู่ในอุโมงค์นั้น เพราะอุโมงค์เป็นคุณสมบัติของโฮสต์ ไม่ใช่ของ URL
ช่องว่างนี้อธิบายอาการที่เกือบจะทำงาน คำขอแรกสำเร็จ แถบที่อยู่เปลี่ยน แล้วการเชื่อมต่อก็ค้างหรือล้มเหลวในขณะที่พร็อกซียังแข็งแรงตลอดเวลา ไม่มีอะไรเสียในการกำหนดค่าพร็อกซี และการปรับมันช่วยไคลเอนต์ที่ไม่มีเส้นทางไปยัง 10.40.0.20 ไม่ได้ ไม่ว่าไคลเอนต์จะได้เส้นทาง หรือพร็อกซีต้องสร้างการเชื่อมต่อแทน
เมื่อมีเพียงพร็อกซีที่เข้าถึงแอปได้
ลบการกระทำเปลี่ยนเส้นทางออก แล้วส่งคำขอเหล่านั้นไปยังแบ็กเอนด์ที่ชี้ไปยังที่อยู่ส่วนตัว ฟรอนต์เอนด์ยังคงชื่อสาธารณะไว้ ส่วนแบ็กเอนด์ตัดสินใจว่าคำขอไปที่ใดจริง ๆ ไม่มีอะไรเปลี่ยนในเส้นทางของไคลเอนต์ เพราะพร็อกซีเลิกอธิบายปลายทางและกลายเป็นปลายทางเสียเอง สำหรับแอปที่ตั้งใจรับฟังบนพอร์ตภายใน 8080 บล็อกเซิร์ฟเวอร์นั้นสั้น:
backend private_app
mode http
option httpchk GET /health
server app1 10.40.0.20:8080 check
อ่านบล็อกนั้นเป็นข้อความเกี่ยวกับตารางเส้นทางของพร็อกซี: 10.40.0.20 ต้องเข้าถึงได้จากโฮสต์พร็อกซีเอง ซึ่งในที่นี้หมายถึงผ่านอินเทอร์เฟซ VPN ไม่ใช่เส้นทางเริ่มต้น คีย์เวิร์ด check เพียงรายงานว่าเส้นทางนั้นทำอะไร และเส้นทางตรวจสอบสุขภาพต้องมีอยู่ในแอป ไม่อย่างนั้นทุกการตรวจจะทำเครื่องหมายเซิร์ฟเวอร์ว่าล่ม การตรวจที่ผ่านไม่ได้พิสูจน์อะไรเกี่ยวกับไคลเอนต์ และไม่ได้แทนนโยบายที่ตัดสินว่าใครใช้แบ็กเอนด์ได้
ส่วนย่อยนี้ไม่ใช่ฟรอนต์เอนด์ที่สมบูรณ์ เก็บตัวรับฟัง การพิสูจน์ตัวตน การเลือกโฮสต์และเส้นทางที่อนุญาต และกฎที่ตัดสินว่าใครเข้าถึงแอปได้เลย จับคู่โปรโตคอลของแบ็กเอนด์ด้วย เพราะแบ็กเอนด์ HTTPS ต้องการการตรวจสอบใบรับรองและการกำหนดค่าอัตลักษณ์เซิร์ฟเวอร์ และการข้ามการตรวจนั้นเปลี่ยนการเชื่อมต่อส่วนตัวให้เป็นการเชื่อมต่อที่ไม่ได้รับการยืนยัน
ยืนยันเส้นทางขากลับทั้งสองทิศทางก่อนประกาศชัยชนะ ตอนนี้แอปเห็นการเชื่อมต่อจากพร็อกซี บันทึกและเมตาดาต้าเกี่ยวกับที่อยู่ไคลเอนต์จึงอธิบายพร็อกซี เว้นแต่คุณจะจัดให้เป็นอย่างอื่น ตัดสินใจว่าจะจัดการอัตลักษณ์และที่อยู่ที่ส่งต่ออย่างไร และทดสอบการตัดสินใจนั้นแทนที่จะสันนิษฐาน
การเปลี่ยนเส้นทางของแอปเองยังชี้เข้าข้างใน
การส่งต่อคำขอแรกเป็นเพียงครึ่งเดียวของการผสาน แอปอาจส่งการเปลี่ยนเส้นทางแบบสัมบูรณ์ URL ของทรัพยากรที่ฝังตายตัว หรือคุกกี้ที่จำกัดขอบเขตไว้ที่ชื่อที่มันรู้จักภายใน และแต่ละอย่างส่งเบราว์เซอร์กลับไปยังที่อยู่ที่เข้าถึงไม่ได้ ส่วนหัว Location ที่ชี้ไปยังชื่อภายในดูเหมือนปัญหาเดิมทุกประการ จึงถูกวินิจฉัยผิดว่าเป็นความล้มเหลวของพร็อกซี
ตั้งค่า URL ภายนอกที่แอประบุไว้และตัวเลือกพร็อกซีของมัน แล้วทำให้ส่วนหัว Host สอดคล้องกับโฮสต์เสมือนและความคาดหวังเรื่องใบรับรอง คุกกี้ที่จำกัดขอบเขตไว้ที่ชื่อภายในจะไม่กลับมาผ่านชื่อสาธารณะ และลูปการลงชื่อเข้าใช้ที่ตามมาจะถูกอ่านว่าเป็นบั๊กการพิสูจน์ตัวตน เปลี่ยน URL ภายนอกก่อน ทดสอบซ้ำจากโปรไฟล์เบราว์เซอร์ที่สะอาด และคาดว่าการตั้งค่าที่ย้ายมาเพียงครึ่งจะให้การลงชื่อเข้าใช้ที่สำเร็จและเซสชันที่ตายทันที
เชื่อถือเมตาดาต้าที่ส่งต่อมาจากพร็อกซีที่กำหนดเท่านั้น ส่วนหัวที่ไคลเอนต์ใดก็ตั้งได้ต้องไม่กลายเป็นค่าอนุญาต ไม่อย่างนั้นพร็อกซีจะกลายเป็นวิธีให้ผู้เรียกอ้างอิงอัตลักษณ์ของคนอื่น กฎนั้นเป็นอิสระจากคำถามเรื่องการเปลี่ยนเส้นทางและคงอยู่ผ่านการออกแบบใหม่ทุกครั้งในภายหลัง
ตัดสินใจว่าคุณมีการออกแบบแบบไหนจริง ๆ
ถ้าผู้ใช้ทุกคนมีสิทธิ์เข้าถึง VPN ที่ได้รับอนุญาตอยู่แล้ว การเปลี่ยนเส้นทางไปยัง URL ส่วนตัวอาจเป็นการออกแบบโดยตั้งใจ ยืนยันข้อกำหนดนั้นอย่างชัดเจนแทนที่จะสันนิษฐาน เพราะการออกแบบทั้งสองแบบให้บริการประชากรที่ต่างกันโดยสิ้นเชิง แบบหนึ่งใช้ไม่ได้เลยจากเครือข่ายโรงแรม อีกแบบเปิดเผยแอปให้ใครก็ตามที่โหลด URL สาธารณะได้ ความแตกต่างนั้นควรอยู่ในบันทึกการออกแบบ
เรียกการตรวจจากเครื่องในเครือข่ายของผู้ใช้ และติดตามทุกการกระโดดที่เบราว์เซอร์ทำ ไม่ใช่แค่การตอบกลับครั้งแรก จับตาแถบที่อยู่และทุกคำขอถัดไป เพราะ URL สัมบูรณ์เพียงตัวเดียวในแท็กทรัพยากรก็พอจะทำให้โฟลว์ที่ผ่านการกระโดดแรกพังได้ การลงชื่อเข้าใช้ต้องทำงานผ่านชื่อสาธารณะ และทรัพยากรที่ควรถูกปฏิเสธต้องยังคงถูกปฏิเสธ
การเผยแพร่รีเวิร์สพร็อกซีเป็นการตัดสินใจเรื่องการเข้าถึงแยกต่างหาก ไม่ใช่การขยาย VPN ของพร็อกซีเองอย่างโปร่งใสให้กับใครก็ตามที่โหลด URL สาธารณะของมันได้ ทั้งสองดูเหมือนกันในแผนภาพ และต่างกันที่ว่าใครได้รับอนุญาตให้เข้า การตัดสินใจเรื่องนั้นหลังการติดตั้งคือวิธีที่แอปภายในกลายเป็นแอปสาธารณะโดยไม่ตั้งใจ
เขียนไว้ว่าคุณสร้างแบบไหนและเพราะอะไร คนถัดไปที่แตะการกำหนดค่าจะสันนิษฐานอีกแบบ การเปลี่ยนเส้นทางเพียงครั้งเดียวที่เพิ่มเพื่อความสะดวกก็พอจะสร้างความล้มเหลวเดิมขึ้นใหม่ และอาการจะดูเหมือนกับสิ่งที่คุณเพิ่งแก้ไปทุกประการ