新聞中心
使用 RBAC 限制對 Kubernetes 資源的訪問
作者:祝祥 翻譯 2022-06-21 08:03:49
云計算
云原生 通過本文,我們將學習如何從頭開始重新創(chuàng)建 Kubernetes RBAC 授權模型,并了解Roles、ClusterRoles、ServiceAccounts、RoleBindings 和 ClusterRoleBindings 之間的關系。

站在用戶的角度思考問題,與客戶深入溝通,找到沿河網站設計與沿河網站推廣的解決方案,憑借多年的經驗,讓設計與互聯網技術結合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:做網站、網站設計、企業(yè)官網、英文網站、手機端網站、網站推廣、域名與空間、雅安服務器托管、企業(yè)郵箱。業(yè)務覆蓋沿河地區(qū)。
通過本文,我們將學習如何從頭開始重新創(chuàng)建 Kubernetes RBAC 授權模型,并了解Roles、ClusterRoles、ServiceAccounts、RoleBindings 和 ClusterRoleBindings 之間的關系。
隨著集群中應用程序和資源數量的增加,我們可能需要查看并限制他們相關的權限,從而避免一些危險操作。這些危險操作往往會嚴重影響生產環(huán)境,有時候,甚至會引起長時間的停機,比如過大的權限導致正常運行的服務被刪除。
正常情況下,我們可能希望限制生產系統僅僅允許少部分人管理以及訪問。
或者,我們可能希望向部署在集群中的維護人員授予一組有限的權限。
我們可以通過Kubernetes 中的基于角色的訪問控制 (RBAC) 來實現上述的需求。
Kubernetes API
在討論RBAC之前,讓我們看看授權模型在圖中的位置。
假設我們希望將以下 Pod 部署到 Kubernetes 集群:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: sise
image: learnk8s/app:1.0.0
ports:
- containerPort: 8080
我們可以使用以下命令將 Pod 部署到集群:
$ kubectl apply -f pod.yaml
當我們輸入時kubectl apply,會觸發(fā)以下的操作。
kubectl 會:
1、從KUBECONFIG讀取配置。
2、從 API 中發(fā)現 API 和對象。
3、驗證資源客戶端(是否有明顯的錯誤?)。
4、將帶有有效負載的請求發(fā)送到kube-apiserver。
當kube-apiserver收到請求時,它不會立即將其存儲在 etcd 中。
首先,它必須驗證請求者是否合法。
換句話說,它必須對請求進行身份驗證。(https://kubernetes.io/docs/reference/access-authn-authz/authentication/)。
一旦通過身份驗證,請求者是否有權創(chuàng)建資源?
身份和權限不是一回事。
僅僅因為我們可以訪問集群并不意味著我們可以創(chuàng)建或讀取所有資源。
授權通常使用基于角色的訪問控制 (RBAC)(https://kubernetes.io/docs/reference/access-authn-authz/rbac/)來完成。
借助基于角色的訪問控制 (RBAC),我們可以分配精細的權限并限制用戶或應用程序可以執(zhí)行的操作。
在更實際的情況下,API 服務器按順序執(zhí)行以下操作:
1、收到請求后,對用戶進行身份驗證。
a. 當驗證失敗時,通過返回來拒絕請求401 Unauthorized。
b, 否則,進入下一階段。
2、用戶已通過身份驗證,但他們是否有權訪問資源
a. 如果他們沒有權限,請通過返回來拒絕請求403 Forbidden。
b. 否則,繼續(xù)。
在本文中,我們將重點關注授權部分。
將用戶和權限與 RBAC 角色解耦
RBAC(Role-Based Access Control)即:基于角色的權限控制。通過角色關聯用戶,角色關聯權限的方式間接賦予用戶權限。如下圖:
有人會問為什么不直接給用戶分配權限,還多此一舉的增加角色這一環(huán)節(jié)呢?
其實是可以直接給用戶分配權限,只是直接給用戶分配權限,少了一層關系,擴展性弱了許多,適合那些用戶數量、角色類型少的平臺。
對于通常的系統,比如:存在多個用戶擁有相同的權限,在分配的時候就要分別為這幾個用戶指定相同的權限,修改時也要為這幾個用戶的權限進行一一修改。有了角色后,我們只需要為該角色制定好權限后,將相同權限的用戶都指定為同一個角色即可,便于權限管理。
對于批量的用戶權限調整,只需調整用戶關聯的角色權限,無需對每一個用戶都進行權限調整,既大幅提升權限調整的效率,又降低了漏調權限的概率。
要了解它是如何工作的,讓我們想象一下,我們必須從頭開始設計一個授權系統。我們該如何確保用戶對特定資源具有寫入權限?
一個簡單的實現可能涉及編寫一個如下所示的列表:
| User | Permission | Resource |
| ----- | ---------- | -------- |
| Bob | read+write | app1 |
| Alice | read | app2 |
| Mo | read | app2 |
在這個例子中:
· Bob 有讀寫權限,可以訪問app1但無權訪問app2。
· Mo 和 Alice對app2有只讀權限,但是無權訪問app1。
上表適用于少數用戶和資源,但一旦開始擴展它就會顯示一些限制。
讓我們假設Mo和Alice在同一個Team中,并且他們被授予對app1的讀取權限。
我們必須將以下條目添加到表中:
| User | Permission | Resource |
| --------- | ---------- | -------- |
| Bob | read+write | app1 |
| Alice | read | app2 |
| Mo | read | app2 |
| Alice | read | app1 |
| Mo | read | app1 |
這很好,但Alice和Mo是否有相同的訪問權限并不明顯,因為他們是同一Team的成員。
- 在典型的授權系統中我們有用戶訪問資源。
- 我們可以直接向用戶分配權限,并定義他們可以使用的資源。
- 這些權限直接映射資源。注意它們是如何作用于用戶的。
- 如果我們決定讓第二個用戶具有相同的權限,則必須關聯相同的權限。
我們可以通過在表中添加“Team”列來解決這個問題,但更好的替代方法是分解關系:
1、我們可以為權限定義一個通用屬性:角色。
2、我們可以為定義的組織“Team”進行授權,而不是直接將權限分配給用戶。
3、最后,我們可以用戶加入到定義組織”Team“。
讓我們看看這有什么不同?,F在你有兩個權限映射關系表:
· 在第一個表中,權限映射到角色
· 在第二個表中,角色與身份相關聯
| Role | Permission | Resource |
| -------- | ---------- | -------- |
| admin1 | read+write | app1 |
| reviewer | read | app2 |
| User | Roles |
| ----- | -------- |
| Bob | admin1 |
| Alice | reviewer |
| Mo | reviewer |
當我們希望 Mo 成為 app1 的管理員時那又該如何做了?
我們可以像這樣將角色添加到用戶:
| User | Roles |
| ----- | ------------------- |
| Bob | admin1 |
| Alice | reviewer |
| M
我們已經可以想象,將用戶與權限與角色分離可以促進擁有大量用戶和權限的大型組織中的安全管理。
- 使用 RBAC 時,我們擁有用戶、資源和角色。
- 權限不會直接分配給用戶。相反,他們被包括在這個角色中。
- 用戶通過綁定關聯到角色。
- 由于角色是通用的,當新用戶需要訪問相同資源時,您可以使用現有角色并將其新綁定關聯。
Kubernetes 中的 RBAC
Kubernetes 實現了一個 RBAC 模型(以及其他幾個模型)(https://kubernetes.io/docs/reference/access-authn-authz/authorization/#authorization-modules) 來保護集群中的資源。
基于角色(Role)的訪問控制(RBAC)是一種基于組織中用戶的角色來調節(jié)控制對 計算機或網絡資源的訪問的方法。
RBAC 鑒權機制使用 rbac.authorization.k8s.io API 組 來驅動鑒權決定,允許你通過 Kubernetes API 動態(tài)配置策略。
要啟用 RBAC,在啟動 API 服務器 時將 --authorization-mode 參數設置為一個逗號分隔的列表并確保其中包含 RBAC。
kube-apiserver --authorization-mode=Example,RBAC --<其他選項> --<其他選項>
因此 Kubernetes 使用了前面解釋過的相同的三個概念:身份、角色和綁定。
它只是用稍微不同的名字來稱呼它們。
例如,讓我們檢查以下授予對 Pod、Service等資源的訪問權限所需的 YAML 定義:
apiVersion: v1
kind: ServiceAccount
metadata:
name: serviceaccount:app1
namespace: demo-namespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role:viewer
namespace: demo-namespace
rules: # Authorization rules for this role
- apiGroups: # 1st API group
- '' # An empty string designates the core API group.
resources:
- services
- pods
verbs:
- get
- list
- apiGroups: # 2nd API group
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- list
- apiGroups: # 3rd API group
- cilium.io
resources:
- ciliumnetworkpolicies
- ciliumnetworkpolicies/status
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: rolebinding:app1-viewer
namespace: demo-namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role:viewer
subjects:
- kind: ServiceAccount
name: serviceaccount:app1
namespace: demo-namespace
該文件分為三個部分:
1、ServiceAccount——這是訪問資源的用戶的身份。
2、Role——包含訪問資源的權限。
3、將身份(ServiceAccount)關聯到權限(Role)的 RoleBinding。
配置提交到集群后,允許使用服務帳戶的應用程序向以下端點發(fā)出請求:
# 1. Kubernetes builtin resources
/api/v1/namespaces/{namespace}/services
/api/v1/namespaces/{namespace}/pods
# 2. A specific API extention provided by cilium.io
/apis/cilium.io/v2/namespaces/{namespace}/ciliumnetworkpolicies
/apis/cilium.io/v2/namespaces/{namespace}/ciliumnetworkpolicies/status
結果很成功,但是我們忽略了很多細節(jié)。
我們究竟授予了哪些資源訪問權限?
什么是服務帳戶?身份不只是集群中的“用戶”嗎?
為什么 Role 包含 Kubernetes 對象列表?
為了理解它們是如何工作的,讓我們拋開 Kubernetes RBAC 模型并嘗試從頭開始重建它。
我們將重點關注三個要素:
1、識別和分配身份。
2、’授予權限。
3、將身份與權限相關聯。
分配身份:用戶,組,robot賬戶
假設我們的新同事希望登錄 Kubernetes 界面。
在這種情況下,我們應該有一個“帳戶”或“用戶”的實體,每個實體都有一個唯一的名稱或 ID(例如電子郵件地址)。
我們應該如何將用戶存儲在集群中?
Kubernetes 沒有代表常規(guī)用戶帳戶的對象。
無法通過 API 調用將用戶添加到集群中。
相反,任何提供由集群的證書頒發(fā)機構 (CA) 簽名的有效證書的參與者都被視為已通過身份驗證。(https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#normal-user)。
在這種情況下,Kubernetes 從證書的“subject”中的通用名稱字段中分配用戶名(例如,“/CN=bob”)。
創(chuàng)建一個臨時用戶信息對象并將其傳遞給授權 (RBAC) 模塊。
深入研究代碼會發(fā)現一個結構映射了從 Authentication 模塊收集的所有詳細信息。
type User struct {
name string // unique for each user
... // other fields
}請注意,User用于集群外的人員或應用。
如果要識別集群中的應用,則應改用服務帳戶。
該帳戶與普通用戶非常相似,但不同之處在于Kubernetes管理它。
服務帳戶通常分配給 pod 以授予權限。
例如,我們可以讓以下應用程序從集群內部訪問資源:
· cilium-agent必須列出特定節(jié)點上的所有 pod 資源· ingress nginx控制器必須列出服務的所有后端端點。
對于這些應用,我們可以定義一個 ServiceAccount (SA)。
由于服務帳戶是在集群中管理的,因此我們可以使用 YAML 創(chuàng)建它們:
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa:app1 # arbitrary but unique string
namespace: demo-namespace
為了方便 Kubernetes 管理,我們還可以定義一組User 或ServiceAccount。
通過這樣,我可以很方便的引用特定namespace中的所有 ServiceAccount。
現在我們已經定義了如何訪問資源,是時候討論權限了。
此時,我們有一種機制來確定誰可以訪問資源。
它可能是一個人、一個robot賬戶或一群人。
但是他們在集群中訪問什么資源呢?
對資源的訪問進行建模
在Kubernetes中,我們感興趣的是控制對資源的訪問,比如Pod、Services、Endpoints等。
這些資源通常存儲在數據庫 (etcd) 中,并通過內置 API 訪問,例如:
/api/v1/namespaces/{namespace}/pods/{name}
/api/v1/namespaces/{namespace}/pods/{name}/log
/api/v1/namespaces/{namespace}/serviceaccounts/{name}限制對這些資源的訪問的最佳方法是控制這些 API 端點的請求方式。
為此,我們將需要兩件事:
1、資源的 API 端點。
2、授予訪問資源的權限類型(例如只讀、讀寫等)。
對于權限,我們將使用verbs,例如get, list, create, patch, delete 等。
想象一下,你想要get, list 以及 watchPods、logs和Services等資源。
我們可以將這些資源和權限組合在一個列表中,如下所示:
resources:
- /api/v1/namespaces/{namespace}/pods/{name}
- /api/v1/namespaces/{namespace}/pods/{name}/log
- /api/v1/namespaces/{namespace}/serviceaccounts/{name}
verbs:
- get
- list
- watch
根據以下信息,我們可以更簡化定義上述信息:
· 基本 URL/api/v1/namespaces/對所有人都是通用的。也許我們可以省略它。
· 我們可以假設所有資源都在當前namespace中并刪除{namespace}路徑。
最終我們可以簡化為:
resources:
- pods
- pods/logs
- serviceaccounts
verbs:
- get
- list
- watch
該定義更人性化,我們可以很清晰的了解相關權限信息。
不過,權限配置不僅僅只有上面的內容,還有更多的內容。
除了 pod、endpoint、service等內置對象的 API 外,Kubernetes 還支持 API 擴展。
例如,當使用安裝 Cilium CNI 時,腳本會創(chuàng)建一個CiliumEndpoint自定義資源 (CR):
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: ciliumendpoints.cilium.io
spec:
group: cilium.io
names:
kind: CiliumEndpoint
scope: Namespaced
# truncated...
這些對象存儲在集群中,可通過 kubectl 獲得:
$ kubectl get ciliumendpoints.cilium.io -n demo-namespace
NAME ENDPOINT ID IDENTITY ENDPOINT STATE IPV4
IPV6
app1 2773 1628124 ready 10.6.7.54
app2 3568 1624494 ready 10.6.7.94
app3 3934 1575701 ready 10.6.4.24
$
可以通過 Kubernetes API 類似地訪問自定義資源:
/apis/cilium.io/v2/namespaces/{namespace}/ciliumendpoints
/apis/cilium.io/v2/namespaces/{namespace}/ciliumendpoints/{name}如果要將它們映射到 YAML 文件中,可以編寫以下內容:
resources:
- ciliumnetworkpolicies
- ciliumnetworkpolicies/status
verbs:
- get
但是,Kubernetes 怎么知道資源是自定義的呢?
它如何區(qū)分使用自定義資源和內置的 API?
不幸的是,從 API endpoint刪除 URL 并不是一個好主意。
我們可以通過稍作更改來恢復它。
我們可以在頂部定義它并稍后使用它來擴展資源的 URL。
apiGroups:
- cilium.io # APIGroup name
resources:
- ciliumnetworkpolicies
- ciliumnetworkpolicies/status
verbs:
- get
對于沒有namespace API的POD之類的資源呢?
Kubernetes “”空API組是一個特殊的組,它引用內置對象。因此,前面的定義應該擴展到:
apiGroups:
- '' # Built-in objects
resources:
- pods
- pods/logs
- serviceaccounts
verbs:
- get
- list
- watch
Kubernetes 讀取 API 組并自動將它們擴展為:
· 如果為空,則將“”轉換為/api/v1/xxx。
· 否則為/apis/{apigroup_name}/{apigroup_version}/xxx。
既然我們知道了如何映射資源和權限,現在終于到了將對多個資源的訪問組合在一起的時候了。在Kubernetes中,resources和verbs的集合稱為rules,您可以將規(guī)則分組到列表中:
rules:
- rule 1
- rule 2
每條規(guī)則都包含我們上述所提到的apiGroups,resources和verbs:
rules: # Authorization rules
- apiGroups: # 1st API group
- '' # An empty string designates the core API group.
resources:
- pods
- pods/logs
- serviceaccounts
verbs:
- get
- list
- watch
- apiGroups: # another API group
- cilium.io # Custom APIGroup
resources:
- ciliumnetworkpolicies
- ciliumnetworkpolicies/status
verbs:
- get
規(guī)則的集合在 Kubernetes 中具有特定的名稱,稱為角色。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
rules: # Authorization rules
- apiGroups: # 1st API group
- '' # An empty string designates the core API group.
resources:
- pods
- pods/logs
- serviceaccounts
verbs:
- get
- list
- watch
- apiGroups: # another API group
- cilium.io # Custom APIGroup
resources:
- ciliumnetworkpolicies
- ciliumnetworkpolicies/status
verbs:
- get
到目前為止,我們定義了:
· 具有用戶、服務帳戶和組的身份。
· 對具有角色的資源的權限。
最后,缺少的部分是將兩者聯系起來。
向用戶授予權限
RoleBinding 將角色中定義的權限授予用戶、服務帳戶或組。讓我們看一個例子:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: role-binding-for-app1
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: viewer
subjects:
- kind: ServiceAccount
name: sa-for-app1
namespace: kube-system
該定義有兩個重要字段:
· 引用viewer角色的roleRef。
· 關聯到sa-for-app1服務帳戶的subjects。
將資源提交到集群后,使用服務帳戶的應用程序或用戶將有權訪問角色中列出的資源。
如果我們刪除綁定,應用程序或用戶將失去對這些資源的訪問權限(但該角色將隨時準備被其他綁定使用)。
請注意該subjects字段是一個包含kind,namespace和name的列表。
該kind屬性是從服務帳戶和組中識別用戶所必需的。
但是namespace了?
將集群拆分為namespace,并將對namespace資源的訪問限制為特定帳戶,這通常很有幫助。
在大多數情況下,Role和RoleBinding與namespace關聯,并授予對特定namespace的訪問權。
然而,這兩種資源是可以混合使用的——稍后我們將描述該如何混合。
在我們總結理論并從實踐開始之前,讓我們看一下subjects的幾個例子:
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
# when the namespace field is not specified, this targets all service accounts in all namespace
我們還可以將多個組、用戶或服務帳戶作為subjects:
subjects:
- kind: Group
name: system:authenticated # for all authenticated users
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:unauthenticated # for all unauthenticated users
apiGroup: rbac.authorization.k8s.io
回顧一下到目前為止所學的內容,讓我們看看如何授予應用程序訪問某些自定義資源的權限。
首先,讓我們介紹一下場景:你有一個應用程序需要訪問Cilium暴露的資源。
- 想象一下,在集群中部署了一個需要通過 API 訪問自定義資源的應用程序。
- 如果不授予對這些API的訪問權限,請求將失敗,并顯示403禁止的錯誤消息。
如何授予訪問這些資源的權限?
使用服務帳戶、角色和角色綁定。
- 首先,我們應該為我們的工作負載創(chuàng)建一個身份。在 Kubernetes 中,這意味著創(chuàng)建一個服務帳戶。
- 然后,我們需要定義權限并將其包含到角色中。
- 最后,我們希望通過RoleBinding將身份(服務帳戶)關聯到權限(角色)。
- 下次應用程序向Kubernetes API發(fā)出請求時,它將被授予訪問Cilium資源的權限。
Namespaces和cluster-wide的資源
當我們討論資源時,您了解到endpoint的結構如下面一樣:
/api/v1/namespaces/{namespace}/pods/{name}
/api/v1/namespaces/{namespace}/pods/{name}/log
/api/v1/namespaces/{namespace}/serviceaccounts/{name}但是沒有namespace的資源,比如持久卷和節(jié)點呢?
namespace資源只能在namespace內創(chuàng)建,并且該namespace的名稱包含在 HTTP 路徑中。
如果資源是全局的,比如節(jié)點,namespace名稱就不會出現在 HTTP 路徑中。
/api/v1/nodes/{name}
/api/v1/persistentvolume/{name}我們可以將它們添加到角色中嗎?
是的,我們可以添加。
畢竟,在引入 Roles 和 RoleBindings 時,我們沒有討論任何namespace的限制。
下面是一個例子:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
rules: # Authorization rules
- apiGroups: # 1st API group
- '' # An empty string designates the core API group.
resources:
- persistentvolumes
- nodes
verbs:
- get
- list
- watch
但是,如果我們嘗試提交該配置并將其關聯到服務帳戶,大家可能會意識到它不起作用。
持久卷和節(jié)點是集群范圍的資源。
但是,角色可以授予對namespace范圍內資源的訪問權限。
如果我們想使用適用于整個集群的 Role,我們可以使用 ClusterRole(以及相應 ClusterRoleBinding的為它分配subject)。
之前的配置應改為:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: viewer
rules: # Authorization rules
- apiGroups: # 1st API group
- '' # An empty string designates the core API group.
resources:
- persistentvolumes
- nodes
verbs:
- get
- list
- watch
請注意,唯一的變化是kind屬性,而其他一切都保持不變。
我們可以使用 ClusterRoles 授予對所有資源的權限——例如,集群中的所有 Pod。
此功能不限于集群范圍的資源。
Kubernetes 已經附帶了一些角色和集群角色。
讓我們來看一下。
$ kubectl get roles -n kube-system | grep "^system:"
NAME
system::leader-locking-kube-controller-manager
system::leader-locking-kube-scheduler
system:controller:bootstrap-signer
system:controller:cloud-provider
system:controller:token-cleaner
# truncated output...
system:前綴表示資源由集群控制平面直接管理。
此外,所有默認的 ClusterRoles 和 ClusterRoleBindings 都標有kubernetes.io/bootstrapping=rbac-defaults。
讓我們也列出 ClusterRoles:
$ kubectl get clusterroles -n kube-system | grep "^system:"
NAME
system:aggregate-to-admin
system:aggregate-to-edit
system:aggregate-to-view
system:discovery
system:kube-apiserver
system:kube-controller-manager
system:kube-dns
system:kube-scheduler
# truncated output...
我們可以使用以下命令檢查每個 Role 和 ClusterRole 的詳細信息:
當前標題:使用RBAC限制對Kubernetes資源的訪問
地址分享:http://www.dlmjj.cn/article/cddiejd.html


咨詢
建站咨詢
