Sổ tay kỹ thuật

SSH config – jump host, ControlMaster, agent, port forward

how-to#linux#ssh· cập nhật 2026-11-06

Dùng khi phải SSH qua bastion tới router/server, muốn tái sử dụng kết nối cho Ansible, hoặc cần tunnel port.

Sửa trang này
Mục lục

Tóm tắt: Khai báo mọi host trong ~/.ssh/config: bastion dùng ProxyJump, bật ControlMaster auto + ControlPersist để các lần SSH sau dùng lại socket (nhanh hơn nhiều với Ansible/scp). Không bật ForwardAgent bừa bãi; qua bastion thì ProxyJump đã đủ. Cần OpenSSH ≥ 7.3 cho ProxyJump.

Luồng hoạt động

flowchart LR L["Laptop (key trong ssh-agent)"] -->|"SSH 1: tới bastion"| B["bastion.example.com"] B -->|"TCP forward, không giải mã"| R1["pe1 198.51.100.11"] B -->|"TCP forward"| R2["pe2 198.51.100.12"] L -.->|"SSH 2: end-to-end qua đường hầm"| R1 L --> S["ControlPath socket"] S -.->|"lần sau dùng lại"| L

Với ProxyJump, phiên SSH tới router được mã hoá end-to-end từ laptop; bastion chỉ chuyển tiếp TCP, private key không rời laptop.

Cấu hình

~/.ssh/config

~/.ssh/config
# Rule đầu tiên khớp sẽ thắng cho từng option: đặt Host cụ thể lên trên, "Host *" ở cuối
 
Host bastion
    HostName bastion.example.com
    User ops
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes
 
# Router/thiết bị sau bastion
Host pe1
    HostName 198.51.100.11
Host pe2
    HostName 198.51.100.12
Host pe* 198.51.100.*
    User automation
    ProxyJump bastion
 
# Thiết bị cũ chỉ hỗ trợ thuật toán yếu: chỉ mở cho đúng nhóm này
Host legacy-*
    KexAlgorithms +diffie-hellman-group14-sha1
    HostKeyAlgorithms +ssh-rsa
    PubkeyAcceptedAlgorithms +ssh-rsa
 
Host *
    ServerAliveInterval 30
    ServerAliveCountMax 3
    ControlMaster auto
    ControlPath ~/.ssh/cm-%C
    ControlPersist 10m
    AddKeysToAgent yes
    HashKnownHosts yes
Option Ý nghĩa
ProxyJump bastion Tương đương ssh -J bastion. Nhiều tầng: ProxyJump jump1,jump2
ControlMaster auto Có socket sẵn thì dùng lại, chưa có thì tạo master mới
ControlPath ~/.ssh/cm-%C %C là hash của host/port/user, đường dẫn ngắn, tránh lỗi socket path quá dài
ControlPersist 10m Master chạy nền thêm 10 phút sau khi phiên cuối đóng
IdentitiesOnly yes Chỉ thử key chỉ định, tránh Too many authentication failures khi agent có nhiều key
ServerAliveInterval 30 Gửi keepalive mỗi 30s, giữ phiên qua NAT/firewall
AddKeysToAgent yes Tự nạp key vào agent sau lần nhập passphrase đầu

chmod 600 ~/.ssh/config và chmod 700 ~/.ssh, nếu không ssh có thể từ chối đọc file.

ssh-agent

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l                       # key đang có trong agent
ssh-add -t 4h ~/.ssh/id_ed25519  # key tự hết hạn sau 4 giờ

ForwardAgent yes cho phép root trên máy đích dùng agent của bạn để SSH đi nơi khác trong lúc bạn đang kết nối. Chỉ bật cho host thật sự tin cậy và cần (vd git pull trên server). Đi qua bastion thì dùng ProxyJump, không cần agent forwarding.

Port forward

Mục đích Lệnh
Qua bastion một lần, không cần config ssh -J ops@bastion.example.com automation@198.51.100.11
Local forward: mở Grafana nội bộ ở localhost:3000 ssh -N -L 3000:198.51.100.20:3000 bastion
Local forward gNMI router về máy mình ssh -N -L 57400:198.51.100.11:57400 bastion
Remote forward: cho server gọi ngược về port 8080 local ssh -N -R 8080:localhost:8080 server
SOCKS proxy động ssh -N -D 1080 bastion rồi dùng socks5://127.0.0.1:1080
Chạy nền sau khi xác thực thêm -f: ssh -f -N -L 3000:198.51.100.20:3000 bastion
scp/rsync qua bastion scp -J bastion file pe1:/tmp/ / rsync -e 'ssh -J bastion' -a dir/ pe1:/tmp/dir/

Đặt sẵn trong config:

~/.ssh/config
Host grafana-tunnel
    HostName bastion.example.com
    User ops
    LocalForward 3000 198.51.100.20:3000
    ExitOnForwardFailure yes

Quản lý ControlMaster

ssh -O check pe1     # master còn sống không
ssh -O exit pe1      # đóng master (khi đổi config, đổi key)
ssh -G pe1 | grep -Ei '^(hostname|user|proxyjump|controlpath) '   # config cuối cùng áp cho host
ssh -vvv pe1         # debug thuật toán, key được thử

Lỗi thường gặp

Triệu chứng Nguyên nhân Cách xử lý
Too many authentication failures Agent đưa nhiều key, server cắt trước key đúng IdentitiesOnly yes + IdentityFile
no matching key exchange method found / no matching host key type Thiết bị cũ chỉ có SHA1/ssh-rsa Thêm KexAlgorithms +... / HostKeyAlgorithms +ssh-rsa chỉ cho host đó
Sửa config mà vẫn hành xử như cũ Đang dùng lại ControlMaster cũ ssh -O exit <host>
ControlPath too long Đường dẫn kiểu %r@%h:%p dài Dùng %C
Option trong Host * không ăn Option đã được gán bởi block khớp trước Đặt Host * cuối file
bind: Address already in use khi -L Port local đang bị dùng Đổi port hoặc ss -tlpn 'sport = :3000'
REMOTE HOST IDENTIFICATION HAS CHANGED Router thay RP/cài lại, host key đổi Xác minh với người vận hành rồi ssh-keygen -R 198.51.100.11
Phiên treo sau vài phút idle NAT/firewall timeout ServerAliveInterval 30

Tham khảo