SSH 2FA: ล็อกอินด้วย SSH Key คู่กับรหัส TOTP บน Linux

เปิด SSH 2FA บน Linux Server ให้ต้องใช้ทั้ง SSH Key และรหัส 6 หลักจากแอป Authenticator ด้วย libpam-google-authenticator พร้อมรหัสฉุกเฉินและวิธีไม่ล็อกตัวเองออก

โดย ทีมงาน THAI DATA CLOUD อัปเดต อ่าน 9 นาที

แชร์FacebookXLINELinkedIn
SSH 2FA — SSH 2FA: ล็อกอินด้วย SSH Key คู่กับรหัส TOTP บน Linux
SSH 2FA: ล็อกอินด้วย SSH Key คู่กับรหัส TOTP บน Linux

คำตอบสั้น ๆ: เปิด SSH 2FA บน Linux Server ให้ต้องใช้ทั้ง SSH Key และรหัส 6 หลักจากแอป Authenticator ด้วย libpam-google-authenticator พร้อมรหัสฉุกเฉินและวิธีไม่ล็อกตัวเองออก

คู่มือนี้อธิบาย SSH 2FA ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย

SSH 2FA คือการให้ผู้ดูแลยืนยันตัวตนสองชั้นก่อนเข้าเซิร์ฟเวอร์ ชั้นแรกคือ SSH Key ชั้นที่สองคือรหัส 6 หลักที่เปลี่ยนทุก 30 วินาที (TOTP) จากแอปบนมือถือ เช่น Google Authenticator หรือ Microsoft Authenticator ถ้า Private Key หลุดจากโน้ตบุ๊กที่ถูกขโมยหรือติดมัลแวร์ ผู้ไม่หวังดีก็ยังเข้าเครื่องไม่ได้ เพราะไม่มีมือถือของคุณ

คู่มือนี้ใช้โมดูล PAM pam_google_authenticator ทำงานแบบออฟไลน์ทั้งหมด ไม่ส่งข้อมูลไปที่ Google เมื่อจบคุณจะมี SSH 2FA ที่ถาม Key ก่อนแล้วจึงถามรหัส มีรหัสฉุกเฉินเก็บไว้ ยกเว้นบัญชีอัตโนมัติได้ และมีทางเข้าสำรองถ้ามือถือหาย

สิ่งที่ต้องเตรียม

  • Linux Server ที่ใช้ Ubuntu 22.04/24.04, Debian 12 หรือ AlmaLinux/Rocky Linux 9 ที่เข้าด้วย SSH Key ได้แล้ว (ดู ตั้งค่า SSH Key)
  • แอป Authenticator ที่รองรับ TOTP บนมือถือ
  • ช่องทางสำรองที่ทดสอบแล้วว่าใช้ได้ เช่น Console ผ่านหน้าเว็บของผู้ให้บริการ (ดู การ Remote เข้า Console ผ่าน Web UI) และรหัสผ่านของผู้ใช้ เพราะ Console ถามรหัสผ่าน ไม่ใช่ Key
  • นาฬิกาเครื่องที่ซิงก์เวลาแล้ว คำสั่ง timedatectl ต้องแสดง System clock synchronized: yes

คำเตือน: ขั้นตอนนี้แก้วิธีล็อกอิน SSH ให้เปิด Session ที่เป็น root ค้างไว้หนึ่งหน้าต่างตลอดการตั้งค่า และทดสอบด้วยหน้าต่างใหม่เสมอ ห้ามปิดหน้าต่างเดิมจนกว่าจะล็อกอินแบบใหม่สำเร็จ

ลำดับการล็อกอิน SSH 2FA ที่ตรวจ SSH Key ก่อน แล้วถามรหัส TOTP ผ่าน PAM ก่อนเข้า Shell
ถ้า Key ไม่ผ่าน ระบบจะไม่ถามรหัสเลย ผู้โจมตีจึงเดารหัส 6 หลักไม่ได้

ขั้นตอนที่ 1: เตรียมทางสำรองก่อนเริ่ม

sudo -i                     # หน้าต่างนี้เปิดค้างไว้
passwd admin                # ตั้งรหัสผ่านไว้ใช้กับ Console
timedatectl | grep synchronized

ก่อนเปิด SSH 2FA ให้ลองเข้า Console ผ่านหน้าเว็บด้วยรหัสผ่านนี้หนึ่งครั้ง ถ้ายังไม่ซิงก์เวลา ให้ตั้งตาม คู่มือซิงก์เวลา ก่อน เพราะ TOTP คำนวณจากเวลา ถ้านาฬิกาคลาดเกินหนึ่งนาที รหัสจะผิดตลอด

