【解構雲原生】K8s 的 RBAC - 基於角色的訪問控制

NetEaseResearch發表於2020-09-25

本文由作者授權釋出,未經許可,請勿轉載。

作者:李嵐清,網易數帆輕舟事業部資深工程師

基於角色的訪問控制(Role-Based Access Control, 即“RBAC”)使用 “rbac.authorization.k8s.io” API Group 實現授權控制,使用者可以通過 Kubernetes API 動態配置策略。

API 物件

RBAC 共包含4個型別的資源物件:Role、ClusterRole、RoleBinding、ClusterRoleBinding。使用者可以通過增刪改查上述四個API物件來實現訪問許可權的動態控制。

假如沒有建立任何ClusterRole和Role,則所有使用者是無許可權訪問任何K8S的API的,K8S的許可權控制是類似於白名單的,通過建立 Role&RoleBinding 和 ClusterRole&ClusterRoleBinding 將使用者許可權新增到“白名單”中,以此來實現授權。

Role 和 ClusterRole

在 RBAC API 中,Role 和 Cluster 都表示一組許可權的集合,Role 是 namespace-scoped的,定義的是某一個namespace中的資源許可權;而如果想要實現叢集級別的或者跨namespace的許可權控制,則需要建立 ClusterRole。

Role example

如上文所說,Role 是 namespace-scoped的,定義的是某一個namespace中的資源許可權。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

上述 pod-reader role,表示可以get/list/watch default namespce下面的pods資源。

Role 中可以定義多條rules,每條rule表示一個許可權,rule型別定義如下:

type Rule struct {
	// Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule.  VerbAll represents all kinds.
	Verbs []string

	// APIGroups is the name of the APIGroup that contains the resources.
	// If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.
	APIGroups []string
	// Resources is a list of resources this rule applies to.  '*' represents all resources in the specified apiGroups.
	// '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups.
	Resources []string
	// ResourceNames is an optional white list of names that the rule applies to.  An empty set means that everything is allowed.
	ResourceNames []string

	// NonResourceURLs is a set of partial urls that a user should have access to.  *s are allowed, but only as the full, final step in the path
	// If an action is not a resource API request, then the URL is split on '/' and is checked against the NonResourceURLs to look for a match.
	// Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding.
	// Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"),  but not both.
	NonResourceURLs []string
}

ClusterRole example

