Kubernetes網(wǎng)絡(luò)策略,這一篇就夠了
目前許多組織都在采用Kubernetes來運行他們的應(yīng)用程序。以至于有些人將Kubernetes稱為新的數(shù)據(jù)中心操作系統(tǒng)。因此,組織開始將Kubernetes(通??s寫為k8s)視為關(guān)鍵任務(wù)平臺,它需要包括網(wǎng)絡(luò)安全在內(nèi)的成熟業(yè)務(wù)流程。
負責(zé)保護這個新平臺的網(wǎng)絡(luò)安全團隊可能發(fā)現(xiàn)它出奇的不同。例如,默認的Kubernetes策略是允許任何連接。
本文提供了一些關(guān)于Kubernetes網(wǎng)絡(luò)策略工作原理的簡介,它們?nèi)绾闻c傳統(tǒng)防火墻策略進行比較以及一些可以幫助你保護Kubernetes應(yīng)用程序的陷阱和最佳實踐。
Kubernetes網(wǎng)絡(luò)策略
Kubernetes提供了一種稱為網(wǎng)絡(luò)策略的機制,可用于對部署在平臺上的應(yīng)用程序?qū)嵤┑?層分隔。網(wǎng)絡(luò)策略缺乏現(xiàn)代防火墻的高級功能,如第7層控制和威脅檢測,但是它們確實提供了基本的網(wǎng)絡(luò)安全,這是一個很好的起點。
網(wǎng)絡(luò)策略控制Pod的通信
Kubernetes的工作負載在pod中運行,pod由一個或多個部署在一起的容器組成。Kubernetes為每個pod分配一個IP地址,這個地址可以從其他所有pod路由,甚至可以跨底層服務(wù)器。Kubernets網(wǎng)絡(luò)策略指定pod組的訪問權(quán)限,類似于云服務(wù)中的安全組用于控制對虛擬機實例的訪問。
編寫網(wǎng)絡(luò)策略
與其他Kubernetes資源一樣,網(wǎng)絡(luò)策略可以使用一種稱為YAML的語言定義。下面是一個簡單的例子,它允許從負載均衡到postgres的訪問。
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.postgres
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: postgres
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: balance
- policyTypes:
- - Ingress
為了編寫你自己的網(wǎng)絡(luò)策略,你需要對yaml有基本的了解。Yaml基于縮進(使用的是空格,而不是tab)??s進項屬于其上方最接近的縮進項。連字符(破折號)開始一個新的列表項。所有其他項都是映射條目。你可以在網(wǎng)上找到大量關(guān)于yaml的信息。
編寫完策略的YAML文件后,使用kubectl創(chuàng)建策略:
- kubectl create -f policy.yaml
網(wǎng)絡(luò)策略定義
網(wǎng)絡(luò)策略定義由四個元素組成:
podSelector:將受此策略約束的pod(策略目標(biāo))。必填
policyType:指定哪些類型的策略包含在這個策略中,ingress或egress。該項是可選的,但建議總是明確的指定它??蛇x
ingress:允許傳入目標(biāo)pod的流量。可選
egress:允許從目標(biāo)pod傳出的流量??蛇x
下面這個例子是從Kubernetes官網(wǎng)上改編的(將“role”改為了“app”),它指定了四個元素:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: test-network-policy
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: db
- policyTypes:
- - Ingress
- - Egress
- ingress:
- - from:
- - ipBlock:
- cidr: 172.17.0.0/16
- except:
- - 172.17.1.0/24
- - namespaceSelector:
- matchLabels:
- project: myproject
- - podSelector:
- matchLabels:
- role: frontend
- ports:
- - protocol: TCP
- port: 6379
- egress:
- - to:
- - ipBlock:
- cidr: 10.0.0.0/24
- ports:
- - protocol: TCP
- port: 5978
注意,你不必包含所有四個元素。podSelector是必填的,其余三個是可選的。
如果你忽略了policyType,則推斷如下:
- 策略總是被認為指定了一個ingress定義。如果你沒有明確的定義它,它將被視為“不允許流量“。
- egress將由是否存在egress元素誘導(dǎo)。
為了避免錯誤,建議總是顯式的指定policyType。
如果沒有提供ingress或egress的定義,并且根據(jù)上面的邏輯假定它們存在,策略將認為它們是“不允許流量”。
默認策略是允許
當(dāng)沒有定義任何策略時,Kubernetes允許所有通信。所有pod都可以相互自由通信。從安全角度來看,這聽起來可能有悖常理,但請記住,Kubernetes是由希望應(yīng)用程序進行通信的開發(fā)人員設(shè)計的。網(wǎng)絡(luò)策略是作為后來的增強功能添加的。
命名空間
命名空間是Kubernetes的多租戶機制,旨在將命名空間環(huán)境相互隔離,但是,命名空間的通信在默認情況下仍然是被允許的。
與大多數(shù)Kubernetes實體一樣,網(wǎng)絡(luò)策略也位于特定的命名空間中。元數(shù)據(jù)頭部告訴Kubernetes策略屬于哪個命名空間:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: test-network-policy
- namespace: my-namespace
- spec:
- ...
如果你沒有明確指定元數(shù)據(jù)的命名空間,它將應(yīng)用于kubectl提供的命名空間(默認是namespace=default)。
- kubectl apply -n my-namespace -f namespace.yaml
建議顯式指定命名空間,除非你正在編寫的策略要統(tǒng)一應(yīng)用在多個命名空間中。
策略中的podSelector元素將從策略所屬的命名空間中選擇pod(它不能從另一個命名空間選擇pod)。
ingress和egress元素中的podSelector也會選擇相同命名空間中的pod,除非你將它們和namespaceSelector一起使用。
策略命名約定
策略的名稱在命名空間中是唯一的。一個命名空間中不能有兩個同名的策略,但是不同的命名空間可以有同名的策略。當(dāng)你想要在多個命名空間重復(fù)應(yīng)用某個策略時,這非常方便。
我喜歡的策略命名方法之一是將命名空間與pod組合起來,例如:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.postgres
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: postgres
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: admin
- policyTypes:
- - Ingress
標(biāo)簽
Kubernetes對象,如pod和namespace,可以附加用戶自定義標(biāo)簽。Kubernetes網(wǎng)絡(luò)策略依賴于標(biāo)簽來選擇它們應(yīng)用于的pod:
- podSelector:
- matchLabels:
- role: db
或者它們應(yīng)用于的命名空間。下面的例子中選擇匹配標(biāo)簽的命名空間中的所有pod:
- namespaceSelector:
- matchLabels:
- project: myproject
需要注意的一點是:如果你使用namespaceSelector,請確保所選擇的命名空間確實具有所使用的標(biāo)簽。請記住,像default和kube-system這樣的內(nèi)置命名空間沒有現(xiàn)成的標(biāo)簽。你可以像這樣給命名空間添加一個標(biāo)簽:
- kubectl label namespace default namespace=default
元數(shù)據(jù)中的namespace是命名空間的實際名稱,而不是標(biāo)簽:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: test-network-policy
- namespace: default
- spec:
- ...
源和終點
防火墻策略由具有源和終點的規(guī)則組成。Kubernetes網(wǎng)絡(luò)策略是為目標(biāo)(應(yīng)用策略的一組pod)定義的,然后為目標(biāo)指定傳入或傳出流量。再次使用相同的例子,你可以看到策略目標(biāo)——默認命名空間中所有具有標(biāo)簽為“db:app”的pod:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: test-network-policy
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: db
- policyTypes:
- - Ingress
- - Egress
- ingress:
- - from:
- - ipBlock:
- cidr: 172.17.0.0/16
- except:
- - 172.17.1.0/24
- - namespaceSelector:
- matchLabels:
- project: myproject
- - podSelector:
- matchLabels:
- role: frontend
- ports:
- - protocol: TCP
- port: 6379
- egress:
- - to:
- - ipBlock:
- cidr: 10.0.0.0/24
- ports:
- - protocol: TCP
- port: 5978
該策略中的ingress項允許到目標(biāo)pod的傳入流量。因此,ingress被解釋為“源”,目標(biāo)被解釋為各自的“終點”。同樣,egress被解釋為“終點”,目標(biāo)是各自的“源”。
Egress和DNS
當(dāng)執(zhí)行egress時,必須小心不要阻止DNS,Kubernetes使用DNS將service的名稱解釋為其IP地址。否則,這個策略將不起作用,因為你沒有允許balance執(zhí)行DNS查找:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.balance
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: balance
- egress:
- - to:
- - podSelector:
- matchLabels:
- app: postgres
- policyTypes:
- - Egress
要解決它,你必須允許訪問DNS服務(wù):
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.balance
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: balance
- egress:
- - to:
- - podSelector:
- matchLabels:
- app: postgres
- - to:
- ports:
- - protocol: UDP
- port: 53
- policyTypes:
- - Egress
“to”元素為空,它隱式選擇了所有命名空間中的所有pod,從而允許balance通過Kubernetes的DNS服務(wù)執(zhí)行DNS查找,DNS服務(wù)通常位于kube-system命名空間中。
雖然這是有效的,但它過于寬松和不安全——它允許在集群外部進行DNS查找。
你可以分階段鎖定它:
1.通過添加一個namespaceSelector只允許在集群內(nèi)進行DNS查找:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.balance
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: balance
- egress:
- - to:
- - podSelector:
- matchLabels:
- app: postgres
- - to:
- - namespaceSelector: {}
- ports:
- - protocol: UDP
- port: 53
- policyTypes:
- - Egress
2.只允許DNS在kube-system命名空間中
為此,你需要為kube-system命名空間添加一個標(biāo)簽:
- kubectl label namespace kube-system namespace=kube-system
然后用namespaceSelector在策略中指定它:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.balance
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: balance
- egress:
- - to:
- - podSelector:
- matchLabels:
- app: postgres
- - to:
- - namespaceSelector:
- matchLabels:
- namespace: kube-system
- ports:
- - protocol: UDP
- port: 53
- policyTypes:
- - Egress
3.偏執(zhí)狂可能想更進一步,將DNS限制為kube-system命名空間中特定的DNS服務(wù)。請參考下面的“通過命名空間和pod過濾”章節(jié)。
另一種選擇是在命名空間級別允許DNS,這樣就不需要為每個服務(wù)指定它了:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.dns
- namespace: default
- spec:
- podSelector: {}
- egress:
- - to:
- - namespaceSelector: {}
- ports:
- - protocol: UDP
- port: 53
- policyTypes:
- - Egress
空的podSelector選擇該命名空間中的所有pod。
第一個匹配和規(guī)則順序
防火墻管理員知道對數(shù)據(jù)包采取的操作(允許或拒絕)由與其匹配的第一個規(guī)則決定。但是在Kubernetes中,策略的順序并不重要。默認的行為是,當(dāng)沒有定義策略時,允許所有通信,因此所有pod之間可以彼此通信。一旦定義了策略,每個至少被一個策略選擇的pod,將根據(jù)選擇它的策略的并集(邏輯或)進行隔離:
沒有被任何策略選中的pod繼續(xù)保持開放。你可以通過定義cleanup規(guī)則來改變這個行為。
Cleanup規(guī)則(拒絕)
防火墻策略通常通過any-any-any-deny規(guī)則來丟棄所有非顯式允許的流量。Kubernetes沒有拒絕操作,但是你可以使用一個常規(guī)的規(guī)則來實現(xiàn)相同的效果,該策略指定policyTypes=Ingress,但是省略了實際ingress的定義,這被解釋為“不允許進入”。
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: deny-all
- namespace: default
- spec:
- podSelector: {}
- policyTypes:
- - Ingress
該策略選擇命名空間中的所有pod作為源,未定義ingress——這意味著不允許流量進入。
類似的,你可以拒絕來自一個命名空間的所有出站流量:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: deny-all-egress
- namespace: default
- spec:
- podSelector: {}
- policyTypes:
- - Egress
請記住,任何其他允許訪問命名空間中pod的策略都將優(yōu)先于此拒絕策略——相當(dāng)于防火墻中將允許策略添加到拒絕策略之上。
Any-Any-Any-Allow
通過使用一個空的ingress元素修改上面的deny-all策略,可以創(chuàng)建一個allow-all策略:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: allow-all
- namespace: default
- spec:
- podSelector: {}
- ingress:
- - {}
- policyTypes:
- - Ingress
這允許所有命名空間中的所有pod(和IP)到默認命名空間中的任何pod的通信。這是默認行為,因此通常不需要這么做。但是,為了查找問題,暫時覆蓋所有其他規(guī)則可能很有用。
你可以縮小此范圍,僅允許訪問默認命名空間中的一組特定的pod:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: allow-all-to-balance
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: balance
- ingress:
- - {}
- policyTypes:
- - Ingress
下面的策略允許任何入站和出站流量(包括訪問集群外的任何IP):
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: allow-all
- spec:
- podSelector: {}
- ingress:
- - {}
- egress:
- - {}
- policyTypes:
- - Ingress
- - Egress
組合多個策略
策略在三個級別上使用邏輯或進行組合。每個pod根據(jù)應(yīng)用于它的所有策略的并集決定是否允許通信。
1.在“from”和“to”項中,你可以定義三種類型的項,他們通過“或”進行組合:
- namespaceSelector——選擇一整個命名空間
- podSelector——選擇pod
- ipBlock——選擇一個子網(wǎng)
你可以在from/to下定義任意數(shù)量的項(即使是相同類型也可以定義多條),它們將通過邏輯或組合在一起:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.postgres
- namespace: default
- spec:
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: indexer
- - podSelector:
- matchLabels:
- app: admin
- podSelector:
- matchLabels:
- app: postgres
- policyTypes:
- - Ingress
2.在一個策略中,ingress策略可以有多個“from”項,它們通過邏輯或組合在一起。同樣,egress策略可以有多個“to”項,它們也通過邏輯或組合在一起:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.postgres
- namespace: default
- spec:
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: indexer
- - from:
- - podSelector:
- matchLabels:
- app: admin
- podSelector:
- matchLabels:
- app: postgres
- policyTypes:
- - Ingress
3.多個策略也通過邏輯或組合在一起。
但是當(dāng)組合策略時,這里有一些限制:Kubernetes只能組合policyType(ingress或egress)不同的策略,多個策略都指定ingress(或egress)將會互相覆蓋。
命名空間之間的通信
默認情況下,命名空間間的通信是允許的。你可以使用deny-all策略來改變它,以阻止從或者到該命名空間的通信。
如果你阻止了對某個命名空間的訪問,可以使用namespaceSelector允許來自一個特定的命名空間的訪問。
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: database.postgres
- namespace: database
- spec:
- podSelector:
- matchLabels:
- app: postgres
- ingress:
- - from:
- - namespaceSelector:
- matchLabels:
- namespace: default
- policyTypes:
- - Ingress
這允許default命名空間中的所有pod訪問database命名空間中的postgres pod。但是,如果只想允許default命名空間中特定的pod訪問postgres該怎么辦呢?
通過namespace和pod聯(lián)合過濾
Kubernetes 1.11及以上允許你將namespaceSelector和podSelector通過邏輯與組合在一起:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: database.postgres
- namespace: database
- spec:
- podSelector:
- matchLabels:
- app: postgres
- ingress:
- - from:
- - namespaceSelector:
- matchLabels:
- namespace: default
- podSelector:
- matchLabels:
- app: admin
- policyTypes:
- - Ingress
為什么這被解釋為“與”,而不是“或”呢?
請注意,podSelector不是以破折號開頭的,在yaml中這意味著,podSelector與前面的namespaceSelector屬于同一個列表項,因此它們通過邏輯與進行組合。如果你在podSelector前面添加一個破折號,將創(chuàng)建一個新的列表項,這將與前面的namespaceSelector通過邏輯或組合。要在所有命名空間中選擇具有特定標(biāo)簽的pod,可以指定一個空的namespaceSelector:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: database.postgres
- namespace: database
- spec:
- podSelector:
- matchLabels:
- app: postgres
- ingress:
- - from:
- - namespaceSelector: {}
- podSelector:
- matchLabels:
- app: admin
- policyTypes:
- - Ingress
多個標(biāo)簽通過邏輯與組合
具有多個對象(主機、網(wǎng)絡(luò)、組...)的防火墻規(guī)則被解釋為邏輯或。例如,如果數(shù)據(jù)包的源匹配HOST_1或HOST_2,則應(yīng)用此規(guī)則:
與之相反的是,在Kubernetes中,podSelector和namespaceSelector中的多個標(biāo)簽通過邏輯與進行組合。例如,這將選擇同時具有標(biāo)簽role=db和version=v2的pod:
- podSelector:
- matchLabels:
- role: db
- version: v2
相同的邏輯適用所有類型的選擇器:策略目標(biāo)的選擇器、pod的選擇器、命名空間的選擇器。
子網(wǎng)和IP地址(ipBlock)
防火墻使用vlan、ip和子網(wǎng)來分割網(wǎng)絡(luò)。在Kubernetes中,pod的IP是自動分配的,并且可能經(jīng)常變動,因此網(wǎng)絡(luò)策略使用標(biāo)簽來選擇pod和命名空間。子網(wǎng)(ipBlock)用于ingress或egress連接(南北向)。例如,下面這個策略允許default命名空間中的所有pod訪問谷歌的DNS服務(wù):
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: egress-dns
- namespace: default
- spec:
- podSelector: {}
- policyTypes:
- - Egress
- egress:
- - to:
- - ipBlock:
- cidr: 8.8.8.8/32
- ports:
- - protocol: UDP
- port: 53
本例中空的podSelector表示“選擇該命名空間中的所有pod”。該策略只允許訪問8.8.8.8,這意味著它拒絕訪問其他任何IP。因此,實際上,你已經(jīng)阻止了對Kubernetes內(nèi)部DNS服務(wù)的訪問。如果你仍然想允許它,需要顯式的指定它。
通常ipBlock和podSelector是互斥的,因為通常你在ipBlock中不使用內(nèi)部pod IP。如果你使用內(nèi)部pod IP指定ipBlock,它實際上將允許與具有這些ip的pod進行通信。但是在實踐中并不知道該用哪些IP,這就是為什么不應(yīng)該用IP來選擇pod。
下面這個策略中包含所有IP,并允許訪問所有其它pod:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: egress-any
- namespace: default
- spec:
- podSelector: {}
- policyTypes:
- - Egress
- egress:
- - to:
- - ipBlock:
- cidr: 0.0.0.0/0
你可以通過排除內(nèi)部IP來只允許訪問外部IP。例如,如果pod的子網(wǎng)是10.16.0.0/14:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: egress-any
- namespace: default
- spec:
- podSelector: {}
- policyTypes:
- - Egress
- egress:
- - to:
- - ipBlock:
- cidr: 0.0.0.0/0
- except:
- - 10.16.0.0/14
端口和協(xié)議
pod通常只監(jiān)聽一個端口,這意味著你可以簡單的在策略中省略端口,默認允許任何端口。但是最好將策略設(shè)置為受限的,顯式的指定端口:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.postgres
- namespace: default
- spec:
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: indexer
- - podSelector:
- matchLabels:
- app: admin
- ports:
- - port: 443
- protocol: TCP
- - port: 80
- protocol: TCP
- podSelector:
- matchLabels:
- app: postgres
- policyTypes:
- - Ingress
請注意,端口應(yīng)用于它們所在的“to”或“from”子句中的所有項。如果你想為不同的項指定不同的端口,你可以將ingress或egress拆分為多個“to”或“from”,每個都有自己的端口:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.postgres
- namespace: default
- spec:
- ingress:
- - from:
- - podSelector:
- matchLabels:
- app: indexer
- ports:
- - port: 443
- protocol: TCP
- - from:
- - podSelector:
- matchLabels:
- app: admin
- ports:
- - port: 80
- protocol: TCP
- podSelector:
- matchLabels:
- app: postgres
- policyTypes:
- - Ingress
端口的默認行為:
- 如果完全省略端口,則表示所有端口和所有協(xié)議
- 如果省略協(xié)議,則默認為TCP
- 如果省略端口,則默認為所有端口
最佳實踐:不要依賴默認行為,顯式的指明。
注意你必須使用pod的端口,而不是service的端口。
策略是為pod定義的還是為service定義的?
當(dāng)一個pod訪問Kubernetes中另一個pod時,它通常要通過service,service是一個虛擬的負載均衡器,它將流量轉(zhuǎn)發(fā)到實現(xiàn)該服務(wù)的pod上。你可能會以為網(wǎng)絡(luò)策略是控制對service的訪問的,但事實并非如此。Kubernetes網(wǎng)絡(luò)策略是應(yīng)用于pod的端口,而非service的端口。
例如,如果一個service監(jiān)聽80端口,但是它將流量轉(zhuǎn)發(fā)到監(jiān)聽8080端口的pod上,你需要在網(wǎng)絡(luò)策略中指定8080端口。
這種設(shè)計不是最優(yōu)的,因為當(dāng)有人更改服務(wù)的內(nèi)部工作方式時(如pod正在監(jiān)聽的端口),你需要更新網(wǎng)絡(luò)策略。
顯然,有一種解決方案可以解決這個問題,即使用命名端口,而不是硬編碼的數(shù)字端口:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default.allow-hello
- namespace: default
- spec:
- podSelector:
- matchLabels:
- app: hello
- policyTypes:
- - Ingress
- ingress:
- - from:
- - podSelector:
- matchLabels:
- run: curl
- ports:
- - port: my-http
你需要在pod的定義中指定這個端口的名字:
- apiVersion: extensions/v1beta1
- kind: Deployment
- metadata:
- labels:
- app: hello
- name: hello
- spec:
- selector:
- matchLabels:
- app: hello
- template:
- metadata:
- labels:
- app: hello
- spec:
- containers:
- - image: gcr.io/hello-minikube-zero-install/hello-node
- imagePullPolicy: Always
- name: hello-node
- ports:
- - containerPort: 8080
- name: my-http
這樣就將網(wǎng)絡(luò)策略和pod解耦了。
Ingress
術(shù)語“ingress”在Kubernetes中有兩種含義:
- ingress網(wǎng)絡(luò)策略允許你控制其他pod或外部IP對pod的訪問
- Kubergess的ingress是一種配置外部負載均衡器路由流量到集群內(nèi)部的方式
你可以編寫一個k8s網(wǎng)絡(luò)策略限制來自Kubernetes ingress的訪問,但在大多數(shù)情況下這不是很有用,因為它只控制負載均衡器的內(nèi)部IP。為了控制可以訪問集群的外部子網(wǎng),你需要在外部實施點(如負載均衡本身或負載均衡前面的防火墻)配置訪問控制。
需要同時定義ingress和egress么?
簡單的回答是肯定的——為了允許pod A訪問pod B,你需要允許pod A通過egress策略創(chuàng)建出站連接,并允許pod B通過ingress策略接受入站連接。
然而,實際上,你可能對兩個方向中的一個使用默認的允許策略。
如果源pod被一個或多個egress策略選中,則將根據(jù)策略聯(lián)合對其進行限制,在這種情況下你需要明確允許它連接到目標(biāo)pod。如果pod不被任何策略選中,則它默認允許所有的出站流量。
同樣,被一個或多個ingress策略選中的目標(biāo)pod,也會受到策略的聯(lián)合限制,在這種情況下你必須明確允許它接受來自源pod的流量。如果pod沒有被任何策略選中,則它默認允許所有入站流量。
hostNetwork陷阱
Kubernetes通常在自己的隔離網(wǎng)絡(luò)中運行pod,然而,你可以指定Kubernetes在主機上運行pod:
- hostNetwork: true
這樣會完全繞開網(wǎng)路策略,pod像主機上運行的其他任何進程一樣進行通信。
流量日志
Kubernetes網(wǎng)絡(luò)策略不能生成流量日志。這很難知道策略是不是像預(yù)期一樣工作。這也是安全分析方面的主要限制。
控制到外部服務(wù)的流量
Kubernetes網(wǎng)絡(luò)策略不允許你為egress指定完全限定的域名(DNS)。當(dāng)試圖控制到無固定IP的外部站點(如aws.com)的流量時,這是一個限制。
策略驗證
防火墻將警告甚至拒絕接受無效的策略。Kubernetes也做了一些驗證。當(dāng)使用kubectl定義網(wǎng)絡(luò)策略時,Kubernetes可能會告訴你策略無效并且拒絕接受。在其它情況下,Kubernetes將接受策略并修改它缺失的細節(jié),你可以通過以下命令查看它:
kubernetes get networkpolicy
請注意,Kubernetes的驗證不是無懈可擊的,它可能允許策略中出現(xiàn)某些類型的錯誤。
執(zhí)行
Kubernetes本身并不執(zhí)行網(wǎng)絡(luò)策略,它只是一個API網(wǎng)關(guān),它將執(zhí)行的艱巨工作傳遞給一個稱為容器網(wǎng)絡(luò)接口(CNI)的底層系統(tǒng)。在沒有合適CNI的Kubernetes集群中定義策略就像在沒有安裝防火墻的服務(wù)器上定義防火墻規(guī)則一樣。你必須確保擁有具有安全功能的CNI,或者,對于托管的Kubernetes平臺,你需要顯式的啟用將為你安裝CNI的網(wǎng)絡(luò)策略。
請注意,如果CNI不支持,你定義了一個網(wǎng)絡(luò)策略,Kubernetes不會向你告警。
有狀態(tài)還是無狀態(tài)?
目前所有的Kubernetes CNI都是有狀態(tài)的,這使得pod能在它發(fā)起的TCP連接上接收應(yīng)答,而不必為應(yīng)答打開高端口。我不知道有沒有Kubernetes標(biāo)準(zhǔn)保證狀態(tài)性。
高級安全策略管理
以下是一些針對Kubernetes實施更高級的網(wǎng)絡(luò)策略的方法:
- 服務(wù)網(wǎng)格設(shè)計模式使用sidecar在服務(wù)級別提供更高級的遙測和流量控制。有關(guān)示例,請參考Istio。
- 一些CNI提供商已經(jīng)將他們的工具擴展到了Kubernetes網(wǎng)絡(luò)策略之外。
- Tufin Orca——用于實現(xiàn)Kubernetes網(wǎng)絡(luò)策略的可視化和自動化。
總結(jié)
Kubernetes網(wǎng)絡(luò)策略為集群劃分提供了一種很好的方法,但是它們不直觀并且有許多注意的地方。我相信,由于這種復(fù)雜性,一定有許多集群在他們的策略中存在“bug”??赡艿慕鉀Q方案是自動化策略定義或其他分割方法。同時,希望本文對澄清和解決你可能遇到的問題有所幫助。