คำตอบสั้น ๆ: ปิด SSH ของเซิร์ฟเวอร์ภายในไม่ให้เปิดสู่อินเทอร์เน็ต แล้วเข้าผ่านเครื่องกลางเพียงเครื่องเดียวด้วย ProxyJump พร้อมตั้งค่าใน ~/.ssh/config
คู่มือนี้อธิบาย ProxyJump ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
เมื่อระบบมีเซิร์ฟเวอร์หลายเครื่อง การเปิดพอร์ต SSH ของทุกเครื่องสู่อินเทอร์เน็ตทำให้พื้นที่ที่ถูกโจมตีได้กว้างขึ้นตามจำนวนเครื่อง วิธีที่ใช้กันในระบบงานจริงคือเปิด SSH ไว้ที่เครื่องกลางเพียงเครื่องเดียว เรียกว่า Bastion Host หรือ Jump Host แล้วให้เครื่องที่เหลือรับการเชื่อมต่อจากเครื่องกลางนั้นเท่านั้น
คู่มือนี้ตั้งค่าตั้งแต่ฝั่งเซิร์ฟเวอร์จนถึงไฟล์ config ฝั่งเครื่องคุณ ให้พิมพ์ ssh db1 แล้วเข้าได้เลยโดยไม่ต้อง SSH ซ้อนสองครั้ง
สิ่งที่ต้องเตรียม
- เซิร์ฟเวอร์อย่างน้อยสองเครื่อง เครื่องหนึ่งมี IP สาธารณะ (Bastion) และเครื่องภายในที่คุยกันได้ผ่านเครือข่ายภายใน
- SSH Key ที่ใช้อยู่แล้ว หากยังไม่มีให้สร้างด้วย
ssh-keygen -t ed25519 - OpenSSH เวอร์ชัน 7.3 ขึ้นไปบนเครื่องคุณ ซึ่งรองรับ
ProxyJumpตรวจด้วยssh -V
ขั้นตอนที่ 1: เตรียมเครื่อง Bastion
เครื่องนี้ควรทำหน้าที่เดียวคือเป็นทางผ่าน ไม่ควรรันเว็บหรือฐานข้อมูล ตั้งค่าให้แน่นที่สุด
sudo nano /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowTcpForwarding yes
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers jump
AllowTcpForwarding yes จำเป็นสำหรับการทำ Jump Host ส่วน AllowUsers จำกัดให้ล็อกอินได้เฉพาะบัญชีที่ตั้งไว้สำหรับงานนี้
sudo sshd -t && sudo systemctl reload ssh
สร้างบัญชีสำหรับใช้ผ่านเครื่องกลาง และวาง Public Key ของคุณไว้
sudo adduser --disabled-password --gecos "" jump
sudo mkdir -p /home/jump/.ssh
sudo nano /home/jump/.ssh/authorized_keys
sudo chown -R jump:jump /home/jump/.ssh
sudo chmod 700 /home/jump/.ssh
sudo chmod 600 /home/jump/.ssh/authorized_keys
ขั้นตอนที่ 2: ปิด SSH ของเครื่องภายในจากอินเทอร์เน็ต
บนเครื่องภายในแต่ละเครื่อง จำกัดให้รับ SSH เฉพาะจาก IP ภายในของ Bastion
# ตัวอย่างด้วย UFW โดย 10.0.0.5 คือ IP ภายในของ Bastion
sudo ufw allow from 10.0.0.5 to any port 22 proto tcp
sudo ufw delete allow 22/tcp
sudo ufw status numbered
หรือให้ sshd ฟังเฉพาะการ์ดเครือข่ายภายใน ซึ่งปลอดภัยกว่าเพราะไม่ต้องพึ่ง Firewall อย่างเดียว
sudo nano /etc/ssh/sshd_config
ListenAddress 10.0.0.11
sudo sshd -t && sudo systemctl restart ssh
sudo ss -tlnp | grep :22
อย่าเพิ่งปิดช่องทางเดิมจนกว่าจะทดสอบเข้าผ่าน Bastion ได้สำเร็จ และให้แน่ใจว่ามี Console สำรองจากผู้ให้บริการไว้ใช้กรณีพลาด
ขั้นตอนที่ 3: วาง Public Key บนเครื่องภายใน
กุญแจที่ใช้ยืนยันตัวตนควรเป็นกุญแจของคุณเอง ไม่ใช่กุญแจที่เก็บไว้บน Bastion การเก็บ Private Key ไว้บนเครื่องกลางทำให้ถ้าเครื่องนั้นถูกยึด ผู้โจมตีจะเข้าได้ทุกเครื่องทันที
ssh-copy-id -o [email protected] [email protected]
จากนั้นเปิด Agent Forwarding เฉพาะเท่าที่จำเป็น หรือหลีกเลี่ยงไปเลยโดยใช้ ProxyJump ซึ่งไม่ต้องใช้ Agent Forwarding อยู่แล้ว
ขั้นตอนที่ 4: ตั้งค่าไฟล์ ~/.ssh/config บนเครื่องคุณ
nano ~/.ssh/config
Host bastion
HostName 203.0.113.10
User jump
Port 22
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
Host web1
HostName 10.0.0.11
User deploy
ProxyJump bastion
Host db1
HostName 10.0.0.12
User deploy
ProxyJump bastion
# ใช้รูปแบบเดียวกับทุกเครื่องในวงเดียว
Host 10.0.0.*
User deploy
ProxyJump bastion
StrictHostKeyChecking accept-new
chmod 600 ~/.ssh/config
ทดสอบ
ssh web1
ssh db1
คำสั่งเดียวจบ SSH จะเชื่อมไป Bastion ก่อนแล้วต่อไปเครื่องปลายทางให้อัตโนมัติ โดยการยืนยันตัวตนกับเครื่องปลายทางเกิดขึ้นจากเครื่องคุณโดยตรง ไม่ผ่านการถอดรหัสบน Bastion