ขั้นตอนที่ 2: ติดตั้งโมดูล Google Authenticator สำหรับ PAM

# Ubuntu / Debian
sudo apt update && sudo apt install -y libpam-google-authenticator

# AlmaLinux / Rocky Linux 9
sudo dnf install -y epel-release
sudo dnf install -y google-authenticator qrencode

ขั้นตอนที่ 3: สร้าง Secret และรหัสฉุกเฉินให้ผู้ใช้

รันด้วยผู้ใช้ที่จะล็อกอิน ไม่ใช้ sudo ตัวเลือกด้านล่างคือ TOTP (-t) ห้ามใช้รหัสเดิมซ้ำ (-d) จำกัด 3 ครั้งต่อ 30 วินาที (-r 3 -R 30) และยอมให้เวลาคลาดได้หนึ่งช่วง (-w 3)

# Ubuntu / Debian
google-authenticator -t -d -f -r 3 -R 30 -w 3

# AlmaLinux / Rocky Linux 9: เก็บไว้ใน ~/.ssh เพื่อให้ SELinux อนุญาต
google-authenticator -t -d -f -r 3 -R 30 -w 3 -s ~/.ssh/google_authenticator
restorecon -Rv ~/.ssh

สแกน QR Code ด้วยแอป แล้วพิมพ์รหัส 6 หลักเพื่อยืนยัน โปรแกรมจะแสดงรหัสฉุกเฉิน (Emergency Scratch Code) 5 ชุด แต่ละชุดใช้ได้ครั้งเดียว ให้เก็บใน Password Manager หรือพิมพ์เก็บไว้ ห้ามเก็บไว้บนเซิร์ฟเวอร์เครื่องนี้ ทำซ้ำขั้นตอนนี้กับทุกผู้ใช้ที่ต้องเข้า SSH ก่อนเปิด SSH 2FA ในขั้นตอนถัดไป เพราะผู้ใช้ที่ไม่มีไฟล์ Secret จะเข้าไม่ได้เลย และควรปิด SSH ของ root (PermitRootLogin no) แล้วใช้ sudo แทน

หน้าจอคำสั่ง google-authenticator สร้าง Secret สำหรับ SSH 2FA ยืนยันรหัสและแสดงรหัสฉุกเฉิน
รหัสฉุกเฉินแสดงครั้งเดียว ให้คัดลอกไปเก็บนอกเซิร์ฟเวอร์ทันที (ค่าในภาพเป็นตัวอย่าง)

ขั้นตอนที่ 4: ให้ PAM ของ sshd ถามรหัส TOTP

แก้ไฟล์ /etc/pam.d/sshd สิ่งสำคัญคือปิดบรรทัดที่ถามรหัสผ่าน Linux ไม่เช่นนั้นระบบจะถาม Key แล้วตามด้วยรหัสผ่านและรหัส TOTP รวมสามชั้น

# Ubuntu / Debian: ใส่ # หน้าบรรทัดนี้ แล้วเพิ่มบรรทัดใหม่ใต้บรรทัดนั้น
#@include common-auth
auth required pam_google_authenticator.so

# AlmaLinux / Rocky Linux 9: ใส่ # หน้าบรรทัด password-auth แล้วเพิ่ม
#auth       substack     password-auth
auth required pam_google_authenticator.so secret=/home/${USER}/.ssh/google_authenticator

ขั้นตอนที่ 5: บังคับให้ SSH ใช้ทั้ง Key และรหัส

สร้างไฟล์ /etc/ssh/sshd_config.d/10-2fa.conf ไฟล์ในโฟลเดอร์นี้ถูกอ่านก่อน sshd_config หลัก และ sshd ใช้ค่าแรกที่เจอ ค่านี้จึงมีผลแม้ไฟล์หลักจะตั้ง KbdInteractiveAuthentication no ไว้

KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

บัญชีอัตโนมัติ เช่น Ansible หรือสคริปต์สำรองข้อมูล ไม่มีคนกดรหัสให้ ยกเว้นได้โดยเพิ่มบล็อกนี้ไว้ ท้ายสุด ของ /etc/ssh/sshd_config และควรจำกัด IP ต้นทางร่วมด้วย

Match User deploy Address 10.10.0.0/24
    AuthenticationMethods publickey

ตรวจไวยากรณ์และค่าที่มีผลจริง แล้วรีสตาร์ต SSH เพื่อเริ่มใช้ SSH 2FA (Session ที่เปิดอยู่จะไม่หลุด)

