Kubernetes 的安全防護仰賴多層機制,系統層級的安全隔離是其中關鍵。透過 Linux 名稱空間,例如主機 PID 名稱空間,可以有效隔離行程,避免 Pod 間互相干擾。精細的 Linux 功能組態則能限制容器的許可權,降低潛在風險。除了系統層級的隔離,網路層級的控管也至關重要。網路策略允許定義 Pod 間的通訊規則,透過入口和出口規則,結合 IPBlock、namespaceSelector 和 podSelector 等設定,可以精準控制 Pod 的網路存取,建立更嚴謹的微服務信任邊界。
在理解 Linux 名稱空間和功能的基礎上,Kubernetes 網路策略提供更細緻的控制。透過 YAML 設定檔,可以定義 Pod 的連線規則,例如允許特定名稱空間或帶有特定標籤的 Pod 進行連線,並限制連線的埠和協定。這對於保護敏感服務,例如資料函式庫,至關重要,可以有效防止未經授權的存取。網路策略的彈性設定,讓管理員可以根據應用程式需求,開發更安全的微服務環境,提升整體叢集的安全性。
系統層級的安全邊界
在 Kubernetes 中,系統層級的安全邊界對於確保微服務的安全至關重要。本章節將探討系統層級的安全邊界,包括 Linux 名稱空間和 Linux 功能。
Linux 名稱空間
Linux 名稱空間是一種機制,用於隔離系統資源,例如行程、網路介面和檔案系統。在 Kubernetes 中,每個 Pod 都執行在自己的名稱空間中,這意味著 Pod 中的行程無法看到其他 Pod 中的行程。
主機 PID 名稱空間
預設情況下,Kubernetes 中的 Pod 不使用主機 PID 名稱空間。這意味著在 Pod 中執行的行程無法看到主機上的其他行程。例如,在 nginx 容器中執行 ps aux 命令,只能看到 nginx 行程和 bash 行程。
root@nginx-container:/# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.0 32648 5256 ? Ss 23:47 0:00 nginx: master process nginx -g daemon off;
nginx 6 0.0 0.0 33104 2348 ? S 23:47 0:00 nginx: worker process
root 7 0.0 0.0 18192 3248 pts/0 Ss 23:48 0:00 bash
root 13 0.0 0.0 36636 2816 pts/0 R+ 23:48 0:00 ps aux
然而,如果 Pod 使用主機 PID 名稱空間,則可以看到主機上的所有行程。
root@gke-demo-cluster-default-pool-c9e3510c-tfgh:/# ps axu
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.2 0.0 99660 7596 ? Ss 22:54 0:10 /usr/lib/systemd/systemd noresume noswap cros_efi
...
Linux 功能
Linux 功能是一種機制,用於將 root 使用者的許可權劃分為不同的單元。在 Kubernetes 中,容器預設被賦予了一組 Linux 功能,例如 CAP_NET_RAW、CAP_DAC_OVERRIDE 等。
這些功能使得容器能夠執行特定的操作,例如開啟原始網路通訊端或覆寫檔案的擁有者。然而,如果容器被賦予了過多的功能,則可能會對其他微服務的安全邊界造成威脅。
例如,如果容器被賦予了 CAP_NET_ADMIN 功能,則可以使用 tcpdump 命令監聽其他 Pod 的網路流量。
root@gke-demo-cluster-default-pool-c9e3510c-tfgh:/# tcpdump -i cali01fb9a4e4b4 -v
tcpdump: listening on cali01fb9a4e4b4, link-type EN10MB (Ethernet), capture size 262144 bytes
23:18:36.604766 IP (tos 0x0, ttl 64, id 27472, offset 0, flags [DF], proto UDP (17), length 86)
10.56.1.14.37059 > 10.60.0.10.domain: 35359+ A? www.google.com.default.svc.cluster.local. (58)
...
因此,應該謹慎地組態 Linux 功能,以避免對其他微服務的安全邊界造成威脅。
網路層級的安全邊界
Kubernetes 網路策略定義了不同 Pod 之間的通訊規則。在本章節中,我們將探討 Kubernetes 網路策略的入口規則,以及其如何幫助建立微服務之間的信任邊界。
Kubernetes 網路策略
Kubernetes 網路策略是一種資源,用於定義 Pod 之間的通訊規則。網路策略可以分為入口規則和出口規則。入口規則定義了允許哪些 Pod 通訊到特定的 Pod,而出口規則定義了允許特定的 Pod 通訊到哪些 Pod。
透過使用網路策略,可以實作微服務之間的安全邊界。例如,可以定義一個網路策略,允許只有特定的 Pod 可以通訊到一個資料函式庫 Pod。
網路層的安全邊界
在前一章中,我們提到根據網路模型的需求,叢集內的 Pod 可以相互通訊。然而,從安全的角度來看,您可能希望限制微服務只能被特定的服務存取。如何在 Kubernetes 中實作這一點?讓我們來看看以下的 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
網路策略解析:
此網路策略被命名為 test-network-policy。以下是一些值得注意的關鍵屬性,用於幫助您瞭解其限制:
- podSelector:根據 Pod 的標籤,將策略應用於特定的 Pod 分組。
- Ingress:適用於頂層 podSelector 所指定的 Pod 的入口規則。不同的元素包括:
- ipBlock:允許與入口來源通訊的 IP CIDR 範圍。
- namespaceSelector:根據名稱空間標籤,允許作為入口來源的名稱空間。
- podSelector:根據 Pod 標籤,允許作為入口來源的 Pod。
- ports:所有 Pod 應該被允許通訊的連線埠和協定。
- Egress:適用於頂層 podSelector 所指定的 Pod 的出口規則。不同的元素包括:
- ipBlock:允許作為出口目的地的 IP CIDR 範圍。
- namespaceSelector:根據名稱空間標籤,允許作為出口目的地的名稱空間。
- podSelector:根據 Pod 標籤,允許作為出口目的地的 Pod。
- ports:所有 Pod 應該被允許通訊的目的地連線埠和協定。
通常,ipBlock 用於指定微服務在 Kubernetes 叢集中被允許互動的外部 IP 範圍,而 namespaceSelector 和 podSelector 用於限制同一 Kubernetes 叢集中微服務之間的網路通訊。
加強網路層的安全邊界
為了從網路層面加強微服務的信任邊界,您可能希望指定允許的外部 IP 範圍或特定名稱空間中的允許微服務。以下是另一個範例,展示如何使用 namespaceSelector 和 podSelector 限制入口來源:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-good
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
from: good
podSelector:
matchLabels:
from: good
策略說明:
請注意,在 podSelector 前面沒有 - 符號。這意味著入口來源只能是具有標籤 from: good 的名稱空間中的具有標籤 from: good 的 Pod。此網路策略保護了預設名稱空間中具有標籤 app: web 的 Pod。
此圖展示了只有具有標籤 from: good 的名稱空間中的具有標籤 from: good 的 Pod 可以存取預設名稱空間中的 nginx-web 服務。其他 Pod 無論是否來自具有標籤 from: good 的名稱空間,但如果沒有標籤 from: good,都無法存取該服務。
重點回顧
- Kubernetes 中的安全域有哪些?
- 您與哪些常見的 Kubernetes 實體互動?
- 如何限制 Kubernetes 使用者存取特定名稱空間中的物件?
- 對 Pod 啟用
hostPID有什麼含義? - 試著組態一個網路策略,以保護您的服務,只允許特定的 Pod 作為入口來源。
第二部分:保護 Kubernetes 部屬與叢集
在本部分中,您將透過實際操作練習學習如何保護 Kubernetes 部屬/叢集,主要涵蓋兩個方面:一是學習如何在建置、佈署和執行階段保護 DevOps 管道;二是學習如何實施縱深防禦,包括合規性、組態、身份驗證、授權、資源管理、日誌記錄和監控、檢測和事件回應。
本部分包含以下章節:
- 第6章:保護叢集元件
- 第7章:身份驗證、授權和准入控制
- 第8章:保護 Kubernetes Pods
- 第9章:DevOps 管道中的映像掃描
- 第10章:Kubernetes 叢集的即時監控和資源管理
- 第11章:縱深防禦
保護叢集元件安全
在前面的章節中,我們探討了 Kubernetes 叢集的架構。一個 Kubernetes 叢集由主控元件(包括 kube-apiserver、etcd、kube-scheduler、CoreDNS、kube-controller-manager 和 cloud-controller-manager)和節點元件(包括 kubelet、kube-proxy 和容器執行環境)組成。主控元件負責叢集管理,形成叢集的控制平面。另一方面,節點元件負責節點上 Pod 和容器的運作。
在第 3 章「威脅建模」中,我們簡要討論了 Kubernetes 叢集中的元件需要進行組態以確保叢集的安全。任何叢集元件的洩露都可能導致資料洩露。環境組態錯誤是傳統或微服務環境中資料洩露的主要原因之一。瞭解每個元件的組態以及每個設定如何開啟新的攻擊面至關重要。因此,叢集管理員瞭解不同的組態至關重要。
在本章中,我們將詳細探討如何保護叢集中的每個元件。在許多情況下,不可能遵循所有的安全最佳實踐,但重要的是要突出風險並制定緩解策略,以防攻擊者試圖利用易受攻擊的組態。
本章涵蓋以下主題:
- 保護
kube-apiserver - 保護
kubelet - 保護
etcd - 保護
kube-scheduler - 保護
kube-controller-manager - 保護
CoreDNS - 對叢集的安全組態進行基準測試
保護 kube-apiserver
kube-apiserver 是叢集的門戶。它實作了一個代表性狀態轉移(REST)應用程式介面(API)來授權和驗證對物件的請求。它是與 Kubernetes 叢集內其他元件進行溝通和管理的中央閘道。它執行三個主要功能:
- API 管理:
kube-apiserver公開了用於叢集管理的 API。這些 API 被開發人員和叢集管理員用來修改叢集的狀態。 - 請求處理:對物件管理和叢集管理的請求被驗證和處理。
- 內部訊息傳遞:API 伺服器與叢集中的其他元件互動,以確保叢集正常運作。
對 API 伺服器的請求在被處理之前會經過以下步驟:
- 身分驗證:
kube-apiserver首先驗證請求的來源。kube-apiserver支援多種身分驗證模式,包括使用者端憑證、持有者令牌和超文字傳輸協定(HTTP)身分驗證。 - 授權:一旦來源的身分得到驗證,API 伺服器就會驗證來源是否被允許執行請求。預設情況下,
kube-apiserver支援根據屬性的存取控制(ABAC)、根據角色的存取控制(RBAC)、節點授權和 Webhooks 進行授權。建議使用 RBAC 作為授權模式。 - 准入控制器:一旦
kube-apiserver對請求進行身分驗證和授權,准入控制器就會解析請求以檢查是否允許在叢集內。如果任何准入控制器拒絕請求,則該請求將被丟棄。
為了保護 API 伺服器,您應該執行以下操作:
內容解密:
- 停用匿名身分驗證:使用
anonymous-auth=false旗標將匿名身分驗證設定為 false。這確保了被所有身分驗證模組拒絕的請求不會被視為匿名請求並被丟棄。- 這項設定的作用是防止未經身分驗證的請求被視為匿名請求,從而減少潛在的安全風險。
- 邏輯是透過停用匿名身分驗證,強制所有請求必須經過身分驗證,否則將被拒絕。
- 停用基本身分驗證:基本身分驗證在
kube-apiserver中僅為方便而支援,不應使用。基本身分驗證密碼會無限期儲存。kube-apiserver使用--basic-auth-file引數來啟用基本身分驗證。確保不使用此引數。- 停用基本身分驗證的原因是其密碼持久儲存且不夠安全。
- 正確的做法是避免使用
--basic-auth-file引數,以防止基本身分驗證被啟用。
- 停用令牌身分驗證:
--token-auth-file為您的叢集啟用根據令牌的身分驗證。不建議使用根據令牌的身分驗證。靜態令牌永遠存在,需要重新啟動 API 伺服器才能更新。應使用使用者端憑證進行身分驗證。- 根據令牌的身分驗證由於靜態令牌永不過期且需要手動更新,因此被認為是不安全的。
- 使用使用者端憑證是更安全的選擇,因為憑證可以透過更安全的方式管理和更新。
- 確保與 kubelet 的連線使用 HTTPS:預設情況下,
--kubelet-https被設定為 true。確保此引數未被設定為 false,以保持與kubelet的連線安全。- 使用 HTTPS 可以加密
kube-apiserver和kubelet之間的通訊,防止資料被竊聽。 - 將
--kubelet-https保持為 true 是預設且推薦的設定。
- 使用 HTTPS 可以加密
- 停用效能分析:啟用效能分析使用
--profiling會暴露不必要的系統和程式詳情。除非您遇到效能問題,否則應透過設定--profiling=false停用效能分析。- 效能分析可能會洩露敏感資訊,因此除錯或效能調優之外,應保持停用狀態。
- 停用效能分析可以減少潛在的資訊洩露風險。
- 停用 AlwaysAdmit:
--enable-admission-plugins可以用來啟用預設未啟用的准入控制外掛程式。AlwaysAdmit接受請求。確保此外掛程式不在--enable-admission-plugins清單中。AlwaysAdmit外掛程式允許所有請求,這可能會引入安全風險。- 不使用
AlwaysAdmit可以確保請求經過適當的准入控制檢查。
透過遵循上述步驟,您可以顯著提高 kube-apiserver 的安全性,從而加強整個 Kubernetes 叢集的安全性。
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: nginx:latest
ports:
- containerPort: 80
內容解密:
這段 YAML 組態定義了一個 Kubernetes Pod 名為 example-pod,其中包含一個名為 example-container 的容器,該容器執行 nginx:latest 映象並暴露埠 80。
- 這項設定的作用是建立一個簡單的 Nginx 伺服器 Pod,可以用於測試或範例用途。
- 邏輯是透過定義 Pod 的 spec,包括容器名稱、使用的映象以及需要暴露的埠,來建立一個基本的 Web 伺服器。