根據我的經驗,以下是加強 Kubernetes 存取控制安全性的關鍵策略:

最小許可權原則

始終遵循最小許可權原則,只為使用者和服務帳戶分配完成其任務所需的最小許可權集。避免使用過於寬鬆的許可權,特別是在生產環境中。

定期審查許可權

定期審查和更新 RBAC 設定,確保它們仍然符合當前的需求。隨著應用程式的演進,某些許可權可能變得不必要,應及時移除。

使用名稱空間隔離

利用名稱空間進行邏輯隔離,並為不同的名稱空間設定適當的資源限制和網路政策。這有助於減少潛在攻擊的影響範圍。

啟用稽核日誌

確保啟用 Kubernetes 稽核日誌,並設定適當的稽核政策。稽核日誌對於事後分析安全事件和合規性檢查至關重要。

實施網路政策

使用 Kubernetes 網路政策限制 Pod 之間的通訊,採用白名單方法,只允許必要的流量。這有助於防止橫向移動攻擊。

保護 API 伺服器

API 伺服器是 Kubernetes 安全的核心。確保正確設定 API 伺服器的身分驗證和授權機制,並考慮使用准入控制器進行額外的安全檢查。

實施多因素身分驗證

對於人類使用者,特別是具有高許可權的管理員,實施多因素身分驗證(MFA)是一個好的做法。這增加了未經授權存取的難度。

Kubernetes 的存取控制是一個多層次的安全架構,涵蓋身分驗證、授權和稽核等關鍵方面。正確設定和管理這些機制對於保護容器化環境至關重要。

透過瞭解潛在的威脅模型,實施最小許可權原則,並採用本文討論的最佳實踐,可以顯著提高 Kubernetes 環境的安全性。記住,安全是一個持續的過程,需要定期審查和更新安全策略,以應對不斷變化的威脅景觀。

在容器安全領域,防禦深度是關鍵。除了存取控制外,還應考慮容器映像安全、執行時安全和網路安全等其他方面,以構建全面的安全策略。只有這樣,才能在享受 Kubernetes 帶來的敏捷性和擴充套件性的同時,確保系統的安全性和可靠性。

ServiceAccount 控制器與身分管理

ServiceAccount 控制器的基本功能

ServiceAccount 控制器作為 Kubernetes 控制器管理器的一部分,確保每個名稱空間中都存在一個預設的服務帳戶。這個機制對於 Kubernetes 中的身分管理至關重要,為工作負載提供基本的身分認證。

例如,kube-system 名稱空間中的預設服務帳戶可以表示為 system:serviceaccount:kube-system:default,其 YAML 定義如下:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: kube-system
secrets:
- name: default-token-v9vsm

服務帳戶的 Secret 資源

每個服務帳戶都會關聯一個 Secret,用於儲存身分驗證所需的憑證。以上面的 default 服務帳戶為例,它使用名為 default-token-v9vsm 的 Secret。我們可以檢視這個 Secret 的詳細內容:

apiVersion: v1
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: default
  name: default-token-v9vsm
  namespace: kube-system
type: kubernetes.io/service-account-token
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tL...==
  namespace: a3ViZS1zeXN0ZW0=
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWk...==

這個 Secret 包含三個關鍵資料:

  • ca.crt:叢集的憑證授權機構證書,用於驗證 API 伺服器的身分
  • namespace:服務帳戶所屬的名稱空間(base64 編碼)
  • token:JWT 格式的身分驗證令牌,用於向 API 伺服器證明身分

Pod 中的服務帳戶掛載

應用程式可以從 Pod 內部存取控制平面提供的服務帳戶資料。在容器內部,這些資料被掛載到特定的目錄:

~ $ ls -al /var/run/secrets/kubernetes.io/serviceaccount/
total 4
drwxrwxrwt 3 root root 140 Jun 16 11:31 .
drwxr-xr-x 3 root root 4096 Jun 16 11:31 ..
drwxr-xr-x 2 root root 100 Jun 16 11:31 ..2021_06_16_11_31_31.83035518
lrwxrwxrwx 1 root root 31 Jun 16 11:31 ..data -> ..2021_06_16_11_31_31.83035518
lrwxrwxrwx 1 root root 13 Jun 16 11:31 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Jun 16 11:31 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Jun 16 11:31 token -> ..data/token