sudo sshd -t
sudo sshd -T | grep -Ei 'authenticationmethods|kbdinteractive'
sudo systemctl restart ssh      # AlmaLinux / Rocky: sudo systemctl restart sshd

ขั้นตอนที่ 6: ทดสอบจากหน้าต่างใหม่

เปิด Terminal ใหม่โดยไม่ปิดหน้าต่างเดิม แล้ว SSH เข้าตามปกติ ระบบจะยืนยัน Key ก่อน แล้วขึ้น Verification code: ให้พิมพ์รหัสจากแอป ถ้าเข้าได้แปลว่า SSH 2FA ทำงานถูกต้อง ดู Log ฝั่งเซิร์ฟเวอร์ด้วย journalctl -u ssh -n 20 (AlmaLinux/Rocky ใช้ -u sshd) ควรเห็น Partial publickey ตามด้วย Accepted keyboard-interactive/pam

หน้าจอทดสอบ SSH 2FA จากหน้าต่างใหม่ ระบบถาม Verification code หลังยืนยัน SSH Key
ข้อความ Verification code ขึ้นหลัง Key ผ่านแล้ว แปลว่าตั้งค่าสองชั้นถูกต้อง

ขั้นตอนที่ 7: เมื่อมือถือหายหรือเปลี่ยนเครื่อง

หลังเปิด SSH 2FA ถ้ามือถือหายหรือเปลี่ยนเครื่อง ให้ใช้รหัสฉุกเฉินหนึ่งชุดแทนรหัส 6 หลักเพื่อเข้าเครื่อง แล้วรัน google-authenticator ใหม่ตามขั้นตอนที่ 3 เพื่อสร้าง Secret ชุดใหม่ ชุดเดิมในมือถือที่หายจะใช้ไม่ได้ทันที ถ้ารหัสฉุกเฉินหมดหรือหาย ให้เข้า Console ผ่านหน้าเว็บด้วยรหัสผ่าน (Console ไม่ผ่าน sshd จึงไม่ถาม TOTP) แล้วสร้าง Secret ใหม่

ปัญหาที่พบบ่อยเกี่ยวกับ SSH 2FA

พิมพ์รหัสจากแอปแล้วขึ้นว่าผิดทุกครั้ง เกิดจากอะไร?

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

ทำไมระบบถามรหัสผ่าน Linux ก่อนถามรหัส TOTP?

บรรทัด @include common-auth (Ubuntu/Debian) หรือ password-auth (AlmaLinux/Rocky) ใน /etc/pam.d/sshd ยังไม่ได้ปิด กลับไปทำขั้นตอนที่ 4 ให้ครบ

SSH 2FA บน AlmaLinux หรือ Rocky Linux ไม่ผ่านทั้งที่รหัสถูก แก้อย่างไร?

มักเป็น SELinux ที่ไม่ให้ sshd อ่านหรือเขียนไฟล์ Secret ในโฟลเดอร์บ้าน ให้ย้ายไฟล์ไปไว้ใน ~/.ssh ตามขั้นตอนที่ 3 รัน restorecon -Rv ~/.ssh และตรวจด้วย sudo ausearch -m avc -ts recent ดูเพิ่มเติมที่ ใช้งาน SELinux โดยไม่ต้องปิด

Ansible หรือสคริปต์สำรองข้อมูลเข้าเครื่องไม่ได้หลังเปิด SSH 2FA ต้องทำอย่างไร?

บัญชีอัตโนมัติตอบรหัส TOTP ไม่ได้ ให้ใช้บล็อก Match User ในขั้นตอนที่ 5 ยกเว้นเฉพาะบัญชีนั้นจาก IP ที่กำหนด และให้บัญชีนั้นมีสิทธิ์เท่าที่จำเป็น

เช็กลิสต์ป้องกันการล็อกตัวเองออกระหว่างเปิด SSH 2FA บน Linux Server
ข้อสีแดงคือสาเหตุที่ทำให้ต้องพึ่ง Console บ่อยที่สุด

ถ้าต้องการวางนโยบายความปลอดภัยการเข้าถึงเซิร์ฟเวอร์ทั้งองค์กร อ่านต่อที่ เช็กลิสต์ความปลอดภัยหลังเปิด Linux Server ใหม่ หรือ ติดต่อทีมงาน THAI DATA CLOUD รายละเอียดตัวเลือกของโมดูลอยู่ที่ google-authenticator-libpam

อ่านเพิ่มเติมเกี่ยวกับ SSH 2FA

แชร์FacebookXLINELinkedIn

มีคำถามเรื่องบริการ? ติดต่อทีมงาน