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

เซสชันเบราว์เซอร์พิสูจน์ได้เพียงทิศทางเดียว

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

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

ตัวเลือก A: เปิดเผยจุดปลายทางแบบแคบ

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

curl -sS -o /dev/null -w "%{http_code}\n" -X POST https://jenkins.example.com/github-webhook/

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

ตัวเลือก B: กลับทิศทางด้วยรีเลย์

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

ssh -N -R 9000:localhost:8080 relay.example.net

คำแนะนำของ Jenkins เกี่ยวกับเว็บฮุกหลังไฟร์วอลล์ อธิบายรูปแบบนี้ และควรอ่านก่อนเขียนตัวส่งต่อเอง ยุติ TLS ที่รีเลย์ ตรวจสอบลายเซ็นก่อนเหตุการณ์ไปถึงงาน และเฝ้าดูลิงก์ขาออก เพราะอุโมงค์ที่ขาดดูเหมือนเหตุการณ์ที่ไม่เคยถูกส่งทุกประการ ตรวจสอบด้วยว่ารีเลย์รักษาเนื้อความของคำขอไว้ทุกไบต์ เนื่องจากการตรวจลายเซ็นล้มเหลวกับ JSON ที่ถูกแยกวิเคราะห์และเข้ารหัสใหม่ระหว่างทาง

ตัวเลือก C: polling รีโพซิทอรีแทน

การ polling แลกความหน่วงกับความเรียบง่ายและไม่ต้องใช้เส้นทางขาเข้าเลย Jenkins สามารถ polling ตามกำหนดการ หรืองานเล็ก ๆ สามารถสอบถาม API และเริ่มบิลด์เมื่อเห็นการแก้ไขที่ไม่คุ้นเคย

curl -sS -u "$USER:$TOKEN" "https://api.github.com/repos/OWNER/REPO/commits?per_page=1"

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

ยอมรับการจัดส่งจริง ไม่ใช่การโหลดหน้าเว็บ

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

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

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