TokenController 建立的 JWT 令牌可以直接讀取:

~ $ cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6InJTT1E1VDlUX1ROZEpRMmZSWi1aVW0yNWVocEh...

ServiceAccount 的使用場景與限制

服務帳戶經常作為構建基礎元件使用,可以與其他機制結合,例如 projected volumes 和 kubelet,用於工作負載身分管理。一個實際例子是 EKS 的「IAM roles for service accounts」功能,它展示了這種組合的應用。

雖然服務帳戶很方便,但它並不提供密碼學上強健的工作負載身分識別,因此對於某些安全要求較高的使用場景可能不夠充分。

密碼學強健的身分識別 - SPIFFE

為瞭解決更嚴格的身分驗證需求,CNCF 的 SPIFFE (Secure Production Identity Framework for Everyone) 專案提供了一個更強大的解決方案。SPIRE 是 SPIFFE API 的生產級參考實作,允許進行節點和工作負載的證明,自動為 Pod 等資源分配密碼學強健的身分識別。

在 SPIFFE 中,工作負載是使用特定設定佈署的程式,在信任域(如 Kubernetes 叢集)的上下文中定義。工作負載的身分採用 SPIFFE ID 的形式,其一般模式如下:

spiffe://trust-domain/workload-identifier

SVID (SPIFFE Verifiable Identity Document) 是工作負載向呼叫者證明其身分的檔案,例如 X.509 憑證或 JWT 令牌。如果 SVID 由信任域中的授權機構簽署,則該 SVID 是有效的。

根據角色的存取控制 (RBAC)

在 Kubernetes 中,根據角色的存取控制 (RBAC) 是授予人類使用者和工作負載存取資源的預設機制。讓我們先了解 RBAC 的基本概念,然後探討如何分析和視覺化 RBAC 關係。

RBAC 基本術語

在 RBAC 的上下文中,我們使用以下術語:

  • 身分識別 (Identity): 人類使用者或服務帳戶
  • 資源 (Resource): 我們希望提供存取許可權的物件(如名稱空間或佈署)
  • 角色 (Role): 用於定義資源操作條件的規則集合
  • 角色繫結 (Role Binding): 將角色附加到身分識別,有效表示對指定資源的一組操作許可權

身分識別對給定資源的允許操作稱為 verbs,分為兩類別:

  • 唯讀操作:getlist
  • 讀寫操作:createupdatepatchdeletedeletecollection

此外,角色的範圍可以是叢集範圍或 Kubernetes 名稱空間的上下文。

RBAC 預防許可權提升

預設情況下,Kubernetes 具有許可權提升預防機制。也就是說,使用者只有在已經擁有角色中包含的所有許可權時,才能建立或更新角色。

角色型別

Kubernetes 中有兩種型別的角色:

  1. Role: 僅在名稱空間上下文中有效
  2. ClusterRole: 在整個叢集範圍內有效

對於相應的繫結也是如此 - RoleBinding 在名稱空間中有效,而 ClusterRoleBinding 在整個叢集中有效。

Kubernetes 預定義了許多可以直接使用或作為起點的預設角色。例如,有一個名為 edit 的預設叢集角色:

$ kubectl describe clusterrole edit
Name: edit
Labels:
  kubernetes.io/bootstrapping=rbac-defaults
  rbac.authorization.k8s.io/aggregate-to-admin=true
Annotations:
  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources                Non-Resource URLs  Resource Names  Verbs
  ---------                -----------------  -------------  -----
  configmaps               []                 []              [create delete ... watch]
  ...

RBAC 例項:授予特定許可權

假設我們想要給開發人員 joey 檢視 yolo 名稱空間中佈署資源的許可權,我們可以按以下步驟操作:

  1. 首先,建立一個定義允許操作的叢集角色 view-deploys
$ kubectl create clusterrole view-deploys \
  --verb=get --verb=list \
  --resource=deployments

這個命令建立了如下 YAML 表示的資源:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: view-deploys
rules:
- apiGroups:
  - apps
  resources:
  - deployments
  verbs:
  - get
  - list
  1. 接下來,透過角色繫結將此叢集角色繫結到使用者 joey:
