分享人:梁文智-睿云智合研發(fā)顧問
時(shí)間:2017-7-20
當(dāng)我們逐漸向著微服務(wù)、云原生邁進(jìn)的時(shí)候,傳統(tǒng)靜態(tài)的、相對(duì)簡單的網(wǎng)絡(luò)安全策略開始顯得吃力。?Kubernetes 的?Network Policy 特性正是來解決這個(gè)問題的。在剛剛出爐不久的1.7版本中,該特性也被扶正成為GA。讓我們來一起看看?Network Policy 是什么,能為我們做什么,以及是如何實(shí)現(xiàn)的。
CNI
Kubernetes 對(duì)網(wǎng)絡(luò)做了較好的抽象。它將對(duì)網(wǎng)絡(luò)的需求交給外部的組件完成,也就是?CNI driver。
Pod 的網(wǎng)絡(luò)必須滿足以下三個(gè)需求:
1 所有?Pod 之間無需?NAT 即可互通
2 主機(jī)和?Pod 之間無需?NAT 即可互通
3 Pod 自省的?IP 地址和之外部看到該?Pod 的地址一致
CNI 對(duì)網(wǎng)絡(luò)的實(shí)現(xiàn)做了詳細(xì)的定義。CNI 的實(shí)現(xiàn)可以被分成三種:
1 3 層路由實(shí)現(xiàn)
2 Overlay 實(shí)現(xiàn)
3 2 層交換實(shí)現(xiàn)
現(xiàn)在比較常用的?CNI 實(shí)現(xiàn)有:Flannel、Calico、Weave。?Flannel 通過?VXLan Overlay 來實(shí)現(xiàn)跨主機(jī)?Pod 網(wǎng)絡(luò),?Calico 則完全通過?3 層路由來實(shí)現(xiàn)了跨主機(jī)的容器網(wǎng)絡(luò),Weave也是?Overlay 的實(shí)現(xiàn)。
什么是Network Policy
隨著業(yè)務(wù)邏輯的復(fù)雜化,微服務(wù)的流行,越來越多的云服務(wù)平臺(tái)需要大量模塊之間的網(wǎng)絡(luò)調(diào)用。
傳統(tǒng)的單一外部防火墻,或依照應(yīng)用分層的防火墻的做法漸漸無法滿足需求。在一個(gè)大的集群里面,各模塊,業(yè)務(wù)邏輯層,或者各個(gè)職能團(tuán)隊(duì)之間的網(wǎng)絡(luò)策略的需求越來越強(qiáng)。
Kubernetes 在?1.3 引入了?Network Policy 這個(gè)功能來解決這個(gè)問題。這些?Policy 允許用戶在同一個(gè)?Cluster 內(nèi)實(shí)現(xiàn)網(wǎng)絡(luò)的隔離。也就是在某些需要的?Pod 之間架起防火墻。可以簡單的理解為各個(gè)微服務(wù)之間的動(dòng)態(tài)防火墻。也有人把這叫做分布式防火墻。
并非所有的網(wǎng)絡(luò)驅(qū)動(dòng)都支持這個(gè)功能。比如大家比較熟悉的,比較流行的?Flannel 就還沒有加入對(duì)?Network Policy 的支持。Calico 和?Weave 都各自實(shí)現(xiàn)了?NPC(network policy controller)。雖然?Flannel 不支持?Network Policy。但是,可以使用?Flannel 提供網(wǎng)絡(luò)方案,同時(shí)使用?Calico 或者Weave 的?NPC 組件來共同完成。Canal 就提供了將?Flannel 和?Calico NPC 組合的方案。
DEMO
下面我們就以Calico為基礎(chǔ),給大家做一個(gè)demo。
這里我已經(jīng)搭好了一個(gè)?Kubernetes 的簡單的集群:只有一個(gè)?master 和兩個(gè)?minion。我們先來部署?Calico。這里要注意的是,由于我們要?demo 的是最新的?Kubernetes API,我們必須使用?Kubernetes 1.7 和?Calico 2.3,并且,Calico只能配置成?Kubernetes Datastore 的模式。在這種模式下,Calico 對(duì)網(wǎng)絡(luò)狀態(tài)的控制是通過?Kubernetes API 來完成的。另外還有一種模式是通過?etcd 集群。那種模式暫時(shí)還不支持最新的API。Kubernetes Datastore 這種方式有時(shí)也叫做KDD — Kubernetes datastore driver。
在進(jìn)行?KDD 模式的?Calico 安裝時(shí)要注意以下這么幾點(diǎn):
1 IPAM 要使用?host-local
2 通過?controller manager 來分配?CIDR
細(xì)節(jié)請(qǐng)點(diǎn)擊:http://t.cn/R97OVqc
配置好?Calico之后,我們來看一個(gè)簡單的?demo,實(shí)際操作一下?Network Policy:
為了簡單起見,我們會(huì)直接使用?default namespace。如果你在一個(gè)現(xiàn)有的環(huán)境里面,?可以將以下的命令在一個(gè)獨(dú)立的?namespace 里面運(yùn)行。
創(chuàng)建?namespace 使用這個(gè)命令:
kubectl?create?ns?np-demo
接下來運(yùn)行一個(gè)簡單的?nginx deployment 并用80端口暴露服務(wù):
kubectl?run?nginx?–replicas=2?–image=nginx
deployment?“nginx”?created
kubectl?expose?deploy?nginx?–port=80
service?“nginx”?exposed
現(xiàn)在我們還沒有做任何的限制,所以?Kubernetes 缺省情況是所有?Pod 都是開放的。
我們來用一個(gè)?BusyBox 的?Pod 驗(yàn)證一下:
kubectl?run?busy?–rm?-ti?–image?busybox?/bin/sh
If?you?don’t?see?a?command?prompt,?try?pressing?enter.
/?#?wget?-q?nginx?-O?–?|?head?-4
上面的?Wget 命令是在?BusyBox 這個(gè)?Pod 里面執(zhí)行的。-q?和?-O –?的組合會(huì)使這個(gè)命令在命令行輸出?nginx 的缺省首頁,這表明我們的驗(yàn)證是成功的。用?Ctl-D 退出容器。
接下來我們就要加入限制了。我們的做法是先限制對(duì)所有?Pod 的訪問,然后建立白名單。?kubectl apply下面的?YAML 文件就可以限制所有訪問:
kind:?NetworkPolicy
apiVersion:?networking.k8s.io/v1
metadata:
name:?default-deny
spec:
podSelector:
注意我們提供了一個(gè)空的?podSelector。
我們?cè)僭囍弥暗?BusyBox 的方式來訪問一下:
kubectl?run?busy?–rm?-ti?–image?busybox?/bin/sh
/?#?wget?-q?–timeout=5?nginx?-O?–
這此我們?cè)O(shè)置了?5 秒的超時(shí)。因?yàn)樵L問被拒接,所以確實(shí)會(huì)超時(shí):
wget:?download?timed?out
好,我們的第一個(gè)?Network Policy 已經(jīng)生效了。然而,限制對(duì)所有?Pod 的訪問顯然是沒有意義的。接下來我們建立一個(gè)白名單?. apply 下面的?YAML 文件:
kind:?NetworkPolicy
apiVersion:?networking.k8s.io/v1
metadata:
name:?access-nginx
spec:
podSelector:
matchLabels:
run:?nginx
ingress:
–?from:
–?podSelector:
matchLabels:
run:?access
這個(gè)?Network Policy 的意思是:標(biāo)簽?run:access 選中的?Pod 可以訪問標(biāo)簽?run:nginx 的?Pod,也就是我們?demo 開始時(shí)創(chuàng)建的?Nginx 的?Pod。這些?label 都是?kubectl run 命令自動(dòng)?添加的。
接下來我們?cè)囋嚳茨芊癯晒Φ卦L問了:
kubectl?run?access?–rm?-ti?–image?busybox?/bin/sh
wget?-q?nginx?-O?–
我們依然會(huì)看到熟悉的?Nginx 缺省首頁。如果我們運(yùn)行一個(gè)不符合上述?selector 的?Pod,就無法訪問。這個(gè)留給有興趣的同學(xué)自己回去驗(yàn)證。
如果你接觸過?1.7 之前的?Network Policy 的話,你可能會(huì)發(fā)現(xiàn)這里的?API 有些不同。Kubernetes 1.7 已經(jīng)將?Network Policy 正式提升到?GA。
正式的?API 和之前的?API 區(qū)別有:
1 不再使用?Annotation 來表達(dá)?default-deny 等這樣的規(guī)則
2 API version 從?extension/beta1 升級(jí)到了?networking.k8s.io/v1
實(shí)現(xiàn)
Calico 的實(shí)現(xiàn)是基于?iptables 的。在每個(gè)?chain 的頂端,Calico 都插入了一條定制的?chain,從而使得?packet 優(yōu)先經(jīng)過?Calico 定義的規(guī)則。我們?cè)谄渲幸粋€(gè)?minion 上面運(yùn)行?iptables-save -c 就可以檢查這些規(guī)則??梢钥闯?kube-proxy 和?Calico 都定義了大量的?iptable 規(guī)則。
這里細(xì)節(jié)很多,我們只需要關(guān)注這幾點(diǎn):
Calico 使用?conntrack 來優(yōu)化。就是說,一旦一個(gè)連接已經(jīng)建立,之后的packet都會(huì)直接被允許通過。比如:
-A?cali-fw-cali7af3f94d3a1?-m?conntrack?–ctstate?RELATED,ESTABLISHED?-j?ACCEPT
-A?cali-fw-cali7af3f94d3a1?-m?conntrack?–ctstate?INVALID?-j?DROP
名為?cali-pi-xxxx 的規(guī)則是負(fù)責(zé)?Network Policy Ingress 的。我們可以想見,如果我們定義了很多?Policy,一個(gè)一個(gè)單獨(dú)定義的規(guī)則會(huì)導(dǎo)致性能下降。這里?Calico 利用了?iptables 的?ipset 特性。使得一個(gè)?rule 可以通過?hash 表來匹配多種地址。
-A?cali-pi-_G7e-YAvXRsfDoqGDf36?-m?set?–match-set?cali4-s:2I5R46OBA_TBIUlpH0dCd_n?src?-j?MARK?–set-xmark?0x1000000/0x1000000
-A?cali-pi-_G7e-YAvXRsfDoqGDf36?-m?mark?–mark?0x1000000/0x1000000?-j?RETURN
Weave 的實(shí)現(xiàn)也類似。底層還是使用了?iptables 和?netfilter。Weave 也創(chuàng)建了自定義的?chain。但由于一個(gè)是?Overlay 一個(gè)是路由,規(guī)則還是有些不同的。
另外一個(gè)細(xì)微的不同是,Weave使用了?-m state 而不是?-m conntrack。conntrack 是比較新的語法,但實(shí)際使用中功能是一樣的。下面是幾個(gè)?Weave 安裝的?iptables rules 的例子:
FORWARD?chain:
-o?weave?-j?WEAVE-NPC
-o?weave?-j?DROP
WEAVE_NPC?chain:
-m?state?–state?RELATED,ESTABLISHED?-j?ACCEPT
-m?state?–state?NEW?-j?WEAVE-NPC-DEFAULT
-m?state?–state?NEW?-j?WEAVE-NPC-INGRESS
-m?set?–match-set?weave-v/q_G.;Q?uK]BuDs2?dst?-j?ACCEPT
-m?set?–match-set?weave-k?Z;25^M}|1s7P3|H?dst?-j?ACCEPGo
Q&A
Q:Calico 和?Weave 從?Policy 處理性能來看,兩者哪個(gè)更優(yōu)?
A:兩者在?iptables 層面上的實(shí)現(xiàn)原理是一樣的。都用了-m
state 和?ipset 優(yōu)化,性能差別不大。
Q:Calico 結(jié)合?Kubernetes 怎么實(shí)現(xiàn)多租戶,比如網(wǎng)絡(luò)隔離之類的?
A:可以考慮用?namespace 來隔離。沒有?Network Policy 的情況下當(dāng)然是互通的。但是?Kubernetes 的?Network Policy 支持?namespaceSelector,可以輕松搞定。
Q:Weave、Calico、Flannel 比較,適用場(chǎng)景和優(yōu)缺點(diǎn)是什么,Flannel out了么?
A:各有各的市場(chǎng)?:-)。
Flannel 比較簡單,資源消耗也會(huì)小些。Flannel 不能算?out 了。Cannel 的出現(xiàn)將?Flannel 和?Calico 整合了起來。
Q:NPC 必須用?iptables 實(shí)現(xiàn)嗎?在某些情況下,Pod 出向流量并不會(huì)由主機(jī)協(xié)議棧,這樣?iptables 就用不了,這種情況下?NPC 怎么實(shí)現(xiàn)呢??
A:Calico、Weave、Romana 的?NPC 都是通過?iptables 實(shí)現(xiàn)的。Pod
egress 不通過主機(jī)協(xié)議棧也會(huì)通過?netfilter。