4 คะแนน โดย GN⁺ 2024-06-24 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • sudo และ doas พึ่งพา ไบนารี setuid และการยกระดับสิทธิ์ จึงเป็นการทดลองที่ให้ sshd ในเครื่องซึ่งผูกกับ Unix domain socket รับหน้าที่รันคำสั่งในฐานะ root
  • เป้าหมายคือให้ เฉพาะผู้ใช้ที่ได้รับอนุญาตเท่านั้นที่รันคำสั่ง root ได้ โดยไม่ทิ้งความสามารถในการยกระดับสิทธิ์ไว้กับเซสชันผู้ใช้ทั้งหมด
  • การใช้งานประกอบด้วยไฟล์ SSH key เฉพาะสำหรับ root, /run/sshd/sshd.sock ที่จำกัดการเข้าถึง, AuthorizedKeysFile และอินสแตนซ์ sshd แยกต่างหากที่มีตัวเลือก PermitRootLogin=yes
  • เนื่องจาก ssh ไม่มีตัวเลือกสำหรับส่งต่อซ็อกเก็ตที่มีอยู่โดยตรง ตอนแรกจึงใช้ ProxyCommand กับ socat และต่อมาส่งต่อ socket file descriptor ด้วย ProxyUseFdpass และสคริปต์ Python สั้น ๆ
  • วิธีนี้ใช้งานได้และพึ่งพา OpenSSH เป็นหลักในการจัดการด้านความปลอดภัย แต่สำหรับการใช้งานประจำวัน ควรทำ passfd.py เป็นไฟล์ปฏิบัติการขนาดเล็กและห่อคำสั่ง ssh ทั้งหมดด้วย wrapper

ข้อจำกัดเชิงโครงสร้างของ sudo และ doas

  • sudo และ doas พึ่งพาไบนารี setuid และ การยกระดับสิทธิ์ เพื่อรันคำสั่งในฐานะ root
  • การออกแบบนี้มีข้อจำกัดหลายอย่าง
    • ต้องคงความสามารถในการยกระดับสิทธิ์ไว้ให้เซสชันผู้ใช้ทั้งหมด
    • ไม่ทำงานเมื่อรันเซสชันผู้ใช้ทั้งหมดภายใน user namespace ที่จำกัด
    • ไบนารี setuid สร้างข้อจำกัดต่อการกำหนดค่าความปลอดภัยของทั้งระบบ
  • s6-sudod เป็นทางเลือกที่แยกโปรแกรมออกเป็นเซิร์ฟเวอร์ที่มีสิทธิ์และไคลเอนต์ที่ไม่มีสิทธิ์

เป้าหมายของการทดลอง

  • ใช้ ssh ในเครื่องเพื่อทำหน้าที่แบบเดียวกับ sudo โดยไม่ให้อินสแตนซ์ sshd นั้นเปิดสู่เครือข่าย
  • เงื่อนไขหลักมีสองข้อ
    • เฉพาะผู้ใช้ที่ได้รับอนุญาตเท่านั้น ที่รันคำสั่งในฐานะ root ได้
    • ไม่ใช้การยกระดับสิทธิ์

การตั้งค่า sshd สำหรับล็อกอิน root ในเครื่อง

  • สร้าง SSH key เฉพาะสำหรับใช้ยืนยันตัวตน root เท่านั้น และเก็บไว้ใน /root/.ssh/local_keys แทน authorized_keys ทั่วไป
  • ผูกอินสแตนซ์ sshd แยกต่างหากกับ Unix domain socket และจำกัดสิทธิ์ของ /run/sshd/ เพื่อไม่ให้ผู้ใช้ที่ไม่ได้รับอนุญาตเข้าถึงซ็อกเก็ตได้
  • ตัวอย่างการรันคือสร้าง /run/sshd/sshd.sock ด้วย s6-ipcserver แล้วส่งตัวเลือกต่อไปนี้ให้ sshd
    • AuthorizedKeysFile=/root/.ssh/local_keys
    • PermitRootLogin=yes
  • ไม่แก้ไข /etc/ssh/sshd_config
    • เพราะไม่ต้องการอนุญาตการล็อกอิน root ใน sshd เดิมที่ bind กับเครือข่าย
    • การตั้งค่าเดิมยังคง PermitRootLogin no ไว้