$ kubectl create rolebinding assign-perm-view-deploys \
  --role=view-deploys \
  --user=joey \
  --namespace=yolo

這會建立如下 YAML 表示的資源:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: assign-perm-view-deploys
  namespace: yolo
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: view-deploys
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: joey

這個 RoleBinding 將三個關鍵元素連線在一起:

  1. 名稱空間 yolo(繫結的作用範圍)
  2. 角色 view-deploys(定義了允許的操作)
  3. 使用者 joey(被授予許可權的主體)

RBAC 關係視覺化

單純檢視 YAML 程式碼來確定許可權通常不是最佳方式。由於 RBAC 的圖形特性,通常需要某種視覺化表示,例如顯示使用者、角色和資源之間關係的圖表。

在簡單情況下,關係看起來很直觀,但實際情況通常更複雜。在實際環境中,你可能需要處理數百個角色、繫結、主體和操作,這些操作橫跨核心 Kubernetes 資源以及自定義資源定義 (CRD)。

要真正瞭解叢集中的 RBAC 設定,需要使用專門的工具來分析和視覺化這些複雜的關係。這些工具可以幫助你識別潛在的許可權問題、安全風險,以及簡化許可權管理。

在 Kubernetes 安全管理中,理解和正確設定 RBAC 是最基本也是最關鍵的一步。透過精確控制誰可以存取哪些資源以及可以執行哪些操作,可以大降低安全風險,同時確保各個團隊和服務能夠得到他們所需的最小許可權。

隨著叢集規模和複雜性的增長,維護清晰的 RBAC 結構變得越來越重要,這也是為什麼許多組織投資於專門的 Kubernetes 許可權管理工具和實踐。

RBAC 許可權自動化:從日誌到角色定義

在 Kubernetes 叢集的安全管理中,最小許可權原則(Least Privilege Principle)一直是安全實踐的根本。這個原則要求我們只授予使用者完成特定任務所需的最小許可權集合 - 許可權太少會導致任務失敗,許可權太多則會為攻擊者提供可乘之機。

然而,精確定義所需許可權集合是一項挑戰。到底需要什麼許可權?需要多少許可權?這些問題常讓管理員困擾。在實踐中,玄貓發現許多團隊往往採取捷徑,直接賦予過多許可權以確保功能正常運作,但這種做法會帶來嚴重的安全隱憂。

audit2rbac:許可權自動化的利器

幸運的是,我們有一個強大的工具可以協助解決這個問題:audit2rbac。這個工具可以透過分析使用者的 API 請求日誌,自動生成所需的 RBAC 角色和繫結。這種根據實際使用模式的許可權定義方式,極大地簡化了最小許可權原則的實施。

讓我們透過一個具體的例子來看 audit2rbac 如何工作。以下是在 AWS EKS 叢集環境中的操作示範:

步驟一:收集稽核日誌

首先,我們需要開啟一個終端工作階段來收集 API 稽核日誌:

# 從 CloudWatch 取得稽核日誌
$ awslogs get /aws/eks/example/cluster \
  "kube-apiserver-audit*" \
  --no-stream --no-group --watch \
  >> audit-log.json

這個命令使用 awslogs 工具從 AWS CloudWatch 中提取 Kubernetes API 伺服器的稽核日誌。引數 --no-stream --no-group --watch 確保我們取得完整的日誌而不是僅檢視實時流,並將結果儲存到 audit-log.json 檔案中。這些日誌記錄了所有對 API 伺服器的請求,包括誰傳送的、做了什麼操作以及結果如何。

雖然這個例子使用的是 AWS 特定的方法,但相同的原理適用於其他雲端平台。例如,在 GKE 中可以使用 gcloud logging read 命令,而 AKS 也提供類別似的日誌存取方式。

步驟二:執行需要許可權的操作

在另一個終端工作階段中,以目標使用者身份執行需要進行許可權設定的 kubectl 命令。在這個例子中,我們想要生成允許列出所有名稱空間中的預設資源(如 pods、services 等)所需的角色:

# 執行需要許可權的操作
$ kubectl get all -A

