這些用來審計 Kubernetes RBAC 策略的方法你都見過嗎?
原文連結:這些用來審計 Kubernetes RBAC 策略的方法你都見過嗎?
認證與授權對任何安全系統來說都至關重要,Kubernetes 也不例外。即使我們不是安全工作人員,也需要了解我們的 Kubernetes 叢集是否具有足夠的訪問控制權限。Kubernetes 社群也越來越關注容器的安全評估(包括滲透測試,配置審計,模擬攻擊),如果你是應用安全工程師,或者是安全感知的 DevOps 工程師,最好了解一下 Kubernetes 的授權模型。
Kubernetes 的授權控制原則與大多數系統一樣:在授予訪問許可權時採用最小授權原則。例如,如果某個 Pod 使用了特定的 serviceAccount
Kubernetes 從 1.6 開始支援基於角色的訪問控制機制(Role-Based Access,RBAC),叢集管理員可以對使用者或服務賬號的角色進行更精確的資源訪問控制。先簡單回顧一下 RBAC 的原理。
1. RBAC 基礎概念
RBAC 授權策略會建立一系列的 Role 和 ClusterRole 來繫結相應的資源實體(serviceAccount 或 group),以此來限制其對叢集的操作。每一個 Role 都基於 Create, Read, Update, Delete(CRUD)模型來構建,並使用“動詞”來應用相應的許可權。例如,動詞 get
Secrets
的訪問許可權,可以建立如下的 ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
關於 RBAC 的更多詳細文件請參考 Kubernetes 官方文件或 CNCF 的部落格。
2. RBAC 實踐
RBAC 授權模型為我們提供了一種精確的訪問控制機制,但隨著環境越來越複雜,這些 RBAC 配置也越來越難維護。RBAC 配置可能包含了 Roles, RoleBindings, ClusterRoles, ClusterRoleBindings, ServiceAccounts 和 Groups 等,想要跟蹤它們之間的關係非常困難。
舉個栗子,先建立一個名叫 helm 的 ServiceAccount
,然後建立相應的 Role
繫結 “tiller-world” namespace,該 Role 只擁有 list pods
的許可權,最後通過建立 RoleBinding
將該 Role 與之前建立的 ServiceAccount
繫結。
apiVersion: v1
kind: ServiceAccount
metadata:
name: helm
namespace: helm-world
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tiller-user
namespace: tiller-world
rules:
- apiGroups:
- ""
resources:
- pods/portforward
verbs:
- create
- apiGroups:
- ""
resources:
- pods
verbs:
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tiller-user-binding
namespace: tiller-world
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: tiller-user
subjects:
- kind: ServiceAccount
name: helm
namespace: helm-world
如果你想知道新建立的授權物件是否僅被授予必要的訪問許可權,就需要審查這些物件及其在叢集中的關係。有時候還需要確保其僅對特定的資源例項具有訪問許可權,不允許訪問所有的資源例項。例如,如果你不想讓上面的 ServiceAccount 訪問所有的 Secret,只允許它訪問特定的 Secret,可以使用 resourceNames
欄位指定:
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["my-pod-secrets"]
verbs: ["get", "watch", "list"]
這個方法的問題在於無法過濾叢集中不存在的資源,這意味著如果資源的名稱是動態變化的,那麼就無法建立相應的 Role,除非在建立 Role 的同時建立資源。
3. 審計很重要
為了檢視每個 Role 的作用以及每個資源物件應該能做哪些事情,我們不得不進行一些審計工作。最簡單的審計就是確認某個 Service Account 是否擁有 Cluster Admin 的許可權,再複雜一點,確認某個 CI/CD Service Account 在指定的 namespace 內是否擁有 Update Pod
的許可權。
基於審計的目標,大致可以分為兩種審計模式:
- 資源審計:識別風險最高的資源物件,並檢視誰可以訪問它們。
- 賬戶審計:檢視賬戶的有效許可權並確保它們的合理性。
賬戶審計比較徹底,但很耗時;資源審計可以更快發現問題,但可能會有所遺漏。舉例:
- 資源審計:檢視誰能訪問某個 Secret 資源,並確保其是否遵循最小授權原則。
- 賬戶審計:遍歷所有的 user,group,Service Account 和 RoleBinding,確保它們是否被授予正確的訪問許可權,並只限定在特定的 namespace 內。
下面提供幾種命令列工具來幫助大家更方便地審計 RBAC。
4. Kubectl Can-I
某些生產環境不允許安裝額外的服務,只能使用 kubectl
,我們可以使用 kubectl 的內建命令 kubectl auth can-i
來檢視 RBAC 許可權。
例如,檢視你是否擁有 get pod 的許可權:
$ kubectl auth can-i get pods
yes
檢視你是否擁有 cluster-admin 的許可權:
$ kubectl auth can-i "*" "*"
yes
列出你在某個 namesapce 中擁有的所有許可權:
$ kubectl auth can-i --list --namespace=secure
Resources Non-Resource URLs Resource Names Verbs
*.* [] [] [*]
[*] [] [*]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
[/api/*] [] [get]
[/api] [] [get]
[/apis/*] [] [get]
[/apis] [] [get]
[/healthz] [] [get]
[/healthz] [] [get]
[/openapi/*] [] [get]
[/openapi] [] [get]
[/version/] [] [get]
[/version/] [] [get]
[/version] [] [get]
[/version] [] [get]
來點更有趣的,我們還可以通過 Kubernetes 的 Impersonation API 來檢視其他賬戶是否擁有訪問特定資源的許可權。例如,檢視名為 unprivileged-service-account
的 Service Account 是否擁有 get pod 的許可權:
$ kubectl auth can-i get pod \
--as system:serviceaccount:secure:unprivileged-service-account
yes
--as
引數用來指定賬戶名稱,類似的引數還有 --as-group
,背後的原理實際上是一組傳遞給 API Server 的請求頭。
Kubernetes 中除了有 Service Account
之外還會有 User
,每建立一個 Service Account,都會自動建立一個對應的 User,名稱格式為:system:serviceaccount:<namespace><serviceaccount>
。想知道某個 Service Account 的 username 可以通過它的 yaml 檔案來推算:
$ kubectl get serviceaccount unprivileged-service-account -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2019-07-23T17:44:31Z"
name: unprivileged-service-account
namespace: default
resourceVersion: "98089"
selfLink: /api/v1/namespaces/default/serviceaccounts/unprivileged-service-account
secrets:
- name: unprivileged-service-account-token-9cggz
通過將 verbs
欄位的值指定為 impersonate,可以讓某個使用者擁有其他使用者的許可權,即可以模擬其他使用者。例如,管理員可以使用此功能通過暫時模擬其他使用者並檢視請求是否被拒絕來除錯授權策略。
例如,如果你想讓非 Cluster Admin 賬戶能夠模擬其他使用者,可以建立如下的 ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: impersonator
rules:
- apiGroups: [""]
resources: ["users", "groups", "serviceaccounts"]
verbs: ["impersonate"]
5. Kubectl Who Can
下面介紹的這款工具是 kubectl 的外掛,外掛名叫 who-can
,顧名思義,用來顯示哪些賬戶擁有訪問特定資源的許可權。安裝方法很簡單,可以通過 kubectl 的外掛管理框架 Krew 來安裝:
- 安裝 krew。參考 https://github.com/kubernetes-sigs/krew/
安裝
who-can
:$ kubectl krew install who-can
假設 secure namespace 中有一個 Secret 名為 cluster-admin-creds,你想檢視誰擁有訪問它的許可權:
$ kubectl who-can get secret cluster-admin-creds -n secure
ROLEBINDING NAMESPACE SUBJECT TYPE SA-NAMESPACE
unpriv_sa_binding secure unprivileged-service-account ServiceAccount secure
CLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE
cluster-admin system:masters Group
輸出資訊也很一目瞭然,沒什麼可說的。提醒一下,該工具只支援檢視 create、update 和 delete 這幾個訪問許可權,不支援 use。use 用來將 Pod Security Policy 繫結到相應的 Role。
6. Rakkess
rakkess 與 who-can 類似,可以列出某個賬戶對所有資源的訪問許可權,可以通過 krew 來安裝。
使用方法也很簡單,如果想檢視當前使用者對所有資源的訪問許可權,可使用如下命令:
如果想檢視某個特定的 Service Account 對所有資源的訪問許可權,可以使用如下命令:
$ kubectl access-matrix --as system:serviceaccount:kube-ovn:ovn -n kube-ovn
更多用例可以參考官方文件。
7. RBack
rback 用來對 kubectl 的輸出結果進行視覺化展示,可以輸出為 .dot
格式,也可以輸出為 .png
或任何格式。
例如:
$ kubectl get sa,roles,rolebindings \
-n monitoring -o json | rback > rback.dot
或者儲存為 png:
$ kubectl get sa,roles,rolebindings \
-n monitoring -o json \
| rback | dot -Tpng > rback.png
8. RBAC-View
rbac-view 也可以用來視覺化賬戶與許可權之間的關係,但與 rback 不同,它是一個 web 應用,安裝方法參考官方文件。
使用方式:
$ kubectl rbac-view
serving RBAC View and http://localhost:8800
在瀏覽器中開啟連結 http://localhost:8800
。
9. 終極測試
上面提到的所有方法都可以幫助我們快速收集資訊,但有時難免會出現誤報的情況。想要確認某賬戶到底有沒有相應的許可權,可以使用下面提到的終極方法。例如,要想確認 secure namespace 中的 unprivileged-service-account 是否具有 get secret
的許可權,可以使用如下的命令:
$ kubectl get secrets \
--as system:serviceaccount:secure:unprivileged-service-account \
-o yaml
10. 模擬攻擊
預防攻擊最好的方法是模擬攻擊,我們可以模擬一個黑客進入其中的某個 Pod,看看能否執行一些不可描述的操作。步驟如下:
- 建立一個 Service Account。
$ kubectl create serviceaccount ncc-sa
- 建立相應的角色。
- 將 Role 與 Service Account 繫結。
- 建立一個測試 Pod,serviceAccountName 指定為
ncc-sa
。
- 進入該 Pod
驗證是否具有
get pod
的許可權。$ kubectl get pod
11. 總結
隨著叢集環境越來越複雜,RBAC Role 與其相關資源物件之間關係的複雜性也會呈指數級增長。如果 Role 太多,那麼運維人員可能很難選擇正確的 Role,容易犯錯;如果 Role 太少,運維人員可能會被迫選擇預設的 Role,這會導致某些 Pod 許可權過大。所以我們需要找到一個平衡點,通常的做法是通過 ansible 或 terraform 將某些部署策略抽象出來變成模板,將 RBAC 策略寫到模板中,這樣可以大大減輕開發人員的壓力。
微信公眾號
掃一掃下面的二維碼關注微信公眾號,在公眾號中回覆◉加群◉即可加入我們的雲原生交流群,群裡高手如雲,張館長、陽明大佬、kubesphere 核心貢獻者都在哦