Using Redsocks and SOCKS5 as Proxy to connect internal Cloud SQL without public IP


演示如何使用 Redsocks 搭配 SOCKS5 快速建立起代理伺服器進行網路代理穿透應用

Background and System HLD

SOCKS5 是一種網路代理(Proxy),這種代理只做封包傳遞,所以速度比 HTTP 代理更快,也支援多種網路應用。SOCKS5 代理主能能讓使用此網路流量匿名,但中間的傳輸沒有加密、無法保證安全性。

在中國大陸一般使用 Redsocks, ShadowsocksSSR 作為 SOCK5 代理伺服器進行翻牆.而將資料庫使用雲端服務託管的則更加可以使用此方式避免需要開出對外 IP 的方式才能連線至該儲存體進行資料調用或是除錯等檢查.

如此一來我們就可以用 Redsocks server 作為跳板訪問原先存取不到的資源.這邊會演示如何透過這層代理讓 vpn-sg的操作都能以 vpn-hk代為轉發,以下是我們的架構圖全貌:

架構示意圖 - Redsocks Server and SOCKS5 Server

這邊會用到以下兩個技術串接:

SSH Tunnel and SOCKS

SSH Tunnel 用途是開啟一個SSH 通道連到代理伺服器,再透過代理伺服器連線到要目標伺服器上,透過這個代理我們就能碰觸到原本不能碰觸或是轉介代理碰觸的實踐.具體可以分為三種設定,這邊可以參考 SSH Tunneling (Port Forwarding) 詳解 這篇,寫得非常仔細.

  • Local Port Forwarding

在 Client 上開啟 bind_address:port 等待連線,當有人連上時,將所有資料轉送到 host:host_port 去。

ssh -L [bind_address:]<port>:<host>:<host_port> <SSH Server>
  • Remote Port Forwarding

在 SSH Server 上開啟 bind_address:port 等待連線,當有人連上時,將所有資料轉送到 host:host_port 去.

ssh -R [bind_address:]<port>:<host>:<host_port> <SSH Server>
  • Dynamic Port Forwarding

在 SSH Server 上啟動一個 SOCKS 代理伺服器,同時在 Client 上開啟 bind_address:port 等待連線,當有人連上時,將所有資料轉送到這個 SOCKS 代理伺服器上,啟動相對應的連線請求。 也是本篇的重點項目之一.

ssh -D [bind_address:]<port> <SSH Server>

Redsocks

Redsocks 是一個允許使用防火牆將任何 TCP 連接重定向到 SOCKS 或 HTTPS 代理,這邊指的重新定向/轉導可能是系統範圍或網絡範圍的。

講網絡流量轉發大socks4,sockes5,或者http代理服務器的工具,實際在整個作業系統的最低層與內核iptables層互動.除了可以轉發 HTTP, HTTPS 與任意 TCP 協定上的傳輸.

RedSocks 功能示意

How to Verify SSH SOCKS5 work

這邊我們用https://myip.com.tw/網站測試證明 IP 位置為 Redsocks Server 所發出的請求:

myip.png

由於 SOCKS 僅需開放 SSH 即可使用,確定預設的 SSH 防火牆有開通個剛剛兩個 VM 內網 IP 後即可以透過 curl 設定 SOCKS 代理的方式進行測試:

# 一般 HTTP GET 查詢
curl https://myip.com.tw

# 有透過 SOCKS 代理
curl --socks5 ip:port https://myip.com.tw

所以當我們的 Redsocks Server 設定好後,透過 SSH 至 vpn-sg 內,直接透過一般的 curl https://myip.com.tw 我們就可以享用 SOCKS5 的轉發功能由香港主機幫我們帶出請求並成功取得香港主機的靜態固定 IP.

gcloud shell create GCP resources

首先透過以下樣板建立 GCP 資源與網路防火牆設定


# 建立樣板 VPN HK
gcloud compute instance-templates create "instance-template-vpn-hk-n2" \
      --description="Instance Template for HK VPN instance"\
      --region asia-east2 \
      --machine-type=n2-standard-2 \
      --image centos-8-v20201112 --image-project centos-cloud\
      --boot-disk-size 20 --boot-disk-type pd-ssd \
      --create-disk size=40,type=pd-ssd

# 建立樣板 VPN SG
gcloud compute instance-templates create "instance-template-vpn-sg-n2" \
      --description="Instance Template for SG VPN instance"\
      --region asia-southeast1 \
      --machine-type=n2-standard-2 \
      --image centos-8-v20201112 --image-project centos-cloud\
      --boot-disk-size 20 --boot-disk-type pd-ssd \
      --create-disk size=40,type=pd-ssd

# 建立防火牆規則, 開通 tcp 的 8888 準備給 SSH SOCKS 使用
gcloud compute firewall-rules create "vpn-hk" \
      --network "default" \
      --target-tags "vpn-hk" \
      --allow tcp:8888

# 透過樣板建立 HK GCE VM
gcloud compute instances create "vpn-hk" \
    --source-instance-template instance-template-vpn-hk-n2\
    --tags "vpn-hk" \
    --zone asia-east2-a