การล็อกบัญชี root และการจัดการล็อกอินด้วยรหัสผ่าน

  • บัญชี root ถูกล็อกไว้ไม่ให้ล็อกอินได้ไม่ว่าด้วยวิธีใด โดยใช้วิธีเติม ! ไว้หน้าค่า password hash
  • sshd ตีความ prefix ! นี้ว่าเป็นการล็อกบัญชี จึงไม่อนุญาตให้ root ล็อกอิน
  • เปลี่ยนค่ารหัสผ่านของ root ใน /etc/passwd โดยแทนที่ ! ด้วย *
    • sshd ไม่ตีความ * เป็นค่าล็อกพิเศษ
    • * ไม่ตรงกับ password hash ใด ๆ ดังนั้นการล็อกอินด้วยรหัสผ่านจึงยังคงถูกปิดใช้งานโดยปริยาย
  • นอกจากนี้ใน sshd_config ยังตั้งค่า PasswordAuthentication no ไว้ และการปิดการยืนยันตัวตนด้วยรหัสผ่านใน sshd เป็นการตั้งค่าที่ปลอดภัย

การเชื่อมต่อไปยัง Unix socket ด้วย ssh

  • sshd มีแฟล็ก -i ที่รับซ็อกเก็ตที่มีอยู่ได้ แต่ ssh ไม่มีแฟล็กที่ทำหน้าที่เดียวกัน
  • ตอนแรกใช้ socat ผ่าน ProxyCommand เพื่อเชื่อมต่อกับ /run/sshd/sshd.sock
  • คำสั่งเชื่อมต่อประกอบด้วยองค์ประกอบต่อไปนี้
    • ProxyCommand='socat STDIO UNIX-CONNECT:/run/sshd/sshd.sock'
    • ระบุ root key เฉพาะด้วย -i .ssh/root-key.pub
    • เชื่อมต่อเป็น root@root
    • เปลี่ยนไปยังไดเรกทอรีปัจจุบันแล้วรัน login shell
  • SSH key ที่ใช้เป็น hardware-bound key ดังนั้นต้องแตะอุปกรณ์จริงเพื่ออนุมัติการเชื่อมต่อ
  • ssh-agent ที่เปิดเผย key เฉพาะหลังจากได้รับการอนุมัติอย่างชัดเจน เช่น hissh-agent ก็อาจเป็นทางเลือกได้

overhead ของ socat และ ProxyUseFdpass

  • socat อ่าน input ทั้งหมดของ ssh แล้วเขียนไปยังซ็อกเก็ต ทำให้ overhead ของการเชื่อมต่อซ้ำซ้อนโดยปริยาย
  • ProxyUseFdpass ให้คำสั่งส่ง socket file descriptor ไปยัง ssh ผ่าน stdout แล้วให้ ssh เชื่อมต่อผ่านซ็อกเก็ตนั้น
  • อ้างอิงจาก ตัวอย่างการใช้ OpenSSH ProxyUseFdpass ปี 2016 จึงเขียนสคริปต์ Python ชื่อ passfd.py
    • เชื่อมต่อกับ Unix domain socket /run/sshd/sshd.sock
    • ส่ง file descriptor ด้วย sendmsg และ SCM_RIGHTS
  • หลังจากนั้น คำสั่งเชื่อมต่อจึงเป็นรูปแบบที่ระบุ passfd.py ใน ProxyCommand และเพิ่ม ProxyUseFdpass=yes
  • nc -FU /run/sshd/sshd.sock ก็ดูเหมือนจะทำได้ แต่คู่มือระบุว่า -F ใช้ร่วมกับ -U ไม่ได้

