Kubernetes 安全防護的雙重機制
在雲端原生時代,Kubernetes 已成為容器編排的事實標準。然而,隨著叢集規模的擴大與應用場景的複雜化,如何確保叢集的安全性與穩定性成為每個平台工程師必須面對的挑戰。Kubernetes 提供了兩層關鍵的安全防護機制:准入控制(Admission Control)與授權(Authorization),它們如同守門員與稽核員,共同保護著叢集資源的安全。
准入控制發生在 API 請求通過身份驗證之後、物件持久化之前。在這個階段,准入控制器可以檢查請求的內容,甚至修改請求或直接拒絕請求。這種機制讓管理者能夠實施各種策略,從簡單的資源配額檢查到複雜的安全合規驗證。授權則決定了經過身份驗證的使用者是否有權限執行特定操作,它確保了最小權限原則的落實。
這兩個機制的結合,構成了 Kubernetes 叢集安全架構的基石。准入控制確保進入叢集的資源符合組織的政策與標準,授權則確保只有被授權的實體才能執行特定操作。理解並正確設定這些機制,對於建構安全可靠的雲端原生平台至關重要。
准入 Webhook 的動態設定架構
Kubernetes 的准入控制系統經歷了從靜態外掛到動態 Webhook 的演進。早期版本的准入控制器需要編譯到 API Server 中,這種靜態方式缺乏靈活性。准入 Webhook 的出現徹底改變了這個局面,它允許管理者在不修改 API Server 的情況下,動態增加自訂的准入邏輯。
准入 Webhook 分為兩種類型:變異准入 Webhook(MutatingAdmissionWebhook)與驗證准入 Webhook(ValidatingAdmissionWebhook)。變異准入 Webhook 在請求驗證之前執行,它可以修改請求的內容,例如自動注入 sidecar 容器、設定預設值或增加標籤。驗證准入 Webhook 則在變異階段之後執行,它檢查請求是否符合特定規則,但不能修改請求內容。
這種設計遵循了單一職責原則。變異 Webhook 專注於資源的標準化與增強,確保所有進入叢集的資源都符合組織的標準格式。驗證 Webhook 則專注於策略執行,確保資源不違反組織的安全政策或業務規則。兩者的協同工作,構成了完整的准入控制流程。
設定 ValidatingWebhookConfiguration 需要仔細規劃每個欄位的值。資源的名稱欄位定義了這個 Webhook 在叢集中的唯一識別。webhooks 陣列可以包含多個 Webhook 定義,每個 Webhook 可以有自己的觸發規則與行為。clientConfig 部分指定了 Webhook 服務的位置,這個服務通常執行在叢集內部,透過 Service 資源進行存取。
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: pod-security-validator
webhooks:
- name: validate.pods.security.example.com
clientConfig:
service:
namespace: webhook-system
name: pod-security-webhook
path: /validate
caBundle: <BASE64_ENCODED_CA_CERT>
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
failurePolicy: Fail
admissionReviewVersions: ["v1"]
sideEffects: None
timeoutSeconds: 10
rules 欄位定義了哪些 API 請求應該被發送到這個 Webhook。operations 陣列指定了觸發 Webhook 的操作類型,常見的有 CREATE、UPDATE、DELETE 與 CONNECT。apiGroups 與 apiVersions 進一步限定了資源的範圍,而 resources 陣列則明確列出了要攔截的資源類型。這種細粒度的控制讓管理者能夠精確地定義 Webhook 的作用範圍。
failurePolicy 欄位的設定需要在安全性與可用性之間取得平衡。設為 Fail 時,如果 Webhook 無法存取或回應超時,API 請求會被拒絕,這提供了更高的安全性,但可能影響叢集的可用性。設為 Ignore 時,Webhook 失敗不會阻止請求,這提高了可用性,但可能讓不符合策略的資源進入叢集。在生產環境中,建議對關鍵的安全策略使用 Fail,對非關鍵的增強功能使用 Ignore。
MutatingWebhookConfiguration 的結構與 ValidatingWebhookConfiguration 相似,但多了 reinvocationPolicy 欄位。這個欄位控制當一個物件被多個變異 Webhook 修改後,是否需要重新呼叫某些 Webhook。IfNeeded 值表示只有當物件被其他 Webhook 修改後才重新呼叫,Never 則表示不重新呼叫。這個設定對於確保變異 Webhook 的冪等性非常重要。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: pod-defaults-injector
webhooks:
- name: inject.defaults.example.com
clientConfig:
service:
namespace: webhook-system
name: pod-defaults-webhook
path: /mutate
caBundle: <BASE64_ENCODED_CA_CERT>
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
failurePolicy: Ignore
admissionReviewVersions: ["v1"]
sideEffects: None
reinvocationPolicy: IfNeeded
timeoutSeconds: 5
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
start
:使用者發送 API 請求;
:API Server 接收請求;
:身份驗證 Authentication;
partition "准入控制階段" {
:變異准入 Webhook;
note right
可修改請求內容
注入預設值或 sidecar
end note
:驗證准入 Webhook;
note right
檢查策略合規性
不可修改請求
end note
if (准入檢查通過?) then (是)
:持久化到 etcd;
:回傳成功;
else (否)
:拒絕請求;
:回傳錯誤訊息;
endif
}
stop
@enduml准入控制的效能最佳化策略
准入 Webhook 直接影響 API Server 的回應時間,因此效能最佳化至關重要。每個 API 請求都需要等待所有相關的准入 Webhook 回應後才能繼續處理,如果 Webhook 回應緩慢,會導致整個叢集的操作變慢。timeoutSeconds 欄位的預設值為 10 秒,但建議設定為更短的時間,例如 3 到 5 秒,以避免長時間阻塞 API 請求。
Webhook 服務本身的實作必須追求極致的效能。避免在 Webhook 處理邏輯中進行耗時的操作,例如複雜的計算、外部 API 呼叫或資料庫查詢。如果必須進行這些操作,應該使用快取機制減少重複的計算。對於需要存取外部服務的場景,應該設定合理的超時時間,並實作降級機制,避免外部服務的故障影響叢集的正常運作。
NamespaceSelector 與 ObjectSelector 是限制 Webhook 作用範圍的有效工具。透過標籤選擇器,可以讓 Webhook 只處理特定命名空間或特定標籤的資源,大幅減少不必要的 Webhook 呼叫。例如,如果某個 Webhook 只需要處理生產環境的 Pod,可以透過 NamespaceSelector 只選擇帶有 environment=production 標籤的命名空間。
webhooks:
- name: prod-validator.example.com
namespaceSelector:
matchLabels:
environment: production
objectSelector:
matchExpressions:
- key: skip-validation
operator: DoesNotExist
kube-system 命名空間包含了 Kubernetes 的核心元件,這些元件的正常運作對整個叢集至關重要。強烈建議在所有 Webhook 設定中排除 kube-system 命名空間,避免 Webhook 的問題影響系統元件的啟動或更新。可以透過 namespaceSelector 明確排除這個命名空間,確保系統元件不受自訂准入邏輯的干擾。
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: NotIn
values: ["kube-system"]
准入控制的最佳實踐指南
設計准入 Webhook 時,冪等性是必須遵守的原則。變異 Webhook 可能會被多次呼叫,每次呼叫都應該產生相同的結果。如果 Webhook 已經修改過某個物件,後續的呼叫不應該再次修改,否則可能導致無限迴圈或不可預期的結果。實作時,應該在修改前檢查物件的當前狀態,只有在需要時才進行修改。
多個變異 Webhook 可能會修改同一個資源,因此應該避免它們修改相同的欄位。如果無法避免,應該明確定義 Webhook 的執行順序,並確保後執行的 Webhook 能夠正確處理前面 Webhook 的修改結果。驗證 Webhook 可以用來確保最終的資源狀態符合預期,即使經過了多個變異 Webhook 的修改。
准入 Webhook 的設定本身也是需要保護的資源。使用 RBAC 限制誰可以建立或修改 ValidatingWebhookConfiguration 與 MutatingWebhookConfiguration 資源,防止未經授權的修改繞過安全策略。建議只允許叢集管理員或特定的自動化系統具有這些權限,普通使用者不應該能夠修改准入控制設定。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: webhook-admin
rules:
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"]
verbs: ["get", "list", "create", "update", "patch", "delete"]
Webhook 服務的高可用性同樣重要。建議執行多個 Webhook Pod 副本,並設定適當的資源請求與限制。使用 Pod Disruption Budget 確保在節點維護或升級期間,至少有一定數量的 Webhook Pod 保持執行。監控 Webhook 的回應時間與錯誤率,及時發現並解決效能問題。
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
package "准入控制最佳實踐" {
component "Webhook 服務" as webhook {
[多副本部署]
[快速回應邏輯]
[錯誤處理機制]
}
component "設定管理" as config {
[NamespaceSelector]
[ObjectSelector]
[failurePolicy 設定]
}
component "安全防護" as security {
[RBAC 權限控制]
[排除 kube-system]
[TLS 加密通訊]
}
}
webhook -down-> config
config -down-> security
@endumlKubernetes 授權機制的多層架構
授權發生在身份驗證之後、准入控制之前。Kubernetes API Server 支援多種授權模組,包括 ABAC(Attribute-Based Access Control)、RBAC(Role-Based Access Control)、Webhook 與 Node 授權。這些模組可以同時啟用,並按順序檢查請求。與准入控制不同,授權只需要任一模組允許請求即可繼續,只有當所有模組都拒絕時,請求才會被拒絕。
ABAC 是最早的授權模式,它透過本地檔案定義授權策略。每條策略規則指定了使用者、資源與允許的操作。雖然 ABAC 提供了很大的靈活性,但它的管理方式過於原始。策略檔案必須放置在每個 API Server 的檔案系統上,修改策略需要重啟 API Server,這在多控制平面的叢集中非常不便。因此,ABAC 已經逐漸被 RBAC 取代,不建議在新專案中使用。
apiVersion: abac.authorization.kubernetes.io/v1beta1
kind: Policy
spec:
user: developer
namespace: development
resource: pods
readonly: false
RBAC 是目前最推薦的授權模式。它透過 Role 與 ClusterRole 定義權限集合,透過 RoleBinding 與 ClusterRoleBinding 將權限授予使用者或服務帳號。RBAC 的策略完全透過 Kubernetes API 管理,不需要重啟 API Server,支援細粒度的權限控制,並且易於審計。Role 與 RoleBinding 作用於特定命名空間,而 ClusterRole 與 ClusterRoleBinding 則作用於整個叢集。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Webhook 授權模組允許將授權決策委託給外部服務。API Server 會將 SubjectAccessReview 請求發送到指定的 Webhook 端點,Webhook 服務檢查後回傳允許或拒絕的決定。這種模式適用於需要整合企業現有身份管理系統或實作複雜授權邏輯的場景。然而,Webhook 授權的可用性完全依賴外部服務,如果 Webhook 服務故障,可能導致整個叢集無法使用,因此必須確保 Webhook 服務的高可用性。
Node 授權是專門為 kubelet 設計的授權模組。它允許 kubelet 讀取與自己相關的資源,例如執行在該節點上的 Pod 及其引用的 Secret 與 ConfigMap,但禁止 kubelet 存取其他節點的資源。這種設計實作了節點級別的隔離,即使某個節點被攻陷,攻擊者也無法透過該節點的 kubelet 存取其他節點的資源。
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
start
:API 請求到達;
:身份驗證;
partition "授權檢查" {
if (ABAC 允許?) then (是)
:授權通過;
stop
endif
if (RBAC 允許?) then (是)
:授權通過;
stop
endif
if (Webhook 允許?) then (是)
:授權通過;
stop
endif
if (Node 允許?) then (是)
:授權通過;
stop
endif
:所有模組都拒絕;
:授權失敗;
stop
}
@endumlRBAC 的精細權限管理實踐
RBAC 的設計遵循最小權限原則。每個使用者或服務帳號應該只被授予完成其工作所需的最小權限集合。避免直接授予 cluster-admin 這樣的超級管理員角色,而是根據實際需求建立自訂的 Role 或 ClusterRole。例如,開發人員可能只需要在開發命名空間中建立與查看 Pod,而不需要刪除或修改生產環境的資源。
ClusterRole 可以定義叢集級別的權限,也可以在 RoleBinding 中使用,將叢集級別的角色綁定到特定命名空間。這種方式讓我們能夠定義一組通用的角色,然後在不同的命名空間中重複使用。例如,定義一個 view-all ClusterRole 允許查看所有類型的資源,然後透過不同的 RoleBinding 將這個角色授予不同命名空間的使用者。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-manager
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
服務帳號(ServiceAccount)是 Pod 中執行的應用程式的身份。每個 Pod 都會自動掛載一個服務帳號的憑證,用於與 API Server 通訊。為不同的應用程式建立專用的服務帳號,並授予適當的權限,避免使用預設的 default 服務帳號。這樣可以實作應用程式級別的權限隔離,即使某個應用程式被攻陷,攻擊者也只能執行該應用程式被授權的操作。
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-reader
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-reader-binding
namespace: production
subjects:
- kind: ServiceAccount
name: app-reader
namespace: production
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
定期審計 RBAC 設定是維護叢集安全的重要環節。使用 kubectl auth can-i 命令檢查特定使用者的權限,確保授權符合預期。對於服務帳號,可以檢查 RoleBinding 與 ClusterRoleBinding 資源,了解哪些服務帳號被授予了哪些權限。移除不再需要的權限綁定,避免權限膨脹導致的安全風險。
kubectl auth can-i create deployments --namespace=production --as=jane
kubectl auth can-i delete pods --namespace=kube-system --as=system:serviceaccount:production:app-reader
GitOps 與宣告式安全管理
GitOps 將 Git 儲存庫作為基礎設施與應用程式設定的單一真實來源。所有對叢集的變更都透過修改 Git 儲存庫中的 YAML 檔案來進行,自動化工具會將 Git 中的期望狀態同步到叢集中。這種方式帶來了版本控制、審計追蹤與回滾能力,非常適合管理 Kubernetes 的安全策略。
准入控制與授權設定同樣可以透過 GitOps 管理。將 ValidatingWebhookConfiguration、MutatingWebhookConfiguration、Role、ClusterRole 等資源定義儲存在 Git 中,透過 Flux 或 Argo CD 等 GitOps 工具自動同步到叢集。任何對安全策略的修改都需要透過 Pull Request 進行,經過審查與批准後才能合併,確保了變更的可追溯性與可審計性。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- webhooks/validating-webhook.yaml
- webhooks/mutating-webhook.yaml
- rbac/cluster-roles.yaml
- rbac/role-bindings.yaml
GitOps 的宣告式特性與 Kubernetes 的設計理念完美契合。我們只需要定義期望的最終狀態,而不需要關心如何達到這個狀態的具體步驟。GitOps 工具會持續監控叢集的實際狀態,當發現與 Git 中的定義不一致時,會自動進行調整。這種持續協調機制確保了叢集始終保持在符合安全策略的狀態,即使有人手動修改了設定,也會被自動還原。
多環境管理是 GitOps 的另一個優勢。透過不同的 Git 分支或目錄管理開發、測試與生產環境的設定,確保每個環境都有適當的安全策略。開發環境可能使用較寬鬆的准入策略,方便開發人員快速迭代,而生產環境則使用嚴格的策略,確保所有資源都符合企業的安全標準。
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
actor 開發者
participant "Git Repository" as git
participant "GitOps Controller" as gitops
participant "Kubernetes API" as api
database "etcd" as etcd
開發者 -> git : 提交策略變更
git -> git : Pull Request 審查
git -> gitops : 偵測到變更
gitops -> git : 拉取最新設定
gitops -> api : 套用資源變更
api -> api : 准入控制檢查
api -> etcd : 持久化設定
gitops -> gitops : 持續監控狀態
gitops -> api : 自動修正偏差
@enduml授權與准入控制的協同防護
授權與准入控制雖然是兩個獨立的機制,但它們共同構成了 Kubernetes 的深度防禦體系。授權確保了使用者只能執行被授權的操作,而准入控制則確保即使是被授權的操作,其結果也必須符合叢集的策略。例如,一個開發人員可能被授權建立 Pod,但准入 Webhook 可以確保這些 Pod 必須設定資源限制、不能使用 privileged 模式、必須使用特定的映像倉庫等。
這種分層的安全模型提供了多個檢查點。即使某個層級的控制被繞過,其他層級仍然能夠提供保護。例如,如果某個使用者透過社交工程獲得了較高的 RBAC 權限,准入 Webhook 仍然能夠阻止該使用者建立不符合策略的資源。這種縱深防禦策略大大提高了叢集的安全性。
監控與審計是安全體系不可或缺的一部分。Kubernetes 的審計日誌記錄了所有 API 請求及其授權結果,透過分析這些日誌,可以發現異常的存取模式或潛在的安全威脅。設定告警規則,當發現敏感操作或授權失敗時及時通知,讓安全團隊能夠快速回應。
定期進行安全評估與滲透測試,驗證授權與准入控制策略的有效性。嘗試以不同角色的使用者身份執行各種操作,確保權限設定符合預期。檢查是否存在權限提升的可能性,確保沒有意外授予過高的權限。這種主動的安全測試能夠在攻擊者發現漏洞之前,及時修補安全缺陷。
企業級 Kubernetes 安全策略實踐
在企業環境中實施 Kubernetes 安全策略,需要平衡安全性與開發效率。過於嚴格的策略可能阻礙開發人員的工作,導致他們尋找繞過策略的方法,反而降低了整體安全性。建議採用漸進式的策略實施方法,從寬鬆的策略開始,逐步收緊,同時提供清晰的文件與培訓,幫助開發人員理解並遵守安全策略。
建立安全基線是實施策略的第一步。定義組織對資源的最低安全要求,例如所有容器必須以非 root 使用者執行、必須設定資源限制、禁止掛載敏感的主機路徑等。將這些要求實作為准入 Webhook 或 Policy Controller,確保所有進入叢集的資源都符合基線要求。
例外處理機制同樣重要。總會有一些特殊情況需要繞過常規策略,例如某些系統元件可能需要特權存取。建立明確的例外申請與審批流程,記錄所有例外情況及其理由。使用標籤或注釋標記例外資源,在准入 Webhook 中透過 ObjectSelector 識別並允許這些例外。
webhooks:
- name: security-policy.example.com
objectSelector:
matchExpressions:
- key: security.example.com/exception
operator: DoesNotExist
持續改進安全策略是一個永無止境的過程。收集准入 Webhook 的拒絕日誌,分析哪些策略經常被觸發,哪些資源經常違反策略。這些資料可以幫助我們了解開發人員面臨的實際問題,調整策略使其更加合理。同時,關注 Kubernetes 社群的安全最佳實踐,及時更新策略以應對新的安全威脅。
總結
Kubernetes 的准入控制與授權機制構成了雲端原生安全架構的核心。准入 Webhook 提供了靈活的策略執行能力,讓組織能夠實施自訂的安全規則。RBAC 實作了精細的權限管理,確保最小權限原則的落實。這兩個機制的結合,加上 GitOps 的宣告式管理方式,為企業提供了完整的安全解決方案。
正確理解與設定這些機制,需要深入了解 Kubernetes 的架構與運作原理。從 Webhook 的效能最佳化到 RBAC 的權限設計,從 failurePolicy 的選擇到命名空間的隔離,每個細節都可能影響叢集的安全性與可用性。透過本文的深入剖析,相信讀者已經掌握了實施企業級 Kubernetes 安全策略所需的知識與技能。
安全是一個持續的過程,而非一次性的任務。隨著應用的演進與威脅環境的變化,安全策略也需要不斷調整與完善。建立自動化的監控與審計機制,定期評估安全狀況,保持對最新安全威脅的警覺,才能確保 Kubernetes 叢集的長期安全運作。