# 透過樣板建立 SG GCE VM
gcloud compute instances create "vpn-sg" \
    --source-instance-template instance-template-vpn-sg-n2\
    --tags "vpn-sg" \
    --zone asia-southeast1-a

因為 SSH 這邊預設有開,所以防火牆就不額外設定 SSH 的開口(但正式環境記得要改成限定的信任 IP才開放 SSH)

VM Prerequisites

這邊當 VM 開出來後記得也要去保留一下當前配發的 vm public ip 從臨時動態ip(ephemeral)改為固靜態定ip(static),具體可以參考官方 Reserving a static external IP address

到此我們已經建立兩個 VM 而且可以讓 vpn-sgvpn-hk 都具備靜態固定 ip 並且將 vpn-hk 的 8888 端口開放準備給 vpn-sg 的 Redsocks 套用.

Assign Public Static IP

  • vpn-hk => 34.150.93.183
  • vpn-sg => 35.240.144.123

Prepare Public/Private Key

這邊我們先產生好等等 SOCKS5 Server 的憑證:

  1. 產生憑證

    sh-keygen -t rsa -f ~/.ssh/vpn-vm
  2. 之後如果要用此憑證當作 ssh 使用記得要將 public key 加入 GCE 於該 VM 實體的meta設定內

    public key 如下:

    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9/dVumpdMez8qNsAPtgKtr4Z3VN0LJgVjfC0ScpDYJKzGtWa8sY/olbfkBrkibl2JHUIPgqYFi/YRS9Xr07U282jvdXoLR3tPZXObwcJm4PvCVVmHRVBIbCFTJZJ9qk/di7sT6w36kBLgLLL9oAmbQloSrUdtv/l3Nsu4X61pG3qUxXZABuAHmlteyKw4o1QYvkFI/+vlV6bKA7B9NEGaH0bNwYTfXRdyMjqeUxKIf9kiQD4MZxw/kcUOV4WoL737O4sxYorvBASTyifxU3bmogH81PrHx7qVg9k1/53U+c4IAZw/Filvy9o1I4qrgzv9GSCdKJl/NpBcq9yqSwWv abc@cs-975921505315-default-default-tjppc

    GCE meta for SSH 參考示意

    細節參考 : Managing SSH keys in metadata

  3. 接下來我們就看透過 scp 的方式私鑰放入 vm 內:

    scp -i ~/.ssh/vpn-vm ~/.ssh/vpn-vm 34.150.93.183:~/.ssh/vpn-vm
    scp -i ~/.ssh/vpn-vm ~/.ssh/vpn-vm 35.240.144.123:~/.ssh/vpn-vm

CentOS update packages and libraries

也是一樣,拿到 GCE VM 我們先做更新的動作:

sudo yum update -y | sudo dnf update -y

SOCKS5 Server(vpn-hk) Setup

這邊我們將我們的 SOCKS5 Server 定為 vpn-hk 這台 VM, 意味這最後到 會是 34.150.93.183 這個 IP.

SSH SOCKS5

而我們使用一般的 SSH SOCKS 的方式運行的話其實只要透過一般的 SOCKS 的方式.下面這行指令就可透過 ssh 帶起設定:

# abc@vpn-hk 都是要換成你的VM的設定
sudo ssh -i ~/.ssh/vpn-vm -4 -NfD 0.0.0.0:8888 abc@vpn-hk

-4 這個設定是指定 IPV4, 如果不打先前看到有人是反應會有 bug 而連不上.(但我自幾沒遇道,只是還是避免遇到而添加上去)

到這邊用 SSH 帶起 SOCKS 就搞定了,但因為 SSH 服務會有長時間運作,程序(process)始終是在前台運行的。為了徹底解決SSH連線保持不超時的這個問題,這邊改用 AutoSSH 來進行 SOCKS 服務建立。

AutoSSH SOCKS5

AutoSSH 是一個用來對 SSH 連接進行監控的程序,可在遇到程序問題或者是網路問題時自動進行重連,以達到長期保持 SSH 穩定連接的目的 。

create autossh user

sudo groupadd --system autossh
sudo useradd -s /sbin/nologin --system -g autossh autossh

Install AutoSSH

sudo yum install wget gcc make -y
wget http://www.harding.motd.ca/autossh/autossh-1.4g.tgz
tar -xf autossh-1.4g.tgz
cd autossh-1.4g
./configure
make
sudo make install

以上是全手動下載後安裝的方式.

# https://mnlwldr.com/proxy-sh/

mkdir ~/keys/
sudo mv ~/.ssh/vpn-vm ~/keys/
sudo chown autossh:autossh ~/keys/
sudo chmod 755 ~/keys/

# 先手動一次同意憑證放入(輸入 yes)
autossh -M 55555 -i ~/keys/vpn-vm -4 -D 0.0.0.0:8888 -N abc@vpn-hk

# 後續即可使用 -f
autossh -M 55555 -f -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -i ~/keys/vpn-vm -4 -D 0.0.0.0:8888 -N abc@vpn-hk

上述指令的 5555 是指 autossh 的監控的 port.

Create autossh-socks-tunnel Service for systemd