สรุปและรูปแบบการใช้งานจริง

  • เทคนิคนี้ใช้งานได้ และมอบการจัดการด้านความปลอดภัยที่ละเอียดอ่อนให้ OpenSSH เป็นหลัก
  • OpenSSH มีประวัติที่ดี และสามารถใช้วิธีการยืนยันตัวตนได้หลายแบบ รวมถึง SSH key ที่อิงฮาร์ดแวร์
  • ขั้นตอนการตั้งค่าบนโฮสต์ใหม่ไม่มีขั้นตอนที่ซับซ้อน และสามารถรันคำสั่ง ipcserver ผ่าน system service manager ได้
  • passfd.py ค่อนข้างเป็นการแฮ็กอย่างรวดเร็วเพื่อดำเนินการทดลอง
  • สำหรับการใช้งานประจำวัน ควรสร้างไฟล์ปฏิบัติการขนาดเล็กที่ทำหน้าที่เดียวกันไว้ใน /usr/local/bin และห่อคำสั่ง ssh ทั้งหมดด้วย wrapper ขนาดเล็ก

1 ความคิดเห็น

 
GN⁺ 2024-06-24
ความคิดเห็นจาก Hacker News
  • เหตุผลคัดค้านที่ใหญ่ที่สุดของวิธีนี้คือ ความซับซ้อนที่เพิ่มขึ้น แทนที่จะมีไบนารี suid ตัวเดียวที่อ่านไฟล์ตั้งค่าแล้วเรียก exec() ก็กลายเป็นว่ามีไบนารีตัวหนึ่งที่รันเป็น root และคอยฟัง UNIX socket กับอีกตัวหนึ่งที่คุยกับ socket นั้น และทั้งสองตัวยังต้องจัดการการเข้ารหัสแบบอสมมาตรด้วย
    ถ้าข้อโต้แย้งหลักต่อ sudo/doas คือ “มีไบนารี suid ที่ผู้ใช้ทุกคนเข้าถึงได้ และถ้ามีบั๊กก็อาจถูกใช้ยกระดับสิทธิ์ได้” ก็ทำแบบด้านล่างได้
    chgrp wheel /usr/bin/sudo
    chmod o-rwx /usr/bin/sudo
    เมื่อใส่ผู้ใช้ sudo ไว้ในกลุ่ม wheel ก็มีเฉพาะผู้ใช้ที่ใช้ sudo ได้เท่านั้นที่อ่านไบต์ของไฟล์จากดิสก์และรันไฟล์ได้ ในแง่การควบคุมการเข้าถึง ความปลอดภัยแทบไม่ต่างจากแนวทางแบบ sshd ที่ให้เฉพาะผู้ใช้ wheel เข้าถึง UNIX socket ได้ แต่ความซับซ้อนต่ำกว่ามาก
    ยิ่งไปกว่านั้น แนวทางแบบ sshd ไม่สามารถจำกัดการเข้าถึง root ไว้เฉพาะคำสั่งบางคำสั่งเหมือน sudo ได้ ดังนั้นแม้จะมีบั๊กที่เลี่ยงข้อจำกัดคำสั่งของ sudo ได้ ก็ไม่ได้ให้สิทธิ์มากกว่าแนวทางแบบ sshd
    ถ้ากังวลว่าตัวจัดการแพ็กเกจจะทำสิทธิ์ของ /usr/bin/sudo พัง ก็ให้ cron แก้ให้เป็นระยะ ๆ หรือถอน sudo ออกไปเลยแล้วติดตั้งด้วยมือจากซอร์สไว้ที่ตำแหน่งอื่นก็ได้ แน่นอนว่าถ้าทำแบบนั้นก็ต้องดูแลและอัปเกรดเองด้วย

    • ส่วนตัวใช้ etckeeper เพื่อติดตามการเปลี่ยนแปลงทั้งหมดใน /etc ไม่ว่าจะเป็นการติดตั้ง/อัปเกรดซอฟต์แวร์หรือการเปลี่ยนแปลงโดยคนก็ถูกบันทึกไว้ และตอนอัปเกรดเป็นรีลีสใหม่ก็มีประโยชน์ เพราะสามารถสร้างแพตช์ของการเปลี่ยนแปลงในเครื่อง นำไปใช้กับการติดตั้งที่สะอาด แล้วตรวจความขัดแย้งด้วยการ merge แบบ 3-way ได้
      https://etckeeper.branchable.com/
    • การใส่ผู้ใช้ sudo ไว้ในกลุ่ม wheel เพื่อให้เฉพาะผู้ใช้ที่ใช้ sudo ได้เท่านั้นอ่านและรันไฟล์ได้ ดูสมเหตุสมผลทีเดียว สงสัยว่าทำไมสิ่งนี้ถึงไม่เป็นค่าเริ่มต้นทุกที่
    • ขออภัยที่ไม่รู้ อยากฟังคำอธิบายว่า กลุ่ม wheel คืออะไรและทำอะไร เข้าใจว่านี่อาจเปิดประเด็นถกเถียงที่ซับซ้อนได้
    • ทำให้ /usr/bin/sudo เป็น immutable ไม่ได้หรือ? แบบนั้นน่าจะช่วยกันไม่ให้ตัวจัดการแพ็กเกจไปแตะต้องมัน
    • ส่วนที่บอกว่าไม่สามารถจำกัดการเข้าถึง root เป็นคำสั่งเฉพาะได้นั้น มีโครงสร้าง ForcedCommand อยู่
  • นี่ไม่ใช่สิ่งที่ systemd run0 ทำอยู่ตอนนี้หรือ? systemd มีเครื่องมือใหม่ชื่อ run0 แต่จริง ๆ แล้วไม่ได้เป็นเครื่องมือใหม่ทั้งหมด หากเรียก systemd-run ที่มีมานานผ่าน symlink ชื่อ run0 มันจะทำงานเหมือนตัวแทน sudo
    ความแตกต่างหลักคือจริง ๆ แล้วมันไม่ใช่ SUID มันขอให้ service manager รันคำสั่งหรือเชลล์ด้วย UID ของผู้ใช้เป้าหมาย จัดสรร PTY ใหม่ แล้วส่งข้อมูลไปมาระหว่าง TTY เดิมกับ PTY นี้
    กล่าวอีกอย่างคือคำสั่งเป้าหมายไม่ได้สืบทอดบริบทของไคลเอนต์ แต่รันในบริบทการประมวลผลที่แยกออกมาและ fork ใหม่จาก PID 1 $TERM ถูกส่งต่อไปก็จริง แต่นั่นเป็นข้อยกเว้นที่ระบุชัดเจน จึงใกล้เคียงกับ allow list มากกว่า block list
    ในหลายแง่ run0 ถือได้ว่ามีพฤติกรรมใกล้กับ ssh มากกว่า sudo
    https://mastodon.social/@pid_eins/112353324518585654

    • ทำไม systemd ต้องสร้างทุกอย่างขึ้นมาใหม่ด้วยนะ?
  • ผมพลาดอะไรไปหรือเปล่า? ไม่เข้าใจว่า การล็อกอิน SSH เป็น root ปลอดภัยกว่าการใช้ sudo อย่างไร เราถูกสอนมาตลอดว่าไม่ควรอนุญาต เลยก็ไม่รู้จริง ๆ ว่ามันอันตรายแค่ไหน
    ที่นี่ดูเหมือนมีการคิดเพื่อกันผู้ใช้ระยะไกลไว้แล้ว ดังนั้นไม่ได้พูดถึงด้านความปลอดภัยส่วนนั้น
    อาจเกี่ยวข้องกับข้อจำกัดข้อ 3 ของ sudo แต่เมื่อเทียบกับข้อ 1 อย่างน้อยก็ยังไม่เห็นข้อดี
    เข้าใจว่านี่เป็นการทดลอง แต่รู้สึกว่ามันน่าจะเปราะบางกว่า sudo ไม่ใช่น้อยกว่า proxy socket ที่เปิดอยู่ดูเสี่ยงต่อการโจมตีแบบ man-in-the-middle
    ถึงอย่างนั้นก็ได้เรียนรู้เทคนิคบางอย่างที่ทำได้ด้วยเครื่องมือเก่า ๆ และชอบที่ได้เห็นอะไรใหม่ ๆ

    • ไบนารี sudo เป็น suid root และเป็นไบนารีที่มีสิทธิ์พิเศษ จึงถูกเปิดเผยโดยตรงต่อผู้ใช้ที่ไม่น่าเชื่อถือ ถ้ามีอะไรผิดพลาดภายใน sudo สภาพแวดล้อมทั้งหมดของผู้ใช้ก็กลายเป็นพื้นที่โจมตีและอาจถูกใช้โจมตีได้
      แนวทางแบบ ssh ไม่เปิดเผยไบนารี suid และใช้ชั้นเครือข่ายของ ssh ดังนั้นจึงไม่ได้ปลอดภัยน้อยกว่าการเข้าถึง ssh ผ่านเครือข่าย ซึ่งถือว่าค่อนข้างปลอดภัย
    • หนึ่งในข้อดีใหญ่ของ sudo คือสามารถรันคำสั่งเป็น sudo ทีละคำสั่งเพื่อเพิ่ม ความสามารถในการตรวจสอบย้อนหลัง แทนที่จะเปิดอะไรอย่าง sudo bash ขึ้นมาเฉย ๆ
    • การล็อกอิน SSH เป็น root ในบทความหมายถึง เซิร์ฟเวอร์ SSH เพิ่มเติม ที่ฟัง Unix socket อยู่ threat model ทั่วไปตอนเปิดเผยการล็อกอิน root ต่ออินเทอร์เน็ตอาจใช้กับกรณีนี้ไม่ได้
    • วิธีนี้กำลังเปรียบเทียบข้อผิดพลาดในการตั้งค่าที่เป็นทฤษฎีหรือช่องโหว่ที่อาจมีหรือไม่มี กับพื้นที่โจมตีใหม่จากการรัน daemon ใหม่
      daemon นั้นก็อาจมีข้อผิดพลาดในการตั้งค่าหรือช่องโหว่ได้ และยังลดชั้นการอนุญาตตามผู้ใช้หลายชั้นลงเหลือระดับ root เดียว
      ถึงอย่างนั้นดูเหมือนยังถูกมองว่าปลอดภัยกว่า จากมุมมองความปลอดภัยที่สมเหตุสมผล มองว่าปลอดภัยกว่าไม่ได้ มันแค่เป็นอีกวิธีหนึ่งเท่านั้น
    • แม้จะกังขากับแนวทางในบทความที่ลิงก์ไว้ แต่คำพูดว่า “การล็อกอิน SSH ระยะไกลโดยตรงเป็น root อันตราย” มีส่วนที่หลงไปกับ ความกลัว·ความไม่แน่นอน·ความสงสัย
      ในความเป็นจริง การล็อกอิน SSH เป็น root โดยตรงนั้น ในความหมายเคร่งครัดปลอดภัยกว่าการล็อกอินเป็นผู้ใช้ผ่าน SSH ระยะไกลแล้วใช้ sudo
      ถ้า user@home ssh ไปเป็น root@server แล้ว root@server จะเสียหายก็ต่อเมื่อ user@home ถูกเจาะ
      แต่ถ้า user@home ssh ไปเป็น user@server แล้วใช้ sudo กลายเป็น root@server แค่ user@home หรือ user@server ฝั่งใดฝั่งหนึ่งถูกเจาะ root ก็เสียหายแล้ว โดยเฉพาะบน user@server มักมีซอฟต์แวร์อื่น ๆ อย่าง daemon หรือ cron job ทำงานอยู่
      ไม่ควรให้การยกระดับสิทธิ์เป็น root ฟรี ๆ แก่คนที่ติดเชื้อสำเร็จผ่านเส้นทางนั้น และยังรวมถึงการเคลื่อนย้ายด้านข้างที่เกิดบ่อยจากการใช้รหัสผ่านซ้ำด้วย
      แน่นอนว่าไม่ใช้กับกรณีที่ sudo ถูกใช้ในโหมดอนุญาตเฉพาะคำสั่งใน allow list และไม่ได้รับรหัสผ่านหรือ credentials ที่เข้าถึงได้เต็มที่จากโฮสต์ระยะไกล
  • ถ้า ssh ไม่เริ่มตอนบูตจะเป็นอย่างไร? เท่าที่จำได้ ในการตั้งค่าทั่วไปมันเริ่มโดยพึ่งพาเครือข่าย ถ้าอย่างนั้นแม้แต่ คอนโซล failsafe ก็จะล็อกอินไม่ได้
    ผมไม่แน่ใจว่าเมื่อเทียบกับ sudo หรือ su แล้วได้อะไรจริง ๆ กันแน่ แทนที่จะหลีกเลี่ยงไบนารี setuid กลับต้องรันบริการเครือข่ายด้วยสิทธิ์ root แม้จะเป็นแค่การเชื่อมต่อกับซ็อกเก็ตก็ตาม

    • ในฐานะคนที่ใช้การตั้งค่าคล้าย ๆ กัน ผมทำแบบนี้บนเดสก์ท็อปหลักของตัวเอง ถ้าเกิดกรณีเลวร้ายที่สุดจริง ๆ ทุกอย่างมีแบ็กอัปอยู่แล้ว ก็แค่ติดตั้งระบบใหม่
      ถ้า SSD ตายล่ะ? ตอนนั้นก็ล็อกอินเข้า failsafe console ไม่ได้เหมือนกัน
      ตลอด 30 ปีที่ใช้ Linux มา ฮาร์ดดิสก์ตายเกิดขึ้นบ่อยกว่ากรณีที่ดีมอน sshd ไม่เริ่มทำงานมาก และถ้าคิดเป็นอัตราส่วนก็ประมาณหารด้วยศูนย์เลย
      ถ้าดีมอน sshd ของระบบปฏิบัติการสุ่มไม่ยอมเริ่มทำงาน ผมจะถือว่านั่นเป็นสัญญาณว่าถึงเวลาย้ายไปใช้ระบบปฏิบัติการที่เสถียรกว่าแล้ว
      สิ่งที่ได้เหนือ sudo หรือ su คือ local privilege escalation exploit จะทำได้ยากขึ้นมาก
    • คอนโซล Linux หรือก็คือ tty ที่ปรากฏบนจอท้องถิ่นหรือ KVM ระยะไกล รวมถึงอุปกรณ์ ttyS* ของพอร์ตอนุกรมและ IPMI SoL ไม่ได้ใช้ sudo หรือ su
      คอนโซลพวกนี้ใช้โปรแกรมอย่าง getty หรือ window manager และสิ่งเหล่านี้เป็นโปรแกรมที่ไม่ใช่ suid ซึ่งเริ่มด้วย root
      สำหรับการล็อกอินผ่านคอนโซล ควรตั้ง รหัสผ่าน root ไว้
    • ในกรณีของผม ใช้ setuid/sudo เพราะต้องการ บันทึก audit log ตอนนี้แทบไม่ได้ดูแลเครื่องแบบผู้ใช้หลายคน/บริการหลายตัวแล้ว และส่วนที่เป็น multi-tenant ส่วนใหญ่เป็น k8s ดังนั้นใช้เอนด์พอยต์ kubectl แทน ssh ก็พอ
      ถ้าล็อกอินได้ ก็ให้ setuid เป็น root ได้ ถ้าเป็นเครื่อง k8s นั่นคือทีมโครงสร้างพื้นฐานแพลตฟอร์ม ส่วนการเข้าถึงบริการที่อยู่บนมันจะผ่านผู้ให้สิทธิ์ของ k8s
      จากมุมของทีมโครงสร้างพื้นฐานแพลตฟอร์ม ถ้าต้องการแค่เมตริกและล็อก มันก็อยู่นอกเครื่องอยู่แล้ว และถ้าต้องทริกเกอร์งานหรือเวิร์กโฟลว์บางอย่าง ก็ใช้ pipeline ได้
      แต่ถ้ายังมีใครล็อกอินเข้าไปทำงานเป็น root ผมก็อยากให้มี audit log เหลือไว้
      นึกไม่ออกเลยว่าในบรรดาเครื่องที่ผมมี จะมีกรณีไหนที่คนที่มีสิทธิ์ล็อกอินไม่ได้มีสิทธิ์ root ทั้งหมด
      แน่นอนว่าผมเข้าใจกรณีที่บริการทำ setuid แต่สำหรับบริการ โดยทั่วไป systemd จะทำ setuid เพื่อปรับสิทธิ์ให้ต่ำลง ไม่ใช่ยกระดับสิทธิ์ขึ้น
    • ถ้าเข้าถึง bootloader ได้ ก็ยังตั้ง systems.unit=emergency.target, init=/bin/bash, rd.break=pre-pivot หรือบูตเข้า live CD environment ได้ ตัวเลือก กู้คืนฉุกเฉิน ทั่วไปทั้งหมดยังทำงาน
      ถ้าเป็นสถานการณ์ฉุกเฉินที่ไม่ร้ายแรงนัก ก็ไม่เห็นเหตุผลว่าอินสแตนซ์ sshd นี้ต้องผูกกับเครือข่ายด้วย
  • น่าเสียดายเล็กน้อยที่ไม่ได้รวมข้อเสียทั้งหมดของแนวทางนี้ไว้ด้วย sudo สามารถควบคุมได้ว่ากลุ่มไหนรันคำสั่งใดได้ คำสั่งนั้นรับอาร์กิวเมนต์อะไรได้บ้าง จะอนุญาตให้สร้าง subshell หรือไม่ ฯลฯ
    วิธีนี้เสีย การควบคุมแบบละเอียด ไปมาก และต้องพึ่งพาคีย์ที่เชื่อถือ ซึ่งจัดการยากกว่าการแก้ไฟล์ sudoers
    ถ้าอยากเห็นความสามารถอันน่าทึ่งที่ sudo ทำได้ ผมขอแนะนำหนังสือ Sudo Mastery จริง ๆ

    • SSH ก็ทำบางส่วนในนั้นได้ด้วย ForceCommand แต่ผมเห็นด้วยว่ามันไม่ได้ยืดหยุ่นหรือแม่นยำเท่ากัน
  • นี่เป็นแนวคิดคล้ายกับ run0 ของ Systemd: https://news.itsfoss.com/systemd-run0/

    • และ run0 ไม่ใช่วิธีแก้ขัดชั่วคราวที่ทำเอง มันผ่านการ audit แล้ว และน่าจะดีกว่าสิ่งที่ทำเอง
  • หนึ่งในปัญหาของ ssh คือ การสร้างโปรเซส ไม่ได้เป็นส่วนหนึ่งของโปรโตคอล และเพราะเป็นโปรโตคอลระยะไกล จึงส่งต่อทรัพยากรภายในเครื่องไปยังกระบวนการลูกไม่ได้
    ดังนั้นจึงส่งอาร์เรย์อาร์กิวเมนต์ที่คั่นด้วย null หรือส่ง file descriptor เพิ่มเติม หรือระบุไฟล์ executable ไม่ได้
    แทนที่จะเป็นอย่างนั้น มันส่งสตริงเดียวให้เชลล์ที่ตั้งไว้บนเซิร์ฟเวอร์ ทำให้ต้องมีการ escape ของเชลล์ และต้องรู้ด้วยว่าฝั่งเซิร์ฟเวอร์ใช้เชลล์อะไร
    ถ้าจะใช้ SSH เป็นตัวแทน sudo ที่เหมาะสมจริง ๆ จำเป็นต้องมีส่วนขยายที่ใกล้เคียงกับ posix_spawn

  • เห็นด้วยอย่างยิ่ง ผมก็ทำอะไรคล้าย ๆ กันอยู่ และเคยอธิบายไว้ในคอมเมนต์ HN มาก่อน
    วิธีของผมต่างออกไปเล็กน้อย ผมใช้เครื่องเฉพาะเป็น คอนโซล SSH ทางกายภาพ และเครื่องนี้อยู่ใน LAN ส่วนตัวที่แยกจากเครื่องอื่น ๆ ในบ้าน ไม่ใช่สวิตช์แบบ managed แต่เป็นสวิตช์ธรรมดา ใช้สายอีเทอร์เน็ต และไม่มี trunk
    ล็อกอินได้ผ่าน SSH เท่านั้น และผมต่อ Yubikey ไว้กับมัน
    เดสก์ท็อป PC มีไฟร์วอลล์ของตัวเอง และอนุญาตเฉพาะทราฟฟิก SSH ที่มาจาก IP/MAC address ของคอนโซล SSH นี้ เฉพาะบน LAN ส่วนตัวที่ทั้งสองใช้ร่วมกันเท่านั้น ส่วนบน LAN กายภาพอื่น เดสก์ท็อปยังเข้าถึงอินเทอร์เน็ตได้
    ดีมอน sshd อนุญาตเฉพาะการล็อกอินด้วย public/private key และปิดการล็อกอินด้วยรหัสผ่านไว้
    เมื่อต้องการ root ก็เปิดบูต “คอนโซล SSH” เครื่องนี้ เป็นเครื่องที่แทบไม่มีอะไรเลยจึงเปิดติดเร็วมาก ล็อกอินแล้วกดลูกศรขึ้นเพื่อเรียกบรรทัด ssh root@... กลับมา กด Enter แล้วแตะ Yubikey
    คอนโซล SSH เครื่องนั้นกับคีย์บอร์ดอยู่บนโต๊ะ อยู่ในระยะเอื้อมมือตลอด
    iptables/nftables + sshd บน LAN ส่วนตัวที่ยังแยกทางกายภาพจาก LAN ส่วนตัวอื่น ๆ ปลอดภัยกว่าหรือน้อยกว่าไบนารี sudo หรือ su ก็ให้แต่ละคนตัดสินเอง
    ถ้าถามว่า “ทำไม” ผมคงตอบว่า “เพราะทำได้” ตั้งค่าไว้นานมากแล้วจนจำไม่ได้ว่าทำเมื่อไหร่ อาจจะเริ่มลองเล่นกับไอเดียนี้ราว 2 ปีก่อน และใช้มาตลอดตั้งแต่นั้น ไม่มีปัญหาเลย

    • แม้การตั้งค่าที่มีจะไม่เหมือนกันเป๊ะ แต่ดูคล้ายแนวคิด bastion host
  • เป็นวิธีแก้ปัญหานี้ที่งดงาม ไม่จำเป็นต้องปฏิบัติกับผู้ใช้เหมือนเด็ก แต่ในขณะเดียวกันก็ควรหลีกเลี่ยงความผิดพลาดที่อาจเกิดขึ้นด้วยค่าเริ่มต้นที่สมเหตุสมผล
    ถ้าต้องการ root ก็ล็อกอินเป็น root ผ่านคอนโซลได้ ดังนั้นผมคิดว่าแม้แต่ su ก็ไม่จำเป็น วิธีนี้ใกล้เคียงกับการล็อกอินเป็น root บน console tty มากที่สุด

    • วิธีที่ว่า ถ้าต้องการ root ก็ให้ล็อกอินเป็น root ผ่านคอนโซล มีปัญหาอยู่สองข้อ
      ข้อแรก ต่างจาก sudo ผู้ใช้ทุกคนต้องรู้ รหัสผ่าน root
      ข้อสอง ถ้าทุกคนล็อกอินเป็น root ไปเลย ก็ไม่มีทาง audit ได้ว่าใครล็อกอินเข้ามาและทำอะไร
  • เคยลองทำอะไรคล้าย ๆ กันเมื่อ 10 ปีก่อน ไม่มีส่วนของ UNIX socket และเปิด sshd แยกต่างหากที่ฟังเฉพาะบน localhost จึงไม่จำเป็นต้องจัดการกับ SCM_RIGHTS
    ก็ไม่ได้มีผลลัพธ์ที่ดีหรือแย่อะไรเป็นพิเศษ แค่หมดความสนใจ แล้วก็ไม่ได้ย้ายการตั้งค่านี้ไปยังเครื่องถัดไป