SSH Port Forwarding / Agent Forwarding

最近看了 The Black Magic Of SSH / SSH Can Do That? ,深覺對 SSH 的應用超級不熟悉,所以就筆記了一些對日常工作有幫助的用法,希望可以幫助自己也幫助別人。

大部份的人都利用 SSH 進行 UNIX-like 作業系統的遠端管理工具,不過 SSH 也常常用來建立加密連線通道(也就是俗稱的 Tunnel)。 The Black Magic Of SSH / SSH Can Do That? 就提到了幾種 Tunnel 的用法。

Local Port Forwarding

Local Port Forwarding 簡單來說就是可以讓 localhost 的 port 透過 SSH 連到遠端的伺服器,例如有台伺服器(secret.server)被限制只能由特定一台伺服器(remote.server)進行存取,這時候如果我們已經擁有可以透過 SSH 連線到 remote.server 的權限的話,就可以利用 SSH 建立與 remote.server 的 Tunnel,並請 remote.server 將連線要求轉至 secret.server ,這樣就能夠直接連到 secret.server 。

簡單的指令如下:

1
ssh -L 3306:secret.server:3306 your.user.name@remote.server

Remote Port Forwarding

也就是俗稱的反向 SSH ,使用的情境通常是有一台伺服器(secret.server)從外網無法連線(例如被防火牆隔絕),但是可以連出外網的情況下,很像一般公司的內部網路配置,此時就可以透過反向
SSH 的方式,先將 secret.server 連線至外網的 remote.server 建立反向 SSH Tunnel ,然後其他人就可以透過 remote.server 連回 secret.server 。簡單來說就是透過雙方都可連線的中間伺服器來達到相連效果。

首先, secret.server 須使用指令連線到 remote.server ,指令如下:

1
ssh -NfR 2345:localhost:22 your.user.name@remote.server

接下來只要其他人連線至 remote.server 後,就可以在 remote.server 使用以下指令突破防火牆連線至 secret.server :

1
ssh your.user.name@localhost

Dynamic Port Forwarding

除了 Tunnel 之外,還可以利用 SSH 架設 SOCKS Server 。通常在公共空間用瀏覽器上網時可以使用這種方式,如此一來連線就可以透過 SSH 加密後並由 remote.server 居中對外溝通,就不怕帳號密碼等機密資訊都被竊聽走。

利用 SSH 建立 SOCKS Server 的指令如下:

1
ssh -D 8080 your.user.name@remote.server

接下來就只要到瀏覽器設定 SOCKS Server 就可以使用了。

Executing a command on remote server

最神奇的是透過 SSH 直接執行指令,就只要多加上 – 就可以直接執行後把結果回傳,並不需登入遠端 SSH 伺服器,方便我們把一些調查資料的日常作業寫成腳本。

以下範例是直接在遠端伺服器上執行 hostname 指令:

1
ssh your.user.name@remote.server -- hostname

把日誌檔(log)從遠端伺服器 Pipe 回來的範例:

1
ssh your.user.name@remote.server -- cat /var/log/apache2/error.log | grep error | tee remote.server.apache2.log

Agent Forwarding

Agent Forwarding 也就是 -A 參數,可以讓你使用本地伺服器的 SSH 金鑰(SSH Key),透過遠端的伺服器(remote.server)轉送,這樣就不需要把重要的金鑰再放一份到 remote.server 。好比說用本地伺服器的金鑰透過 remote.server 連線到 github.com :

1
ssh -A your.user.name@remote.server -- ssh git@github.com

Agent Forwarding 可以應用在 ProxyCommand/Bastion Host ,例如連線到 customer.server 都必須透過 remote.server ,同時不把金鑰放在 remote.server 以確保安全:

1
your host ----SSH---> remote.server ---- SSH ----> customer.server

此外,可以利用設定檔設定 ProxyCommand :

1
vim ~/.ssh/config
1
2
3
4
5
6
Host customer
Hostname customer.server
User your.user.name.on.customer.server
ForwardAgent yes
Port 22
ProxyCommand ssh your.user.name@remote.server -p 22 -W %h %p

這樣一來只要輸入以下指令就是直接透過 remote.server 連線到 customer.server 了!

1
ssh customer

後記:

-nNT 參數:上述的指令都會佔用一個 tty ,其實這是不必要的,如果只是要 Tunnel 功能,可以加上 -nNT 參數,讓 SSH 不要佔用一個 tty 。
範例:

1
ssh -nNT -L 9000:imgur.com:80 user@example.com

References

https://vimeo.com/54505525

http://tom.scogland.com/blog/2012/07/04/ssh-tricks/

https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts