Kubernets中獲取客戶端真實(shí)IP總結(jié)

1. 導(dǎo)言

絕大多數(shù)業(yè)務(wù)場景都是需要知道客戶端IP的
在k8s中運(yùn)行的業(yè)務(wù)項(xiàng)目凉唐,如何獲取到客戶端真實(shí)IP?
本文總結(jié)了通行的2種方式
要答案的直接看方式一、方式二和總結(jié)
SEO 關(guān)鍵字
nginx ingress客戶端真實(shí)ip
kubernets獲取客戶端真實(shí)ip
rke獲取客戶端真實(shí)ip
rancher獲取客戶端真實(shí)ip
本文由 www.iamle.com 流水理魚 原創(chuàng),wx公眾號同名

1.1 流量鏈路介紹

7層轉(zhuǎn)發(fā)鏈路 Client(客戶端) > Nginx > K8s Ingress(Nginx ingress)
4層轉(zhuǎn)發(fā)鏈路 Client(客戶端) > 公有云LB > K8s Ingress(Nginx ingress)
ps: 實(shí)際業(yè)務(wù)會串聯(lián)更多層級的轉(zhuǎn)發(fā)。WAF惯退、CDN、Api Gateway一般是http 7層轉(zhuǎn)發(fā)从藤,LB一般是4層tcp轉(zhuǎn)發(fā)

1.2 準(zhǔn)備whoami探針

whomai是一個(gè)go編寫的調(diào)試探針工具催跪,回顯http頭信息
在k8s中部署一個(gè)containous/whoami用來作為探針,配置好ingress公網(wǎng)和訪問夷野,這樣客戶端web訪問可以看到基本的http頭信息懊蒸,方便調(diào)試

kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
  namespace: default
  labels:
    app: whoami
spec:
  replicas: 1
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
      - image: containous/whoami
        imagePullPolicy: Always
        name: whoami
        ports:
        - containerPort: 80
          name: 80tcp02
          protocol: TCP
      dnsPolicy: ClusterFirst
      restartPolicy: Always
EOF 

ps:ingress自行增加

客戶端web訪問,回顯http頭示例

Hostname: whoami-65b8cc4b-6vwns
IP: 127.0.0.1
IP: 10.42.2.12
RemoteAddr: 10.42.1.0:47850
GET / HTTP/1.1
Host: whoami.iamle.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6,la;q=0.5
Cookie: _ga=GA1.2.30707523.1570429261;
Dnt: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 8.8.8.8, 10.0.0.1
X-Forwarded-Host: whoami.iamle.com
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Original-Forwarded-For: 8.8.8.8
X-Original-Uri: /
X-Real-Ip: 8.8.8.8
X-Request-Id: 3852c9780589ffba4c1f9f2785691d5f
X-Scheme: https

2. 兩種方式 7層http頭X-Forwarded-For透傳 和 4層Proxy Protocol透傳

獲得客戶端真實(shí)IP有針對7層和針對4層兩種方式

2.1 7層http頭X-Forwarded-For透傳介紹

http工作在網(wǎng)絡(luò)第7層,http中有個(gè)X-Forwarded-For字段

大部分CDN悯搔、WAF骑丸、LB用X-Forwarded-For字段來存客戶端IP,也有用X-Real-Ip字段妒貌,cloudflare通危、百度云加速還擴(kuò)展了CF-Connecting-IP字段
標(biāo)準(zhǔn)數(shù)據(jù)為

X-Forwareded-For:Client,proxy1灌曙,proxy2菊碟,proxy3……

第一個(gè)ip是客戶端ip,后面的proxy為路過一層就加一層的ip
這里的proxy可以是WAF在刺、CDN逆害、LB、Api Gateway等

2.2 4層Proxy Protocol透傳

tcp工作在網(wǎng)絡(luò)第4層,Proxy Protocol就是在tcp中增加一個(gè)小的報(bào)頭增炭,用來存儲額外的信息

代理協(xié)議即 Proxy Protocol,是haproxy的作者Willy Tarreau于2010年開發(fā)和設(shè)計(jì)的一個(gè)Internet協(xié)議忍燥,通過為tcp添加一個(gè)很小的頭信息,來方便的傳遞客戶端信息(協(xié)議棧隙姿、源IP、目的IP厂捞、源端口输玷、目的端口等),在網(wǎng)絡(luò)情況復(fù)雜又需要獲取客戶IP時(shí)非常有用靡馁。
其本質(zhì)是在三次握手結(jié)束后由代理在連接中插入了一個(gè)攜帶了原始連接四元組信息的數(shù)據(jù)包欲鹏。

目前 proxy protocol有兩個(gè)版本,v1僅支持human-readable報(bào)頭格式(ASCIII碼)臭墨,v2需同時(shí)支持human-readable和二進(jìn)制格式赔嚎,即需要兼容v1格式
proxy protocol的接收端必須在接收到完整有效的 proxy protocol 頭部后才能開始處理連接數(shù)據(jù)。因此對于服務(wù)器的同一個(gè)監(jiān)聽端口,不存在兼容帶proxy protocol包的連接和不帶proxy protocol包的連接尤误。如果服務(wù)器接收到的第一個(gè)數(shù)據(jù)包不符合proxy protocol的格式侠畔,那么服務(wù)器會直接終止連接。

