<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          k8s生產實踐之獲取客戶端真實IP

          共 9640字,需瀏覽 20分鐘

           ·

          2021-05-23 14:37

          目錄

          • 1、概述

          • 2、環(huán)境介紹

          • 3、相關說明

          • 4、環(huán)境準備

          • 5、負載配置

          • 6、Ingress Controller 配置

          • 7、服務端驗證

          • 8、小結


          1、概述

          通常web應用獲取用戶客戶端的真實ip一個很常見的需求,例如將用戶真實ip取到之后對用戶做白名單訪問限制、將用戶ip記錄到數(shù)據(jù)庫日志中對用戶的操作做審計等等

          vm時代是一個比較容易解決的問題,但當一切云原生化(容器化)之后變得稍微復雜了些

          k8s中運行的應用通過Service抽象來互相查找、通信和與外部世界溝通,在k8s中是kube-proxy組件實現(xiàn)了Service的通信與負載均衡,流量在傳遞的過程中經過了源地址轉換SNAT,因此在默認的情況下,常常是拿不到用戶真實的ip

          這個問題在k8s官方文檔(https://kubernetes.io/zh/docs/tutorials/services/source-ip/)中基于Cluster IPNodePortLoadBalancer三種不同的Service類型進行了一定的說明,這里不再剖析

          2、環(huán)境介紹

          本篇僅介紹私有云+外部硬件負載+k8s集群的真實場景下如何進行配置

          相關環(huán)境及設備說明如下

          組件名型號或版本
          硬件負載設備SANGFOR(深信服) AD 6.5R1
          k8s Ingress 控制器NGINX Ingress Controller 0.25.0
          k8s 集群Kubernetes 1.17.0

          3、相關說明

          真實生產場景下,一般提供給用戶的都是七層https服務

          首先域名解析在外部負載設備綁定的公網ip上,負載周邊可能還會有一些安全設備例如WAF等,這里不多介紹

          流量經過負載后進入到k8s集群中,其中Ingress ControllerDaemonSet方式部署并使用hostNetwork模式接收并處理到達宿主機的80443端口流量

          關于https證書的配置,一般有以下兩種可選方式:

          • 配置在負載設備(負載類型如果只考慮七層負載),由負載負責將數(shù)據(jù)包封包解包,并轉發(fā)到后端,如果用戶通過https形式訪問,流量經過的流程是:用戶端——>負載80端口——>負載443端口——>服務端(k8s node)的80端口

          • 配置在后端,例如Ingress資源上,如果用戶通過https形式訪問,流量經過的流程是:用戶端——>負載80端口——>服務端(k8s node)的80端口——>服務端(k8s node)的443端口

          但是為了獲取用戶的真實ip,只能選擇方式一,因為如果證書配置在后端服務,流量經過負載時是加密的,負載一般在沒有證書的情況下,是無法對數(shù)據(jù)包進行解包操作透傳用戶ip

          以上在公有云環(huán)境下,例如騰訊云CLB、阿里云新的應用型負載ALB或傳統(tǒng)型負載CLB均有涉及,可能不盡詳細

          4、環(huán)境準備

          首先需要準備一個后端獲取用戶請求,顯示打印或輸出的應用,可以自己手擼一個簡單應用,當然為了操作簡單也可以選擇nginx容器在應用日志中查看,更好的方式是選擇whoamiechoserver這類鏡像

          其中whoami可以在控制臺訪問服務時打印用戶請求等相關信息,echoserver可以在瀏覽器呈現(xiàn)用戶請求等相關信息

          這里為了模擬和真實應用一樣的場景,選擇更為直觀的echoserver,其源鏡像地址為gcr.io/google-containers/echoserver

          如果網絡不佳,可以從我的地址獲取ssgeek/echoserver

          首先基于k8s部署該應用,創(chuàng)建deploysvcing,定義如下

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: echoserver
            labels:
              app: echoserver
          spec:
            selector:
              matchLabels:
                app: echoserver
            template:
              metadata:
                labels:
                  app: echoserver
              spec:
                containers:
                - name: echoserver
                  image: ssgeek/echoserver:latest
                  ports:
                  - containerPort: 8080
                  env:
                    - name: NODE_NAME
                      valueFrom:
                        fieldRef:
                          fieldPath: spec.nodeName
                    - name: POD_NAME
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.name
                    - name: POD_NAMESPACE
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.namespace
                    - name: POD_IP
                      valueFrom:
                        fieldRef:
                          fieldPath: status.podIP

          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: echoserver
            labels:
              app: echoserver
          spec:
            ports:
            - port: 80
              targetPort: 8080
              name: http
            selector:
              app: echoserver

          ---
          apiVersion: extensions/v1beta1
          kind: Ingress
          metadata:
            name: echoserver
            annotations:
              kubernetes.io/ingress.class: nginx
          spec:
            rules:
            - host: echo.ssgeek.com
              http:
                paths:
                - backend:
                    serviceName: echoserver
                    servicePort: 80
                  path: /

          5、負載配置

          這里簡單分析及列出關鍵配置

          • 插入請求頭以透傳ip

          部署好后端服務后,開始配置外部(深信服)負載,除了導入https證書外,還需要在轉發(fā)的請求頭中插入X-Forwarded-For頭部,確保用戶ip在經過負載時作為請求頭的一部分傳遞到后端服務器

          • 負載設備到后端請求頭部改寫

          由于負載設備到后端的80端口,因此后端只接收http請求,也就是請求經過負載處理https及證書相關動作

          未添加請求頭部改寫時,對請求抓包的現(xiàn)象對比如下(分別為無https配置時和有https配置但未改寫請求頭部時)

          6、Ingress Controller 配置

          修改Nginx Ingress Controller配置,添加如下內容

          參考:https://kubernetes.github.io/ingress-nginx/user-guide/

          data:
            use-forwarded-headers: "true"
            compute-full-forwarded-for: "true"
            forwarded-for-header: "X-Forwarded-For"
          • use-forwarded-headers

            如果為true,會將傳入的X-Forwarded-*頭傳遞給upstreams

            如果為false,會忽略傳入的X-Forwarded-*頭,用看到的請求信息填充它們。如果直接暴露在互聯(lián)網上,或者它在基于L3/packet-based load balancer后面,并且不改變數(shù)據(jù)包中的源IP時使用此選項

          • forwarded-for-header

            設置標頭字段以標識客戶端的原始IP地址。默認: X-Forwarded-For

          • compute-full-forwarded-for

            將遠程地址附加到 X-Forwarded-For標頭,而不是替換它。啟用此選項后,upstreams應用程序將根據(jù)其自己的受信任代理列表提取客戶端IP

          7、服務端驗證

          服務端請求暴露及應用獲取ip效果如下

          正常情況可拿到以下幾類ip

          • pod ip

          k8s pod自身的ip

          • node ip

          k8s pod所在nodeip

          • 負載 ip

          位于請求頭X-Forwarded-For字段中

          • 用戶真實 ip

          位于請求頭X-Forwarded-For字段、x-original-forwarded-for字段、x-real-ip字段中

          關于x-forwarded-forx-original-forwarded-forx-real-ip的說明:

          X-Forwarded-For用于記錄從客戶端地址到最后一個代理服務器的所有地址

          X-Real-IP用于記錄請求的客戶端地址

          X-Original-Forwarded-For字面意思是原始轉發(fā) IP,這是Ingress的功能,Ingress將用戶的真實IP記錄到了這個字段

          對應用來說,以java應用為例,獲取用戶ip的代碼如下

          /**
           * 獲取操作用戶ip
           * @return
           */

          private String getIp() {

              HttpServletRequest request;
              try {
                  request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
              } catch (NullPointerException e) {
                  return "127.0.0.1";
              }

              //取客戶端ip
              String ipAddress = request.getHeader("x-forwarded-for");
              if (ipAddress == null || ipAddress.length() == 0
                      || "unknown".equalsIgnoreCase(ipAddress)) {
                  ipAddress = request.getHeader("Proxy-Client-IP");
              }
              if (ipAddress == null || ipAddress.length() == 0
                      || "unknown".equalsIgnoreCase(ipAddress)) {
                  ipAddress = request.getHeader("WL-Proxy-Client-IP");
              }
              if (ipAddress == null || ipAddress.length() == 0
                      || "unknown".equalsIgnoreCase(ipAddress)) {
                  ipAddress = request.getRemoteAddr();
                  if (ipAddress.equals("127.0.0.1")) {
                      // 根據(jù)網卡取本機配置的IP
                      InetAddress inet = null;
                      try {
                          inet = InetAddress.getLocalHost();
                      } catch (UnknownHostException e) {
                          e.printStackTrace();
                      }
                      ipAddress = inet.getHostAddress();
                  }
              }
              // 對于通過多個代理的情況,第一個IP為客戶端真實IP,多個IP按照','分割
              if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                  // = 15
                  if (ipAddress.indexOf(",") > 0) {
                      ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                  }
              }
              return ipAddress;
          }

          8、小結

          本文記錄了私有云和有外部負載的真實場景下,k8s集群中的應用獲取用戶ip的相關實現(xiàn)邏輯及關鍵處理,希望能幫助到大家

          See you ~

          瀏覽 88
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美激情综合色综合啪啪五月 | 俺去俺来也WWW色老板 | 国产麻豆天美果冻无码视频 | 欧美激情精品久久久久久变态 | 久久夫妻视频 |