設置Kubernetes網路政策 – 詳細指南

  • 2019 年 12 月 4 日
  • 筆記

這篇客座文章由StackRox技術人員Viswajith Venugopal撰寫,最初發布在Stackrox上。

https://www.stackrox.com/post/2019/04/setting-up-kubernetes-network-policies-a-detailed-guide/

容器編排戰爭結束了,Kubernetes贏了。隨著大大小小的公司迅速採用該平台,安全性已成為一個重要問題 – 部分原因在於了解任何新基礎架構所固有的學習曲線,部分原因是最近公布的漏洞。

Kubernetes帶來另一種安全考慮 – 它的默認設置旨在使用戶能夠輕鬆地快速啟動和運行,以及向後兼容缺乏重要安全功能的早期版本的Kubernetes。因此,默認情況下,許多重要的Kubernetes配置都不安全。

從安全形度來看需要注意的一個重要配置是網路政策功能。網路政策指定允許pod組與彼此和其他網路端點進行通訊的方式。你可以將它們視為Kubernetes等同於防火牆。

另外,如果你還沒有這樣做,請升級到最新的Kubernetes版本,因為最近的Kubernetes更新已經解決了一些最關鍵的Kubernetes安全問題。

如何設置網路政策

我們在此列出了有關如何設置網路政策的分步指南。網路政策規範錯綜複雜,可能難以正確理解和使用。在本指南中,我們提供了可顯著提高安全性的建議。用戶可以輕鬆應用這些建議,而無需詳細了解規範。

快速說明:本指南僅關注入口(ingress)網路政策。在開始時,最大的安全性收益來自應用入口政策,因此我們建議首先關注它們,然後添加出口(egress)政策。我們將詳細討論出口政策,並在本系列的後續文章中提供建議。

使用支援網路政策的網路插件

首先要做的事情 – 使用實際執行網路政策的網路插件。雖然Kubernetes總是支援對NetworkPolicy資源的操作,只是創建沒有實現它的插件的資源將沒有任何效果。示例插件包括Calico、Cilium、Kube-router、Romana和Weave Net。

「隔離」你的pod

每個網路政策都有一個podSelector欄位,用於選擇一組(零個或多個)pod。當網路政策選擇了pod時,稱該網路政策適用於該pod。

每個網路政策還指定允許(入口和出口)連接的列表。創建網路政策後,其應用到的所有pod允許建立或接受列出的連接。換句話說,網路政策本質上是允許連接的白名單 – 如果至少有一個適用於該pod的網路政策允許,則允許與pod之間的連接。

然而,這個故事有一個重要的轉折:基於到目前為止所描述的所有內容,人們會認為,如果沒有網路政策應用於pod,則不允許與其進行任何連接。事實恰恰相反:如果沒有網路政策適用於pod,則允許與其進行的所有網路連接。

這種行為與「隔離」的概念有關:如果至少有一個網路政策適用於它們,那麼它就是「隔離的」;如果沒有適用的政策,它們是「非隔離的」。不對非隔離的pod執行網路政策。儘管有些反直覺,這種行為的存在使得集群的啟動和運行變得更加容易 – 不了解網路政策的用戶可以運行他們的應用程式而無需創建網路政策。

因此,我們建議你首先應用「default-deny-all」網路政策。以下政策規範的作用是隔離所有pod,這意味著只允許其他網路政策明確列入白名單的連接。

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: default-deny-all  spec:    podSelector: {}    policyTypes:    - Ingress

如果沒有這樣的政策,很容易遇到刪除網路政策的情況,希望禁止其中列出的連接,但發現結果是所有與某些pod的連接突然被允許 – 包括那些沒有以前不允許。當你刪除的網路政策是唯一應用於特定pod的網路政策時,會出現這種情況,這意味著刪除網路政策會導致pod變為「非隔離」。

重要說明:由於網路政策是命名空間資源,因此你需要為每個命名空間創建此政策。你可以通過為每個命名空間運行kubectl -n create -f來實現。

明確允許需要訪問Internet的pod

使用default-deny-all政策,你的任何pod都不能相互通訊或從Internet接收流量。要使大多數應用程式正常工作,你需要允許一些pod從外部源接收流量。允許此設置的一種便捷方式是指定你希望允許從Internet訪問的那些pod的標籤,並創建以這些標籤為目標的網路政策。例如,以下網路政策允許具有「networking/allow-internet-access=true」標籤的pod的所有(包括外部)源的流量:

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: internet-access  spec:    podSelector:      matchLabels:        networking/allow-internet-access: "true"    policyTypes:    - Ingress    ingress:    - {}

對於更加鎖定的政策集,理想地你希望指定更細粒度的CIDR塊以及明確列出允許的埠和協議。但是,此政策提供了一個良好的起點,具有比默認值更高的安全性。

明確允許必要的pod-to-pod通訊