Proxy protocol是比較新的協(xié)議损晤,但目前已經(jīng)有很多軟件支持软棺,如haproxy、nginx尤勋、apache喘落、squid、mysql等等最冰,要使用proxy protocol需要兩個(gè)角色sender和receiver,sender在與receiver之間建立連接后瘦棋,會先發(fā)送一個(gè)帶有客戶信息的tcp header,因?yàn)楦牧藅cp協(xié)議頭,需receiver也支持proxy protocol暖哨,否則不能識別tcp包頭兽狭,導(dǎo)致無法成功建立連接。
nginx是從1.5.12起開始支持的

3. 方式一 X-Forwarded-For配置

適用于7層http轉(zhuǎn)發(fā)

3.1 NGINX Ingress Controller X-Forwarded-For配置

查看NGINX Ingress Controller的ConfigMaps配置文檔鹿蜀,可以找到以下配置項(xiàng)
use-forwarded-headers
如果為true箕慧,NGINX會將傳入的 X-Forwarded-* 頭傳遞給upstreams。當(dāng)NGINX位于另一個(gè)正在設(shè)置這些標(biāo)頭的 L7 proxy / load balancer 之后時(shí)茴恰,請使用此選項(xiàng)颠焦。
如果為false,NGINX會忽略傳入的 X-Forwarded-* 頭往枣,用它看到的請求信息填充它們伐庭。如果NGINX直接暴露在互聯(lián)網(wǎng)上,或者它在基于 L3/packet-based load balancer 后面分冈,并且不改變數(shù)據(jù)包中的源IP圾另,請使用此選項(xiàng)。
ps: NGINX Ingress Controller直接暴露互聯(lián)網(wǎng)也就是Edge模式不能開啟為true雕沉,否則會有偽造ip的安全問題集乔。也就是k8s有公網(wǎng)ip,直接讓客戶端訪問坡椒,本配置不要設(shè)為true扰路!

forwarded-for-header
設(shè)置標(biāo)頭字段以標(biāo)識客戶端的原始IP地址。 默認(rèn): X-Forwarded-For
ps:如果 NGINX Ingress Controller 在CDN倔叼,WAF汗唱,LB等后面,設(shè)置從頭的哪個(gè)字段獲取IP丈攒,默認(rèn)是X-Forwarded-For
這個(gè)配置應(yīng)該和use-forwarded-headers配合使用

compute-full-forwarded-for
將遠(yuǎn)程地址附加到 X-Forwarded-For 標(biāo)頭哩罪,而不是替換它授霸。 啟用此選項(xiàng)后,upstreams應(yīng)用程序?qū)⒏鶕?jù)其自己的受信任代理列表提取客戶端IP

修改configmap nginx-configuration配置

kubectl -n ingress-nginx edit cm nginx-configuration

在apiVersion: v1下际插,kind: ConfigMap上加入

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

或者直接apply附加配置

kubectl apply -f - <<EOF
apiVersion: v1
data:
  compute-full-forwarded-for: "true"
  forwarded-for-header: X-Forwarded-For
  use-forwarded-headers: "true"
kind: ConfigMap
metadata:
  labels:
    app: ingress-nginx
  name: nginx-configuration
  namespace: ingress-nginx
EOF

ps:如果nginx-configuration不在namespace ingress-nginx中就在namespace kube-system中找

3.2 Nginx作為邊緣節(jié)點(diǎn)(Edge)配置

作為Edge需要重寫remote_addr碘耳,保證了客戶端IP不會被偽造
必須:X-Forwarded-For 重寫為 remote_addr 非必須擴(kuò)展:X-Real-IP 重寫為remote_addr

upstream wwek-k8s {
    server 8.8.8.8:443;
    server 8.8.8.7:443;
    server 8.8.8.6:443;
}

map $http_upgrade $connection_upgrade {
    default Upgrade;
    ''      close;
}
server {
    if ($http_x_forwarded_proto = '') {
        set $http_x_forwarded_proto  $scheme;
   }
location / {

        proxy_set_header Host              $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port  $server_port;
        #proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-For   $remote_addr;
        proxy_set_header X-Real-IP         $remote_addr;

        proxy_pass          https://wwek-k8s;
        proxy_http_version  1.1;
        proxy_set_header    Upgrade $http_upgrade;
        proxy_set_header    Connection $connection_upgrade;
        proxy_read_timeout 900s;
        proxy_buffering off;
    }
}

3.3 X-Forwarded-For是否可以偽造

客戶端是否能偽造IP,取決于邊緣節(jié)點(diǎn)(Edge)是如何處理X-Forwarded-For字段的腹鹉。
客戶端直接連接的首個(gè)proxy節(jié)點(diǎn)都叫做邊緣節(jié)點(diǎn)(Edge)藏畅,不管是網(wǎng)關(guān)、CDN功咒、LB等只要這一層是直接接入客戶端訪問的愉阎,那么他就是一個(gè)邊緣節(jié)點(diǎn)。

