20221222 13. RBAC
Service Accounts
用户账户与服务账户
Kubernetes 区分用户账户和服务账户的概念主要基于以下原因:
-
User (用户账户) 是针对人而言的。Service Accounts (服务账户) 是针对运行在 pod 中的进程而言的。
-
用户账户是全局性的。 其名称在集群的各个 namespace 中都是全局唯一的,未来的用户资源不会做 namespace 隔离, 服务账户是 namespace 隔离的。
-
通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 (即权限最小化原则 )。
-
对人员和服务账户审计所考虑的因素可能不同。
-
针对复杂系统的配置可能包含系统组件相关的各种服务账户的定义。 因为服务账户可以定制化地创建,并且有 namespace 级别的名称,这种配置是很轻量的。
服务账户的自动化
三个独立组件协作完成服务账户相关的自动化 :
-
服务账户准入控制器(Service account admission controller)
-
Token 控制器(Token controller)
-
服务账户控制器(Service account controller)
服务账户准入控制器
对 pod 的改动通过一个被称为 Admission Controller 的插件来实现。它是 apiserver 的一部分。 当 pod 被创建或更新时,它会同步地修改 pod。 当该插件处于激活状态 ( 在大多数发行版中都是默认的),当 pod 被创建或更新时它会进行以下动作:
-
如果该 pod 没有 ServiceAccount 设置,将其 ServiceAccount 设为 default
-
保证 pod 所关联的 ServiceAccount 存在,否则拒绝该 pod
-
如果 pod 不包含 ImagePullSecrets 设置,那么 将 ServiceAccount 中的 ImagePullSecrets 信息添加到 pod 中
-
将一个包含用于 API 访问的 token 的 volume 添加到 pod 中
-
将挂载于
/var/run/secrets/kubernetes.io/serviceaccount
的 volumeSource 添加到 pod 下的每个容器中。
Token 管理器
Token 管理器是 controller-manager 的一部分。 以异步的形式工作:
-
检测服务账户的创建,并且创建相应的 Secret 以支持 API 访问
-
检测服务账户的删除,并且删除所有相应的服务账户 Token Secret
-
检测 Secret 的增加,保证相应的服务账户存在,如有需要,为 Secret 增加 token
-
检测 Secret 的删除,如有需要,从相应的服务账户中移除引用
你需要通过 --service-account-private-key-file
参数项传入一个服务账户私钥文件至 Token 管理器。 私钥用于为生成的服务账户 token 签名。 同样地,你需要通过 --service-account-key-file
参数将对应的公钥传入 kube-apiserver 。 公钥用于认证过程中的 token 校验。
服务账户管理器
服务账户管理器管理各个命名空间下的服务账户,并且保证每个活跃的命名空间下存在一个名为 default
的服务账户
RBAC
使用 RBAC 鉴权。基于角色(Role)的访问控制(RBAC)是一种基于企业中用户的角色来调节控制对计算机或网络资源的访问方法。 RBAC 使用 rbac.authorization.k8s.io
API 组 来驱动鉴权操作,允许管理员通过 Kubernetes API 动态配置策略。
在 1.8 版本中,RBAC 模式是稳定的并通过 rbac.authorization.k8s.io/v1
API 提供支持。
要启用 RBAC,在启动 API 服务器时添加 --authorization-mode=RBAC
参数。
Role 和 ClusterRole
在 RBAC API 中,一个角色包含一组相关权限的规则。权限是纯粹累加的(不存在拒绝某操作的规则)。
角色可以用 Role 来定义到某个命名空间上, 或者用 ClusterRole 来定义到整个集群作用域。
一个 Role 只可以用来对某一命名空间中的资源赋予访问权限。
下面的 Role 示例定义到名称为 default
的命名空间,可以用来授予对该命名空间中的 Pods 的读取权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 指定核心 API 组
resources: ["pods"]
verbs: ["get", "watch", "list"]
ClusterRole 可以授予的权限和 Role 相同, 但是因为 ClusterRole 属于集群范围,所以它也可以授予以下访问权限:
-
集群范围资源(比如节点(Node))
-
非资源端点(比如
/healthz
) -
跨名字空间访问的名字空间作用域的资源(如 Pod)
比如,你可以使用 ClusterRole 来允许某特定用户执行
kubectl get pods --all-namespaces
下面是一个 ClusterRole 的示例,可用来为任一特定名字空间中的 Secret 授予读访问权限, 或者跨名字空间的访问权限(取决于该角色是如何绑定的):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
name: secret-reader
rules:
- apiGroups: [""]
# 在 HTTP 层面,用来访问 Secret 资源的名称为 "secrets"
resources: ["secrets"]
verbs: ["get", "watch", "list"]
RoleBinding 和 ClusterRoleBinding
角色绑定( RoleBinding )是将角色中定义的权限赋予一个或者一组用户。 它包含若干主体(用户,组和服务账户)的列表和对这些主体所获得的角色的引用。
可以使用 RoleBinding 在指定的命名空间中执行授权, 或者在集群范围的命名空间使用 ClusterRoleBinding 来执行授权。
一个 RoleBinding 可以引用同一的名字空间中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。
下面的例子中的 RoleBinding 将 "pod-reader" Role 授予在 "default" 名字空间中的用户 "jane"。 这样,用户 "jane" 就具有了读取 "default" 名字空间中所有 Pod 的权限。
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pod
# 你需要在该命名空间中有一个名为 “pod-reader” 的 Role
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: jane # "name" 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
RoleBinding 也可以引用 ClusterRole ,对 ClusterRole 所定义的、位于 RoleBinding 命名空间内的资源授权。 这可以允许管理者在 整个集群中定义一组通用的角色,然后在多个命名空间中重用它们