完成上述步驟後,你還需要添加網路政策以允許pod相互通訊。根據你的具體情況,你可以選擇如何啟用pod-to-pod通訊:

如果你不知道哪個Pod需要互相交談

在這種情況下,一個好的起點是允許同一命名空間中的所有pod相互通訊並明確地將命名空間列入命名空間,因為這通常更為罕見。你可以使用以下網路政策允許命名空間內的所有pod-to-pod通訊:

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: allow-same-namespace  spec:    podSelector: {}    policyTypes:    - Ingress    ingress:    - from:      - podSelector: {}

如果你知道溝通的來源和匯點

通常,應用程式中的pod之間的通訊遵循hub-and-spoke範例,其中有許多其他pod需要與之交談的中央pod。在這種情況下,你可以考慮創建一個標籤,指定允許與「hub集線器」通訊的pod。例如,如果你的集線器是資料庫pod並且具有app=db標籤,則可以通過應用以下政策,僅允許具有networking/allow-db-access=true標籤的pod訪問資料庫:

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: allow-db-access  spec:    podSelector:      matchLabels:        app: "db"    policyTypes:    - Ingress    ingress:    - from:      - podSelector:          matchLabels:            networking/allow-db-access: "true"

如果你的伺服器啟動與許多其他pod的連接,你可以執行類似的操作。如果要明確將允許伺服器與之通訊的pod列入白名單,可以在其上設置networking/allow-server-to-access=true標籤,並應用以下網路政策(假設你的伺服器具有app=server標籤):

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: allow-server-to-access  spec:    podSelector:      matchLabels:        networking/allow-server-to-access: "true"    policyTypes:    - Ingress    ingress:    - from:      - podSelector:          matchLabels:            app: "server"

如果你確切知道應該允許哪些連接

在同一名稱空間內

準確了解應用程式中應允許哪些pod-to-pod連接的高級用戶可以明確允許每個此類連接。如果你希望部署A中的pod能夠與部署B中的Pod進行通訊,則可以在使用特定部署的標籤替換標籤後,創建以下政策以將該連接列入白名單:

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: allow-server-to-access  spec:    podSelector:      matchLabels:        deployment-b-pod-label-1-key: deployment-b-pod-label-1-value        deployment-b-pod-label-2-key: deployment-b-pod-label-2-value    policyTypes:    - Ingress    ingress:    - from:      - podSelector:          matchLabels:            deployment-a-pod-label-1-key: deployment-a-pod-label-1-value            deployment-a-pod-label-2-key: deployment-a-pod-label-2-value

跨命名空間

要允許跨命名空間的連接,你需要為源命名空間創建標籤(遺憾的是,Kubernetes默認情況下在命名空間上沒有任何標籤),並在podSelector查詢旁邊添加namespaceSelector查詢。 要標記命名空間,只需運行命令:kubectl label namespace networking/namespace =

使用此命名空間標籤,你可以通過應用以下網路政策,允許命名空間N1中的部署A與命名空間N2中的部署B通訊:

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: allow-n1-a-to-n2-b    namespace: N2  spec:    podSelector:      matchLabels:        deployment-b-pod-label-1-key: deployment-b-pod-label-1-value        deployment-b-pod-label-2-key: deployment-b-pod-label-2-value    policyTypes:    - Ingress    ingress:    - from:      -  namespaceSelector:          matchLabels:            networking/namespace: N1         podSelector:          matchLabels:            deployment-a-pod-label-1-key: deployment-a-pod-label-1-value            deployment-a-pod-label-2-key: deployment-a-pod-label-2-value

新部署怎麼樣?

雖然以這種方式明確地將連接列入白名單對於安全性很有用,但這種方法確實會影響可用性。創建新部署時,默認情況下,在應用網路政策之前,它們將無法與任何內容進行通訊。為了緩解這種可能令人沮喪的用戶體驗,你可以創建以下一對網路政策,這些政策允許標記為networking/allow-all-connections=true的pod與同一名稱空間中的所有其他pod進行通訊:

apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: allow-ingress-from-new  spec:    podSelector: {}    policyTypes:    - Ingress    ingress:    - from:      - podSelector:          matchLabels:            networking/allow-all-connections: "true"  ---  apiVersion: networking.k8s.io/v1  kind: NetworkPolicy  metadata:    name: allow-ingress-to-new  spec:    podSelector:      matchLabels:        networking/allow-all-connections: "true"    policyTypes:    - Ingress    ingress:    - from:      - podSelector: {}

然後,你可以將networking/allow-all-connections=true標籤應用於所有新創建的部署,以便你的應用程式可以運行,直到你為它們創建特製的網路政策,此時你可以刪除標籤。

總結

雖然這些建議提供了一個良好的起點,但網路政策涉及的範圍更廣。如果你有興趣更詳細地探索它們,請務必查看Kubernetes教程以及一些方便的網路政策配方。

https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/

https://github.com/ahmetb/kubernetes-network-policy-recipes