這個命令嘗試列出叢集中所有名稱空間(-A 引數)的所有預設資源。這個操作需要特定的許可權,系統會記錄這些 API 請求到稽核日誌中。如果你想為其他使用者生成許可權,可以使用 --as 引數來模擬該使用者,例如 kubectl --as joey get all -A

步驟三:生成 RBAC 定義

現在我們有了稽核日誌,可以使用 audit2rbac 來分析這些日誌並生成相應的 RBAC 資源:

# 根據稽核日誌生成 RBAC 定義
$ audit2rbac --user kubernetes-admin \
  --filename audit-log.json \
  > list-all.yaml
Opening audit source...
Loading events....
Evaluating API calls...
Generating roles...
Complete!

這個命令使用 audit2rbac 工具分析之前收集的稽核日誌(audit-log.json),為使用者 kubernetes-admin 生成執行 kubectl get all -A 命令所需的最小許可權集合。--user 引數指定目標使用者,--filename 指定稽核日誌檔案,結果輸出到 list-all.yaml 檔案中。

工具會分析日誌中的 API 呼叫,評估需要哪些許可權,然後生成相應的角色和繫結。

生成的 RBAC 資源

以下是 audit2rbac 生成的 RBAC 資源範例(經過簡化):

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    audit2rbac.liggitt.net/version: v0.8.0
  labels:
    audit2rbac.liggitt.net/generated: "true"
    audit2rbac.liggitt.net/user: kubernetes-admin
  name: audit2rbac:kubernetes-admin
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - replicationcontrollers
  - services
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    audit2rbac.liggitt.net/version: v0.8.0
  labels:
    audit2rbac.liggitt.net/generated: "true"
    audit2rbac.liggitt.net/user: kubernetes-admin
  name: audit2rbac:kubernetes-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: audit2rbac:kubernetes-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: kubernetes-admin

這個 YAML 檔案包含兩個資源:

  1. ClusterRole:定義了允許的操作許可權,包括對 pods、replicationcontrollers 和 services 等資源的 get、list 和 watch 許可權。
  2. ClusterRoleBinding:將上述 ClusterRole 繫結到使用者 kubernetes-admin,使該使用者獲得這些許可權。

值得注意的是,audit2rbac 生成的許可權集合是根據實際 API 呼叫的最小集合,這正是實施最小許可權原則的理想方式。

快速許可權查詢工具

除了 audit2rbac,還有一個名為 who-can 的 krew 外掛,可以快速查詢誰有許可權執行特定操作,這對於許可權稽核和故障排除非常有用。

# 安裝 who-can 外掛
$ kubectl krew install who-can

# 查詢誰有許可權刪除 default 名稱空間中的 pods
$ kubectl who-can delete pods -n default

透過自動化 RBAC 設定的建立,我們可以更輕鬆地遵循最小許可權原則,避免因為便利而給予過多許可權的誘惑。這種做法不僅提高了安全性,也使許可權管理更加可維護。

RBAC 分析與視覺化:理解複雜許可權關係

隨著叢集規模和複雜性的增長,RBAC 設定也會變得越來越複雜。手動分析和理解這些許可權關係幾乎是不可能的任務,因為它們形成了巨大的有向無環圖 (DAG),包含主體、角色、繫結和操作等多種元素。

為了有效管理這種複雜性,我們需要工具來視覺化這些關係或查詢特定許可權路徑。在玄貓多年的 Kubernetes 安全工作中,發現視覺化是理解複雜 RBAC 設定的最有效方式之一。

RBAC 工具資源

為了幫助社群發現和使用 RBAC 工具及最佳實踐,有一個專門的網站 rbac.dev,該網站收集了各種 RBAC 相關工具和資源,並接受透過 issues 和 pull requests 提出的建議。

靜態分析工具

如果你想對 RBAC 設定進行靜態分析,可以考慮使用 krane 工具。它能識別潛在的安全風險,並提供緩解這些風險的建議。

# 使用 krane 分析 RBAC 安全風險
$ krane scan --kubeconfig ~/.kube/config

RBAC 視覺化例項

讓我們透過兩個例子來展示 RBAC 視覺化的強大功能:

例子一:rbac-view

rbac-view 是一個 krew 外掛,提供了 RBAC 關係的互動式 Web 介面:

# 安裝 rbac-view 外掛
$ kubectl krew install rbac-view

