使用 Cilium 增强 Kubernetes 网络安全
作者 | Addo Zhang
來源 | 云原生指北
TL;DR
在本篇,我們分別使用了 Kubernetes 原生的網(wǎng)絡(luò)策略和 Cilium 的網(wǎng)絡(luò)策略實(shí)現(xiàn)了 Pod 網(wǎng)絡(luò)層面的隔離。不同的是,前者只提供了基于 L3/4 的網(wǎng)絡(luò)策略;后者支持 L3/4、L7 的網(wǎng)絡(luò)策略。
通過網(wǎng)絡(luò)策略來提升網(wǎng)絡(luò)安全,可以極大降低了實(shí)現(xiàn)和維護(hù)的成本,同時(shí)對(duì)系統(tǒng)幾乎沒有影響。
尤其是基于 eBPF 技術(shù)的 Cilium,解決了內(nèi)核擴(kuò)展性不足的問題,從內(nèi)核層面為工作負(fù)載提供安全可靠、可觀測的網(wǎng)絡(luò)連接。
背景
為什么說 Kubernetes 網(wǎng)絡(luò)存在安全隱患?集群中的 Pod 默認(rèn)是未隔離的,也就是 Pod 之間的網(wǎng)絡(luò)是互通的,可以互相通信的。
這里就會(huì)有問題,比如由于數(shù)據(jù)敏感服務(wù) B 只允許特定的服務(wù) A 才能訪問,而服務(wù) C 無法訪問 B。要禁止服務(wù) C 對(duì)服務(wù) B 的訪問,可以有幾種方案:
在 SDK 中提供通用的解決方案,實(shí)現(xiàn)白名單的功能。首先請(qǐng)求要帶有來源的標(biāo)識(shí),然后服務(wù)端可以接收規(guī)則設(shè)置放行特定標(biāo)識(shí)的請(qǐng)求,拒絕其他的請(qǐng)求。
云原生的解決方案,使用服務(wù)網(wǎng)格的 RBAC、mTLS 功能。RBAC 實(shí)現(xiàn)原理與應(yīng)用層的 SDK 方案類似,但是屬于基礎(chǔ)設(shè)施層的抽象通用方案;mTLS 則會(huì)更加復(fù)雜一些,在連接握手階段進(jìn)行身份驗(yàn)證,涉及證書的簽發(fā)、驗(yàn)證等操作。
以上兩種方案各有利弊:
SDK 的方案實(shí)現(xiàn)簡單,但是規(guī)模較大的系統(tǒng)會(huì)面臨升級(jí)推廣困難、多語言支持成本高等問題。
服務(wù)網(wǎng)格的方案是基礎(chǔ)設(shè)施層的通用方案,天生支持多語言。但是對(duì)于未落地網(wǎng)格的用戶來說,架構(gòu)變化大,成本高。如果單純?yōu)榱私鉀Q安全問題,使用網(wǎng)格方案性價(jià)比又很低,且不說現(xiàn)有網(wǎng)格實(shí)現(xiàn)等落地難度大及后期的使用維護(hù)成本高。
繼續(xù)向基礎(chǔ)設(shè)施下層找方案,從網(wǎng)絡(luò)層入手。Kubernetes 提供了的網(wǎng)絡(luò)策略 *NetworkPolicy*[1],則可以實(shí)現(xiàn)“網(wǎng)絡(luò)層面的隔離”。
示例應(yīng)用
在進(jìn)一步演示?NetworkPolicy?的方案之前,先介紹用于演示的示例應(yīng)用。我們使用 Cilium 在互動(dòng)教程?Cilium getting started[2]?中使用的“星球大戰(zhàn)”場景。
這里有三個(gè)應(yīng)用,星戰(zhàn)迷估計(jì)不會(huì)陌生:
死星?deathstar:在?80?端口提供 web 服務(wù),有 2 個(gè) 副本,通過 Kubernetes Service 的負(fù)載均衡為帝國戰(zhàn)機(jī)對(duì)外提供”登陸“服務(wù)。
鈦戰(zhàn)機(jī)?tiefighter:執(zhí)行登陸請(qǐng)求。
X翼戰(zhàn)機(jī)?xwing:執(zhí)行登陸請(qǐng)求。
如圖所示,我們使用了?Label?對(duì)三個(gè)應(yīng)用進(jìn)行了標(biāo)識(shí):org?和?class。在執(zhí)行網(wǎng)絡(luò)策略時(shí),我們會(huì)使用這兩個(gè)標(biāo)簽識(shí)別負(fù)載。
#?app.yaml --- apiVersion:?v1 kind:?Service metadata:name:?deathstarlabels:app.kubernetes.io/name:?deathstar spec:type:?ClusterIPports:-?port:?80selector:org:?empireclass:?deathstar --- apiVersion:?apps/v1 kind:?Deployment metadata:name:?deathstarlabels:app.kubernetes.io/name:?deathstar spec:replicas:?2selector:matchLabels:org:?empireclass:?deathstartemplate:metadata:labels:org:?empireclass:?deathstarapp.kubernetes.io/name:?deathstarspec:containers:-?name:?deathstarimage:?docker.io/cilium/starwars --- apiVersion:?v1 kind:?Pod metadata:name:?tiefighterlabels:org:?empireclass:?tiefighterapp.kubernetes.io/name:?tiefighter spec:containers:-?name:?spaceshipimage:?docker.io/tgraf/netperf --- apiVersion:?v1 kind:?Pod metadata:name:?xwinglabels:app.kubernetes.io/name:?xwingorg:?allianceclass:?xwing spec:containers:-?name:?spaceshipimage:?docker.io/tgraf/netperfKubernetes 網(wǎng)絡(luò)策略
可以通過官方文檔[3]獲取更多詳細(xì)信息,這里我們直接放出配置:
#?native/networkpolicy.yaml apiVersion:?networking.k8s.io/v1 kind:?NetworkPolicy metadata:name:?policynamespace:?default spec:podSelector:matchLabels:org:?empireclass:?deathstarpolicyTypes:-?Ingressingress:-?from:-?podSelector:matchLabels:org:?empireports:-?protocol:?TCPport:?80podSelector?:表示要應(yīng)用網(wǎng)絡(luò)策略的工作負(fù)載均衡,通過?label?選擇到了?deathstar?的 2 個(gè) Pod。
policyTypes?:表示流量的類型,可以是?Ingress?或?Egress?或兩者兼具。這里使用?Ingress,表示對(duì)選擇的?deathstar?Pod 的入站流量執(zhí)行規(guī)則。
ingress.from:表示流量的來源工作負(fù)載,也是使用?podSelector?和?Label?進(jìn)行選擇,這里選中了?org=empire?也就是所有“帝國的戰(zhàn)機(jī)”。
ingress.ports:表示流量的進(jìn)入端口,這里列出了?deathstar?的服務(wù)端口。
接下來,我們測試下。
測試
先準(zhǔn)備環(huán)境,我們使用?K3s[4]?作為 Kubernetes 環(huán)境。但由于 K3s 默認(rèn)的 CNI 插件 Flannel 不支持網(wǎng)絡(luò)策略,我們需要換個(gè)插件,這里選擇?Calico[5],即 K3s + Calico 的方案。
先創(chuàng)建一個(gè)單節(jié)點(diǎn)的集群:
curl?-sfL?https://get.k3s.io?|?K3S_KUBECONFIG_MODE="644"?INSTALL_K3S_EXEC="--flannel-backend=none?--cluster-cidr=10.42.0.0/16?--disable-network-policy?--disable=traefik"?sh?-此時(shí),所有的 Pod 都處于?Pending?狀態(tài),因?yàn)檫€需要安裝 Calico:
kubectl?apply?-f?https://projectcalico.docs.tigera.io/manifests/calico.yaml待 Calico 成功運(yùn)行后,所有的 Pod 也會(huì)成功運(yùn)行。
接下來就是部署應(yīng)用:
kubectl?apply?-f?app.yaml執(zhí)行策略前,執(zhí)行下面的命令看看“戰(zhàn)機(jī)能否登陸死星”:
kubectl?exec?tiefighter?--?curl?-s?-XPOST?deathstar.default.svc.cluster.local/v1/request-landing Ship?landedkubectl?exec?xwing?--?curl?-s?-XPOST?deathstar.default.svc.cluster.local/v1/request-landing Ship?landed從結(jié)果來看,兩種 ”戰(zhàn)機(jī)“(Pod 負(fù)載)都可以訪問?deathstar?服務(wù)。
此時(shí)執(zhí)行網(wǎng)絡(luò)策略:
kubectl?apply?-f?native/networkpolicy.yaml再次嘗試”登陸“,xwing?的登陸請(qǐng)求會(huì)停在那(需要使用?ctrl+c?退出,或者請(qǐng)求時(shí)加上?--connect-timeout 2)。
思考
使用 Kubernetes 網(wǎng)絡(luò)策略實(shí)現(xiàn)了我們想要的,從網(wǎng)絡(luò)層面為服務(wù)增加了白名單的功能,這種方案沒有改造成本,對(duì)系統(tǒng)也幾乎無影響。
Cilium 還沒出場就結(jié)束了?我們繼續(xù)看:
有時(shí)我們的服務(wù)會(huì)對(duì)外暴露一些管理端點(diǎn),由系統(tǒng)調(diào)用執(zhí)行一些管理上的操作,比如熱更新、重啟等。這些端點(diǎn)是不允許普通服務(wù)來調(diào)用,否則會(huì)造成嚴(yán)重的后果。
比如示例中,tiefighter?訪問了?deathstar?的管理端點(diǎn)?/exhaust-port:
kubectl?exec?tiefighter?--?curl?-s?-XPUT?deathstar.default.svc.cluster.local/v1/exhaust-port Panic:?deathstar?explodedgoroutine?1?[running]: main.HandleGarbage(0x2080c3f50,?0x2,?0x4,?0x425c0,?0x5,?0xa)/code/src/github.com/empire/deathstar/temp/main.go:9?+0x64 main.main()/code/src/github.com/empire/deathstar/temp/main.go:5?+0x85出現(xiàn)了?Panic?錯(cuò)誤,檢查 Pod 你會(huì)發(fā)現(xiàn)?dealthstar?掛了。
Kubernetes 的網(wǎng)絡(luò)策略僅能工作在 L3/4 層,對(duì) L7 層就無能為力了。
還是要請(qǐng)出 Cilium。
Cilium 網(wǎng)絡(luò)策略
由于 Cilium 涉及了 Linux 內(nèi)核、網(wǎng)絡(luò)等眾多知識(shí)點(diǎn),要講清實(shí)現(xiàn)原理篇幅極大。故這里僅摘取了官網(wǎng)的介紹,后期希望有時(shí)間再寫一篇關(guān)于實(shí)現(xiàn)的。
Cilium 簡介
Cilium[6]?是一個(gè)開源軟件,用于提供、保護(hù)和觀察容器工作負(fù)載(云原生)之間的網(wǎng)絡(luò)連接,由革命性的內(nèi)核技術(shù)?eBPF[7]?推動(dòng)。
eBPF 是什么?
Linux 內(nèi)核一直是實(shí)現(xiàn)監(jiān)控/可觀測性、網(wǎng)絡(luò)和安全功能的理想地方。不過很多情況下這并非易事,因?yàn)檫@些工作需要修改內(nèi)核源碼或加載內(nèi)核模塊, 最終實(shí)現(xiàn)形式是在已有的層層抽象之上疊加新的抽象。eBPF 是一項(xiàng)革命性技術(shù),它能在內(nèi)核中運(yùn)行沙箱程序(sandbox programs), 而無需修改內(nèi)核源碼或者加載內(nèi)核模塊。
將 Linux 內(nèi)核變成可編程之后,就能基于現(xiàn)有的(而非增加新的)抽象層來打造更加智能、 功能更加豐富的基礎(chǔ)設(shè)施軟件,而不會(huì)增加系統(tǒng)的復(fù)雜度,也不會(huì)犧牲執(zhí)行效率和安全性。
我們來看下 Cilium 的網(wǎng)絡(luò)策略:
#?cilium/networkpolicy-L4.yaml apiVersion:?"cilium.io/v2" kind:?CiliumNetworkPolicy metadata:name:?"rule1" spec:description:?"L7?policy?to?restrict?access?to?specific?HTTP?call"endpointSelector:matchLabels:org:?empireclass:?deathstaringress:-?fromEndpoints:-?matchLabels:org:?empiretoPorts:-?ports:-?port:?"80"protocol:?TCP與 Kubernetes 的原生網(wǎng)絡(luò)策略差異不大,參考前面的介紹也都看懂,我們直接進(jìn)入測試。
測試
由于 Cilium 本身就實(shí)現(xiàn)了 CNI,所以之前的集群就不能用了,先卸載集群:
k3s-uninstall.sh #?!!!切記要清理之前的 cni 插件 sudo?rm?-rf?/etc/cni/net.d還是使用同樣的命令創(chuàng)建單節(jié)點(diǎn)的集群:
curl?-sfL?https://get.k3s.io?|?K3S_KUBECONFIG_MODE="644"?INSTALL_K3S_EXEC="--flannel-backend=none?--cluster-cidr=10.42.0.0/16?--disable-network-policy?--disable=traefik"?sh?-#?cilium?會(huì)使用該變量 export?KUBECONFIG=/etc/rancher/k3s/k3s.yaml接下來安裝 Cilium CLI:
curl?-L?--remote-name-all?https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz{,.sha256sum} sha256sum?--check?cilium-linux-amd64.tar.gz.sha256sum sudo?tar?xzvfC?cilium-linux-amd64.tar.gz?/usr/local/bin rm?cilium-linux-amd64.tar.gz{,.sha256sum}cilium?version cilium-cli:?v0.10.2?compiled?with?go1.17.6?on?linux/amd64 cilium?image?(default):?v1.11.1 cilium?image?(stable):?v1.11.1 cilium?image?(running):?unknown.?Unable?to?obtain?cilium?version,?no?cilium?pods?found?in?namespace?"kube-system"安裝 Cilium 到集群:
cilium?install待 Cilium 成功運(yùn)行:
cilium?status/ˉˉ\/ˉˉ\__/ˉˉ\????Cilium:?????????OK\__/ˉˉ\__/????Operator:???????OK/ˉˉ\__/ˉˉ\????Hubble:?????????disabled\__/ˉˉ\__/????ClusterMesh:????disabled\__/Deployment????????cilium-operator????Desired:?1,?Ready:?1/1,?Available:?1/1 DaemonSet?????????cilium?????????????Desired:?1,?Ready:?1/1,?Available:?1/1 Containers:???????cilium?????????????Running:?1cilium-operator????Running:?1 Cluster?Pods:?????3/3?managed?by?Cilium Image?versions????cilium-operator????quay.io/cilium/operator-generic:v1.11.1@sha256:977240a4783c7be821e215ead515da3093a10f4a7baea9f803511a2c2b44a235:?1cilium?????????????quay.io/cilium/cilium:v1.11.1@sha256:251ff274acf22fd2067b29a31e9fda94253d2961c061577203621583d7e85bd2:?1部署應(yīng)用:
kubectl?apply?-f?app.yaml待應(yīng)用啟動(dòng)后測試服務(wù)調(diào)用:
kubectl?exec?tiefighter?--?curl?-s?-XPOST?deathstar.default.svc.cluster.local/v1/request-landing Ship?landed kubectl?exec?xwing?--?curl?-s?-XPOST?deathstar.default.svc.cluster.local/v1/request-landing Ship?landed執(zhí)行 L4 網(wǎng)絡(luò)策略:
kubectl?apply?-f?cilium/networkpolicy-L4.yaml再次嘗試“登陸”死星,xwing?戰(zhàn)機(jī)同樣無法登陸,說明 L4 層的規(guī)則生效。
我們?cè)賴L試 L7 層的規(guī)則:
#?cilium/networkpolicy-L7.yaml apiVersion:?"cilium.io/v2" kind:?CiliumNetworkPolicy metadata:name:?"rule1" spec:description:?"L7?policy?to?restrict?access?to?specific?HTTP?call"endpointSelector:matchLabels:org:?empireclass:?deathstaringress:-?fromEndpoints:-?matchLabels:org:?empiretoPorts:-?ports:-?port:?"80"protocol:?TCPrules:http:-?method:?"POST"path:?"/v1/request-landing"執(zhí)行規(guī)則:
kubectl?apply?-f?cilium/networkpolicy-L7.yaml這回,使用?tiefighter?調(diào)用死星的管理接口:
kubectl?exec?tiefighter?--?curl?-s?-XPUT?deathstar.default.svc.cluster.local/v1/exhaust-port Access?denied #?登陸接口工作正常 kubectl?exec?tiefighter?--?curl?-s?-XPOST?deathstar.default.svc.cluster.local/v1/request-landing Ship?landed這回返回了?Access denied,說明 L7 層的規(guī)則生效了。
參考資料
[1]?網(wǎng)絡(luò)策略?NetworkPolicy:?https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/
[2]?Cilium getting started:?https://play.instruqt.com/isovalent/tracks/cilium-getting-started
[3]?官方文檔:?https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/
[4]?K3s:?https://k3s.io
[5]?Calico:?https://www.tigera.io/project-calico/
[6]?Cilium:?https://cilium.io
[7]?eBPF:?https://ebpf.io
往期推薦
Android 13 第一個(gè)開發(fā)者版本來了,網(wǎng)友直呼:Android 12 還沒玩透!
CSDN企業(yè)數(shù)字化之路 ——「低代碼」發(fā)展研討會(huì)北京站現(xiàn)場實(shí)錄大放送
使用這個(gè)庫,讓你的服務(wù)操作 Redis 速度飛起
將 k8s 制作成 3D 射擊游戲,好玩到停不下來
點(diǎn)分享
點(diǎn)收藏
點(diǎn)點(diǎn)贊
點(diǎn)在看
總結(jié)
以上是生活随笔為你收集整理的使用 Cilium 增强 Kubernetes 网络安全的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 100%移植阿里云移动测试技术,竟仅需1
- 下一篇: Medusa 又一个 Shopify