ClusterRole 是用來實現叢集級別的或者跨namespace的許可權控制:

  • cluster-scoped 型別的資源,比如nodes
  • non-resource 型別的api,比如/healthz`
  • namespace-scoped 型別的資源,實現跨namespace的許可權控制
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" omitted since ClusterRoles are not namespaced
  name: secret-reader
rules:
- apiGroups: [""]
  #
  # at the HTTP level, the name of the resource for accessing Secret
  # objects is "secrets"
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

secret-reader 表示 get/list/watch 所有namespaces下面的secrets資源的許可權。

RoleBinding 和 ClusterRoleBinding

Role 和 ClusterRole 都表示了許可權的集合,許可權只有授予某個user或者group才有實際意義。許可權和使用者之間的關聯關係 是通過 RoleBinding 和 ClusterRoleBinding 兩個API資源來實現的。RoleBinding 是 namespace-scoped的,而 ClusterRoleBinding是 cluster-scoped的。

RoleBinding example

RoleBinding 可以引用在同一名稱空間內定義的 Role 物件。 下面示例中定義的 RoleBinding 物件在“default” 名稱空間中將“pod-reader” 角色授予使用者“jane”。 這一授權將允許使用者“jane” 從“default” 名稱空間中讀取 pod。

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

RoleBinding 物件也可以引用一個 ClusterRole 物件用於在 RoleBinding 所在的名稱空間內授予使用者對所引用的 ClusterRole 中 定義的名稱空間資源的訪問許可權。這一點允許管理員在整個叢集範圍內首先定義一組通用的角色,然後再在不同的名稱空間中複用這些角色。

例如,儘管下面示例中的 RoleBinding 引用的是一個 ClusterRole 物件,但是使用者”dave”(即角色繫結主體)還是隻能讀取”development” 名稱空間中的 secret(即 RoleBinding 所在的名稱空間)。

# 以下角色繫結允許使用者 "dave" 讀取 "development" 名稱空間中的 secret。
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-secrets
  namespace: development # 這裡表明僅授權讀取 "development" 名稱空間中的資源。
subjects:
- kind: User
  name: dave
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding example

可以使用ClusterRoleBinding在叢集級別和所有名稱空間中授予許可權。下面示例中所定義的ClusterRoleBinding允許在使用者組”manager” 中的任何使用者都可以讀取叢集中任何名稱空間中的 secret。

以下 ClusterRoleBinding 物件允許在使用者組 "manager" 中的任何使用者都可以讀取叢集中任何名稱空間中的 secret。

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

更多型別的資源引用

大多數資源由代表其名字的字串表示,例如”pods”,就像它們出現在相關 API endpoint 的 URL 中一樣。然而,有一些 Kubernetes API 還 包含了” 子資源”,比如 pod 的 logs。在 Kubernetes 中,pod logs endpoint 的 URL 格式為:

GET /api/v1/namespaces/{namespace}/pods/{name}/log

在這種情況下,“pods” 是名稱空間資源,而“log” 是 pods 的子資源。為了在 RBAC 角色中表示出這一點,我們需要使用斜線來劃分資源 與子資源。如果需要角色繫結主體讀取 pods 以及 pod log,您需要定義以下角色:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]

通過resourceNames列表,角色可以針對不同種類的請求根據資源名引用資源例項。當指定了resourceNames列表時,不同動作 種類的請求的許可權,如使用get、delete、update、patch 等動詞的請求,將被限定到資源列表中所包含的資源例項上。 例如,如果需要限定一個角色繫結主體只能“get” 或者“update” 一個 configmap 時,您可以定義以下角色:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: configmap-updater
rules:
- apiGroups: [""]
  resources: ["configmap"]
  resourceNames: ["my-configmap"]
  verbs: ["update", "get"]

值得注意的是,如果設定了resourceNames,則請求所使用的動詞不能是 list、watch、create 或者 deletecollection。 由於資源名不會出現在 create、list、watch 和 deletecollection 等 API 請求的 URL 中,所以這些請求動詞不會被設定了resourceNames的規則所允許,因為規則中的resourceNames 部分不會匹配這些請求。

更多示例

角色定義示例

  • 允許讀取 core API Group 中定義的資源 pods:
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
  • 允許讀寫在 extensions 和 apps API Group 中定義的 deployments :
rules:
- apiGroups: ["extensions", "apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  • 允許讀取 pods 以及讀寫 jobs :
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["batch", "extensions"]
  resources: ["jobs"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  • 允許讀取一個名為 my-config 的ConfigMap例項(需要將其通過RoleBinding繫結從而限制針對某一個名稱空間中定義的一個ConfigMap例項的訪問):
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["my-config"]
  verbs: ["get"]
  • 允許讀取 core API Group 中的 nodes 資源(由於Node是叢集級別資源,所以此ClusterRole定義需要與一個ClusterRoleBinding繫結才能有效):
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch"]
  • 允許對非資源 endpoint /healthz 及其所有子路徑的 GET 和 POST 請求(此ClusterRole定義需要與一個ClusterRoleBinding繫結才能有效):
rules:
- nonResourceURLs: ["/healthz", "/healthz/*"] # 在非資源 URL 中,'*' 代表字尾萬用字元
  verbs: ["get", "post"]
  • 所有api 訪問許可權
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

角色繫結示例

  • 一個名為 alice@example.com 的使用者:
subjects:
- kind: User
  name: "alice@example.com"
  apiGroup: rbac.authorization.k8s.io
  • 一個名為 frontend-admins 的使用者組:
subjects:
- kind: Group
  name: "frontend-admins"
  apiGroup: rbac.authorization.k8s.io
  • kube-system 名稱空間中的預設服務賬戶:
subjects:
- kind: ServiceAccount
  name: default
  namespace: kube-system
  • 名為 qa 名稱空間中的所有服務賬戶:
subjects:
- kind: Group
  name: system:serviceaccounts:qa
  apiGroup: rbac.authorization.k8s.io
  • 叢集中的所有服務賬戶
subjects:
- kind: Group
  name: system:serviceaccounts
  apiGroup: rbac.authorization.k8s.io
  • 所有認證過的使用者
subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io
  • 所有沒認證的使用者
subjects:
- kind: Group
  name: system:unauthenticated
  apiGroup: rbac.authorization.k8s.io
  • 所有使用者
subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: system:unauthenticated
  apiGroup: rbac.authorization.k8s.io

作者簡介

李嵐清,網易數帆輕舟事業部資深系統開發工程師,具有多年 Kubernetes 開發運維經驗,負責在 / 離線業務混部、容器網路編排等多個專案,推動和協助網易內部多個業務實現容器化。目前專注於雲原生、分散式系統架構等技術領域。

相關文章