1.背景信息
公司游戲官網的項目,集群使用ingress開放出去,后端由於是php語言編寫,所以在php的pod里面也需要一個nginx來開放連接。所以本次的路由順序就如以下:
騰訊雲LB → ingress → nginx
所以本次環境,ingress和nginx都需要獲取客戶端的真實IP。所以本篇文檔還是主要講解一下使用方式和注意事項。
2.基本概念
以上講解了ingress和nginx獲取真實IP的方式,這里還是簡單的了解一下基本概念。
(1)remote_addr
代表客戶端的IP,但它的值不是由客戶端提供的,而是服務端根據客戶端的ip指定的
當你的瀏覽器訪問某個網站時,假設中間沒有任何代理,那么網站的web服務器(Nginx,Apache等)
就會把remote_addr設為你的機器IP,如果你用了某個代理,那么你的瀏覽器會先訪問這個代理,然后再由這個代理轉發到網站
這樣web服務器就會把remote_addr設為這台代理機器的IP,除非代理將你的IP附在請求header中一起轉交給web服務器
(2)X-Forwarded-For(簡稱XFF)
X-Forwarded-For 是一個 HTTP 擴展頭部,HTTP協議並沒有對它的定義,它最開始是由 Squid 這個緩存代理軟件引入
用來表示 HTTP 請求端真實 IP,如今它已經成為事實上的標准,被各大 HTTP 代理、負載均衡等轉發服務廣泛使用
並被寫入 RFC 7239(Forwarded HTTP Extension)標准之中
XFF的格式為X-Forwarded-For: client, proxy1, proxy2
XFF 的內容由「英文逗號 + 空格」隔開的多個部分組成,最開始的是離服務端最遠的設備 IP,然后是每一級代理設備的 IP
(注意:如果未經嚴格處理,可以被偽造)
如果一個 HTTP 請求到達服務器之前,經過了三個代理 Proxy1、Proxy2、Proxy3,IP 分別為 IP1、IP2、IP3,用戶真實 IP 為 IP0
那么按照 XFF 標准,服務端最終會收到以下信息
X-Forwarded-For: IP0, IP1, IP2
Proxy3 直連服務器,它會給 XFF 追加 IP2,表示它是在幫 Proxy2 轉發請求
列表中並沒有 IP3,IP3 可以在服務端通過 Remote Address 字段獲得
(3)X-Real-IP
這又是一個自定義頭部字段,通常被 HTTP 代理用來表示與它產生 TCP 連接的設備 IP
這個設備可能是其他代理,也可能是真正的請求端,這個要看經過代理的層級次數或是是否始終將真實IP一路傳下來
(注意:如果未經嚴格處理,可以被偽造)
3.Ingress 獲取客戶端真實IP
通常,用戶ip的傳遞依靠的是X-Forwarded-*參數。但是默認情況下,ingress是沒有開啟的。
ingress的文檔還比較詳細,這里介紹一下可能用到的這3個參數:
ingress官方文檔: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#use-forwarded-headers
以上有三個比較重要的參數。下面一一解釋
3.1 use-forwarded-headers
- 如果Nginx在其他7層代理或負載均衡后面,當期望Nginx將X-Forwarded-*的頭信息傳遞給后端服務時,則需要將此參數設為true
- 如果設為false(默認為false),Nginx會忽略掉X-Forwarded-*的頭信息。false設置適用於Nginx直接對外或前面只有3層負載均衡的場景
由於ingress的主配置是從configmap中獲取的,更新參數則需要修改名為nginx-configuration的configmap的配置:在data配置塊下添加use-forwarded-headers: "true"
修改后,ingress nginx會自動加載更新nginx.conf主配置文件。下圖為更新前后配置文件變化對比:
注意:左邊為開啟use-forwarded-headers后ingress nginx主配置文件,右邊為開啟前
3.2 forwarded-for-header
用來設置識別客戶端來源真實ip的字段,默認是X-Forwarded-For。如果想修改為自定義的字段名,則可以在configmap的data配置塊下添加:forwarded-for-header: "THE_NAME_YOU_WANT"。通常情況下,我們使用默認的字段名就滿足需求,所以不用對這個字段進行額外配置。當然,你想顯示的配置也可以。
3.3 compute-full-forwarded-for
如果只是開啟了use-forwarded-headers: "true"的話,會發現還是沒能獲取到客戶端來源的真實ip,原因是當前X-Forwarded-For變量是從remote_addr獲取的值,每次取到的都是最近一層代理的ip。為了解決這個問題,就要配置compute-full-forwarded-for字段了,即在configmap的data配置塊添加:compute-full-forwarded-for: "true"。其作用就是,將客戶端用戶訪問所經過的代理ip按逗號連接的列表形式記錄下來。
待ingress nginx加載configmap並更新主配置文件后,對比更新前后變化如下:
注:左邊是未開啟compute-full-forwarded-for配置的ingress nginx主配置文件,右邊是開啟了的
3.4 舉例說明
如果從客戶端ip0發起一個HTTP請求到達服務器之前,經過了三個代理proxy1、proxy2、proxy3,對應的ip分別為ip1、ip2、ip3,那么服務端最后得到的X-Forwarded-For值為:ip0,ip1,ip2。列表中並沒有ip3,ip3可以在服務端通過remote_addr來獲得。這樣應用程序通過獲取X-Forwarded-For字段的第一個ip,就可以得到客戶端用戶真實ip了。
3.5 注意項
值得注意的是,並不是所有的場景都能通過X-Forwarded-For來獲取用戶正式ip。
比如,當服務器前端使用了CDN的時候,X-Forwarded-For方式獲取到的可能就是CDN的來源ip了,
這種情況,可以根CDN廠商約定一個字段名來記錄用戶真實ip,然后代理將這個字段逐層傳遞,最后到服務端。
4.Nginx獲取客戶端真實IP
先講解ingress在講解nginx原因是因為,在架構圖里面,nginx在ingress后面,這里有一個非常需要注意的點就是,如果ingress不先拿到客戶端的真實IP,nginx不管怎么配置都拿不到,因為在ingress那一層就沒有真實的客戶端IP了。往后面nginx傳遞的也就沒有真實IP了。
4.1 配置
#放在http模塊等,個人比較喜歡放在http set_real_ip_from 192.168.1.0/24; #真實服務器上一級代理的IP地址或者IP段,可以寫多行。 real_ip_header X-Forwarded-For; #從哪個header頭檢索出所要的IP地址。 real_ip_recursive on; #遞歸的去除所配置中的可信IP。排除set_real_ip_from里面出現的IP。如果出現了未出現這些IP段的IP,那么這個IP將被認為是用戶的IP。
Nginx使用以上的配置就可以了
參考:https://www.cnblogs.com/yudai/p/10974444.html