本文的目的是向讀者介紹 Kubernetes 中的網路和管理網路策略的基礎知識,以及擴展標準功能的第三方 Calico 外掛程式。 在此過程中,我們將使用我們操作經驗中的真實範例來演示配置的簡單性和一些功能。
Kubernetes 網路設備快速介紹
無法想像沒有網路的 Kubernetes 叢集。 我們已經發布了有關其基礎知識的資料:“
在本文中,需要注意的是,K8s 本身不負責容器和節點之間的網路連接:為此,各種 CNI 插件 (容器網路介面)。 關於這個概念的更多信息,我們
例如,這些插件中最常見的是
並提供「開箱即用」的方式在 Kubernetes 叢集中組織網路策略管理
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: 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
這不是最原始的例子
從邏輯上講,有兩種類型的流量:進入 Pod 的流量(Ingress)和從 Pod 流出的流量(Egress)。
實際上,政治根據運動方向分為這兩類。
下一個必需的屬性是選擇器; 規則適用的人。 這可以是一個 Pod(或一組 Pod)或一個環境(即命名空間)。 一個重要的細節:這兩種類型的物件都必須包含一個標籤(標籤 在 Kubernetes 術語中)—這些是政客所使用的。
除了有限數量的選擇器(由某種標籤聯合起來)之外,還可以以不同的變體編寫“允許/拒絕一切/所有人”之類的規則。 為此,使用以下形式的結構:
podSelector: {}
ingress: []
policyTypes:
- Ingress
— 在此範例中,環境中的所有 Pod 都會被阻止接收傳入流量。 透過以下結構可以實現相反的行為:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
同樣對於傳出:
podSelector: {}
policyTypes:
- Egress
- 將其關閉。 以下是要包含的內容:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
回到叢集的 CNI 插件的選擇,值得注意的是 並非每個網頁外掛程式都支援 NetworkPolicy。 例如已經提到的Flannel不知道如何設定網路策略,這
了解 Calico:理論
Calico 插件可以與 Flannel 整合使用(子項目
使用 K8s「盒裝」解決方案和 Calico 的 API 集提供了哪些機會?
以下是 NetworkPolicy 的內建內容:
- 政治家受到環境的限制;
- 策略應用於標有標籤的 Pod;
- 規則可以應用於 Pod、環境或子網路;
- 規則可以包含協定、命名或符號連接埠規格。
以下是 Calico 如何擴展這些功能:
- 策略可以應用於任何物件:pod、容器、虛擬機器或介面;
- 規則可以包含特定的操作(禁止、許可、記錄);
- 規則的目標或來源可以是連接埠、一系列連接埠、協定、HTTP 或 ICMP 屬性、IP 或子網路(第四代或第六代)、任何選擇器(節點、主機、環境);
- 此外,您可以使用 DNAT 設定和流量轉送策略來調節流量的通過。
Calico 儲存庫中 GitHub 上的首次提交可以追溯到 2016 年 XNUMX 月,一年後該專案在組織 Kubernetes 網路連接方面佔據了領先地位 - 例如,調查結果就證明了這一點:
許多使用 K8s 的大型託管解決方案,例如
至於性能,這裡一切都很棒。 在測試他們的產品時,Calico 開發團隊展示了天文學數位般的效能,在 50000 個實體節點上運行了 500 多個容器,每秒創建 20 個容器。 沒有發現縮放問題。 這樣的結果
該專案發展非常迅速,它支援在流行的解決方案管理的K8s、OpenShift、OpenStack中工作,在部署叢集時可以使用Calico
與 Calico 一起練習
在使用普通 Kubernetes 的一般情況下,安裝 CNI 歸結為使用該文件 calico.yaml
, kubectl apply -f
.
通常,目前版本的外掛程式與 Kubernetes 的最新 2-3 個版本相容:舊版中的操作未經測試且無法保證。 據開發人員稱,Calico 運行在 3.10 以上的 Linux 核心上,運行 CentOS 7、Ubuntu 16 或 Debian 8,基於 iptables 或 IPVS。
環境內隔離
為了進行一般性理解,讓我們來看一個簡單的案例,以了解 Calico 表示法中的網路策略與標準策略有何不同,以及創建規則的方法如何簡化其可讀性和配置靈活性:
叢集中部署了 2 個 Web 應用程式:Node.js 和 PHP,其中之一使用 Redis。 要阻止從 PHP 存取 Redis,同時保持與 Node.js 的連接,只需套用以下策略:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-redis-nodejs
spec:
podSelector:
matchLabels:
service: redis
ingress:
- from:
- podSelector:
matchLabels:
service: nodejs
ports:
- protocol: TCP
port: 6379
本質上,我們允許從 Node.js 傳入 Redis 埠的流量。 他們顯然沒有禁止任何其他事情。 NetworkPolicy一出現,其中提到的所有選擇器就開始被隔離,除非另有說明。 但是,隔離規則不適用於選擇器未覆寫的其他物件。
此範例使用 apiVersion
Kubernetes 開箱即用,但沒有什麼可以阻止您使用它
apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
name: allow-redis-nodejs
spec:
selector: service == 'redis'
ingress:
- action: Allow
protocol: TCP
source:
selector: service == 'nodejs'
destination:
ports:
- 6379
上述用於允許或拒絕通過常規 NetworkPolicy API 的所有流量的結構包含帶有括號的結構,這些結構難以理解和記憶。 對於 Calico,要將防火牆規則的邏輯變更為相反的邏輯,只需更改 action: Allow
上 action: Deny
.
環境隔離
現在想像這樣一種情況:應用程式產生業務指標,以便在 Prometheus 中收集並使用 Grafana 進行進一步分析。 上傳的內容可能包含敏感數據,預設情況下這些數據也是公開可見的。 讓我們隱藏這些數據以免被窺探:
通常,Prometheus 放置在單獨的服務環境中 - 在範例中它將是這樣的命名空間:
apiVersion: v1
kind: Namespace
metadata:
labels:
module: prometheus
name: kube-prometheus
領域 metadata.labels
事實證明這並非偶然。 正如剛才所提到的, namespaceSelector
(也 podSelector
)與標籤一起操作。 因此,要允許從特定連接埠上的所有 Pod 取得指標,您必須新增某種標籤(或從現有標籤中取得),然後套用如下配置:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-metrics-prom
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
module: prometheus
ports:
- protocol: TCP
port: 9100
如果您使用 Calico 策略,語法將如下所示:
apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
name: allow-metrics-prom
spec:
ingress:
- action: Allow
protocol: TCP
source:
namespaceSelector: module == 'prometheus'
destination:
ports:
- 9100
一般來說,透過針對特定需求添加此類策略,可以防止叢集中應用程式的運行受到惡意或意外幹擾。
根據 Calico 的創建者的說法,最佳實踐是「阻止所有內容並明確打開您需要的內容」方法,記錄在
使用額外的 Calico 對象
讓我提醒您,透過 Calico API 的擴充集,您可以調節節點的可用性,而不僅限於 pod。 在下面的範例中使用 GlobalNetworkPolicy
在叢集中傳遞 ICMP 請求的功能已關閉(例如,從 pod 到節點、pod 之間或從節點到 IP pod 的 ping):
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
name: block-icmp
spec:
order: 200
selector: all()
types:
- Ingress
- Egress
ingress:
- action: Deny
protocol: ICMP
egress:
- action: Deny
protocol: ICMP
在上述情況下,叢集節點仍可透過 ICMP 相互「聯繫」。 這個問題是透過以下方式解決的 GlobalNetworkPolicy
,應用於實體 HostEndpoint
:
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
name: deny-icmp-kube-02
spec:
selector: "role == 'k8s-node'"
order: 0
ingress:
- action: Allow
protocol: ICMP
egress:
- action: Allow
protocol: ICMP
---
apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
name: kube-02-eth0
labels:
role: k8s-node
spec:
interfaceName: eth0
node: kube-02
expectedIPs: ["192.168.2.2"]
VPN 案例
最後,我將給出一個非常真實的範例,當一組標準策略不夠時,使用 Calico 函數來處理近集群互動的情況。 要存取 Web 應用程序,用戶端使用 VPN 隧道,且此存取受到嚴格控制並僅限於允許使用的特定服務清單:
用戶端透過標準 UDP 連接埠 1194 連接到 VPN,並在連接後接收 Pod 和服務的叢集子網路的路由。 推送整個子網,以免在重新啟動和位址變更期間遺失服務。
配置中的連接埠是標準的,這給配置應用程式並將其傳輸到 Kubernetes 叢集的過程帶來了一些細微差別。 例如,去年年底,AWS LoadBalancer for UDP 確實出現在有限的區域清單中,而 NodePort 由於在所有叢集節點上轉送而無法使用,並且無法擴展伺服器執行個體的數量容錯的目的。 另外,您必須更改連接埠的預設範圍...
經過搜尋可能的解決方案,選擇以下方案:
- 具有 VPN 的 Pod 按節點調度
hostNetwork
,即為實際IP。 - 該服務透過外部發布
ClusterIP
。 連接埠實體安裝在節點上,可以從外部訪問,但需要進行少量保留(有條件地存在真實 IP 位址)。 - 確定豆莢升起的節點超出了我們故事的範圍。 我只想說,你可以將服務緊緊地「釘」在一個節點上,或者編寫一個小型sidecar 服務來監視VPN 服務的當前IP 位址並編輯向客戶端註冊的DNS 記錄- 無論誰有足夠的想像力。
從路由的角度來看,我們可以透過VPN伺服器發佈的IP位址來唯一標識VPN客戶端。 以下是限制此類客戶端存取服務的原始範例,在上述 Redis 上進行了說明:
apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
name: vpnclient-eth0
labels:
role: vpnclient
environment: production
spec:
interfaceName: "*"
node: kube-02
expectedIPs: ["172.176.176.2"]
---
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
name: vpn-rules
spec:
selector: "role == 'vpnclient'"
order: 0
applyOnForward: true
preDNAT: true
ingress:
- action: Deny
protocol: TCP
destination:
ports: [6379]
- action: Allow
protocol: UDP
destination:
ports: [53, 67]
在這裡,嚴格禁止連接到連接埠 6379,但同時保留 DNS 服務的操作,在製定規則時,該服務的功能經常受到影響。 因為,如前所述,當選擇器出現時,除非另有指定,否則預設拒絕策略將會套用到它。
結果
因此,使用 Calico 的高級 API,您可以靈活配置和動態更改叢集內部和周圍的路由。 一般來說,它的使用看起來就像用大砲射麻雀,並且在平坦網路上的簡單Kubernetes 安裝中實現具有BGP 和IP-IP 隧道的L3 網路看起來很可怕......但是,除此之外,該工具看起來非常可行且有用。
隔離群集來滿足安全要求可能並不總是可行,這就是 Calico(或類似的解決方案)可以解決的問題。 本文中給出的範例(稍作修改)已用於我們在 AWS 中的多個客戶端安裝。
聚苯乙烯
另請閱讀我們的博客:
- «
面向安全專業人員的 Kubernetes 網絡策略簡介 “; - “Kubernetes 網絡圖解指南”:
第 1 部分和第 2 部分(網絡模型、覆蓋網絡) ,第 3 部分(服務和流量處理) ; - «
容器網路介面 (CNI) - Linux 容器的網路介面和標準 “。
來源: www.habr.com