本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
為容器網路介面(CNI)提供商定義網路策略一致性
特別感謝 Tim Hockin 和 Bowie Du (Google)、Dan Winship 和 Antonio Ojea (Red Hat)、Casey Davenport 和 Shaun Crampton (Tigera) 以及 Abhishek Raut 和 Antonin Bas (VMware) 對這項工作的支援,並與我們合作,隨著時間的推移解決不同容器網路介面 (CNI) 中的問題。
2020 年 4 月,關於“節點本地”網路策略的簡短討論促成了 SIG Network 下的網路策略子專案的建立。顯而易見,作為一個社群,我們需要一個關於如何在 Kubernetes 上進行 Pod 網路安全的可靠方案,並且這個方案需要一個社群來支援,以便促進企業安全模式在 K8s 中的文化採納。
在這篇文章中,我們將討論
- 我們為什麼為網路策略建立一個子專案
- 我們如何修改 Kubernetes e2e 框架以
視覺化
您的 CNI 提供商的網路策略實現 - 我們基於這些原則構建的全面網路策略一致性驗證器 Cyclonus 的初步結果
- 子專案貢獻者對網路策略使用者體驗的改進
我們為什麼為網路策略建立一個子專案
在 2020 年 4 月,許多 CNI 正在湧現,並且許多供應商以微妙不同的方式實現這些 CNI。使用者開始對如何在不同場景下實施策略感到困惑,並要求提供新功能。很明顯,我們需要開始統一 Kubernetes 中網路策略的思考方式,以避免 API 碎片化和不必要的複雜性。
例如
- 為了適應使用者環境,Calico 作為 CNI 提供商可以以 IPIP 或 VXLAN 模式執行,或不帶封裝開銷。Antrea 和 Cilium 等 CNI 也提供類似的配置選項。
- 一些 CNI 外掛除了其他選項外還為網路策略提供 iptables,而其他 CNI 則使用完全不同的技術棧(例如,Antrea 專案使用 Open vSwitch 規則)。
- 一些 CNI 外掛只實現了 Kubernetes 網路策略 API 的一個子集,而另一些則實現了一個超集。例如,某些外掛不支援以命名埠為目標的能力;其他外掛不適用於某些 IP 地址型別,並且相似策略型別的語義也存在差異。
- 一些 CNI 外掛與其他 CNI 外掛結合以實現網路策略(canal),一些 CNI 可能會混合實現(multus),並且一些雲服務將路由與網路策略實現分開處理。
儘管這種複雜性在一定程度上是為了支援不同的環境所必需的,但終端使用者發現他們需要遵循多步驟過程來實施網路策略以保護他們的應用程式
- 確認他們的網路外掛支援網路策略(有些不支援,例如 Flannel)
- 確認其叢集的網路外掛支援他們感興趣的特定網路策略功能(再次,命名埠或埠範圍的示例在這裡浮現在腦海中)
- 確認其應用程式的網路策略定義正在做正確的事情
- 找出供應商策略實現的細微差別,並檢查該實現是否具有 CNI 中立實現(這有時足以滿足使用者需求)
上游 Kubernetes 中的 NetworkPolicy 專案旨在提供一個社群,人們可以在其中學習和貢獻 Kubernetes NetworkPolicy API 及其周圍生態系統。
第一步:一個直觀易懂的網路策略驗證框架
Kubernetes 端到端套件一直都有網路策略測試,但這些測試並未在 CI 中執行,而且它們的實現方式未能提供關於策略在叢集中如何工作的全面、易於理解的資訊。這是因為最初的測試沒有提供任何叢集連線的視覺化摘要。因此,我們最初的目標是讓驗證 CNI 對網路策略的支援變得容易,方法是讓端到端測試(管理員或使用者通常用於診斷叢集一致性)易於解釋。
為了解決確認 CNI 支援大多數使用者關心的基本策略功能的問題,我們在 Kubernetes e2e 框架中構建了一個新的 NetworkPolicy 驗證工具,該工具允許對策略及其對叢集中一組標準 Pod 的影響進行視覺化檢查。例如,以下是測試輸出。我們在 OVN Kubernetes 中發現了一個 bug。這個 bug 現已解決。使用這個工具,該 bug 非常容易表徵,即某些策略導致狀態修改,後來導致流量被錯誤地阻塞(即使所有 NetworkPolicy 已從叢集中刪除)。
這是相關測試的網路策略
metadata:
creationTimestamp: null
name: allow-ingress-port-80
spec:
ingress:
- ports:
- port: serve-80-tcp
podSelector: {}
這些是預期的連線結果。測試設定有 9 個 Pod(3 個名稱空間:x、y 和 z;每個名稱空間有 3 個 Pod:a、b 和 c);每個 Pod 在沒有網路策略的情況下,以相同的埠和協議執行一個伺服器,可以透過 HTTP 呼叫訪問。透過使用 agnhost 網路實用程式向其他 Pod 預期提供服務的埠和協議發出 HTTP 呼叫來驗證連線。測試場景首先執行連線檢查,以確保每個 Pod 都可以訪問其他 Pod,共 81 (= 9 x 9) 個數據點。這是“控制組”。然後根據測試場景應用擾動:建立、更新和刪除策略;從 Pod 和名稱空間新增和刪除標籤,等等。每次更改後,重新收集連線矩陣並與預期連線進行比較。
這些結果以簡單的矩陣形式直觀地顯示了連線情況。最左邊的列是“源”Pod,即發出請求的 Pod;最頂部的行是“目標”Pod,即接收請求的 Pod。.
表示允許連線;X
表示連線被阻止。例如
Nov 4 16:58:43.449: INFO: expected:
- x/a x/b x/c y/a y/b y/c z/a z/b z/c
x/a . . . . . . . . .
x/b . . . . . . . . .
x/c . . . . . . . . .
y/a . . . . . . . . .
y/b . . . . . . . . .
y/c . . . . . . . . .
z/a . . . . . . . . .
z/b . . . . . . . . .
z/c . . . . . . . . .
以下是 OVN Kubernetes bug 案例中觀察到的連線結果。請注意,前三行表明來自名稱空間 x 的所有請求,無論 Pod 和目標如何,都被阻止。由於這些實驗結果與預期結果不匹配,因此將報告失敗。請注意,特定的失敗模式清晰地揭示了問題的性質——由於來自特定名稱空間的請求都失敗了,我們有了明確的線索來開始調查。
Nov 4 16:58:43.449: INFO: observed:
- x/a x/b x/c y/a y/b y/c z/a z/b z/c
x/a X X X X X X X X X
x/b X X X X X X X X X
x/c X X X X X X X X X
y/a . . . . . . . . .
y/b . . . . . . . . .
y/c . . . . . . . . .
z/a . . . . . . . . .
z/b . . . . . . . . .
z/c . . . . . . . . .
這是我們在網路策略小組中取得的早期成功之一,我們能夠與 OVN Kubernetes 小組合作,修復了出口策略處理中的一個 bug。
然而,儘管此工具使驗證大約 30 種常見場景變得容易,但它無法驗證*所有*網路策略場景——因為可能建立的排列組合數量巨大(從技術上講,考慮到可以建立無限數量的名稱空間/Pod/埠/協議變體,我們可以說這個數字是無限的)。
一旦這些測試到位,我們與上游 SIG Network 和 SIG Testing 社群(感謝 Antonio Ojea 和 Ben Elder)合作,建立了 testgrid Network Policy 作業。此作業持續針對 GCE 並使用 Calico 作為網路策略提供商執行整個網路策略測試套件。
作為子專案的一部分,我們的職責是幫助確保當這些測試失敗時,我們能夠有效地對其進行分類。
Cyclonus:網路策略一致性的下一步
在我們完成驗證工作的同時,社群明確表示,總的來說,我們需要解決測試所有可能的網路策略實現的整體問題。例如,最近編寫了一個 KEP,其中引入了網路策略微版本化的概念,以適應 Dan Winship 在 API 層面描述此問題。
為了應對日益明顯的全面評估所有供應商網路策略實現的需求,Matt Fenwick 決定透過建立 Cyclonus 來再次發展我們的網路策略驗證方法。
Cyclonus 是一款全面的網路策略模糊測試工具,透過定義類似於端到端測試中所示的真值表/策略組合,並提供策略“類別”的分層表示,驗證 CNI 提供商是否符合數百種不同的網路策略場景。到目前為止,我們已經在測試的幾乎所有 CNI 中發現了一些有趣的細微差別和問題,甚至還貢獻了一些修復。
要執行 Cyclonus 驗證執行,您可以建立一個類似的 Job manifest
apiVersion: batch/v1
kind: Job
metadata:
name: cyclonus
spec:
template:
spec:
restartPolicy: Never
containers:
- command:
- ./cyclonus
- generate
- --perturbation-wait-seconds=15
- --server-protocol=tcp,udp
name: cyclonus
imagePullPolicy: IfNotPresent
image: mfenwick100/cyclonus:latest
serviceAccount: cyclonus
Cyclonus 輸出它將執行的所有測試用例的報告
test cases to run by tag:
- target: 6
- peer-ipblock: 4
- udp: 16
- delete-pod: 1
- conflict: 16
- multi-port/protocol: 14
- ingress: 51
- all-pods: 14
- egress: 51
- all-namespaces: 10
- sctp: 10
- port: 56
- miscellaneous: 22
- direction: 100
- multi-peer: 0
- any-port-protocol: 2
- set-namespace-labels: 1
- upstream-e2e: 0
- allow-all: 6
- namespaces-by-label: 6
- deny-all: 10
- pathological: 6
- action: 6
- rule: 30
- policy-namespace: 4
- example: 0
- tcp: 16
- target-namespace: 3
- named-port: 24
- update-policy: 1
- any-peer: 2
- target-pod-selector: 3
- IP-block-with-except: 2
- pods-by-label: 6
- numbered-port: 28
- protocol: 42
- peer-pods: 20
- create-policy: 2
- policy-stack: 0
- any-port: 14
- delete-namespace: 1
- delete-policy: 1
- create-pod: 1
- IP-block-no-except: 2
- create-namespace: 1
- set-pod-labels: 1
testing 112 cases
請注意,Cyclonus 根據正在建立的策略型別標記其測試,因為策略本身是自動生成的,因此沒有有意義的名稱可供識別。
對於每個測試,Cyclonus 會輸出一個真值表,該真值表再次類似於 E2E 測試的真值表,以及正在驗證的策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
creationTimestamp: null
name: base
namespace: x
spec:
egress:
- ports:
- port: 81
to:
- namespaceSelector:
matchExpressions:
- key: ns
operator: In
values:
- "y"
- z
podSelector:
matchExpressions:
- key: pod
operator: In
values:
- a
- b
- ports:
- port: 53
protocol: UDP
ingress:
- from:
- namespaceSelector:
matchExpressions:
- key: ns
operator: In
values:
- x
- "y"
podSelector:
matchExpressions:
- key: pod
operator: In
values:
- b
- c
ports:
- port: 80
protocol: TCP
podSelector:
matchLabels:
pod: a
policyTypes:
- Ingress
- Egress
0 wrong, 0 ignored, 81 correct
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| TCP/80 | X/A | X/B | X/C | Y/A | Y/B | Y/C | Z/A | Z/B | Z/C |
| TCP/81 | | | | | | | | | |
| UDP/80 | | | | | | | | | |
| UDP/81 | | | | | | | | | |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| x/a | X | X | X | X | X | X | X | X | X |
| | X | X | X | . | . | X | . | . | X |
| | X | X | X | X | X | X | X | X | X |
| | X | X | X | X | X | X | X | X | X |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| x/b | . | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| x/c | . | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| y/a | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| y/b | . | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| y/c | . | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| z/a | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| z/b | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| z/c | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
| | X | . | . | . | . | . | . | . | . |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Cyclonus 和 e2e 測試都使用相同的策略來驗證網路策略 - 透過 TCP 或 UDP 探測 Pod,並支援 SCTP(如果 CNI 支援,例如 Calico)。
以下示例說明了我們如何使用 Cyclonus 從網路策略角度幫助改進 CNI 實現
好訊息是,Antrea 和 Calico 已經合併了所有發現問題的修復,其他 CNI 提供商也在 SIG Network 和 Network Policy 子專案的支援下努力解決問題。
您有興趣驗證叢集上的網路策略功能嗎?(如果您關心安全或提供多租戶 SaaS,您應該會感興趣) 如果是,您可以執行上游端到端測試、Cyclonus,或兩者都執行。
- 如果您剛剛開始使用網路策略,並且只想快速診斷並驗證大多數 CNI 都應正確實現的“常見”網路策略案例,那麼您最好只執行 e2e 測試。
- 如果您對 CNI 提供商的網路策略實現深感好奇,並希望對其進行驗證:請使用 Cyclonus。
- 如果您想測試*數百*個策略,並評估您的 CNI 外掛的全面功能,以深入發現潛在的安全漏洞:請使用 Cyclonus,並考慮執行端到端叢集測試。
- 如果您正在考慮參與上游網路策略工作:請使用 Cyclonus,並至少閱讀相關 e2e 測試的概述。
從何處開始進行網路策略測試?
- Cyclonus 在您的叢集上執行起來很簡單,請檢視 github 上的說明,並確定*您的*特定 CNI 配置是否完全符合數百種不同的 Kubernetes 網路策略 API 構造。
- 或者,您可以使用 sonobuoy 等工具執行 Kubernetes 中現有的 E2E 測試,並帶有
--ginkgo.focus=NetworkPolicy
標誌。請確保您使用 K8s 1.21 或更高版本的 K8s 一致性映象(例如,透過使用--kube-conformance-image-version v1.21.0
標誌),因為舊映象將不包含新的網路策略測試。
網路策略 API 和使用者體驗的改進
除了清理實現網路策略的 CNI 外掛的驗證工作外,子專案貢獻者還花了一些時間改進 Kubernetes 網路策略 API,以滿足一些常見請求的功能。經過數月的審議,我們最終確定了幾個核心改進領域
埠範圍策略:我們現在允許您為策略指定一個埠*範圍*。這使得對 FTP 或虛擬化等場景感興趣的使用者能夠啟用高階策略。網路策略的埠範圍選項將在 Kubernetes 1.21 中可用。請閱讀以埠範圍為目標以獲取更多資訊。
名稱空間作為名稱策略:允許 Kubernetes >= 1.21 的使用者在構建網路策略物件時使用名稱來指定名稱空間。這是與 API 機器方面的 Jordan Liggitt 和 Tim Hockin 協作完成的。這一更改使我們能夠在不實際更改 API 的情況下改進網路策略使用者體驗!有關更多詳細資訊,您可以閱讀名稱空間頁面中的自動標籤。簡單來說,對於 Kubernetes 1.21 及更高版本,所有名稱空間預設新增以下標籤
kubernetes.io/metadata.name: <name-of-namespace>
這意味著您可以針對此名稱空間編寫名稱空間策略,即使您無法編輯其標籤。例如,此策略將“正常工作”,而無需執行 kubectl edit namespace
等命令。事實上,即使您根本無法編輯或檢視此名稱空間的資料,它也能夠正常工作,這得益於 API 伺服器預設設定的魔力。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
# Allow inbound traffic to Pods labelled role=db, in the namespace 'default'
# provided that the source is a Pod in the namespace 'my-namespace'
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: my-namespace
結果
在我們的測試中,我們發現
- Antrea 和 Calico 在支援所有 Cyclonus 場景方面已達到一定水平,只需進行一些非常小的調整即可。
- Cilium 也符合大多數策略,除了已知未完全支援的功能(例如,與 Cilium 處理 Pod CIDR 策略的方式相關)。
如果您是 CNI 提供商,並有興趣幫助我們更好地管理大量的網路策略測試,請與我們聯絡!我們正在繼續在此處整理 Cyclonus 的網路策略一致性結果,但我們無法獨自維護網路策略測試資料中的所有細微之處。目前,我們使用 github actions 和 Kind 在 CI 中進行測試。
未來展望
我們還在為網路策略的未來進行一些改進,包括
- 完全限定域名策略:Google Cloud 團隊建立了一個 FQDN 策略原型(我們對此感到非常興奮)。該工具使用網路策略 API 來針對 L7 URL 強制執行策略,方法是查詢它們的 IP 並在發出請求時主動阻止它們。
- 叢集管理策略:我們正在努力為未來實現*管理*或*叢集範圍*的網路策略。這些正在逐步提交給 NetworkPolicy 子專案。您可以在叢集範圍的網路策略中閱讀相關內容。
網路策略子專案於美國東部時間每週一下午 4 點舉行會議。有關詳細資訊,請檢視 SIG Network 社群儲存庫。我們很樂意與您交流、共同開發,並儘可能幫助您在叢集中採用 K8s 網路策略。
關於使用者反饋的快速說明
我們從使用者那裡獲得了大量關於網路策略的創意和反饋。許多人對網路策略有有趣的看法,但我們發現,作為一個子專案,很少有人真正有興趣全面實現這些想法。
幾乎所有對 NetworkPolicy API 的更改都涉及數週或數月的討論,以涵蓋不同的情況並確保沒有引入 CVE。因此,長期所有權是我們在改進 NetworkPolicy 使用者體驗方面最大的障礙。
我們鼓勵任何人向我們提供反饋,但我們目前最緊迫的問題是尋找*長期所有者來幫助我們推動變革*。
這不需要大量的技術知識,而只需要長期致力於幫助我們保持組織、處理文書工作並迭代 K8s 功能流程的許多階段。如果您想幫助我們並參與其中,請在 SIG Network 郵件列表或 k8s.io Slack 頻道中的 SIG Network 房間聯絡我們!
任何人都可以盡一份力,讓網路策略變得更好!