接著來建立專屬的 autossh-socks-tunnel 服務,讓VM開關機都能自動運作不被影響

sudo vi /etc/systemd/system/autossh-socks-tunnel.service

需要特別移除 -f, 因為systemctl 已經在跑背景服務了不能再強制用 daemon(會導致 systemctl 以為服務終止了), 並將 private key CP 至 home/autossh/keys/vpn-vm

[Unit]
Description=AutoSSH tunnel service SOCKS over 8888
After=network.target

[Service]
Type=simple
User=autossh
Group=autossh
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/local/bin/autossh -M 55555 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -i /home/autossh/.ssh/vpn-vm -4 -D 0.0.0.0:8888 -N abc@vpn-hk
Restart=always

[Install]
WantedBy=multi-user.target

接著沒給權限的就陸續給權限,如下面這些…

sudo chown autossh:autossh /etc/systemd/system/autossh-socks-tunnel.service
sudo chmod 755 /etc/systemd/system/autossh-socks-tunnel.service

/home/autossh/keys
/home/autossh/.ssh

sudo chmod 600 vpn-vm.pub
sudo chmod 600 vpn-vm
# Reload systemd(如果有修改到上面的 autossh-socks-tunnel.service 就要執行下面的指令仔入修改):
sudo systemctl daemon-reload

# Start the Autossh service:
sudo systemctl stop autossh-socks-tunnel.service
sudo systemctl start autossh-socks-tunnel.service

# Enable at boot:
sudo systemctl enable autossh-socks-tunnel.service

# Check status with:
sudo systemctl status autossh-socks-tunnel

Redsocks Server(vpn-sg)

接著來安裝 Redsocks 並且調整 iptables 設定

Redsocks Setup

# Install compile tool
sudo yum install libevent-devel git gcc make openssl-devel -y

# Download and compile
cd ~/
git clone https://github.com/darkk/redsocks
cd ~/redsocks/
make
sudo cp ~/redsocks/redsocks /usr/local/bin/

# Set path and .conf
sudo mkdir -R /data/log/redsocks/
sudo vi /etc/redsocks.conf

這邊將下面的內容放入 /etc/redsocks.conf:

base {
      log_debug = off;
      log_info = on;
      log = "file:/data/log/redsocks/redsocks.log";
      daemon =off;
      redirector = iptables;
      redsocks_conn_max = 200;
      connpres_idle_timeout = 30;
}

redsocks {
      local_ip = 0.0.0.0;
      local_port = 12345;

      ip = 10.170.0.34;
      port = 8888;
      type = socks5;
}

可以看到我們這邊是透過內網 10.170.0.34 的 IP 來進行 SOCKS 的串接.

調整一下 iptables, 重新指派 routing 規則:

# skip local
sudo iptables -t nat -A OUTPUT -d 10.170.0.9 -j RETURN
sudo iptables -t nat -A OUTPUT -d 10.0.0.0/8 -j RETURN
sudo iptables -t nat -A OUTPUT -d 172.16.0.0/16 -j RETURN
sudo iptables -t nat -A OUTPUT -d 192.168.0.0/16 -j RETURN
sudo iptables -t nat -A OUTPUT -d 127.0.0.0/8 -j RETURN

# Create and config for Redsocks Routing

sudo iptables -t nat -N REDSOCKS

sudo iptables -t nat -A OUTPUT -j REDSOCKS -p tcp -m comment --comment 'redsocks proxy'
sudo iptables -t nat -A REDSOCKS -j REDIRECT -p tcp --dport 31380 --to-ports 12345 -m comment --comment 'use redsocks for all TCP'

# Save and avoid missing from restart
sudo iptables-save | sudo tee /etc/iptables/rules.v4

# Set systemd for redsocks.service
sudo vi /etc/systemd/system/redsocks.service

redsocks.service 具體內容:

[Unit]
Description=redsocks
Requires=network-online.target
After=network-online.target

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/redsocks -c /etc/redsocks.conf

[Install]
WantedBy=multi-user.target

這邊也是跟剛剛上方 AutoSSH 的啟動服務註冊與運作、狀態查詢一樣,只是更換了註冊服務,這邊就不贅述了:

sudo systemctl daemon-reload
sudo systemctl enable redsocks
sudo systemctl start redsocks
sudo systemctl status redsocks
sudo systemctl stop redsocks

systemctl list-unit-files | grep enabled

Result and Verify

到上面就這邊就完成所有設定了,最後驗證結果,在 vpn-sg 上面進行遠程調用可以取回 vpn-hk 的 ip 回應證明完成:

GCP 資源上配給 GCE VM 的靜態保留 IP

vpn-sg 上直接使用 curl 會帶出 vpn-hk 主機所指配的靜態保留 IP

In the end…

本回最多感觸的應該是 iptables 的設定,附上當時參考(我覺得畫得最完整的版本)

圖片來源:http://xkr47.outerspace.dyndns.org/netfilter/packet_flow/

Ref


作者: Blackie Tsai
版權聲明: 本站所有文章除特別聲明外,均採用 CC BY 4.0 許可協議。轉載請註明來源 Blackie Tsai !
  目錄