不重寫-不安全的邊緣節(jié)點(diǎn)(Edge)
邊緣節(jié)點(diǎn)如果是透傳http頭中的X-Forwarded-For字段力奋,那么這個(gè)就是不安全的榜旦,客戶端可以在http中實(shí)現(xiàn)包含X-Forwarded-For字段值,這個(gè)值又被透傳了景殷。

#不安全
X-Forwareded-For:Client(Edge不重寫溅呢,只透傳),proxy1猿挚,proxy2咐旧,proxy3……

重寫-安全的邊緣節(jié)點(diǎn)(Edge)
邊緣節(jié)點(diǎn)(Edge)如果重寫remote_addr到X-Forwarded-For,那么這就是安全的绩蜻。邊緣節(jié)點(diǎn)(Edge)獲取的remote_addr就是客戶端的真實(shí)IP

#安全
X-Forwareded-For:Client(Edge獲取的remote_addr)铣墨,proxy1,proxy2办绝,proxy3……

4. 方式二 Proxy Protocol 配置實(shí)例

適用于4層tcp轉(zhuǎn)發(fā)
公有云的負(fù)載均衡LB一般都支持Proxy Protocol

查看NGINX Ingress Controller的ConfigMaps配置文檔伊约,可以找到如何配置Proxy Protocol
use-proxy-protocol
啟用或禁用roxy Protocol,以接收通過代理服務(wù)器和負(fù)載均衡器(例如HAProxy和Amazon Elastic Load Balancer(ELB))傳遞的客戶端連接(真實(shí)IP地址)信息孕蝉。

NGINX Ingress Controller 作為receiver角色 Proxy Protocol配置

kubectl -n ingress-nginx edit cm nginx-configuration

在apiVersion: v1下屡律,kind: ConfigMap上加入

data:
  use-proxy-protocol: "true"

或者直接apply附加配置

kubectl apply -f - <<EOF
apiVersion: v1
data:
  use-proxy-protocol: "true"
kind: ConfigMap
metadata:
  labels:
    app: ingress-nginx
  name: nginx-configuration
  namespace: ingress-nginx
EOF

ps: 注意需要上一層LB支持Proxy Protocol,才能這么配置降淮,否則會導(dǎo)致無法鏈接

5. 總結(jié)

7層http頭X-Forwarded-For透傳
鏈路proxy有透傳X-Forwarded-For
訪問鏈路上多層proxy超埋,任意一個(gè)節(jié)點(diǎn)不支持Proxy Protocol

4層協(xié)議Proxy Protocol透傳
上下游可控都支持Proxy Protocol協(xié)議
鏈路proxy中丟失了http頭
https反向代理http(某些情況下由于Keep-alive導(dǎo)致不是每次請求都傳遞x-forword-for

應(yīng)該用那種方式?
7層用X-Forwarded-For骤肛,4層用Proxy Protocol
如果鏈路的邊緣節(jié)點(diǎn)(Edge)X-Forwarded-For字段是安全的纳本,建議用X-Forwarded-For
如果鏈路proxy全路徑都支持Proxy Protocol,那么建議用Proxy Protocol
如果有4層tcp業(yè)務(wù)應(yīng)用腋颠,那么獲取客戶端IP就的用Proxy Protocol
總之搞清楚了這2種方式的原理按照場景選擇

5. 參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市土涝,隨后出現(xiàn)的幾起案子佛寿,更是在濱河造成了極大的恐慌,老刑警劉巖但壮,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冀泻,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜡饵,警方通過查閱死者的電腦和手機(jī)弹渔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來溯祸,“玉大人肢专,你說我怎么就攤上這事〗垢ǎ” “怎么了博杖?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長筷登。 經(jīng)常有香客問我剃根,道長,這世上最難降的妖魔是什么仆抵? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任跟继,我火速辦了婚禮,結(jié)果婚禮上镣丑,老公的妹妹穿的比我還像新娘舔糖。我一直安慰自己,他們只是感情好莺匠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布金吗。 她就那樣靜靜地躺著,像睡著了一般趣竣。 火紅的嫁衣襯著肌膚如雪摇庙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天遥缕,我揣著相機(jī)與錄音卫袒,去河邊找鬼。 笑死单匣,一個(gè)胖子當(dāng)著我的面吹牛夕凝,可吹牛的內(nèi)容都是我干的宝穗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼码秉,長吁一口氣:“原來是場噩夢啊……” “哼逮矛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起转砖,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤须鼎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后府蔗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晋控,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年礁竞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糖荒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡模捂,死狀恐怖捶朵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狂男,我是刑警寧澤综看,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站岖食,受9級特大地震影響红碑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泡垃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一析珊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔑穴,春花似錦忠寻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捐腿,卻和暖如春纵朋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背茄袖。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工操软, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宪祥。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓寺鸥,卻偏偏與公主長得像猪钮,于是被迫代替她去往敵國和親品山。 傳聞我的和親對象是個(gè)殘疾皇子胆建,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容