# 啟動 rbac-view
$ kubectl rbac-view
INFO[0000] Getting K8s client
INFO[0000] serving RBAC View and http://localhost:8800
INFO[0010] Building full matrix for json
INFO[0010] Building Matrix for Roles
INFO[0010] Retrieving RoleBindings
INFO[0010] Building Matrix for ClusterRoles
...

執行後,你可以在瀏覽器中開啟 http://localhost:8800,透過互動式介面檢視和查詢角色訊息。這種視覺化表示使得理解複雜的許可權關係變得更加直觀。

例子二:rback

rback 是一個命令列工具,可以查詢 RBAC 相關訊息並生成服務帳戶、角色和存取規則的圖形表示:

# 取得 RBAC 資源並生成圖形
$ kubectl get sa,roles,rolebindings,clusterroles,clusterrolebindings \
  --all-namespaces \
  -o json | \
  rback | \
  dot -Tpng > rback-output.png

這個命令執行了以下步驟:

  1. 使用 kubectl get 列出所有名稱空間中的服務帳戶、角色、角色繫結、叢集角色和叢集角色繫結,並以 JSON 格式輸出
  2. 將結果透過管道傳遞給 rback 工具,該工具會分析 RBAC 關係並生成 dot 格式的圖形定義
  3. 使用 dot 程式將圖形定義轉換為 PNG 影像,儲存為 rback-output.png

生成的影像會顯示服務帳戶、角色和許可權規則之間的關係,這對於理解複雜的 RBAC 設定非常有幫助。

透過這些視覺化工具,管理員可以更容易地理解和管理複雜的 RBAC 設定,識別潛在的安全問題,並確保許可權設定符合最小許可權原則。

RBAC 相關攻擊與安全考量

雖然 RBAC 相關的 CVE(通用漏洞和暴露)報告相對較少,但仍然存在一些基本的攻擊模式需要注意:

過於寬鬆的許可權

由於時間限制或缺乏安全意識,管理員常授予比實際需要更多的許可權。例如,你可能只想讓使用者列出和檢視佈署,但卻給了他們編輯許可權。這違反了最小許可權原則,熟練的攻擊者可能會利用這種設定進行惡意操作。

在玄貓的實踐中,曾遇到一個案例,開發團隊被授予了對生產名稱空間的 edit 角色,而實際上他們只需要 view 許可權來進行故障診斷。這種過度授權導致一次意外的生產事故,當一名開發人員誤刪了關鍵設定。

模糊的責任界限

在雲環境中執行容器時,分享責任模型的界限有時並不清晰。例如,雖然通常明確誰負責修補工作節點,但並不總是明確誰維護應用程式包及其依賴項。如果沒有仔細審查,預設建議的過於寬鬆的 RBAC 設定可能會導致攻擊向量,這種攻擊既隱蔽(“啊,我以為你負責這個”)又可能帶來意外後果。

Helm 相關安全問題

在 Helm 3 之前,Helm 使用了一個許可權過高的元件 Tiller,這引發了各種安全問題,特別是混淆代理(confused deputy)情況。雖然這個問題在 Helm 3 中已經得到解決,但你可能需要檢查叢集中是否仍在使用 Helm 2。

# 檢查是否存在 Tiller 佈署
$ kubectl get deployments -n kube-system | grep tiller

如果發現 Tiller 佈署,應考慮遷移到 Helm 3,或至少確保 Tiller 的許可權受到適當限制。

防範 RBAC 安全風險的最佳實踐

根據玄貓的經驗,以下是一些防範 RBAC 相關安全風險的最佳實踐:

  1. 定期審核許可權:定期檢查和審核 RBAC 設定,確保它們仍然符合最小許可權原則
  2. 使用自動化工具:利用 audit2rbac 等工具自動生成根據實際使用模式的最小許可權集合
  3. 實施許可權時間限制:考慮使用臨時提權機制,而不是永久授予高許可權
  4. 許可權分離:實施職責分離,確保關鍵操作需要多人協作才能完成
  5. 監控異常活動:實施監控和告警,檢測可能表明許可權濫用的異常活動

透過這些實踐,可以顯著降低 RBAC 相關安全風險,同時保持系統的可用性和可管理性。