SSH key: ตั้งค่าการล็อกอินเซิร์ฟเวอร์โดยไม่ใช้รหัสผ่าน
การตั้งค่า SSH key มีสามขั้นตอน: สร้างคู่กุญแจด้วย ssh-keygen -t ed25519 คัดลอกกุญแจสาธารณะไปยังเซิร์ฟเวอร์ด้วย ssh-copy-id user@host แล้วทดสอบการล็อกอิน จากนั้นปิดการล็อกอินด้วยรหัสผ่านใน /etc/ssh/sshd_config (PasswordAuthentication no) และกำหนดการเชื่อมต่อที่ใช้บ่อยไว้ใน ~/.ssh/config
SSH key คือไฟล์คู่หนึ่ง กุญแจส่วนตัวเก็บไว้ที่เครื่องของคุณ ส่วนกุญแจสาธารณะถูกวางบนเซิร์ฟเวอร์ เมื่อเชื่อมต่อ เซิร์ฟเวอร์จะตรวจว่าคุณมีกุญแจส่วนตัวที่คู่กับกุญแจสาธารณะที่อนุญาตหรือไม่ ถ้ามีก็อนุญาตให้เข้าโดยไม่ต้องใช้รหัสผ่าน วิธีนี้สะดวกและปลอดภัยกว่ารหัสผ่านมาก เพราะแทบเป็นไปไม่ได้ที่จะเดากุญแจด้วยการลองทุกค่า ด้านล่างเป็นคู่มือการตั้งค่า SSH key ตั้งแต่การสร้างจนถึงการปิดการล็อกอินด้วยรหัสผ่าน พร้อมอธิบายข้อผิดพลาดที่พบบ่อยที่สุด
การยืนยันตัวตนด้วยกุญแจทำงานอย่างไร
กุญแจเป็นแบบอสมมาตร กุญแจสาธารณะ (id_ed25519.pub) เปิดเผยให้ใครก็ได้ได้ โดยไม่สามารถย้อนกลับไปหากุญแจส่วนตัวได้ กุญแจส่วนตัว (id_ed25519) จะไม่ออกจากเครื่องของคุณ และไม่ถูกส่งผ่านเครือข่าย
เมื่อล็อกอิน client จะแจ้งเซิร์ฟเวอร์ว่าต้องการใช้กุญแจใด เซิร์ฟเวอร์จะค้นหากุญแจสาธารณะนั้นในไฟล์ ~/.ssh/authorized_keys ของผู้ใช้ และถ้าพบ จะขอให้ client ลงลายเซ็นข้อมูลของเซสชันด้วยกุญแจส่วนตัว ลายเซ็นจะถูกตรวจด้วยกุญแจสาธารณะ และอนุญาตให้ล็อกอิน รหัสผ่านไม่ถูกส่งไปเลย
ขั้นที่ 1. สร้างกุญแจ: ssh-keygen
บนเครื่องของคุณ (Linux, macOS หรือ Windows 10/11 ที่มี OpenSSH) รัน:
ssh-keygen -t ed25519 -C "alena@laptop"
ตัวเลือก -t กำหนดอัลกอริทึม -C คือคอมเมนต์ที่จะติดอยู่ท้ายกุญแจสาธารณะ ช่วยให้จำได้ว่าเป็นของใคร Ed25519 เป็นอัลกอริทึมสมัยใหม่ที่แนะนำ กุญแจสั้น เร็ว และปลอดภัย หากเซิร์ฟเวอร์เก่ามากและไม่รองรับ Ed25519 ใช้ RSA ที่ความยาวอย่างน้อย 3072 บิต: ssh-keygen -t rsa -b 4096
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alena/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alena/.ssh/id_ed25519
Your public key has been saved in /home/alena/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:Xq3v0m6c1y2pVv8m3N0uYv9yQm0e6dFv5gH2rZt1aBc alena@laptop
ต้องตั้ง passphrase หรือไม่
passphrase เข้ารหัสกุญแจส่วนตัวบนดิสก์ หากแล็ปท็อปถูกขโมยหรือไฟล์รั่วไหล กุญแจก็ไร้ประโยชน์หากไม่มี passphrase สำหรับกุญแจส่วนตัวควรตั้ง และเพื่อไม่ต้องพิมพ์ทุกครั้งที่เชื่อมต่อ ให้ใช้ ssh-agent ซึ่งเก็บกุญแจที่ถอดรหัสแล้วไว้ในหน่วยความจำจนจบเซสชัน
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l # รายการกุญแจที่โหลดไว้
กุญแจที่ไม่มี passphrase เหมาะกับงานอัตโนมัติ เช่น CI หรือ script สำรองข้อมูลเท่านั้น และควรจำกัดสิทธิ์ของกุญแจนั้นบนเซิร์ฟเวอร์ (ดูด้านล่าง)
ขั้นที่ 2. คัดลอกกุญแจสาธารณะไปยังเซิร์ฟเวอร์: ssh-copy-id
วิธีที่ง่ายที่สุดคือ ssh-copy-id คำสั่งจะเชื่อมต่อด้วยรหัสผ่านเป็นครั้งสุดท้าย เพิ่มกุญแจสาธารณะของคุณลงใน ~/.ssh/authorized_keys บนเซิร์ฟเวอร์ และตั้งสิทธิ์ให้ถูกต้อง
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@203.0.113.10
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/alena/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
deploy@203.0.113.10's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'deploy@203.0.113.10'"
and check to make sure that only the key(s) you wanted were added.
หากเซิร์ฟเวอร์ใช้พอร์ตที่ไม่ใช่มาตรฐาน เพิ่ม -p 2222
หากไม่มี ssh-copy-id
บน Windows ไม่มีคำสั่ง ssh-copy-id สามารถส่งกุญแจด้วยตนเองได้ด้วยคำสั่งเดียว:
cat ~/.ssh/id_ed25519.pub | ssh deploy@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
ผู้ให้บริการคลาวด์มักให้ระบุกุญแจสาธารณะตั้งแต่ตอนสร้างเซิร์ฟเวอร์ กุญแจจะถูกใส่ใน authorized_keys ผ่าน cloud-init
ขั้นที่ 3. ทดสอบการล็อกอิน
ssh deploy@203.0.113.10
หากไม่ถามรหัสผ่านอีก (หรือถามเฉพาะ passphrase ของกุญแจ) ก็ใช้งานได้แล้ว การเชื่อมต่อครั้งแรกกับเซิร์ฟเวอร์ใหม่ SSH จะแสดงลายนิ้วมือของกุญแจโฮสต์และถามว่าจะเชื่อถือหรือไม่ เมื่อตอบ yes ลายนิ้วมือจะถูกบันทึกใน ~/.ssh/known_hosts และหลังจากนั้น SSH จะเตือนหากกุญแจของเซิร์ฟเวอร์เปลี่ยน
หากต้องการดูว่า client ลองกุญแจใดบ้างและเซิร์ฟเวอร์ปฏิเสธเพราะอะไร เชื่อมต่อด้วยโหมดรายละเอียด:
ssh -v deploy@203.0.113.10
ไฟล์ ~/.ssh/config: ชื่อสั้นสำหรับเซิร์ฟเวอร์
เมื่อมีเซิร์ฟเวอร์หลายเครื่อง การพิมพ์ชื่อผู้ใช้ IP พอร์ต และพาธของกุญแจทุกครั้งเป็นเรื่องน่าเบื่อ ทั้งหมดนี้กำหนดได้ใน ~/.ssh/config:
Host prod
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host bastion
HostName bastion.example.com
User alena
Host db-internal
HostName 10.0.0.15
User admin
ProxyJump bastion
Host *
ServerAliveInterval 60
AddKeysToAgent yes
หลังจากนี้เพียงพิมพ์ ssh prod และ scp rsync กับ Git ก็เข้าใจชื่อเหล่านี้ด้วย เช่น rsync -av ./site/ prod:/var/www/
IdentitiesOnly yes— ใช้เฉพาะกุญแจที่ระบุ หากไม่มีบรรทัดนี้ client จะลองทุกกุญแจใน agent และเซิร์ฟเวอร์อาจตัดการเชื่อมต่อเพราะพยายามเกินจำนวนที่กำหนดก่อนจะถึงกุญแจที่ถูกต้องProxyJump— เชื่อมต่อเซิร์ฟเวอร์ภายในผ่านเซิร์ฟเวอร์กลาง (bastion) ด้วยคำสั่งเดียวServerAliveInterval— ส่งสัญญาณ "ping" ทุก 60 วินาที เพื่อไม่ให้การเชื่อมต่อขาดเมื่อไม่มีการใช้งาน
ไฟล์นี้ต้องมีสิทธิ์ 600 มิฉะนั้น SSH อาจปฏิเสธการอ่าน: chmod 600 ~/.ssh/config
Agent forwarding: เมื่อไรควรใช้และอันตรายอย่างไร
บางครั้งจากเซิร์ฟเวอร์ต้องเชื่อมต่อต่อไปยังที่อื่น เช่น git pull จากรีโพซิทอรีส่วนตัว ห้ามคัดลอกกุญแจส่วนตัวไปยังเซิร์ฟเวอร์ แต่ให้ใช้ ssh -A หรือ ForwardAgent yes เซิร์ฟเวอร์จะเข้าถึง agent ของคุณได้ตลอดเซสชัน แต่ผู้ที่มีสิทธิ์ root บนเซิร์ฟเวอร์นั้นก็สามารถใช้ agent ได้ในช่วงที่คุณเชื่อมต่ออยู่ ดังนั้นเปิดการ forward เฉพาะกับโฮสต์ที่เชื่อถือได้ และสำหรับการผ่านเซิร์ฟเวอร์กลางควรใช้ ProxyJump เพราะไม่เปิด agent
ขั้นที่ 4. ปิดการล็อกอินด้วยรหัสผ่าน
ตราบใดที่ยังอนุญาตรหัสผ่าน เซิร์ฟเวอร์ยังเป็นเป้าของการเดารหัสผ่าน เมื่อแน่ใจแล้วว่าล็อกอินด้วยกุญแจได้ ให้ปิดรหัสผ่าน สำคัญมาก: อย่าปิดเซสชันปัจจุบัน จนกว่าจะทดสอบการล็อกอินในหน้าต่างใหม่แล้ว มิฉะนั้นคุณอาจเข้าเซิร์ฟเวอร์ไม่ได้
เปิด /etc/ssh/sshd_config (หรือสร้างไฟล์ใน /etc/ssh/sshd_config.d/ หากไฟล์หลักมี Include) และตั้งค่า:
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
PermitRootLogin no ห้ามการล็อกอินด้วย root โดยสิ้นเชิง ผู้ดูแลระบบจะล็อกอินด้วยบัญชีของตนเองและยกระดับสิทธิ์ด้วย sudo หากไม่สามารถยกเลิกการล็อกอินด้วย root ได้ ใช้ PermitRootLogin prohibit-password ซึ่งอนุญาตเฉพาะด้วยกุญแจ
ตรวจไวยากรณ์และรีสตาร์ตบริการ:
sudo sshd -t
sudo systemctl reload ssh # บน Debian/Ubuntu; บนตระกูล RHEL ใช้ sshd
คำสั่ง sshd -t จะไม่แสดงอะไรหากการตั้งค่าถูกต้อง จากนั้นในเทอร์มินัลใหม่ ตรวจว่าการล็อกอินด้วยกุญแจยังใช้ได้ และการล็อกอินด้วยรหัสผ่านถูกเซิร์ฟเวอร์ปฏิเสธ:
$ ssh -o PubkeyAuthentication=no deploy@203.0.113.10
deploy@203.0.113.10: Permission denied (publickey).
การป้องกันเพิ่มเติม
การปิดรหัสผ่านเป็นมาตรการหลัก หลังจากนั้นมักจำกัดพอร์ต 22 ด้วยไฟร์วอลล์ (ufw allow from 198.51.100.0/24 to any port 22) และติดตั้ง fail2ban ซึ่งบล็อก IP หลังจากพยายามล็อกอินล้มเหลวหลายครั้ง สถานะการป้องกัน SSH ดูได้ด้วย sudo fail2ban-client status sshd
กุญแจสำหรับงานอัตโนมัติจำกัดได้ใน authorized_keys ด้วยตัวเลือกที่วางไว้หน้ากุญแจ เช่น from="198.51.100.7",no-port-forwarding,no-pty ssh-ed25519 AAAA... backup อนุญาตการล็อกอินจากที่อยู่เดียวและไม่เปิด shell แบบโต้ตอบ
ข้อผิดพลาดที่พบบ่อยและวิธีแก้
Permission denied (publickey)
เป็นข้อผิดพลาดที่พบบ่อยที่สุด สาเหตุเรียงจากพบบ่อยไปหาน้อย:
- สิทธิ์ไม่ถูกต้องบนเซิร์ฟเวอร์ sshd จะไม่สนใจ
authorized_keysหากไดเรกทอรีหรือไฟล์เขียนได้โดยผู้อื่น วิธีแก้:chmod 700 ~/.sshและchmod 600 ~/.ssh/authorized_keysและไดเรกทอรีโฮมต้องไม่ให้กลุ่มหรือผู้อื่นเขียนได้ - เจ้าของไม่ถูกต้อง หากคุณสร้างไฟล์ด้วย
sudoไฟล์จะเป็นของ root วิธีแก้:sudo chown -R deploy:deploy /home/deploy/.ssh - กุญแจถูกวางให้ผู้ใช้ผิดคน คุณคัดลอกกุญแจให้
rootแต่ล็อกอินด้วยdeployหรือกลับกัน - client ส่งกุญแจผิด ดู
ssh -vบรรทัดOffering public keyจะแสดงกุญแจที่กำลังลอง ระบุกุญแจที่ถูกต้องด้วย-iหรือIdentityFile - กุญแจเสียหายจากการคัดลอก กุญแจสาธารณะต้องอยู่บรรทัดเดียว การขึ้นบรรทัดใหม่ตอนวางจาก clipboard จะทำให้กุญแจใช้ไม่ได้
สาเหตุฝั่งเซิร์ฟเวอร์จะแสดงใน log: sudo journalctl -u ssh -n 30 (บน RHEL ใช้ -u sshd) อาจพบข้อความเช่น Authentication refused: bad ownership or modes for directory /home/deploy/.ssh
UNPROTECTED PRIVATE KEY FILE
client ปฏิเสธการใช้กุญแจส่วนตัวที่ผู้อื่นสามารถอ่านได้ วิธีแก้: chmod 600 ~/.ssh/id_ed25519
REMOTE HOST IDENTIFICATION HAS CHANGED
กุญแจของโฮสต์ไม่ตรงกับที่บันทึกไว้ใน known_hosts อาจเกิดหลังติดตั้งเซิร์ฟเวอร์ใหม่หรือเปลี่ยน IP แต่หน้าตาเหมือนการโจมตีแบบ man-in-the-middle ทุกประการ ตรวจให้แน่ใจว่าเซิร์ฟเวอร์ถูกติดตั้งใหม่จริง แล้วลบรายการเก่า: ssh-keygen -R 203.0.113.10
Too many authentication failures
agent ส่งกุญแจให้เซิร์ฟเวอร์มากเกินไป และเซิร์ฟเวอร์ปิดการเชื่อมต่อตาม MaxAuthTries วิธีแก้คือ IdentitiesOnly yes และ IdentityFile ที่ชัดเจนใน ~/.ssh/config
สรุป
การตั้งค่า SSH key ใช้เวลาห้านาที: ssh-keygen -t ed25519 ssh-copy-id ทดสอบการล็อกอิน จากนั้น PasswordAuthentication no และรีสตาร์ต sshd ขณะที่ยังมีเซสชันที่สองเปิดอยู่ ไฟล์ ~/.ssh/config ช่วยให้ไม่ต้องพิมพ์คำสั่งยาว และสิทธิ์ 700/600 แก้ข้อผิดพลาด "Permission denied" ได้ส่วนใหญ่ SSH, rsync และการป้องกันเซิร์ฟเวอร์ด้วยไฟร์วอลล์และ fail2ban ถูกสอนแบบลงมือทำในหลักสูตร Linux
คำถามที่พบบ่อย
ใช้กุญแจ SSH เดียวกันกับทุกเซิร์ฟเวอร์ได้ไหม?
ทำได้ในทางเทคนิค และหลายคนทำเช่นนั้น แต่สำหรับขอบเขตที่ต่างกัน (งาน โปรเจกต์ส่วนตัว CI) ควรสร้างกุญแจแยกกัน หากกุญแจหนึ่งรั่วไหล จะไม่เปิดทางเข้าสู่ทุกระบบ
กุญแจ SSH บน Windows เก็บไว้ที่ไหน?
OpenSSH ที่มาพร้อมระบบเก็บไว้ที่ C:\Users\ชื่อคุณ\.ssh\ ได้แก่ id_ed25519, id_ed25519.pub, known_hosts และ config สร้างกุญแจด้วยคำสั่ง ssh-keygen เดียวกันใน PowerShell
จะเปลี่ยน passphrase ของกุญแจที่มีอยู่แล้วอย่างไร?
รัน ssh-keygen -p -f ~/.ssh/id_ed25519 คำสั่งจะถามทั้ง passphrase เดิมและใหม่ ตัวกุญแจไม่เปลี่ยน ไม่ต้องนำไปวางบนเซิร์ฟเวอร์ใหม่
จะเพิกถอนสิทธิ์การเข้าถึงด้วยกุญแจได้อย่างไร?
ลบบรรทัดที่มีกุญแจสาธารณะนั้นออกจาก ~/.ssh/authorized_keys บนเซิร์ฟเวอร์ คอมเมนต์ท้ายกุญแจช่วยให้หาบรรทัดที่ถูกต้องได้ง่าย
ถ้ามีเฉพาะกุญแจส่วนตัว จะได้กุญแจสาธารณะคืนมาอย่างไร?
คำสั่ง ssh-keygen -y -f ~/.ssh/id_ed25519 จะแสดงกุญแจสาธารณะที่คำนวณจากกุญแจส่วนตัว
หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Linux: с нуля до уверенного администрирования”
- Удалённый доступ и сетевые хранилища: SSH, rsync, NFS и SMB
- Firewall и защита сервера: ufw, nftables, fail2ban и GPG