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

ใครเป็นเจ้าของเนมสเปซของพอร์ต

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

services:
  vpn:
    image: vpn-client-image
    cap_add: [NET_ADMIN]
    ports:
      - "127.0.0.1:8080:8080"
  app:
    network_mode: "service:vpn"

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

ทำให้แอปฟังในที่ที่เนมสเปซคาดหวัง

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

docker compose exec app ss -lntp
docker port vpn
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/

รายการตัวรับฟังภายในแอปบอกความจริงเกี่ยวกับที่อยู่ที่ผูก และ docker port บอกว่าเจ้าของเผยแพร่สิ่งใดจริง ๆ ถ้าตัวแรกแสดง 127.0.0.1 และตัวที่สองแสดงการแมปบนโฮสต์ คุณพบความไม่ตรงกันโดยไม่ต้องแตะการกำหนดค่า VPN

เลือกว่าทางบริหารจะเข้ามาอย่างไร

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

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

เปิดพอร์ตบริหารโดยไม่เปิดทุกอย่าง

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

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

ตรวจสอบจากอุปกรณ์บริหาร แล้วตรวจสอบอีกครั้งภายหลัง

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

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

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