Kubernetes Auth¶

Kubernetes 如何管理用户和权限

RBAC¶

提到 k8s 的用户和权限离不开 RBAC。

先简单介绍下 RBAC 是什么

RBAC 就是 Role-based access control,基于角色的访问控制

k8s 中的 RBAC 的核心就两个资源 Role 和 Binding:

  • 同命名空间:Role、RoleBinding
  • 跨命名空间:ClusterRole、ClusterRoleBinding

Role 定义权限,Binding 将 Role 绑定到身份账户(username、usergroup、sa)。

https://s3.laisky.com/uploads/2021/12/role.jpg

Role 定义具体资源的具体权限:

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"]

然后用 RoleBinding 绑定到用户或者 sa:

apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
# You need to already have a Role named "pod-reader" in that namespace.
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
# You can specify more than one "subject"
- kind: User
  name: jane # "name" is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  # "roleRef" specifies the binding to a Role / ClusterRole
  kind: Role #this must be Role or ClusterRole
  name: pod-reader # this must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io

资源(pods 等)通过和 sa 关联来获取权限。

Role 和 RoleBinding 都仅限于某个 namespace,如果要跨 namespace 或者绑定一些集群的非资源(如接口),则需要使用 ClusterRole,ClusterRoleBinding。

看上去除了一些 clusterRole 之类的新概念外并不难。

问题在于,用户在哪?从哪来?

User¶

k8s 的用户体系是一个很有意思的东西,很多人用了很多年可能都没认真想过

虽然 RBAC 的认证对象是用户,但是 k8s 并没有用户体系😂

k8s 的用户体系比较奇特,它内部不存储任何用户信息,一切的身份校验都是围绕以 kube-ca 这个根 CA 为核心的证书签发来实现的。

先来简单回顾下 k8s 的 CA

主要的几个 CA:

  • kubernetes-ca:root ca
  • etcd-ca:和 etcd 相关功能所需的 CA
  • kubernetes-front-proxy-ca(可选):apiserver aggregator 的 CA
  • sa.pub/key:服务账户管理的密钥对

https://s3.laisky.com/uploads/2021/11/certs.png

k8s 里所谓的用户,实际上就是用核心根证书 kubernetes-ca 签发的一个客户端证书

创建一个用户:

# 生成用户私钥
openssl genrsa -out hello.key 2048

# 创建用户的 CSR,指定用户名和 group
openssl req -new -key hello.key -out hello.csr -subj "/CN=hello/O=app1/O=app2"

# 用 kube-ca 这个集群根 CA 签发用户证书
openssl x509 -req -in hello.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out hello.crt -days 500

# 为 kubectl 设置用户
kubectl config set-credentials hello --client-certificate=hello.crt  --client-key=hello.key
kubectl config set-context employee-context --cluster=minikube --namespace=office --user=employee

上述 CSR 就是申请创建一个名为 hello,用户组为 app1 和 app2 的用户。

前面提到过,RBAC 需要用过 RoleBiding 将 Role 绑定到 username/group。

k8s 本身不存储用户,当请求到达 apiserver 时,从证书或 token 中获取 username,然后根据 username 查询相关联的 ClusterRole 和 Role,再根据这些 roles 获取用户的全部权限。

可以通过 kubectl 查询当前用户是否有某个权限 kubectl auth can-i xxx。

没有存储用户信息带来一个恶果就是没法维护用户状态,比如你没法吊销用户身份。

一个曲线的方法是吊销某个用户的 RoleBinding 来解除其权限(虽然能 authenticated 但是无法 authorizated)。这样做的前提是你的 RoleBing 都是绑定到用户而不是绑定到用户组。

要想支持吊销等用户操作,就不能使用默认方案,而要使用外部的 OpenID Connect/webhook 方案。

OpenID Connect/webhook 方案的原理实际上很简单,因为 k8s 不存储用户,所以 k8s 其实只需要知道“用户名”就够了。

如 oidc 方案中,用户通过 oauth2 登陆后,通过 jwt token 告知 k8s 用户的关键信息(username/group)即可。

至于权限,仍然通过 Role/RoleBinding 的形式设置和绑定。

https://s3.laisky.com/uploads/2021/12/openid.png

Authentication & Authorization¶

术语:

  • Authentication:身份校验,确认你确实是一个合法的用户。
  • Authorization(ACL):权限校验,虽然你是合法用户,但是也需要检查你是否有某项操作的权限。

https://s2.laisky.com/uploads/2021/12/api-flow.jpg

可以看到 Authentication 排在最前面,请求到达 apiserver 后,首先需要验明身份。

然后才是一系列准入控制器(admission controllers),可以将其理解为一系列的中间件 MiddleWares。

最后才会触达数据层,也就是 ETCD。

Authorization¶

Authorization 就是指对已经验明身份的用户进行权限校验。

k8s 的权限校验就是 RBAC,前面已经提到过,核心就是这张图

https://s3.laisky.com/uploads/2021/12/role.jpg

Admission Controllers 准入控制器¶

当到达 apiserver 的请求已经通过身份认证和 ACL 后,还会经过一系列的准入控制器(中间件)。

这些准入控制器是编译在 apiserver 的二进制文件中,系统管理员可配置其开启。

https://s3.laisky.com/uploads/2021/12/ac.png

默认开启的准入控制器有:CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, LimitRanger, MutatingAdmissionWebhook, NamespaceLifecycle, PersistentVolumeClaimResize, Priority, ResourceQuota, RuntimeClass, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook。

其中有两个特殊的控制器:

  • MutatingAdmissionWebhook:是第一个执行的控制器,可以修改请求
  • ValidatingAdmissionWebhook:是最末执行的控制器

上述两个 webhook 控制器可以动态调用用户配置的远端第三方 webhook server 实现动态的准入控制。