在容器服務中獲取客戶端真實源 IP

騰訊雲原生發表於2020-10-16

適用範圍:騰訊雲容器服務(Tencent Kubernetes Engine ,TKE), 以下簡稱 TKE。

為什麼需要獲取客戶端真實源 IP?

當需要能感知到服務請求來源去滿足一些業務需求時,就需要後端服務能準確獲取到請求客戶端的真實源 IP, 比如以下場景:

  1. 對服務請求的來源有做審計的需求,如異地登陸告警。
  2. 針對安全攻擊或安全事件溯源需求,如 APT 攻擊、DDoS 攻擊等。
  3. 業務場景資料分析需求,如業務請求區域統計。
  4. 其他需要獲取客戶端地址的需求。

在 TKE 使用場景下如何獲取客戶端真實源 IP?

在TKE中預設的外部負載均衡器是 騰訊雲負載均衡器,作為服務流量的訪問首入口,騰訊雲負載均衡器會將請求流量負載轉發到 Kubernetes 工作節點的 Kubernets Service(預設),此負載均衡過程會保留客戶端真實源 IP(透傳轉發),但在 Kubernetes Service 轉發場景下,無論是使用 iptbales 還是 ipvs 的負載均衡轉發模式,轉發時都會對資料包做 SNAT,即不會保留客戶端真實源 IP,為了能夠準確的獲取到客戶端的真實源 IP,在 TKE 使用場景下,主要有四種方法獲取客戶端真實源 IP,下面將逐個展開介紹下。

一、通過 Service 資源的配置選項保留客戶端源 IP

要啟用保留客戶端 IP 功能,可在 Service 資源中配置欄位 Service.spec.externalTrafficPolicy,此欄位表示服務是否希望將外部流量路由到節點本地或叢集範圍的端點。有兩個選項值:Cluster(預設)和 Local 方式,如下圖所示:

img

Cluster 表示隱藏了客戶端源 IP, LoadBalancerNodePort 型別服務流量可能會被轉發到其他節點的 Pods; Local 表示保留客戶端源 IP 並避免 LoadBalancerNodePort 型別的服務流量轉發到其他節點的 Pods,詳情請參考 kubernets設定外部負載均衡器說明。相關 YAML 配置示例如下:

apiVersion: v1
kind: Service
metadata:
  name: example-Service
spec:
  selector:
    app: example-Service
  ports:
    - port: 8765
      targetPort: 9376
  externalTrafficPolicy: Local
  type: LoadBalancer

優點:只需要修改 Kubernets Service 資源配置即可。

缺點:會存在潛在的 Pods(Endpoints)流量負載不均衡風險。

二、通過TKE原生的 CLB 直通 Pod 轉發模式獲取

使用TKE原生支援的 CLB 直通 Pod 的轉發功能(CLB 透傳轉發,並繞過 Kubernetes Service 流量轉發),後端 Pods 收到的請求的源IP即是客戶端真實源IP,此方式無論是在四層還是七層服務的轉發場景下都適用,轉發原理如下圖:

img

詳細介紹和配置請參考文件 TKE場景下騰訊雲CLB直通Pod使用場景介紹

優點:TKE原生支援的功能特性,只需在控制檯按照文件配置即可。

缺點:叢集需要開啟 VPC-CNI 模式網路,詳情參考文件 VPC-CNI 模式說明

三、通過 HTTP Header 獲取

在七層(HTTP/HTTPS)服務轉發場景下,可以通過獲取 Http Header 中 X-Forwarded-ForX-Real-IP 欄位的值來獲取客戶端真實源 IP, TKE 中有兩種場景使用方式,原理介紹如下:

img

在場景一中,騰訊雲負載均衡器(CLB 七層) 預設會將客戶端真實源IP放到 HTTP Header 的 X-Forwarded-ForX-Real-IP 欄位,當服務流量在經過 Service 四層轉發後會保留上述欄位,後端通過WEB伺服器代理配置或應用程式碼方式獲取到客戶端真實源IP,詳情參考請文件 負載均衡如何獲取客戶端真實 IP - 最佳實踐 - 文件中心 - 騰訊雲

