ใบรับรอง SSH: ประสบการณ์ SSH ที่ดีกว่า
(jpmens.net)- ใบรับรอง SSH ช่วยแก้ความยุ่งยากของ การยืนยันตัวตน SSH แบบอิงกุญแจสาธารณะ แบบเดิม และมอบ ความเชื่อถืออัตโนมัติ ระหว่างไคลเอนต์กับเซิร์ฟเวอร์
- รองรับตั้งแต่ OpenSSH 5.4 โดย CA (หน่วยงานออกใบรับรอง) จะลงนามคีย์ของผู้ใช้และโฮสต์ ทำให้ยืนยันตัวตนได้โดยไม่ต้องแก้
authorized_keys - ในใบรับรองสามารถระบุ ระยะเวลาที่มีผล, ผู้ใช้ที่อนุญาต (principal), IP ที่เข้าถึงได้, คำสั่งบังคับ (force-command) เป็นต้น เพื่อรองรับการควบคุมสิทธิ์การเข้าถึงอย่างละเอียด
- ตัดขั้นตอน TOFU (Trust on First Use) ออกไป และเมื่อมีการเปลี่ยนโฮสต์คีย์ก็ยังเชื่อมต่อได้อย่างปลอดภัยโดยไม่มีคำเตือน
- หากใช้เซิร์ฟเวอร์หรือตัวมือช่วยลงนามอัตโนมัติ ก็จะช่วย ทำให้การจัดการ SSH ในสภาพแวดล้อมเซิร์ฟเวอร์ขนาดใหญ่เป็นอัตโนมัติ และเพิ่มความปลอดภัยได้
ภาพรวมของใบรับรอง SSH และข้อจำกัดของการยืนยันตัวตนด้วยคีย์ SSH แบบเดิม
- เมื่อเชื่อมต่อ SSH ไปยังเซิร์ฟเวอร์ที่ไม่เคยเข้ามาก่อน ต้องตรวจสอบ ลายนิ้วมือโฮสต์คีย์ (fingerprint) ของเซิร์ฟเวอร์ และผู้ใช้ส่วนใหญ่มักไม่ตรวจสอบจริงแต่พิมพ์
yesเลย ซึ่งเป็นแนวทางแบบ TOFU (Trust on First Use)- ผู้ดูแลระบบสามารถตรวจสอบลายนิ้วมือของเซิร์ฟเวอร์โดยตรง หรือใช้คำสั่ง
ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_keyเพื่อตรวจสอบได้
- ผู้ดูแลระบบสามารถตรวจสอบลายนิ้วมือของเซิร์ฟเวอร์โดยตรง หรือใช้คำสั่ง
- การยืนยันตัวตนแบบอิงกุญแจสาธารณะช่วยให้เชื่อมต่อได้โดยไม่ต้องใช้รหัสผ่าน แต่ต้องกระจายกุญแจสาธารณะไปไว้ในไฟล์
authorized_keysของแต่ละเซิร์ฟเวอร์ - หากใช้ SSH agent (
ssh-agent) ก็สามารถเก็บกุญแจส่วนตัวไว้ในหน่วยความจำและยืนยันตัวตนซ้ำได้โดยไม่ต้องป้อนทุกครั้ง - ข้อจำกัดของวิธีเดิม
- ต้องคัดลอกกุญแจสาธารณะไปยังเซิร์ฟเวอร์สำหรับผู้ใช้แต่ละคน
- เมื่อมีการเปลี่ยนโฮสต์คีย์ ฝั่งไคลเอนต์จะมี ข้อความเตือน ปรากฏขึ้น
- การจัดการความเชื่อถือทำได้ไม่สะดวกเพราะอาศัย TOFU
ใบรับรอง SSH และ CA (หน่วยงานออกใบรับรอง)
- ใบรับรอง SSH (Certificate) รองรับตั้งแต่ OpenSSH 5.4 (มีนาคม 2010) และเป็นโครงสร้างที่ขยายจากฟอร์แมตคีย์ SSH เดิม
- SSH CA ประกอบด้วย คู่คีย์ SSH โดยกุญแจสาธารณะทำหน้าที่เป็นรากความเชื่อถือ
- ข้อดีหลัก
- ไม่จำเป็นต้องแก้ไฟล์
authorized_keysของเซิร์ฟเวอร์ - ไม่มีคำเตือนเมื่อเปลี่ยนโฮสต์คีย์
- สร้าง ความเชื่อถืออัตโนมัติ ได้ด้วยการตัดขั้นตอน TOFU
- ในใบรับรองสามารถใส่ ผู้ใช้ที่อนุญาต (principal), IP ที่อนุญาต, ระยะเวลาที่มีผล, คำสั่งบังคับ (force-command) เป็นต้นได้
- เมื่อใบรับรองหมดอายุ การเข้าถึงจะถูกบล็อกโดยอัตโนมัติ
- ไม่จำเป็นต้องแก้ไฟล์
การสร้าง SSH CA และขั้นตอนการลงนาม
- บนระบบ CA ให้สร้าง คู่คีย์ CA ด้วยอัลกอริทึม ECDSA
ssh-keygen -t ecdsa -C "SSH CA" -f CA/ssh-ca
- ผู้ใช้ส่งกุญแจสาธารณะของตน (
*.pub) ไปยัง CA แล้ว CA จะ ลงนาม (sign) เพื่อออกใบรับรอง (*-cert.pub)- ตัวอย่าง:
ssh-keygen -s CA/ssh-ca -I "Jane Jolie" -n jane -z 001 -V +1w jane.pub
- ตัวอย่าง:
- การตั้งค่าเซิร์ฟเวอร์
- บันทึกกุญแจสาธารณะของ CA ไว้ที่
/etc/ssh/ssh-ca.pubและเพิ่มการตั้งค่าTrustedUserCAKeys - ลงนามโฮสต์คีย์ของเซิร์ฟเวอร์ด้วย CA (
ssh-keygen -h -s CA/ssh-ca ...) แล้วลงทะเบียนในรายการHostCertificate
- บันทึกกุญแจสาธารณะของ CA ไว้ที่
- การตั้งค่าไคลเอนต์
- เพิ่มหนึ่งบรรทัด
@cert-authorityลงในไฟล์known_hosts - ตัวอย่าง:
@cert-authority *.example.com $(cat CA/ssh-ca.pub)
- เพิ่มหนึ่งบรรทัด
การเชื่อมต่อและการตรวจสอบด้วยใบรับรอง SSH
- ผู้ใช้เชื่อมต่อโดยใช้ใบรับรองที่ลงนามแล้วร่วมกับกุญแจส่วนตัว (
ssh -i jane -l jane alice.example.com) - ในล็อกของเซิร์ฟเวอร์จะมีการบันทึก ID, serial และลายนิ้วมือของ CA ของใบรับรอง
- สามารถเพิ่มชื่อโฮสต์หรือ IP ได้หลายรายการเป็น principal ในใบรับรอง
- หากพยายามล็อกอินด้วยผู้ใช้อื่นที่ไม่อยู่ใน principal ของใบรับรอง จะเกิดข้อผิดพลาด “Certificate invalid: name is not a listed principal”
- สามารถกำหนด คำสั่งบังคับ (force-command) หรือ IP ที่อนุญาต (source-address) ในใบรับรองเพื่อควบคุมสิทธิ์การเข้าถึงอย่างละเอียดได้
เช็กลิสต์สำหรับตรวจสอบและแก้ปัญหา
-
รายการตรวจสอบฝั่งเซิร์ฟเวอร์
- มีการตั้งค่า
TrustedUserCAKeysและมีกุญแจสาธารณะของ CA อยู่จริง - มีการลงนามโฮสต์คีย์และระบุ
HostCertificateแล้ว - ต้องรีสตาร์ต
sshd
- มีการตั้งค่า
-
รายการตรวจสอบฝั่งไคลเอนต์
- คีย์ของผู้ใช้ต้องได้รับการลงนามโดย CA
- รายการ
@cert-authorityในknown_hostsและ principal ต้องตรงกัน - เมื่อใบรับรองหมดอายุ จะมีข้อความ “Certificate invalid: expired” แสดงขึ้น
- หากเงื่อนไขจำกัดของใบรับรองไม่ตรงกัน จะมีการร้องขอรหัสผ่าน
- เมื่อนำใบรับรองเข้า SSH agent จะมีการลงทะเบียนทั้งคีย์และใบรับรอง (
ssh-add jane) - สามารถควบคุมฟังก์ชันด้วยตัวเลือก (
-O) ตอนลงนาม - ตัวอย่าง: ใช้
-O clearเพื่อล้างสิทธิ์ทั้งหมดก่อน แล้วอนุญาตเฉพาะpermit-agent-forwarding,permit-port-forwarding
การทำใบรับรองโฮสต์คีย์ให้เป็นอัตโนมัติ
- ใช้โมดูล Python sshkey-tools และ BottlePy เพื่อสร้าง เซิร์ฟเวอร์ลงนามอัตโนมัติ (hkbot)
- รัน
hkbot.pyบนเซิร์ฟเวอร์ CA แล้วเมื่อต้องมีคำขอ HTTP เพื่ออัปโหลดกุญแจสาธารณะของโฮสต์ ก็จะมีการลงนามให้อัตโนมัติ - ที่ฝั่งไคลเอนต์สามารถติดตั้งอัตโนมัติได้ด้วยคำสั่ง
curl -F hostkey=@/etc/ssh/ssh_host_ed25519_key.pub http://CA:8870 | sh - แก้ไข
/etc/ssh/sshd_configและตรวจสอบแล้วจึงใช้systemctl restart sshdเพื่อให้มีผล
- รัน
- หลังจากนั้น เมื่อเชื่อมต่อ SSH ก็จะสามารถเชื่อถือและล็อกอินแบบอัตโนมัติด้วยใบรับรองได้
สรุปข้อดีของใบรับรอง SSH
- ไม่ต้องใช้ TOFU และสร้างความเชื่อถืออัตโนมัติระหว่างไคลเอนต์กับเซิร์ฟเวอร์
- ออก ใบรับรองอายุสั้น เพื่อควบคุมการเข้าถึงชั่วคราวได้
- เมื่อใบรับรองหมดอายุ การเข้าถึงจะถูกบล็อกอัตโนมัติ และไม่ต้องคอยจัดการ
authorized_keys - ตั้งค่านโยบายละเอียดได้ เช่น คำสั่งบังคับ, การจำกัด PTY, การควบคุม IP ที่เข้าถึงได้
- ใช้เครื่องมืออัตโนมัติเพื่อ ทำให้การดูแลสภาพแวดล้อมเซิร์ฟเวอร์ขนาดใหญ่ง่ายขึ้น
- แนะนำโปรเจกต์ที่เกี่ยวข้องคือ Smallstep SSH
เอกสารอ้างอิงเพิ่มเติม
- แนวทางความปลอดภัย OpenSSH ของ Mozilla
- งานวิจัยเรื่องการตรวจสอบลายนิ้วมือโฮสต์คีย์ SSH บนพื้นฐาน DNS
- เอกสารการรองรับ OpenSSH certificate ของ PuTTY และ คู่มือการตั้งค่า
อัปเดต
- SSH CA มีประโยชน์อย่างยิ่งในสภาพแวดล้อมที่ มีเซิร์ฟเวอร์ของตนเองและมีสิทธิ์ระดับ root
- ในระบบหลายผู้ใช้ วิธี
known_hostsและauthorized_keysแบบเดิมยังคงจำเป็นอยู่ - ร่างมาตรฐานฟอร์แมตใบรับรอง SSH:
draft-miller-ssh-cert-06
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
น่าแปลกใจที่คนยังใช้ รหัสผ่าน SSH กันอยู่
โดยเฉพาะในสภาพแวดล้อมองค์กรใหญ่ที่มีนโยบายรหัสผ่านหลายชุดพันกันอยู่ ทำให้แค่จะเข้าเซิร์ฟเวอร์ก็เสียเวลาแล้ว
เพราะงั้นต่อให้บอกให้ใช้คีย์ด้วย
ssh-keygenคนส่วนใหญ่ก็มักจะคิดว่า “ไว้วันหลังค่อยทำ” แล้วสุดท้ายก็ไม่ทำแต่ในความเป็นจริงก็มักจัดการกันเละ เช่น ใช้คีย์สาธารณะอันเดียวกับหลายเซิร์ฟเวอร์ หรือแชร์คีย์กันไปมา
อย่างน้อยรหัสผ่านก็มีข้อดีตรงที่เรียบง่าย
ไม่มีรหัสผ่าน แต่ตอนล็อกอินต้องแตะ Yubikey จริง ๆ
ทุก ๆ ไม่กี่เดือนก็จะมีคนค้นพบ ใบรับรอง SSH ใหม่อีกครั้งแล้วเขียนบล็อกถึงมัน
ฉันเองก็เคยเขียนบทความเกี่ยวกับเรื่องนี้เมื่อ 15 ปีก่อน แต่ตอนนี้กลับไปดูแล้วก็ยังไม่ดีพอ
แม้แต่วิศวกรความปลอดภัยเองก็ยังลืมว่าตัวเองใช้การยืนยันตัวตนด้วยคีย์ ไม่ใช่ใบรับรอง SSH
การต้องจัดการคีย์ของหลายเซิร์ฟเวอร์ด้วยมือนั้นยุ่งยากเกินไป
ตอนนี้ก็กำลังคิดอยู่ว่าย้ายตอนนี้ยังจะคุ้มไหม
วิธีแบบ TOFU (Trust On First Use) นั้นเรียบง่าย แต่ก็ไปได้ไกลพอสมควร
บนเซิร์ฟเวอร์ของฉัน พอตรวจสอบ host key ด้วยตัวเองครั้งหนึ่งแล้วก็ถือว่าเพียงพอ
ในสภาพแวดล้อมองค์กรใหญ่ แค่เอารายการ public key ของเซิร์ฟเวอร์ภายในไปลงไว้บนเว็บภายในที่เซ็นด้วย SSL ก็พอ
แต่ถ้ามีเซิร์ฟเวอร์จำนวนมากหรือมีการเปลี่ยนบ่อย ใบรับรองจะดีกว่ามาก และ TOFU ก็มีข้อจำกัดในหลายด้าน
อยากให้เบราว์เซอร์มีฟีเจอร์แจ้งเตือนเวลาคีย์ TLS ของเซิร์ฟเวอร์เปลี่ยนด้วย
ส่วนใหญ่ก็แค่พิมพ์ “yes” แล้วผ่านไป
ที่บริษัทเสียทั้งเวลาและเงินไปมหาศาลเพราะ การตรวจสอบ SSL ของ Zscaler
พอขึ้น error ว่า “self-signed certificate in certificate chain” ทีไรก็ปวดหัวทุกที
มันฝัง root certificate ของตัวเอง และล็อกการตั้งค่าเบราว์เซอร์เพื่อไม่ให้ใช้พร็อกซีได้
ต่อให้แก้ไฟล์ตั้งค่าของ Firefox หรือ Chrome มันก็เขียนทับกลับทันที
ขนาดจะปิดจาก GUI ยังต้องมีรหัสผ่านของฝ่าย IT
พูดได้แค่ว่าดีกว่าแอนติไวรัส Cybereason นิดหน่อย
มันทำให้โปรโตคอลที่อิง HTTP พังไปหมด
ทั้ง Git, RubyGems, go mod, Nix และเครื่องมืออีกมากมายใช้ไม่ได้
ผู้ขายบอกว่า “โปร่งใส” แต่ในความเป็นจริงไม่โปร่งใสเลย
ต้องเสียเวลาหลายชั่วโมงกว่าจะวินิจฉัยปัญหาได้ และผู้ดูแลส่วนใหญ่ก็ไม่รู้ว่ามันทำลายได้มากแค่ไหน
ในบทความพูดถึงแต่ข้อดีของใบรับรอง CA แต่ ข้อเสีย ก็มีอยู่ชัดเจนเหมือนกัน
ฉันไม่เคยเจอปัญหาด้านความปลอดภัยจาก TOFU เลย
ถ้าใบรับรอง SSH มีข้อเสีย อยากรู้ว่าเป็นเรื่องไหนโดยเฉพาะ
ถ้าอยากเพิ่มความปลอดภัย ก็แลก public key กันผ่าน ช่องทางที่ปลอดภัย อย่าง USB ได้
ต่อให้ใช้ใบรับรอง สุดท้ายก็ต้องผ่านขั้นตอนคล้ายกันอยู่ดี ต่างกันแค่ว่าย้ายภาระการจัดการจากผู้ใช้ไปอยู่ฝั่งผู้ดูแล
ในองค์กรขนาดใหญ่ใบรับรองอาจมีประโยชน์ แต่ในแง่ความปลอดภัยทั่วไปก็เท่าเดิม
แค่ใส่ไว้ในสคริปต์ติดตั้งหรืออิมเมจสำหรับ deploy
TOFU จะมีความหมายก็ต่อเมื่อเข้าถึงเครื่องที่ตั้งค่าไปแล้วเท่านั้น
ในสภาพแวดล้อม dev/stg ของเรา มีการลงเครื่องใหม่ครึ่งหนึ่งทุกวัน
ด้วย ใบรับรองโฮสต์ SSH เลยสะดวกขึ้นมาก เพราะไม่ต้องลบ
known_hostsหรือพยายามคงคีย์เดิมไว้ฉันกำลังทำเครื่องมือชื่อ Sshifu เป็นโปรเจกต์ส่วนตัว
มันเป็นเครื่องมือที่ทำให้การล็อกอินด้วยใบรับรอง SSH และ SSO เป็นเรื่องง่าย
ติดตั้ง
sshifu-serverบนเซิร์ฟเวอร์เพื่อใช้เป็น CA แล้วตั้งให้แต่ละเซิร์ฟเวอร์ SSH เชื่อถือ CA นี้ฝั่งผู้ใช้แค่รันคำสั่ง
npx sshifuเพื่อล็อกอินก็จบดูได้ที่ GitHub repository
ในสภาพแวดล้อมใช้งานจริง การเข้าถึงแบบอิงใบรับรองมักนำไปสู่ ปัญหาการจัดการที่ซับซ้อน
มีทั้งเรื่องใบรับรองหมดอายุ การลบผู้ใช้ การล็อกอินระหว่างเซิร์ฟเวอร์ล่ม และประเด็นอื่น ๆ อีกมาก
ที่ Userify เราจัดการปัญหาเหล่านี้มา 15 ปีแล้ว และการสร้างโครงสร้างพื้นฐานสำหรับการยืนยันตัวตนผ่าน SSH ที่เสถียรนั้นไม่ง่ายเลย
เราเพิ่มการรองรับใบรับรอง SSH ให้กับ pico.sh แล้ว และมันมีประโยชน์มากเพราะทำให้ทำ การควบคุมการเข้าถึงสไตล์ RBAC ได้
ดู เอกสาร
ในโปรดักชัน ใบรับรอง SSH กลับยิ่ง รวมศูนย์ความซับซ้อน จนทำให้ปัญหาใหญ่ขึ้น
ต้องมี CA เดี่ยวที่พร้อมใช้งานตลอดเวลา และถ้ามันล่ม การเข้าถึงทั้งหมดก็หยุดทันที
ยังมีปัญหาใช้งานจริงอีกมาก เช่น การปรับ TTL การจัดการ trust root และความยากในการดีบัก
สุดท้ายผู้คนก็มักต้องเอาแคชหรือเอเจนต์กลับมาใช้อีก
ฝั่งเราทำตรงกันข้าม โดยให้แต่ละโหนดซิงก์ข้อมูลผู้ใช้ผ่าน HTTPS ลงสู่
authorized_keysแบบโลคัลแบบนี้ยังคงการควบคุมจากศูนย์กลางได้ แต่จำกัดผลกระทบของความล่มให้อยู่เฉพาะจุด
ที่ Userify เราใช้วิธีนี้อยู่ และมันจัดการได้ทั้งการยืนยันตัวตนและการจัดการสิทธิ์
ใบรับรองอย่างเดียวไม่สามารถแก้ปัญหาอย่างการสร้างผู้ใช้ บทบาท sudo หรือการเก็บกวาด home directory ได้