該死的防火牆詛咒之2: K8S拔除

Shawn Ho
輕鬆小品-k8s的點滴
9 min readJun 16, 2021

最近WFH,前同事推薦了一部好看的卡通:咒術迴戰~ 裏面主要是咒術師,咒靈和詛咒師的戰爭~裡面說道一句名言:『詛咒就應該用詛咒來拔除』。

防火牆最近對我就像個詛咒一樣,上一篇講過用Script來拔除。沒想到最近親愛的客戶要開始介接GCP上的GKE和地端服務,又跟防火牆扯上關係了。大概的狀況就是想要用GKE裡的Pod,去存取地端的某個特定服務。原本神經大條的我想說 這有什麼問題?不是interconnect已經通了嗎?結果,是因為地端防火牆(對,又是它)必須有白名單Allow-List,資安團隊要求必須提供1~2個IP位置。如果玩過K8S的捧油,大概了解~Pod本身的IP是不固定的~有人可能說,那就透過Node IP的SNAT,把Node的IP加入防火牆白名單吧~這個…GKE支援AutoScaler…所以未來這些Node的IP可能也會變唷~

真正要實現這個機制,很多地端的K8S Distribution必須仰賴CNI+SDN的方式解決,如: Openshift的Egress Route是通過OVN(open-virtual-networking),以及Tanzu裡的NSX。但如果部署不了支援的SDN區域怎麼辦呢?我遇到的詛咒就是這樣的一個狀況~那我們就走老派方法,SNAT吧!

很多人看到SNAT,可能第一時間想到的是『買一台』,其實一台Linux Server(e.g. CentOS or Ubuntu)其實都可以快速支援NAT的功能,底下我們來介紹,如何用GCE快速搭建一對具有自癒能力的NAT Server。

上方圖示是大概的架構圖。這裡面橘色部分是通過GCE創建的SNAT Server,主要創建的方法是通過設定GCE VM(標示為橘色SNAT),使用IPTables的masquerade機制,並在VPC內強迫Worker Node(標示為N1)節點的靜態路由導向SNAT的兩台GCE VM。

同時考量是企業使用,我們一併通過Instance Group搭建出具有自癒能力的GCE VM,自癒能力是通過Healthcheck偵測GCE VM上的http服務是否回覆200 OK。結合這兩種需求,我們可將SNAT的Cloud-Init安裝腳本設置如下:

# nat-startup.sh
#!/bin/bash
# 安裝iptables-persistent於GCE上export DEBIAN_FRONTEND=noninteractive
apt-get -y update
apt-get install -y debconf-utils
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
apt-get -y install iptables-persistent
# 設定OS准許封包直接轉傳
sysctl -w net.ipv4.ip_forward=1
sed -i= 's/^[# ]*net.ipv4.ip_forward=[[:digit:]]/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
# 設定Iptables上的masquerade (由於我們使用預設Debian GCE VM,網卡名稱為ens4)
iptables -t nat -A POSTROUTING -o ens4 -j MASQUERADE
iptables-save
# Create a web-server for healthcheck
sudo apt update && sudo apt -y install apache2
echo '<!doctype html><html><body><h1>Hello World!</h1></body></html>' | sudo tee /var/www/html/index.html

接下來,我們使用以下的Script,將安裝腳本快速打包成Instance Template,並將兩台機器快速產出,並將靜態路由設定完畢:

#!/bin/zsh# 將上述啟動script打包成instance template
gcloud compute instance-templates create natgw \
--machine-type n1-standard-2 --can-ip-forward --tags natgw --network private-cluster-1-network --subnet private-cluster-1-subnetwork --metadata-from-file=startup-script=nat-startup.sh
# 設定HealthCheck,基於安裝的http server預設路徑為"/"
gcloud compute health-checks create http nat-health-check \
--check-interval 30 --healthy-threshold 1 --unhealthy-threshold 3 \
--timeout 5s --port 80 --request-path /
# 設定GCE instance group VM數量為2,並指定基於前面打包的instance template
gcloud compute instance-groups managed create natgw --size=2 --template=natgw --zone=asia-east1-a
gcloud beta compute instance-groups managed set-autohealing natgw \
--health-check nat-health-check --initial-delay 120 --zone asia-east1-a
# 設定static route path到這兩台GCE上,由於priority相同,兩台GCE都會被輪到
# 該Route的規則僅會使用於VM Tag為no-ip的機器上。
gws=( $(gcloud compute instances list | grep natgw | awk '{print $1}') )
for gw in $gws[@]; do
gcloud compute routes create nat-route-${gw} --network private-cluster-1-network \
--destination-range 0.0.0.0/0 \
--next-hop-instance $gw \
--next-hop-instance-zone asia-east1-a \
--tags no-ip --priority 900

上述Script執行完畢後,需要將Worker Node這些VM,打上no-ip的Tag方能生效,或是我們也可以使用GKE VM上預設的Tag作為routes的選擇標的。

最後,若需要提供固定GCE VM 的IP位置,我們可以使用本文件的建議作法

# 通過gcloud compute instances describe找出accessConfigs下的name欄位
gcloud compute instances describe $VM_NAME
- accessConfigs:
- kind: compute#accessConfig
name: external-nat
natIP: 107.167.180.77
networkTier: PREMIUM
type: ONE_TO_ONE_NAT
# 移除Access Config (即取消VM的外部IP)
gcloud compute instances delete-access-config $VM_NAME \
--access-config-name="external-nat"

# 新增固定IP位置 (IP取得,請用gcloud compute addresses create)
gcloud compute instances add-access-config $VM_NAME \
--access-config-name="external-nat" --address=35.221.178.7

這樣,當我們訪問外部服務器時(e.g. https://whatismyipaddress.com)

# 兩台GCE VM
snat-gke % gcloud compute instances list | grep natgw
natgw-1kl4 asia-east1-a n1-standard-2 10.81.68.135 35.221.178.7 RUNNING
natgw-p12l asia-east1-a n1-standard-2 10.81.68.140 35.234.33.83 RUNNING
# 使用任一台有no-ip tag的VM,訪問whatismyipaddress.com會看到,IP被SNAT為上方兩台GCE VM的IP位置shawnho@client:~$ curl https://whatismyipaddress.com | grep "Your IP"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 <span class="cf-footer-item sm:block sm:mb-1"><span>Your IP</span>: 35.234.33.83</span>
100 12403 0 12403 0 0 346k 0 --:--:-- --:--:-- --:--:-- 346k

--

--

Shawn Ho
輕鬆小品-k8s的點滴

一個心態年輕的中年大叔。年輕時不學好~ 台大電機畢業後,去美國取得了博士學位,念完博士後,不想教書。當過補習班老師,碼農,產品總監,ISO稽核顧問,技術銷售,目前在Google Cloud跟客戶一起玩Kubernetes,也跟喜歡的客戶在金融, 政府, 電信, 高科技業內共同成長學習是斜槓人生的好案例。