在場景二中, Nginx Ingress 服務部署需要 Nginx Ingress 能直接感知客戶端真實源 IP,可以採用保留客戶端源IP的配置方式(詳情參考 kubernets設定外部負載均衡器說明 ),或通過 CLB 直通 Pod 的方式(詳情參考 TKE場景下騰訊雲CLB直通Pod使用場景介紹),當 Nginx Ingress 在轉發請求時會通過 X-Forwarded-ForX-Real-IP 欄位來記錄客戶端源 IP,後端可以通過此欄位獲得客戶端真實源 IP。

下面詳細介紹在 TKE 中兩種場景的配置使用方法:

  • 場景一:使用 TKE Ingress 獲取真實源 IP

    在TKE控制檯先為工作負載建立一個主機埠訪問方式的 Service 資源,如下圖:

img

然後在控制檯為 Service 新建一個對應的 Ingress 訪問入口,如下圖:

img

待配置生效後,在後端通過獲取 HTTP Header 中的 X-Forwarded-ForX-Real-IP 欄位值得到客戶端真實源 IP。後端抓包測試結果示例如下:

img

  • 場景二: 使用 Nginx Ingress 獲取真實源 IP

Nginx Ingress 可以通過 TKE 應用商店、自定義 YAML 配置或使用官方(helm 安裝)方式安裝,原理和部署方法可參考文件 在 TKE 上部署 Nginx Ingress 中的部署方案一或方案三,若選擇方案一部署,則需要修改 Nginx Ingress Controller Service 的 externalTrafficPolicy 欄位值為 Local 。安裝完成後,會在TKE控制檯自動為 Nginx Ingress Controller 服務建立一個 CLB(四層)訪問入口,如下圖所示:

img

為要轉發的後端服務建立一個 Ingress 資源並配置轉發規則, 可以使用以下 YAML 建立:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx  # ingressClass類為"nginx"
  name: example
  namespace: default
spec:
  rules:  # 配置服務轉發規則
     - http:
        paths:
          - backend:
              serviceName: nginx  
              servicePort: 80
            path: /

待配置生效後,在後端獲取 Http Header 中的 X-Forwarded-ForX-Real-IP 欄位值得到客戶端真實源 IP,後端抓包測試結果示例如下:

img

以上介紹的兩種場景都可以滿足獲取客戶端真實源 IP 的需求,且具有以下優點和缺點:

優點:在七層(HTTP/HTTPS)流量轉發場景下比較推薦,可通過WEB服務代理的配置或後端應用程式碼直接獲取 Http Header 中的欄位即可拿到客戶端真實IP,非常簡單高效。

缺點:僅適用於七層(HTTP/HTTPS)流量轉發場景,不適用於四層轉發場景,如果是四層轉發場景,請使用後面介紹的其他方式。

四、通過 TOA 核心模組載入獲取真實源 IP

TOA 核心模組原理和載入方式參考 全球應用加速 獲取訪問使用者真實 IP - 操作指南 - 文件中心 - 騰訊雲 文件。

優點:對於 TCP 傳輸方式,在核心層面且僅對 TCP 連線的首包進行改造,幾乎沒有效能損耗。

缺點

  1. 需要在叢集工作節點上載入 TOA 核心模組,且需在服務端通過函式呼叫獲取攜帶的源 IP、埠資訊,配置使用比較麻煩。
  2. 對於 UDP 傳輸方式,會對每個資料包改造新增 option 資料(源 IP 和源埠),帶來網路傳輸通道效能損耗。

總結

本文主要介紹了在TKE使用場景下服務端如何獲取客戶端真實源 IP,以滿足使用者相關使用場景的需求,使用者可通過對比上述四幾種方式的優點和缺點,選擇適合實際需求場景的最佳方案。

參考資料

【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公眾號,及時獲取更多幹貨!!

相關文章