คู่มือ SSH แบบละเอียดสุด ๆ (แต่เฉพาะสิ่งที่มีประโยชน์กับผม)
(grahamhelton.com)- SSH เป็นเครื่องมือที่ครอบคลุมตั้งแต่การเข้าถึงระยะไกล ไปจนถึง port forwarding, jump host, ไฟล์ตั้งค่า และการจัดการคีย์ โดยตัวอย่างเว็บเซิร์ฟเวอร์สามารถนำไปประยุกต์ใช้กับ บริการอื่น ๆ เช่น RDP และ SQL ได้เช่นกัน
- local, remote และ dynamic port forwarding ตั้งค่าด้วย
-L,-R,-Dตามลำดับ โดยความแตกต่างสำคัญคือพอร์ตถูกเปิดที่ฝั่งใด และทราฟฟิกไหลไปที่ไหน - ในเครือข่ายที่เข้าถึงโดยตรงไม่ได้ สามารถใช้ jump host
-JและProxyJumpเพื่อเชื่อมต่อผ่านหลายจุด SSH ไปยังปลายทางได้ ssh-agentและ agent forwarding-Aช่วยให้ใช้คีย์ในเครื่อง local ได้แม้บนโฮสต์ระยะไกล จึงสะดวก แต่ควรตรวจสอบความเสี่ยงด้านความปลอดภัยจากการใช้ agent ในทางที่ผิดก่อน- เมื่อใช้
~/.ssh/config,ssh-copy-id,ssh-keygenและ SSH console~?·~Cร่วมกัน จะช่วยลดการพิมพ์ออปชันซ้ำ ๆ และทำให้การเพิ่ม forwarding ระหว่างเซสชัน การแจกจ่าย public key รวมถึงการสร้างและตรวจสอบคีย์ทำได้ง่ายขึ้น
สิ่งที่ต้องเข้าใจก่อนเรียนรู้ SSH port forwarding
- SSH port forwarding เข้าใจทิศทางการไหลได้ยากหากดูแค่ไดอะแกรม จึงจะเข้าใจง่ายขึ้นเมื่อดูคำสั่งจริงควบคู่กับสถานการณ์เครือข่าย
- ตัวอย่างจะอิงกับการเข้าถึงเว็บเซิร์ฟเวอร์ แต่แนวทางเดียวกันนี้ใช้ได้กับ แทบทุกบริการ เช่น RDP, SQL เป็นต้น
- ออปชันที่ใช้ซ้ำ ๆ มีความหมายดังนี้
-N: ไม่รันคำสั่งบนเซิร์ฟเวอร์ระยะไกล และไม่เปิดเชลล์-f: ส่ง SSH ไปทำงานเบื้องหลังroot@host: ล็อกอินด้วยผู้ใช้และโฮสต์ที่จะใช้สร้าง tunnel
local port forwarding -L
- local port forwarding คือการส่งต่อพอร์ตของเครื่อง local ไปยังพอร์ตของเซิร์ฟเวอร์ระยะไกล
- สถานการณ์ตัวอย่าง
internal-web.intโฮสต์หน้าเว็บที่เข้าถึงได้เฉพาะผ่าน loopback interface- จาก
campfire.intสามารถเข้าถึงinternal-web.intผ่าน SSH ได้ - ต้องการเข้าถึงเว็บเซิร์ฟเวอร์ของ
internal-web.intผ่านพอร์ต local ของcampfire.int
- คำสั่งที่ใช้
ssh -N -f -L 1337:127.0.0.1:80 root@internal-web.int
- คำอธิบายออปชัน
-L: ระบุ local forwarding1337:127.0.0.1:80: bind พอร์ต local1337เข้ากับ127.0.0.1:80ฝั่ง remote
- หลังสร้าง tunnel แล้ว จาก
campfire.intสามารถส่งคำขอไปยังพอร์ต local1337เพื่อสื่อสารกับพอร์ต80ของinternal-web.intได้ - สิ่งที่ควรจำคือใน
-Lพอร์ต local จะอยู่ด้านซ้าย ของที่อยู่
remote port forwarding -R
- remote port forwarding คือการนำพอร์ตที่เข้าถึงได้จากฝั่ง local ไปเปิดเผยเป็นพอร์ตบนเซิร์ฟเวอร์ระยะไกล
- สถานการณ์ตัวอย่าง
internal-web.intโฮสต์หน้าเว็บที่เข้าถึงได้เฉพาะจาก loopbackcampfire.intเข้าถึงinternal-web.intโดยตรงไม่ได้เพราะ firewallvuln-server.intเข้าถึงได้จากทั้งcampfire.intและinternal-web.int
- คำสั่งที่ใช้
ssh -N -f -R 3000:127.0.0.1:80 root@vuln-server.int
- คำอธิบายออปชัน
-R: ระบุ remote forwarding3000:127.0.0.1:80: bind พอร์ต3000ของvuln-server.intเข้ากับ127.0.0.1:80ฝั่ง local
- หลังจากนั้น หากส่งคำขอ
curlไปยังvuln-server.int:3000ก็จะเข้าถึงหน้าเว็บภายในที่ทำงานอยู่บนพอร์ต80ของinternal-web.intได้ - สิ่งที่ควรจำคือใน
-Rพอร์ต local จะอยู่ด้านขวา ของที่อยู่
dynamic port forwarding -D และ SOCKS proxy
- dynamic port forwarding คือการใช้ตัวเลือก
-Dเพื่อสร้าง SOCKS proxy และส่งทราฟฟิกผ่าน SSH hop - สถานการณ์ตัวอย่าง
internal-web.intโฮสต์เว็บแอปพลิเคชันที่เข้าถึงได้เฉพาะในเครือข่ายภายในvuln-server.intอยู่ในเครือข่ายภายในเดียวกัน และเข้าถึงinternal-web.intได้- ต้องการ proxy ทราฟฟิกจาก
campfire.intผ่านvuln-server.int
- การตั้งค่า
/etc/proxychains.confต้องตรงกับพอร์ตของคำสั่ง SSHsocks5: ให้ proxychains ใช้ SOCKS5127.0.0.1: ใช้ localhost8080: ต้องตรงกับพอร์ตที่กำหนดใน SSH-D
- คำสั่งที่ใช้
ssh -N -f -D 8080 root@vuln-server.int
- หลังสร้าง forwarding แล้ว เมื่อตั้งค่า
socks5 127.0.0.1 8080ก็สามารถใช้proxychains curl 192.168.1.185เพื่อเข้าถึงหน้าเว็บภายในได้ - DNS ผ่าน SOCKS อาจทำงานได้ไม่ดีขึ้นอยู่กับสภาพแวดล้อม ตัวอย่างจึงใช้ IP address แทน hostname
- ใน Firefox ก็สามารถใช้ SOCKS proxy ผ่านการตั้งค่า proxy แบบ manual ได้
- เส้นทาง: Settings → Privacy & Security → Network Settings
- เลือก Manual proxy configuration
- ติ๊ก “Proxy DNS when using SOCKS V5”
- ตั้ง SOCKS host เป็น
127.0.0.1และ port เป็น8080
jump host -J
- jump host ช่วยให้เชื่อมต่อไปยังปลายทางที่เข้าถึงโดยตรงจากโฮสต์ปัจจุบันไม่ได้ โดยผ่าน SSH hop หลายจุด
- ตัวอย่าง chain คือ
campfire.int→vuln-server.int→internal-web.int→dns.int - คำสั่งที่ใช้
ssh -J root@vuln-server.int,root@internal-web.int root@dns.int
- จุดหมาย jump หลายรายการคั่นด้วย เครื่องหมายจุลภาค
agent forwarding -A
ssh-agentช่วยให้เพิ่ม private key หรือ ID บนเครื่อง local ได้ด้วยssh-add <private_key_file>- สามารถตรวจสอบคีย์ที่เพิ่มแล้วได้ด้วย
ssh-add -l - เมื่อเพิ่มคีย์เข้า
ssh-agentแล้ว จะสามารถเชื่อมต่อ SSH ด้วยคีย์นั้นโดยไม่ต้องป้อนรหัสผ่านซ้ำ ซึ่งมีประโยชน์ทั้งสำหรับผู้ใช้และ service account - agent forwarding
-Aทำให้บนเครื่อง remote ที่เชื่อมต่ออยู่สามารถใช้คีย์จาก local agent ได้ - ก่อนใช้งานควรตรวจสอบความเสี่ยงด้านความปลอดภัยจาก Zero Effort Private Key Compromise: Abusing SSH-Agent for Lateral Movement
- คำสั่งตัวอย่าง
ssh -A -J root@vuln-server.int root@internal-web.int
- คำสั่งนี้เชื่อมต่อไปยัง
internal-web.intผ่านvuln-server.intพร้อมทำให้สามารถใช้คีย์ที่อยู่ใน SSH agent ของcampfire.intฝั่ง local ได้ - หลังจากนั้น เมื่อรัน
ssh root@dns.intจากinternal-web.intก็สามารถเชื่อมต่อได้โดยไม่ต้องระบุ private key หรือกรอก credentials
การจัดสรรคำสั่ง TTY -t
- ตัวเลือก
-tมีประโยชน์เมื่ออยากรันคำสั่งที่ต้องมีการโต้ตอบบนเซิร์ฟเวอร์ระยะไกลอย่างรวดเร็ว - ตัวอย่างคือคำสั่งที่ต้องใช้ TTY เช่น
Vimหรือtop - คำสั่งที่ใช้
ssh root@internal-web.int -t top
- เมื่อรันแล้วจะได้รับ TTY บนเซิร์ฟเวอร์ระยะไกลพร้อมคำสั่ง
top
-g ที่ทำให้โฮสต์ภายนอกเชื่อมต่อเข้าพอร์ต forwarding ฝั่ง local ได้
- ตัวเลือก
-gทำให้โฮสต์ระยะไกลสามารถเชื่อมต่อเข้าพอร์ตที่ถูก local forwarding ได้ - คล้ายกับ local port forwarding
-Lแต่ต่างกันตรงที่เครื่องภายนอกก็สามารถใช้พอร์ต “local” นั้นได้ - สถานการณ์ตัวอย่าง
- มี shell access ไปยัง
vuln-server.int - ต้องการ proxy การเชื่อมต่อที่เข้ามายังพอร์ต
2222ของvuln-server.intไปยังพอร์ต22ของinternal-web.int
- มี shell access ไปยัง
- คำสั่งที่ใช้
ssh -N -f -g -L 2222:localhost:22 root@internal-web.int
- คำอธิบายออปชัน
-g: อนุญาตให้โฮสต์ remote เชื่อมต่อเข้าพอร์ต local forwarding ได้-L: ระบุ local forwarding
- แม้จะ SSH เข้าไปที่พอร์ต
2222ของvuln-server.intแต่ shell จริงจะอยู่บนinternal-web.int
SSH console ~? และ forwarding ระหว่างเซสชัน
- SSH console เป็นฟีเจอร์ซ่อนที่ใช้ควบคุม SSH เองโดยไม่ต้องโต้ตอบกับระบบ remote โดยตรง
- มีประโยชน์เมื่อ shell เสียหรือเมื่อจำเป็นต้องควบคุม SSH session เอง
- เปิด help console ได้ด้วย
~? - ออปชันที่มีประโยชน์
~.: ปิด SSH session ปัจจุบัน~C: เปิด SSH console เพื่อเพิ่มออปชัน forwarding ได้
- แม้จะเชื่อมต่อกับ
vuln-server.intอยู่แล้วด้วยคำสั่งsshปกติ ก็สามารถกด~Cแล้วพิมพ์-D 8080เพื่อใช้ session นั้นเหมือนเป็น dynamic forwarding session ได้ - หากบน
campfire.intตั้งค่า/etc/proxychains.confให้ใช้พอร์ต8080ไว้ ก็สามารถใช้ proxychains ได้เหมือนเริ่มด้วยssh -Dตั้งแต่แรก
ไฟล์ตั้งค่า SSH ~/.ssh/config
- ไฟล์ตั้งค่า SSH อยู่ที่
~/.ssh/configและช่วยประหยัดเวลาโดยเก็บออปชัน SSH ที่ต้องพิมพ์ซ้ำ ๆ - เมื่อเชื่อมต่อ SSH ระบบจะ parse ไฟล์นี้ และหากมีการตั้งค่า
hostที่ตรงกับปลายทาง ก็จะใช้ออปชันเหล่านั้น - argument บน command line มีลำดับความสำคัญสูงกว่าไฟล์ตั้งค่า
- เช่น แม้ในไฟล์ตั้งค่าจะระบุผู้ใช้ของ
internal-web.intเป็นrootแต่ถ้ารันssh graham@internal-web.intก็จะพยายามล็อกอินเป็นgraham
- เช่น แม้ในไฟล์ตั้งค่าจะระบุผู้ใช้ของ
- ตัวอย่างการตั้งค่าพื้นฐาน
# You can put comments with a `#` at the beginning of the line only.
host internal-web.int
User root
IdentityFile /home/smores/ssh_agent/internal-web-no-pw
Port 2222
- ลำดับการประมวลผลเมื่อรัน
ssh internal-web.int- จับคู่
internal-web.intจาก command line กับhost internal-web.intใน~/.ssh/config - หากตรงกัน จะดึงออปชันที่ไม่ได้ระบุใน command line จากไฟล์ตั้งค่ามาใช้
- หากไม่ตรงกัน จะใช้เฉพาะออปชันที่กำหนดใน command line
- จับคู่
คีย์เวิร์ด SSH config ที่ใช้บ่อย
IdentityFile /path/to/private_key- ระบุ private key ที่จะใช้กับโฮสต์
- ทำหน้าที่เดียวกับ
ssh -i
ForwardAgent- ทำหน้าที่เดียวกับ
ssh -A - ก่อนใช้ agent forwarding ต้องตรวจสอบ Zero Effort Private Key Compromise: Abusing SSH-Agent for Lateral Movement
- ทำหน้าที่เดียวกับ
ProxyJump root@internal-web.int- ระบุเซิร์ฟเวอร์ที่จะใช้ proxy ทราฟฟิก
- ทำหน้าที่เดียวกับตัวเลือก
-J - ในตัวอย่าง แสดงให้เห็นว่าระบบจะขอ authentication ของ
vuln-server.intก่อน เพื่อให้ทราฟฟิกผ่านโฮสต์นั้น
Match- ใช้คีย์เวิร์ด SSH config ตามเงื่อนไข
- ในตัวอย่าง หาก exit code ของคำสั่ง
export | grep PROXYME=TRUEเป็น0จะใช้ProxyJumpใต้บล็อกMatch - หากไม่มี environment variable
PROXYMEจะใช้เฉพาะบล็อกhost internal-web.intปกติ - หลังตั้งค่า
export PROXYME=TRUEแล้วรันssh internal-web.intเดิม ก็จะผ่าน authentication ของvuln-server.intก่อน จากนั้นได้รับ shell ของinternal-web.int
- โดยทั่วไป
scpและยูทิลิตีบางตัวที่ใช้ SSH เป็นฐานก็สามารถใช้ SSH config ได้เช่นกัน- ในสภาพแวดล้อมที่ไม่ได้ใช้อัตโนมัติ สามารถระบุได้ด้วย
-F ~/.ssh/config
- ในสภาพแวดล้อมที่ไม่ได้ใช้อัตโนมัติ สามารถระบุได้ด้วย
การคัดลอก public key ด้วย ssh-copy-id
ssh-copy-idเป็นยูทิลิตีขนาดเล็กสำหรับอัปโหลด public key ไปยังเซิร์ฟเวอร์อย่างรวดเร็ว- คำสั่งที่ใช้
ssh-copy-id -i internal-web root@internal-web.int
- คำอธิบายออปชัน
-i internal-web: ระบุชื่อ private key ที่จะใช้สำหรับ authentication กับเซิร์ฟเวอร์root@internal-web.int: ระบุเซิร์ฟเวอร์ที่จะอัปโหลด public key ไป
การสร้างและตรวจสอบคีย์ด้วย ssh-keygen
ssh-keygenเป็นยูทิลิตีสำหรับสร้างคู่ private key และ public key- โดยทั่วไปแนะนำให้ใช้ตัวเลือก
-bเพื่อระบุขนาดคีย์ที่ใหญ่ขึ้น - ขนาดคีย์เริ่มต้นในสภาพแวดล้อมตัวอย่างคือ
3072 - อัลกอริทึมเริ่มต้นคือ RSA แต่สามารถใช้ flag
-tเพื่อระบุอัลกอริทึมอื่นได้- ตัวอย่าง:
ssh-keygen -t ecdsa -b 521
- ตัวอย่าง:
- สามารถตรวจสอบ fingerprint และขนาดเป็นไบต์ของคีย์ได้ด้วยคำสั่งต่อไปนี้
ssh-keygen -lf <file-name>
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ที่นี่ขาด directive ที่เรียบง่ายอย่างน่าทึ่งไปอย่างหนึ่ง: ตั้งค่าใน
sshd_configเช่นAuthorizedKeysCommand /usr/bin/php /etc/ssh/auth.php %uแล้วให้สคริปต์ดึงhttps://github.com/{$user}.keysของ GitHub มาก็พอแน่นอนว่าไม่ใช่โค้ดคุณภาพระดับ production แต่แสดงแก่นของแนวคิดได้
หลังจากตรวจสอบว่าสังกัดองค์กร/กลุ่มของ GitHub หรือไม่ ถ้าผู้ใช้มีอยู่จริงและถูกแมปด้วยอย่าง
nss-atoก็สามารถอนุญาตให้ล็อกอินเข้าเซิร์ฟเวอร์ได้เวลา onboarding/offboarding คน เพียงเพิ่ม/ลบออกจาก กลุ่ม GitHub ก็สามารถให้หรือเพิกถอนสิทธิ์เข้าถึงเครื่องได้ ช่วยลดความยุ่งยาก
ใน Amazon Linux 2 หรือต่ำกว่า จะเรียกใช้คำสั่ง
opensslจาก command line เพื่อตรวจรูปแบบคีย์แต่ละตัวในไฟล์authorized_keysแต่ถูก hardcode ไว้เป็น RSA ดังนั้นแม้เวอร์ชัน OpenSSH จะรองรับed25519ก็ไม่สามารถยืนยันตัวตนด้วยed25519บนโฮสต์ Amazon Linux 2 ได้ในทางทฤษฎีมันช่วยเปิดทางให้ฟีเจอร์เจ๋ง ๆ¹ ได้ ซึ่งก็ดี แต่ในทางปฏิบัติมันกลับทำให้ฟังก์ชันพื้นฐานพังแม้กับคนที่ไม่ได้ใช้ฟีเจอร์เหล่านั้น ทำให้ไว้ใจ Amazon Linux น้อยลง
ตอนเจอปัญหานี้ครั้งแรก ผมกำลังพยายาม SSH เข้าเครื่องที่เป็นของเพื่อนร่วมงานสาย DevOps ที่ cloud-first และเพราะผมแตะเครื่องโดยตรงไม่ได้จึงวินิจฉัยยาก
เขารู้จัก AWS ดีแต่รู้ Linux น้อยกว่า จึงไม่รู้ว่าควรดูตรงไหน และเลือก Amazon Linux เพราะคิดว่าเป็นดิสโทรที่เจ้าของแพลตฟอร์มคลาวด์ทำเอง น่าจะ “เข้ากันได้มากกว่า” แต่ตรงนี้ “เข้ากันได้มากกว่า” จริง ๆ หมายถึง “มี surprises โง่ ๆ มากกว่า”
¹ https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-...
เพราะขอบเขตงานคือ “เครือข่ายทำงานไม่ถูกต้อง” เลยพลาดฟีเจอร์เท่ ๆ แบบนี้ไป
น่าจะมีคนจำนวนมากที่ไม่รู้ว่า parser คอนฟิกของ OpenSSH จะละเว้น directive ที่ซ้ำกัน และมีผลเฉพาะ ตัวแรก ของ directive เดียวกันเท่านั้น
โดยปกติใน parser คอนฟิกหรือ rules engine มักเป็น directive ที่มาทีหลังเขียนทับตัวก่อนหน้า จึงค่อนข้างขัดกับสัญชาตญาณ
อาจดูเหมือนเรื่องเล็ก แต่เวลาเปลี่ยนค่า default อย่าง
/etc/ssh/sshd_configคนและซอฟต์แวร์มักมีแนวโน้มจะต่อท้ายการเปลี่ยนแปลงไว้ท้ายไฟล์หรือท้ายบล็อก directive และคาดหวังว่ามันจะถูกนำไปใช้บริษัทหรือองค์กรด้านความปลอดภัย รวมถึงผลิตภัณฑ์ SSH bastion หลายตัวก็พลาดเรื่องนี้ และคำแนะนำ CIS Benchmarks กับเครื่องมือตรวจ audit CIS ของ third-party ส่วนใหญ่ก็ไม่คำนึงถึงลำดับความสำคัญหรือจัดการผิด
ถ้าต้องการตรวจว่า directive คอนฟิกของ OpenSSH ถูกกำหนดตามที่คาดหรือไม่ อย่าไล่อ่านไฟล์คอนฟิกเอง แต่ควร dump คอนฟิกภายใน ที่ถูก derive ออกมาด้วย
sshd -Tหรือssh -Gsudoersก็ทำงานแบบเดียวกันสำหรับซอฟต์แวร์ยืนยันตัวตน/อนุญาตสิทธิ์ผู้ใช้ ผมมองว่าวิธีนี้เป็นสิ่งที่พึงประสงค์
เพราะทำให้สร้างการตั้งค่าที่ไม่สามารถถูก override ได้ง่าย แม้จะเพิ่มไฟล์ใหม่ในไดเรกทอรี
whatever.conf.dแค่กำหนดค่านั้นในไฟล์คอนฟิกหลักก่อนโหลด
whatever.conf.d/*แล้วใส่การป้องกันพิเศษให้ไฟล์นั้นไว้ก็พอแม้จะไม่ใช่กรณีที่มีคนพยายามเลี่ยงการควบคุม วิธีนี้ก็เป็นประโยชน์ต่อ configuration management เพราะแม้พนักงานใหม่ที่ไม่รู้บริบททั้งหมดจะเพิ่มไฟล์ใหม่ หรือแพ็กเกจบางตัวติดตั้งค่า default แปลก ๆ สำหรับบริการของตัวเอง ค่ามาตรฐานก็ยังคงมีสิทธิก่อน
เหตุผลที่ในบริบทอื่นเรามักเห็นพฤติกรรมตรงข้ามบ่อยกว่า คือสิ่งที่ต้องการไม่ใช่ “ค่ามาตรฐาน” แต่เป็นค่า default ในความหมายเคร่งครัดที่ใช้เมื่อผู้ใช้/นักพัฒนา/ผู้ดูแลไม่ได้ตั้งค่าไว้อย่างชัดเจน
AllowUsersแต่เมื่อวาน NixOS เปลี่ยนลำดับการ merge แบบกะทันหัน ทำให้
AllowUsersในไฟล์ของผมถูกย้ายไปอยู่ใต้Matchของไฟล์อื่นแล้วถูกล็อกไปคำอธิบายในบทความที่ว่า
-Lคือ local forwarding ที่ local อยู่ทางซ้ายของ address และ-Rคือ remote forwarding ที่ local port อยู่ทางขวาของ address เป็นประโยคที่สำคัญและกระชับที่สุดผมสับสนกับ
-Lและ-Rมาตั้งแต่แรก และการที่ instance ของ port ไหนเป็น local จะเปลี่ยนไปตาม L/R นั้นค่อนข้างน่ารำคาญผมเข้าใจว่า
-Lกับ-Rเปลี่ยนทิศทางตามเจตนา กล่าวคือผู้เริ่มต้นกับผู้ตอบสนองอยู่ที่ไหน แต่ก็น่าจะโอเคถ้าให้port:address:portหมายถึงlocal:binding:remoteเสมอ แล้วให้-L/-Rเป็นตัวกำหนดว่าฝั่งไหนเป็นผู้รับฟังและฝั่งไหนเป็นผู้ส่ง-Lรับฟังที่ local port ของตัวเลขที่ตามมาทันที และ-Rรับฟังที่ remote port ของตัวเลขที่ตามมาทันทีส่วน
host:portที่เหลือเป็นเพียงรูปแบบทั่วไปที่บอกว่าจะเชื่อมต่อไปที่ไหนเนื่องจากเป็นการทำ port forwarding ผ่าน SSH tunnel จึงเป็นธรรมชาติด้วยที่ host จะถูกติดต่อจากฝั่งที่มี receiving port อยู่คนละด้านกับ tunnel
SSH มีฟีเจอร์ที่ไม่ค่อยเป็นที่รู้จักแต่มีประโยชน์มากอย่างหนึ่งคือ การมัลติเพล็กซ์การเชื่อมต่อ
แทนที่จะสร้าง TCP connection ใหม่และผ่านขั้นตอนการยืนยันตัวตนใหม่ทุกครั้ง สามารถตั้งให้ใช้ connection เดิมซ้ำได้
ตัวโปรโตคอลเองมีแนวคิดเรื่อง channel อยู่แล้ว และแต่ละ data frame จะมี metadata สำหรับแยก stream ต่าง ๆ ออกจากกัน ฟีเจอร์นี้ก็ใช้กลไกนั้น
ข้อดีใหญ่คือ session ถัด ๆ ไปไม่ต้องทำการยืนยันตัวตนเต็มรูปแบบอีกครั้ง
เหมาะเป็นพิเศษในกรณีที่เครื่องปลายทางไม่มี
tmuxอะไรทำนองนั้น และต้องใช้หลาย panel ผ่านหน้าต่าง terminal หลายอัน ยิ่งถ้าการยืนยันตัวตนมีขั้นตอนที่กินเวลาหลายวินาที เช่น passphrase หรือแตะ HSM ก็จะยิ่งรู้สึกได้ชัดยังมีการตั้งค่า “คงการเชื่อมต่อไว้” ด้วย จึงไม่ต้องยืนยันตัวตนใหม่ทุกครั้งเมื่อสลับไปมาระหว่าง server ไม่กี่เครื่อง
โดยรวมถือว่าเป็นฟีเจอร์ที่มีไว้ก็ดี แต่ไม่ได้ถึงขั้นเปลี่ยนชีวิต
บาง server ปิดฟีเจอร์นี้ไว้ ซึ่งพอปิดจะรู้สึกถึงการไม่มีมันชัดกว่าตอนที่เปิดอยู่
ดูเพิ่มเติม: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing
SSH เป็นโปรโตคอลที่ค่อนข้างคุยเยอะ ต่างจาก TLS ที่ optimize เพื่อลดจำนวนรอบไป-กลับ และ ตัวเลือกมัลติเพล็กซ์ นี้แทบจะเป็นข้อยกเว้นเดียว
ProxyJumpจะทำให้ใช้ Ansible ได้สะดวกขึ้นมากถ้ามี host จำนวนมากใน
~/.ssh/configสามารถใช้ directiveIncludeที่รองรับ wildcard เพื่อป้องกันไม่ให้ไฟล์รกเกินไปได้เช่น ใน
~/.ssh/configใส่Include config.d/*.confแล้วแยกการตั้งค่าhost,hostname,userไว้ใน~/.ssh/config.d/work.confหรือclient1.confได้Hostก็รองรับ wildcard เช่นกันเช่น เพิ่ม
host *_workแล้วใส่การตั้งค่าร่วมสำหรับ host งานทั้งหมดอย่างhost1_workได้Includeไว้ข้างใน directiveHost/Matchได้เช่น ถ้าใส่
Host proj1.*.corpกับInclude ~/.ssh/proj1.confใน~/.ssh/configก็จะวาง match แยกตาม project ไว้ใกล้ ๆ ด้านบนได้ และลดความจำเป็นต้องไล่เปิดไฟล์ย่อยจำนวนมากเวลาตรวจสอบเวลา forwarding แทบไม่ใช้
-fเลยมันทำให้ยากที่จะรู้ว่า forwarding ไหนยังเปิดอยู่และกำลังทำงานอยู่ จนอาจกลายเป็น ปืนใต้เท้าตัวเอง ได้
-tเป็นทริกที่เจ๋ง และเป็นฟีเจอร์ที่ไม่เคยรู้มาก่อนจุดสำคัญที่มักพลาดในรายการคำสั่ง escape ของ
~คือ แม้อยู่ใน session ซ้อนกัน ก็ยังสามารถซ้อน escape ได้ด้วยมีประโยชน์เวลาที่ไม่ใช้
-Jไม่ว่าด้วยเหตุผลใดก็ตามรายการนี้ตรงกับสิ่งที่มีประโยชน์ดี และยังได้เรียนรู้อะไรเพิ่มอีกสองสามอย่าง
-tยอดเยี่ยมมาก ผมใช้ประมาณssh -t my-dev-vps 'tmux new-session -A -s main'เพื่อให้ทุกครั้งที่รัน กลับไปยังตำแหน่งเดิมใน tmux session ได้ทันทีนอกจากต้องไปไล่ดู process list เองแล้ว ถ้า SSH ส่งออกสถานะ forwarding ออกมาในรูปแบบที่สมเหตุสมผลได้ก็คงดี
ตอนนี้มี pull request ที่เพิ่มการรองรับ
AF_UNIXอยู่ ถ้า merge เข้ามาแล้วจะทำให้ forwarding ที่น่าสนใจสารพัดแบบเป็นไปได้เพราะจะทำให้ proxy การเชื่อมต่อ SSH ผ่าน local process ใด ๆ ได้ง่ายขึ้น และ process นั้นจะจัดการส่งข้อมูลต่อไปจนถึงปลายทางระยะไกลอย่างไรก็ได้ตามต้องการ
https://github.com/openssh/openssh-portable/pull/431
-Dที่ใช้AF_UNIXแต่การที่ทุกอย่างสามารถทำงานบนAF_UNIXได้ก็เป็นเรื่องดีดูเหมือนว่าตั้งแต่ประมาณ 1 ปีก่อน
curlสามารถใช้AF_UNIXSOCKS ผ่าน syntax ของALL_PROXYแบบsocks5://localhost/pathหรือsocks5hได้แล้วน่าจะเพิ่มเข้ามาเพราะ Tor ใช้
AF_UNIXSOCKS proxyถ้าสามารถตั้งค่าการเข้าถึง network ด้วย permission มาตรฐานของ Unix ได้ก็คงดี และโดยส่วนตัว ถ้าผลัก TCP/IP ออกจาก kernel ได้หมดก็คงยิ่งดี
ตอนเห็น SSH console ครั้งแรกนี่ตกใจมาก
เพื่อนร่วมงานโชว์
~#ให้ดู รู้สึกเหมือนค้นพบ เมนูลับสูตรโกง ที่น่าจะโผล่มาในเกม SEGA Genesisทำไมต้องเป็น tilde? เพราะ
rlogin,rshใช้มันแล้วทำไม
rlogin,rshถึงใช้ tilde? เพราะcuใช้มันแล้วทำไมเป็น
cu? ถ้ามี modem หรือ serial line ก็ใช้cuสื่อสาร และต้องส่ง Hayes code แต่ถ้าใช้ escape sequence ของ Hayes code ก็จะหลุดออกไปที่ modem ดังนั้นจึงต้องมีสัญญาณแยกต่างหากสำหรับออกจากcuทำไมไม่ใช่
^[? เพราะนั่นเป็นของ telnetดังนั้นถ้าเชื่อมต่อเข้า host ผ่าน telnet แล้วต่อไปยัง modem ด้วย
cuก็ต้องมี ไวยากรณ์ escape แยกต่างหาก เพื่อกลับไปที่cuโดยไม่หลุดออกไปที่ telnetสุดท้ายจึงกลายเป็นโครงสร้างที่มีไวยากรณ์ escape ซ้อนกันไม่รู้จบ
และในทางปฏิบัติ มันไม่ใช่ tilde หรอก แต่เป็น tilde นั่นแหละ
CR, tilde,.มาตลอด หรือที่ผ่านมาผมใช้ผิดมาตลอด?ส่วน
ssh-copy-idตอนแรกอธิบายว่าคำสั่งนี้อัปโหลด public key แล้วจู่ ๆ ก็เปลี่ยนเป็นอัปโหลด private key ดูเหมือนจะเป็น typoอีกอย่าง คำสั่งนี้ไม่ได้แค่อัปโหลด key เฉย ๆ แต่ append เข้า
~/.ssh/authorized_keysด้วย จึงมีประโยชน์กว่ามากสุดท้าย ในส่วน
ssh-keygenจากข้อมูลที่ได้อ่านมา ช่วงนี้ed25519เป็นที่นิยมกว่าecdsa