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

適用範圍:騰訊雲容器服務(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,以滿足用戶相關使用場景的需求,用戶可通過對比上述四幾種方式的優點和缺點,選擇適合實際需求場景的最佳方案。

參考資料

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