What is SSH Tunneling?

網路的連線由 2 個端點組成,而連線中經常會經過 untrusted networks(例如 internet),其中的資料傳輸就不安全,可能會有被偷窺,甚至收到錯誤資料的風險,tunneling 技術就是為此而生。

Tunneling 指的是將網路上的 2 個端點用某種方式連接起來,形成一個隧道,而 SSH tunneling 就是用 SSH protocol 建立隧道,不但能加密通訊,即便中間有設下防火牆或者要連上在別的內網的機器,SSH tunneling 都能建立連線。

舉例而言,今天有個 web server 建立在 remote server 的 9000 port,而該 server 並沒有 external IP,而是需要透過 jump host 才能連上。
我們可以透過 SSH 的 port forwarding 來建立一個在自己的 machine 與 remote server 間的 tunnel,如此一來便能連上架設在 remote server 上的 web server

Type of port forwarding

port forwarding 可以分為:

  • Local port forwarding
  • Remote port forwarding
  • Dynamic port forwarding

以下將分別介紹各個 port forwarding 的使用方式以及使用場景。

Local port forwarding

command

Local port forwarding 的指令格式如下:

1
ssh -L [bind_address:]local_port:host:remote_port user@remote-server

注意 host address 是對於 remote-server 的 address,因此若 host 為 localhost 則是指 remote-server 自己。

假設我們要將 local 的 9090 port forward 到 remote server 的 8080 port,指令如下:

1
ssh -L 9090:localhost:8080 user@remote-server

即在 client 上開啟 9090 port 等待連線,當有人連上時,將所有的資料送到 remote-server:8080,也就是將 request 導向 server 上。

scenario

SSH local port forwarding 的使用情境為何?讓我們看一個例子。

假設在 server 的 8080 port 架有一個 website,而該 server 需要透過 jump host 才能連上(也就是沒有 external IP),若我們想要在自己電腦的瀏覽器 access 該 website,可以怎麼做呢?

首先,設定 SSH 讓自己的電腦可以透過 SSH 連上 remote server,可以透過編輯 ~/.ssh/config 設定使用 jump host,而這並不是本篇學記的重點,因此不多著墨。

目前的 ~/.ssh/config 如下:

1
2
3
4
5
6
7
8
Host jumpHost
HostName 1.2.3.4
User mike

Host remoteServer
HostName remote-server.com
User mike
ProxyJump jumpHost

測試連線:

1
ssh remoteServer

local port forwarding:

1
ssh -L 9090:localhost:8080 remoteServer

此時當我們在瀏覽器打開 localhost:9090,會將瀏覽器的連線請求導向 remote server 的 8080 port,也就是該網頁架設的地點,如此一來我們便可以透過 ssh port forwarding 連上原本無法連上的服務。

Remote port forwarding

Remote port forwarding 的指令、使用方法與場景跟 local port forwarding 類似。

command

Remote port forwarding 的指令格式如下:

1
ssh -R [bind_address:]port:host:host_port user@remote-server

注意 host address 是對於 client 的 address,因此若 host 為 localhost 的話則是你的電腦自己。

假設我們要將 remote server 的 8080 port forward 到自己的 9090 port,指令如下:

1
ssh -R 0.0.0.0:8080:localhost:9090 user@remote-server

即當有人連線到 remote server 的 8080 port,將所有的資料送到你電腦的 9090 port 上,此時若你的電腦有 web server 架設在 9090 port,便可以收到該資料。

綜上,我們可以看出 remote 跟 local port forwarding 的差別在於 service 架設在哪裡,在自己的電腦要給別人連線(remote port forwarding)或是在 server 上,要用自己電腦的瀏覽器連線(local port forwarding)。

scenario

Remote port forwarding 的使用情境,我們看以下的例子。

假設我要在自己的電腦上架設一個 web server(9090 port),而不想直接暴露自己的 IP,要求 user 透過 ssh server 連線,此時我們可以透過以下指令將 ssh server 的 8080 port forward 到我的 9090 port:

1
ssh -R 8080:localho:9090 user@remote-server

此時當 user 連線上 remote server 的 8080 port,我架設在我電腦 9090 port 的 web service 便會收到 request,因為我透過 remote port forwarding 將 remote server 的 8080 port 上的所有資料送到我電腦上的 9090 port 了。

Demo

我前幾天想要查看在 remote server 上的 prometheus 資料,該 server 需要透過多層 jump host 才能連上,但我又想要在自己電腦的瀏覽器上查看 grafana dashboard(一個資料視覺化的工具,有支援 prometheus)。此時可以透過 local port forwarding 將 local 的 9000 port forward 到 remote 的 9000 port,再將架設在 remote server 的 kubernetes cluster 中的 grafana port forward 到 remote server 的 9000 port,這樣一來所有連線請求送到我電腦的 9000 port 就會被 forward 到執行 grafana 的 container 上,因此就可以看到 grafana 的資料了!

local port forwarding:

1
ssh -L 9000:localhost:9000 remoteServer

kubernetes port forward:

1
kubectl port-forward svc/prometheus-grafana 9000:90

90 port 是透過 kubectl get svc 查看得知。

打開瀏覽器連線 localhost:9000: