Kubernetes 认证和授权

学习参考:API 访问控制

环境准备

root@master30:~# kubectl create ns auth
root@master30:~# kubectl config set-context --current --namespace auth

访问控制流程

学习参考:Kubernetes API 访问控制

当用户使用User 或 服务账号访问Kubernetes API时,每个请求都会经过多阶段的访问控制之后才会被接受,包括身份认证、鉴权以及准入控制(Admission Control)。

如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

传输安全

默认情况下,Kubernetes API 服务器在第一个非 localhost 网络接口的 6443 端口上进行监听, 受 TLS 保护。在一个典型的 Kubernetes 生产集群中,API 使用 443 端口。 该端口可以通过 --secure-port 进行变更,监听 IP 地址可以通过 --bind-address 标志进行变更。

客户端向 Kubernetes API 服务器发起请求时,**API 服务器出示证书。**该证书可以使用私有证书颁发机构(CA)签名,也可以基于链接到公认的 CA 的公钥基础架构签名。 该证书和相应的私钥可以通过使用 --tls-cert-file 和 --tls-private-key-file 标志进行设置。

如果你的集群使用私有证书颁发机构,你需要在客户端的 ~/.kube/config 文件中提供该 CA 证书的副本, 以便你可以信任该连接并确认该连接没有被拦截。

身份认证

如上图步骤 ① 所示:Kubernetes 操作前首先进行身份认证(Authentication)。

Kubernetes 使用认证模块进行认证,认证模块包含客户端证书、密码、普通令牌、引导令牌和 JSON Web 令牌(JWT,用于服务账号)等。如果 Kubernetes 指定多个认证模块,服务器依次尝试每个验证模块,直到其中一个成功。

  • 如果请求认证通过,下一步对该用户名进行鉴权。
  • 如果请求认证不通过,服务器将以 HTTP 状态码 401 拒绝该请求。

身份认证组件在认证节中有更详细的描述。

鉴权

如上图的步骤 ② 所示,将请求验证为来自特定的用户后,请求必须被鉴权(Authorization)。请求必须包含请求者的用户名、请求的行为以及受该操作影响的对象。 如果现有策略声明用户有权完成请求的操作,那么该请求被鉴权通过。

示例: 以下策略,Bob 只能在 projectCaribou 名称空间中读取 Pod。

apiVersion: abac.authorization.kubernetes.io/v1beta1     # ABAC鉴权策略所属API组与版本,基于属性的访问控制使用该专属API版本
kind: Policy                                              # 资源类型,Policy为ABAC鉴权的策略定义单元,每条规则对应一条鉴权匹配逻辑
spec:                                                     # 策略核心配置段,定义鉴权的匹配属性与权限范围
  user: bob                                               # 用户属性匹配条件;该策略仅对账号名为bob的用户生效,精确匹配用户身份属性
  namespace: projectCaribou                               # 命名空间属性匹配条件;权限仅在projectCaribou命名空间内生效,限定资源作用域
  resource: pods                                          # 资源类型匹配条件;仅对pods资源授予访问权限,不对其他资源生效
  readonly: true                                          # 操作权限标记;true表示仅允许读操作(GET/LIST/WATCH),禁止创建、更新、删除等写操作

  • 如果 Bob 执行以下请求:读取 projectCaribou 名称空间中的对象清单,其鉴权请求将被允许。
apiVersion: authorization.k8s.io/v1beta1     # 授权审查所属API组与beta版本,用于提交权限校验请求,该资源为非持久化的校验请求
kind: SubjectAccessReview                     # 资源类型,主体访问审查;向API Server提交鉴权查询,校验请求主体是否具备对应资源的操作权限
spec:                                         # 审查规则配置段,定义待校验的访问操作属性
  resourceAttributes:                         # 资源类访问属性;描述待校验的资源维度操作请求,用于资源类权限的校验
    namespace: projectCaribou                 # 目标资源所在命名空间;限定本次权限校验的命名空间范围
    verb: get                                 # 待校验的操作动作;get表示读取单个资源实例,对应HTTP GET请求
    group: unicorn.example.org                # 目标资源所属API组;校验自定义API组下的资源权限,核心内置资源对应空字符串
    resource: pods                            # 目标资源类型;本次校验针对pods资源的访问权限

  • 如果 Bob 在 projectCaribou 名字空间中请求写(create 或 update)对象或在其它名字空间中请求读取(get)对象,其鉴权请求会被拒绝。

**注意:**Kubernetes 鉴权要求使用公共 REST 属性与现有的组织范围或云提供商范围的访问控制系统进行交互。 使用 REST 格式很重要,因为这些控制系统可能会与 Kubernetes API 之外的 API 交互。

Kubernetes 支持多种鉴权模块,例如 ABAC 模式、RBAC 模式和 Webhook 模式等。 管理员创建集群时,他们配置应在 API 服务器中使用的鉴权模块。 如果配置了多个鉴权模块,则 Kubernetes 会检查每个模块,任意一个模块鉴权该请求,请求即可继续; 如果所有模块拒绝了该请求,请求将会被拒绝(HTTP 状态码 403)。

要了解更多有关 Kubernetes 鉴权的更多信息,包括有关使用支持鉴权模块创建策略的详细信息, 请参阅鉴权。

准入控制

这一操作如上图的步骤 ③ 所示。

  • 准入控制器对创建、修改、删除或(通过代理)连接对象的请求进行操作。 当有多个准入控制器被配置时,服务器将依次调用它们。准入控制器不会对仅读取对象的请求起作用。准入控制模块是可以修改或拒绝请求的软件模块。 除鉴权模块可用的属性外,准入控制模块还可以访问正在创建或修改的对象的内容。
  • 与身份认证和鉴权模块不同,如果任何准入控制器模块拒绝某请求,则该请求将立即被拒绝。除了拒绝对象之外,准入控制器还可以为字段设置复杂的默认值。
  • 请求通过所有准入控制器后,将使用检验例程检查对应的 API 对象,然后将其写入对象存储(如步骤 4 所示)。

可用的准入控制模块参考 准入控制器。

审计

Kubernetes 审计职责是按时间顺序记录集群中与安全相关的操作。 集群对用户、使用 Kubernetes API 的应用程序以及控制平面本身产生的活动进行审计。

更多信息请参考 审计。

认证管理

学习参考:认证

Kubernetes 中的用户

Kubernetes 集群有两类用户:

  • 普通用户,Kubernetes 中普通用户不是由 kubernetes 直接提供,而是身份认证插件提供,Kubernetes 并不包含用来代表普通用户账号的对象。 普通用户的信息无法通过 API 调用添加到集群中,Kubernetes 认为:能够提供由集群的证书机构签名的合法证书的用户是通过身份认证的用户。 基于这样的机制,Kubernetes 使用证书中的 ‘subject’ 的通用名称(Common Name)字段 (例如,“/CN=bob”)来确定用户名。 接下来,基于角色访问控制(RBAC)子系统会确定用户是否有权针对某资源执行特定的操作。
  • 服务账号,Kubernetes 中服务账号是 Kubernetes API 所管理的用户。它们被绑定到特定的名字空间, 或者由 API 服务器自动创建,或者通过 API 调用创建。服务账号与一组以 Secret 保存的凭据相关,这些凭据会被挂载到 Pod 中,从而允许集群内的进程访问 Kubernetes API。

每个 API 请求必须包含一个用户:普通用户相关或者服务账号,客户端也可以发起匿名请求。这意味着集群内外的每个进程在向 API 服务器发起请求时都必须通过身份认证,否则会被视作匿名用户。

身份认证策略

Kubernetes 通过身份认证插件认证 API 请求的身份。HTTP 请求发给 API 服务器时,插件会将以下属性关联到请求本身:

  • 用户名:用来辩识最终用户的字符串。常见的值可以是 kube-admin 或 jane@example.com。
  • 用户 ID:用来辩识最终用户的字符串,旨在比用户名有更好的一致性和唯一性。
  • 用户组:取值为一组字符串,其中各个字符串用来标明用户是某个命名的用户逻辑集合的成员。 常见的值可能是 system:masters 或者 devops-team 等。
  • 附加字段:一组额外的键-值映射,键是字符串,值是一组字符串; 用来保存一些鉴权组件可能觉得有用的额外信息。

所有(属性)值对于身份认证系统而言都是不透明的, 只有被鉴权组件解释过之后才有意义。

可以同时启用多种身份认证方法,通常至少使用两种方法:

  • 针对服务账号使用服务账号令牌。
  • 至少另外一种方法对用户的身份进行认证,例如X509客户证书。

Kubernetes 默认使用的是服务账号和X509客户证书。本课程深入探讨以上两种方法。

认证插件

Kubernetes支持同时开启多个认证插件,只要有一个认证通过即可。如果认证成功,则用户的username会被传入鉴权模块做进一步鉴权验证;而对于认证失败的请求则返回HTTP 401。

X509 客户证书
  • 客户端用户与Kubernetes交互时候,使用的认证凭据文件.kube/config就是使用X509证书。
  • API Server启动时配置 –client-ca-file=SOMEFILE 参数。
root@master30:~# cat /etc/kubernetes/manifests/kube-apiserver.yaml |\ grep -- --client-ca-file - --client-ca-file=/etc/kubernetes/pki/ca.crt
静态令牌文件
  • API Server启动时配置 –token-auth-file=SOMEFILE 参数。
root@master30:~# cat /etc/kubernetes/manifests/kube-apiserver.yaml |\ grep -- --token-auth-file

默认未启用。

  • 文件为 csv格式,每行至少包括三列 token,username,user id。第四列为可选group 名项。如果有多个group名,列必须用””双引号包含其中,例如:
token,user,uid,"group1,group2,group3"
启动引导令牌
  • 为了支持平滑地启动引导新的集群,Kubernetes 包含了一种动态管理的持有者令牌类型, 称作 启动引导令牌(Bootstrap Token)。 这些令牌以 Secret 的形式保存在 kube-system 名字空间中,可以被动态管理和创建。 使用 kubeadm 引导和管理集群时,kubeadm 会自动完成这些设置。
  • 你必须在 API 服务器上设置 --enable-bootstrap-token-auth 标志来启用基于启动引导令牌的身份认证组件。
root@master30:~# cat /etc/kubernetes/manifests/kube-apiserver.yaml |\ grep bootstrap - --enable-bootstrap-token-auth=true
  • 请参阅启动引导令牌, 以了解关于启动引导令牌身份认证组件详细信息。
服务账号令牌
  • 服务账号(Service Account)是一种自动被启用的用户认证机制,使用经过签名的持有者令牌来验证请求。
  • 服务账号通常由 API 服务器自动创建并通过 ServiceAccount 准入控制器关联到集群中运行的 Pod 上。 持有者令牌会挂载到 Pod 中可预知的位置,允许集群内进程与 API 服务器通信。
  • 服务账号也可以使用 Pod 规约的 serviceAccountName 字段显式地关联到 Pod 上。
Webhook 令牌身份认证

Webhook 身份认证是一种用来验证持有者令牌的回调机制。

身份认证代理

API 服务器可以配置成从请求的头部字段值(如 X-Remote-User)中辩识用户。 这一设计是用来与某身份认证代理一起使用 API 服务器,代理负责设置请求的头部字段值。

basic-auth-file认证

在kubernetes 1.19 及之后的版本中,kubernetes放弃了 basic-auth-file 认证方式。

匿名请求

如果请求没有被已配置的身份认证方法拒绝, 则被视作匿名请求(Anonymous Requests)。这类请求获得用户名 system:anonymous 和对应的用户组 system:unauthenticated。

  • 在 1.5.1-1.5.x 版本中,匿名访问默认情况下是被禁用的,可以通过为 API 服务器设定 --anonymous-auth=true 来启用。
  • 在 1.6 及之后版本中,如果所使用的鉴权模式不是 AlwaysAllow,则匿名访问默认是被启用的。 从 1.6 版本开始,ABAC 和 RBAC 鉴权模块要求对 system:anonymous 用户或者 system:unauthenticated 用户组执行显式的权限判定,所以之前的为用户 * 或用户组 * 赋予访问权限的策略规则都不再包含匿名用户。

**例如,**在一个配置了令牌身份认证且启用了匿名访问的服务器上,如果请求提供了非法的持有者令牌, 则会返回 401 Unauthorized 错误。如果请求没有提供持有者令牌,则被视为匿名请求。

创建账户

以下探讨使用 X509客户证书 插件管理用户。

客户端准备

客户端要想访问集群,必须安装与集群版本一致的kubectl工具。

root@client:~# apt install -y kubectl=1.30.2-1.1

准备申请材料

# 创建私钥
root@client:~# openssl genrsa -out cyw.key 2048

# 根据私钥,创建请求证书
root@client:~# openssl req -new -key cyw.key -out cyw.csr -subj '/CN=cyw/O=kubernets'
# 参数说明:
## C,Country,代表国家
## ST,STate,代表省份
## L,Location,代表城市
## O,Organization,代表组织,公司
## OU,Organization Unit,代表部门
## CN,Common Name,代表服务器域名
## emailAddress,代表联系人邮箱地址。

# 其他示例:
root@client:~# openssl req -new -key servera.key -out servera.csr -subj "/C=CHINA/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=servera.lab.example.com/emailAddress=cyw@lab.example.com"

# 客户端将自己请求证书发给kubernetes管理员
root@client:~# scp cyw.csr root@master30:
创建用户凭据

管理员使用以下资源文件创建用户的kubeconfig。

# 使用ca.crt和ca.key签名cyw.csr,得到cyw.crt证书
root@master30:~# openssl x509 -req -in cyw.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out cyw.crt -days 1095

# 导出kubeconfig模版
root@master30:~# kubectl config view > config.tpl

# 将kubeconfig模板、cyw.crt和kubernetes的ca证书发给客户端
root@master30:~# scp config.tpl cyw.crt /etc/kubernetes/pki/ca.crt root@client:~
创建 kubeconfig

kubeconfig创建方法:

  • **方法一:**使用kubectl config命令创建。

修改模版config.tpl,结果如下:

apiVersion: v1     # kubeconfig配置文件的API版本,属于核心组v1版本
clusters:          # 集群配置列表;定义所有可连接的Kubernetes集群的API Server地址与集群侧认证参数
- cluster:         # 单个集群的配置项
    server: https://10.1.8.30:6443     # 集群API Server的访问地址;HTTPS协议,IP为10.1.8.30,端口为Kubernetes默认6443,是kubectl与集群交互的入口端点
  name: kubernetes     # 该集群配置的别名;用于在上下文中引用,可自定义命名区分不同集群
contexts:          # 上下文配置列表;上下文是「集群地址+用户身份+默认命名空间」的组合,用于快速切换不同的访问环境
- context:         # 单个上下文的配置项
    cluster: kubernetes     # 关联的集群名称;对应上方clusters中定义的集群别名
    namespace: default      # 该上下文的默认命名空间;kubectl执行命令不指定-n时,默认作用于该命名空间
    user: cyw               # 关联的用户身份;对应下方users中定义的用户凭证
  name: cyw@kubernetes      # 该上下文的别名;可通过kubectl config use-context切换使用该访问配置
current-context: cyw@kubernetes     # 当前生效的上下文;kubectl默认使用该上下文对应的集群、用户身份执行操作
kind: Config        # 资源类型,Config表示这是kubectl客户端配置文件,不属于集群API资源对象
users:              # 用户身份配置列表;定义访问集群的用户认证凭证,通常包含客户端证书、Bearer Token、用户名密码等信息
- name: cyw         # 用户身份的别名;对应上下文中引用的用户名称,可自定义命名

# 设置 cluster
root@client:~# mv config.tpl config
root@client:~# kubectl config set-cluster kubernetes --kubeconfig=config --certificate-authority=ca.crt --embed-certs 

# --kubeconfig指定kubeconfig文件
# --server指定kubernetes服务器认证地址
# --certificate-authority选项指定ca证书
# --embed-certs选项作用是将ca.crt的内容添加到config文件中,
# 如果没有该选项,则添加 --certificate-authority 选项指定的路径,也就是ca.crt

# 设置credentials
root@client:~# kubectl config set-credentials cyw --kubeconfig=config --client-key=cyw.key --client-certificate=cyw.crt --embed-certs

# --client-key 指定用户私钥
# --client-certificate 指定服务器为用户生成的证书

# 设置context
root@client:~# kubectl config set-context cyw --kubeconfig=config --namespace=default --cluster=kubernetes --user=cyw
# --namespace指定Namespace
# --cluster指定集群
# --user指定用户

# 授权用户cyw集群管理员角色,后续详细讲解角色管理
root@master30:~# kubectl create clusterrolebinding cyw-admin --clusterrole=cluster-admin --user=cyw

# 验证结果
root@client:~# kubectl get nodes --kubeconfig=config --context default
NAME                  STATUS   ROLES           AGE   VERSION
master30.cyw.cloud   Ready    control-plane   40h   v1.30.2
worker31.cyw.cloud   Ready    <none>          40h   v1.30.2
worker32.cyw.cloud   Ready    <none>          40h   v1.30.2
  • **方法二:**使用文本编辑器创建(不推荐)。
# 获取文件ca.crt base64编码,填充到certificate-authority-data
root@client:~# cat ca.crt | base64 | tr -d '\n'

# 获取文件cyw.key base64编码,填充到client-key-data
root@client:~# cat cyw.key | base64 | tr -d '\n'

# 获取文件cyw.crt base64编码,填充到client-certificate-data
root@client:~# cat cyw.crt | base64 | tr -d '\n'

# 使用上面的base64编码修改配置文件对应值
root@master30:~# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://10.1.8.30:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-cyw
  name: kubernetes-cyw@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-cyw
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

删除账户

# 通过删除证书进行删除账户即可,为了后续操作方便,该账户不删除

# k8s删除用户csr资源后,客户端用户仍可以访问集群。
# 解释:用户认证功能由x509提供,与k8s无关。
# 如果不予许用户登录,应该从x509认证机制方面下手,例如ca.crt将相应客户端csr加入黑名单。

# 删除权限
root@master30:~# kubectl delete clusterrolebindings.rbac.authorization.k8s.io cyw-admin

# 验证权限
root@client:~# kubectl get nodes
Error from server (Forbidden): nodes is forbidden: User "cyw" cannot list resource "nodes" in API group "" at the cluster scope

授权管理

学习参考:鉴权、使用 RBAC 鉴权

鉴权概述

Kubernetes API 服务器对 API 请求进行鉴权。 它根据所有策略评估所有请求属性来决定允许或拒绝请求。 一个 API 请求的所有部分都必须被某些策略允许才能继续。 这意味着默认情况下拒绝权限。

当系统配置了多个鉴权模块时,Kubernetes 将按顺序使用每个模块。

  • 如果任何鉴权模块批准或拒绝请求,则立即返回该决定,并且不会与其他鉴权模块协商。
  • 如果所有模块对请求没有意见,则拒绝该请求。 被拒绝响应返回 HTTP 状态代码 403。

鉴权模式

鉴权模式定义认证成功的用户对集群的操作权限。

Kubernetes 鉴权模式由kube-apiserver配置文件指定:

root@master30:~# cat /etc/kubernetes/manifests/kube-apiserver.yaml |grep mode
    - --authorization-mode=Node,RBAC

Kubernetes 使用RBAC和Node模式。

支持以下模式:

  • Node,是节点专用的鉴权模式,根据调度到 kubelet 上运行的 Pod 为 kubelet 授予权限。 要了解有关使用节点鉴权模式的更多信息,请参阅节点鉴权。
  • ABAC,基于属性的访问控制(ABAC)定义了一种访问控制范型,通过使用将属性组合在一起的策略, 将访问权限授予用户。策略可以使用任何类型的属性(用户属性、资源属性、对象,环境属性等)。 要了解有关使用 ABAC 模式的更多信息,请参阅 ABAC 模式。
  • RBAC,基于角色的访问控制(RBAC) 是一种基于企业内个人用户的角色来管理对计算机或网络资源的访问的方法。要了解有关使用 RBAC 模式的更多信息,请参阅 RBAC 模式。
  • 被启用之后,RBAC(基于角色的访问控制)使用 rbac.authorization.k8s.io API 组来驱动鉴权决策,从而允许管理员通过 Kubernetes API 动态配置权限策略。
  • 要启用 RBAC,请使用 --authorization-mode = RBAC 启动 API 服务器。
  • Webhook —— WebHook 是一个 HTTP 回调:发生某些事情时调用的 HTTP POST; 通过 HTTP POST 进行简单的事件通知。 实现 WebHook 的 Web 应用程序会在发生某些事情时将消息发布到 URL。 要了解有关使用 Webhook 模式的更多信息,请参阅 Webhook 模式。
  • AlwaysAllow,允许用户所有请求。
# 前面我们删除了用户cyw权限,更改为AlwaysAllow模式,测试cyw用户权限。
root@master30:~# vim /etc/kubernetes/manifests/kube-apiserver.yaml
......
spec:
  containers:
  - command:
    - --authorization-mode=AlwaysAllow
......

# 更改完成后,kubernetes会自动重启pod/kube-apiserver,等该pod状态为running再次验证。
root@client:~# kubectl get nodes
NAME                   STATUS   ROLES           AGE   VERSION
master30.cyw.cloud   Ready    control-plane   12d   v1.30.2
worker31.cyw.cloud   Ready    <none>          12d   v1.30.2
worker32.cyw.cloud   Ready    <none>          12d   v1.30.2
  • AlwaysDeny,拒绝用户所有请求,不管用户是否具有权限,但不限制admin用户。

role 管理

kubernetes 方便管理权限,将一组特定权限赋予角色,然后将角色赋予用户,那么用户将继承该角色具有的权限。

角色分类
  • role,namespace 角色,限定用户访问特定namespace。role绑定给用户,称之为rolebinding。
  • clusterrole,cluster 角色,可以管理集群,包括所有namespace中资源。clusterrole绑定给用户,称之为clusterrolebinding。

权限由kubernetes系统预定义的,clusterroles/admin中包涵系统中全部权限列表。

root@master30:~# kubectl describe clusterroles admin
Name:         admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources                                       Non-Resource URLs  Resource Names  Verbs
  ---------                                       -----------------  --------------  -----
  rolebindings.rbac.authorization.k8s.io          []                 []              [create delete deletecollection get list patch update watch]
  roles.rbac.authorization.k8s.io                 []                 []              [create delete deletecollection get list patch update watch]
  configmaps                                      []                 []              [create delete deletecollection patch update get list watch]
  endpoints                                       []                 []              [create delete deletecollection patch update get list watch]
......

输出说明:

  • Resources:代表系统中资源类型,例如Secret,Configmap等。

  • Resource Names:代表特定资源。如果Resources是Secret,那么这里就指特定Secret。

  • Non-Resource URLs: 被称为非资源URL或虚拟URL对象,是k8s中所需要的特殊动作(不需要关注)。

  • Verbs:代表针对资源执行的动作,包括操作get、list、create、delete、update、edit、watch、exec。

  • get,用于获得特定资源信息,例如,针对pod,可以执行GET /api/v1/namespaces/{namespace}/pods/{podname}。

    ```bash root@client:~# kubectl get pod -n kube-system Error from server (Forbidden): pods is forbidden: User “cyw” cannot list resource “pods” in API group “” in the namespace “kube-system”

    root@client:~# kubectl get pod kube-proxy-8kp8w -n kube-system NAME READY STATUS RESTARTS AGE kube-proxy-8kp8w 1/1 Running 4 52d ```

  • list,用户查看某一类型资源清单,例如针对pod,可以执行GET /api/v1/namespaces/{namespace}/pods。

    ```bash root@client:~# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-6dfcd885bf-lq4n5 1/1 Running 4 52d calico-node-44cf4 1/1 Running 4 52d calico-node-48sm4 1/1 Running 4 52d …

    root@client:~# kubectl get pod kube-proxy-8kp8w -n kube-system Error from server (Forbidden): pods “kube-proxy-8kp8w” is forbidden: User “cyw” cannot get resource “pods” in API group “” in the namespace “kube-system” ```

    更多API信息参考:https://kubernetes.io/docs/reference/kubernetes-api/

创建 role
root@master30:~# kubectl create role -h
Create a role with single rule.

Usage:
  kubectl create role NAME --verb=verb --resource=resource.group/subresource
[--resource-name=resourcename] [--dry-run=server|client|none] [options]

示例1:可以对项目中所有pods执行get、list、watch操作

root@master30:~# kubectl create role pod-role --verb=get,list,watch --resource=pods -n default --dry-run=client -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: pod-role
  namespace: default
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
root@master30:~# kubectl create role pod-role --verb=get,list,watch --resource=pods -n default

root@master30:~# kubectl get roles pod-role -n default
NAME         CREATED AT
pod-role   2021-08-24T10:24:36Z

root@master30:~# kubectl describe roles pod-role -n default
Name:         pod-role
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods       []                 []              [get list watch]

示例2:访问特定资源pods/readablepod

root@master30:~# kubectl create role pod-role --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod -n default

示例3:可以对项目中所有replicasets执行get list watch操作

root@master30:~# kubectl create role foo --verb=get,list,watch --resource=replicasets -n default
修改 role
# 增加create权限
root@master30:~# kubectl edit roles -n default pod-role
......
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
# 在verbs下添加相应权限
  - list
  - get
  - watch
  - create
apiGroups
  • 角色的 rules 属性中 apiGroups 默认为空。
  • pod、service 资源的 apiVersion 是v1,apiGroups为""。
  • Deployment、DaemonSet 资源的 apiVersion 是apps/v1,apiGroups为"apps"。如下:
apiVersion: rbac.authorization.k8s.io/v1     # RBAC授权API组的稳定版本,角色与角色绑定资源均使用该版本
kind: Role                                   # 资源类型,Role为命名空间级权限角色,仅在指定命名空间内生效,用于定义该命名空间下的资源访问权限集合
metadata:                                    # 元数据区块,定义角色的标识属性与生效范围
  creationTimestamp: null                    # 创建时间戳;静态清单定义时置空,资源创建到集群后由API Server自动填充
  name: deployments-role                     # 角色名称,命名空间内唯一标识,供RoleBinding资源引用以绑定到用户/服务账号
  namespace: default                         # 角色生效的命名空间;该角色定义的所有权限仅在default命名空间内有效,无法跨命名空间使用
rules:                                       # 权限规则列表;可配置多条规则,每条规则定义一组API组、资源与操作权限的组合,多条规则权限累加生效
- apiGroups:                                 # 规则匹配的API组列表;指定权限作用的资源所属API分组
  - "apps"                                   # apps API组;Deployment、StatefulSet、DaemonSet等工作负载资源均归属于该API组
  resources:                                 # 规则匹配的资源类型列表;指定权限作用的具体资源对象
  - deployments                              # deployments资源;授予对Deployment工作负载对象的操作权限
  verbs:                                     # 允许执行的操作动作列表;定义对上述资源可执行的访问操作
  - get                                      # 读取单个资源;允许查询指定名称的Deployment详情
  - list                                     # 列表查询;允许列出命名空间内所有的Deployment资源条目
  - watch                                    # 监听变更;允许持续监听Deployment资源的创建、更新、删除事件

**示例1:**定义角色,无法操作deployments,因为apiGroups未指定apps。

apiVersion: rbac.authorization.k8s.io/v1     # RBAC授权API组的稳定版本,角色与角色绑定资源均使用该版本
kind: Role                                   # 资源类型,Role为命名空间级权限角色,仅在指定命名空间内生效
metadata:                                    # 元数据区块,定义角色的标识属性与生效范围
  creationTimestamp: null                    # 创建时间戳;静态清单定义时置空,资源创建到集群后由API Server自动填充
  name: deployments-role                     # 角色名称,命名空间内唯一标识,供RoleBinding资源引用以绑定到用户/服务账号
  namespace: default                         # 角色生效的命名空间;该角色定义的所有权限仅在default命名空间内有效
rules:                                       # 权限规则列表;可配置多条规则,多条规则权限累加生效
- apiGroups:                                 # 规则匹配的API组列表;指定权限作用的资源所属API分组
  - ""                                       # 空字符串代表核心(core) API组,对应v1版本原生资源,如pods、services、configmaps等
  resources:                                 # 规则匹配的资源类型列表;指定权限作用的具体资源对象
  - deployments                              # deployments工作负载资源
  verbs:                                     # 允许执行的操作动作列表;定义对上述资源可执行的访问操作
  - get                                      # 读取单个资源;允许查询指定名称的资源详情
  - list                                     # 列表查询;允许列出命名空间内所有对应资源条目
  - watch                                    # 监听变更;允许持续监听资源的创建、更新、删除事件

**示例2:**定义一个可以 scale deployments 的角色。

apiVersion: rbac.authorization.k8s.io/v1     # RBAC授权API组的稳定版本,角色与角色绑定等权限资源均使用该版本
kind: Role                                   # 资源类型,Role为命名空间级权限角色,仅在指定命名空间内生效,定义该命名空间下的资源访问权限集合
metadata:                                    # 元数据区块,定义角色的标识属性与生效范围
  creationTimestamp: null                    # 创建时间戳;静态清单定义时置空,资源创建到集群后由API Server自动填充
  name: deployments-role                     # 角色名称,命名空间内唯一标识,供RoleBinding资源引用以绑定到用户/服务账号
  namespace: default                         # 角色生效的命名空间;该角色定义的所有权限仅在default命名空间内有效,无法跨命名空间使用
rules:                                       # 权限规则列表;可配置多条规则,多条规则的权限累加生效
- apiGroups:                                 # 规则匹配的API组列表;指定权限作用的资源所属API分组
  - "apps"                                   # apps API组;Deployment、StatefulSet、DaemonSet等工作负载资源均归属于该API组
  resources:                                 # 规则匹配的资源类型列表;指定权限作用的具体资源对象,支持主资源与子资源单独授权
  - deployments                              # deployments主资源;授予对Deployment工作负载完整对象的访问权限
  # 额外添加以下资源
  - deployments/scale                        # deployments的scale子资源;对应Deployment副本数扩缩容的专属接口,需单独授权,管控扩缩容操作权限,与主资源权限相互独立
  verbs:                                     # 允许执行的操作动作列表;定义对上述资源可执行的访问操作
  - get                                      # 读取单个资源;允许查询指定Deployment的详情与当前副本数配置
  - list                                     # 列表查询;允许列出命名空间内所有Deployment资源条目
  - watch                                    # 监听变更;允许持续监听Deployment资源的创建、更新、删除事件
  # 额外添加以下权限
  - patch                                    # 部分更新操作;允许通过PATCH接口增量修改资源,此处可用于调整Deployment副本数实现扩缩容,也可部分更新Deployment的其他配置字段

**示例3:**定义一个对不同类型资源赋予不同权限的角色。

apiVersion: rbac.authorization.k8s.io/v1     # RBAC授权API组的稳定版本,角色与角色绑定等权限资源均使用该版本
kind: Role                                   # 资源类型,Role为命名空间级权限角色,仅在指定命名空间内生效,定义该命名空间下的资源访问权限集合
metadata:                                    # 元数据区块,定义角色的标识属性与生效范围
  creationTimestamp: null                    # 创建时间戳;静态清单定义时置空,资源创建到集群后由API Server自动填充
  name: all-role                             # 角色名称,命名空间内唯一标识,供RoleBinding资源引用以绑定到用户/服务账号
  namespace: default                         # 角色生效的命名空间;该角色定义的所有权限仅在default命名空间内有效,无法跨命名空间使用
rules:                                       # 权限规则列表;可配置多条规则,多条规则的权限累加生效
- apiGroups:                                 # 第一条规则:核心资源权限配置
  - ""                                       # 空字符串代表核心(core) API组,对应v1版本原生资源,如Pod、Service、ConfigMap等
  resources:                                 # 规则匹配的资源类型列表
  - pods                                     # pods资源;授予对Pod对象的访问权限
  verbs:                                     # 允许执行的操作动作列表
  - get                                      # 读取单个Pod详情
  - list                                     # 列出命名空间内所有Pod条目
  - watch                                    # 持续监听Pod资源的创建、更新、删除事件
- apiGroups:                                 # 第二条规则:工作负载资源权限配置
  - "apps"                                   # apps API组;Deployment、StatefulSet、DaemonSet等工作负载资源均归属于该API组
  resources:                                 # 规则匹配的资源类型列表,支持主资源与子资源单独授权
  - deployments                              # deployments主资源;授予对Deployment工作负载完整对象的访问权限
  - deployments/scale                        # deployments的scale子资源;对应Deployment副本数扩缩容的专属接口,需单独授权,与主资源权限相互独立
  verbs:                                     # 允许执行的操作动作列表
  - get                                      # 读取单个Deployment详情与副本配置
  - list                                     # 列出命名空间内所有Deployment资源条目
  - watch                                    # 持续监听Deployment资源的变更事件
  - patch                                    # 部分更新操作;允许通过PATCH接口增量修改资源,可用于调整Deployment副本数实现扩缩容,也可部分更新Deployment的其他配置字段

常见apiGroups

TypeapiVersionapiGroups
Pod、Service、PersistentVolume、PersistentVolumeClaimv1“”
Deployment、DaemonSet、StatefulSetsapps/v1apps
Jobbatch/v1batch
CronJobbatch/v1beta1batch
Role RoleBinding ClusterRole ClusterRoleBindingrbac.authorization.k8s.io/v1rbac.authorization.k8s.io
NetworkPolicynetworking.k8s.io/v1networking.k8s.io

每种类型资源的 apiVersion 都可以通过以下命令查询:

# 查询Deployment资源对应的API版本;explain输出资源完整定义文档,grep过滤提取版本关键字行
root@master30:~# kubectl explain deployment|grep VERSION
VERSION:  apps/v1     # Deployment归属apps API组的v1稳定版本,是当前生产环境的标准正式版本

# 查询NetworkPolicy资源对应的API版本;查看网络策略资源的API归属分组与版本号
root@master30:~# kubectl explain networkpolicy|grep VERSION
VERSION:  networking.k8s.io/v1     # 网络策略归属networking.k8s.io API组的v1稳定版本

# 枚举集群全部API资源并筛选Deployment条目;api-resources列出所有支持的资源类型,-i忽略大小写匹配
root@master30:~/auth# kubectl api-resources |grep -i deploy
deployments                       deploy       apps/v1                                true         Deployment
# 输出字段依次说明:资源全名、资源简称、API版本、是否为命名空间级资源、资源Kind名称;deploy是Deployment的通用简写

role 绑定

将 role 绑定给用户。

root@master30:~# kubectl create rolebinding default-pod-cyw -n default --role=pod-role --user=cyw --dry-run=client -o yaml
# 注意:--user选项和--username选项是不同效果。
--username  (Username for basic authentication to the API server)
--user      (Usernames to bind to the role.)

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: null
  name: default-pod-cyw
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-role
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: cyw
# 绑定 ns/default 中角色 pod-role 给 cyw
root@master30:~# kubectl create rolebinding default-pod-cyw -n default --role=pod-role --user=cyw
# 角色绑定完成后,角色的权限发生变化,用户获得的权限也会跟着动态变化。

root@master30:~# kubectl get rolebindings -n default default-pod-cyw 
NAME                    ROLE              AGE
default-pod-cyw   Role/pod-role   2m15s

root@master30:~# kubectl describe rolebindings -n default default-pod-cyw 
Name:         default-pod-cyw
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  pod-role
Subjects:
  Kind  Name   Namespace
  ----  ----   ---------
  User  cyw 

# 验证
root@client:~# kubectl run web --image=hub.cyw.cloud/library/httpd --image-pull-policy=IfNotPresent -n default --kubeconfig=config

root@client:~# kubectl get pod -n default --kubeconfig=config
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          2m30s


root@client:~# kubectl get pod -n default -w --kubeconfig=config
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          2m42s
role 回收
root@master30:~# kubectl delete rolebindings default-pod-cyw -n default
rolebinding.rbac.authorization.k8s.io "default-pod-cyw" deleted

# 再次验证
root@client:~# kubectl get pod -n default
Error from server (Forbidden): pods is forbidden: User "cyw" cannot list resource "pods" in API group "" in the namespace "default"
role 删除
root@master30:~# kubectl delete roles pod-role -n default

clusterrole 管理

常见 clusterrole

kubernetes系统中已经预定义了很多clusterrole,常见的clusterrole如下:

  • view,对系统中几乎所有的对象都有get、list和watch权限。
  • edit,对系统中几乎所有的对象都有get、list和watch权限。其中部分对象额外具有 create、delete、deletecollection、patch、update 权限。
  • admin,对系统中大部分的对象具有所有权限。
  • cluster-admin,对系统中所有的对象具有所有权限。
创建 clusterrole
root@master30:~# kubectl create clusterrole -h
Usage:
  kubectl create clusterrole NAME --verb=verb --resource=resource.group
[--resource-name=resourcename] [--dry-run=server|client|none] [options]

示例1:创建一个可以get、list、watch所有项目中pods的clusterrole

# 客户端模拟生成集群角色YAML模板;create clusterrole创建集群级权限角色,--verb指定允许的操作集合,--resource指定授权资源类型,--dry-run=client本地校验不提交集群,-o yaml输出完整YAML清单
root@master30:~# kubectl create clusterrole pod-role --verb=get,list,watch --resource=pods --dry-run=client -o yaml
apiVersion: rbac.authorization.k8s.io/v1     # RBAC授权API组稳定版本,集群角色与集群角色绑定均使用该版本
kind: ClusterRole                            # 资源类型,ClusterRole为集群级权限角色,权限在整个集群范围内生效,不受命名空间限制
metadata:
  creationTimestamp: null                    # 创建时间戳;dry-run生成时置空,实际创建到集群后由API Server自动填充
  name: pod-role                             # 集群角色名称,集群范围内唯一标识,供ClusterRoleBinding资源引用
rules:                                       # 权限规则列表,多条规则权限累加生效
- apiGroups:
  - ""                                       # 空字符串代表核心(core) API组,Pod属于核心组v1原生资源
  resources:
  - pods                                     # 授权作用的资源类型为pods
  verbs:
  - get                                      # 允许读取单个Pod的详情信息
  - list                                     # 允许列出全集群范围内所有Pod条目
  - watch                                    # 允许持续监听全集群Pod的创建、更新、删除事件

# 正式创建集群角色资源;移除dry-run参数后向API Server提交请求,在集群中正式创建pod-role角色
root@master30:~# kubectl create clusterrole pod-role --verb=get,list,watch --resource=pods

# 查询集群角色基础信息;get clusterrole查看指定角色的名称与创建时间,验证资源是否创建成功
root@master30:~# kubectl get clusterrole pod-role
NAME       CREATED AT
pod-role   2021-08-25T14:31:21Z     # 输出角色名称与UTC创建时间戳,资源已正常创建

# 查看集群角色详细权限配置;describe输出角色完整的权限规则明细,核对授权范围与操作权限
root@master30:~# kubectl describe clusterrole pod-role
Name:         pod-role     # 集群角色名称
Labels:       <none>       # 角色标签集合,当前未配置任何标签
Annotations:  <none>       # 角色注解集合,当前未配置任何注解
PolicyRule:                # 权限规则汇总表头
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods       []                 []              [get list watch]
  # 字段说明:Resources为授权的资源类型;Non-Resource URLs为非资源路径授权,此处为空;Resource Names为指定名称授权,此处为空表示匹配所有Pod;Verbs为允许执行的操作动作集合

示例2:创建一个可以get、list、watch所有项目中pods/readablepod和pods/anotherpod的clusterrole

root@master30:~# kubectl create clusterrole pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod

示例3:创建一个可以get、list、watch所有项目中pods和pods/status的clusterrole

root@master30:~# kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status
修改 clusterrole
root@master30:~# kubectl edit clusterrole pod-role
......
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
  # 添加create权限
  - create
clusterrole 绑定

clusterrole有两种绑定模式:

  • ClusterRoleBinding:全局绑定 → ClusterRole 权限所有命名空间生效
  • RoleBinding:命名空间内绑定 → ClusterRole 仅在当前这个命名空间生效

示例:创建clusterrolebinding将clusterrole绑定给用户。

# 客户端模拟生成集群角色绑定YAML模板;创建集群级角色绑定,将指定集群角色授权给目标用户,--dry-run=client本地校验不提交集群,-o yaml输出完整资源清单
root@master30:~# kubectl create clusterrolebinding cyw-pod-role --clusterrole=pod-role --user=cyw --dry-run=client -o yaml
apiVersion: rbac.authorization.k8s.io/v1     # RBAC授权API组稳定版本,集群角色绑定使用该版本
kind: ClusterRoleBinding                     # 资源类型,集群角色绑定;将集群级角色权限授予指定主体,权限在全集群范围内生效
metadata:
  creationTimestamp: null                    # 创建时间戳;dry-run生成时置空,实际创建后由API Server自动填充
  name: cyw-pod-role                         # 集群角色绑定名称,集群范围内唯一标识
roleRef:                                     # 角色引用配置;指定要绑定的权限角色,该字段创建后不可修改
  apiGroup: rbac.authorization.k8s.io        # 角色所属API组,固定为rbac授权组
  kind: ClusterRole                          # 角色类型;此处绑定集群级ClusterRole,对应全集群权限
  name: pod-role                             # 目标角色名称;将pod-role集群角色的权限授予下方主体
subjects:                                    # 授权主体列表;可包含用户、服务账号、用户组,多个主体共享该角色权限
- apiGroup: rbac.authorization.k8s.io        # 主体所属API组;用户类型主体归属rbac授权组
  kind: User                                 # 主体类型;User表示授权给普通用户账号
  name: cyw                                  # 目标用户名;将集群角色权限授予cyw用户

# 正式创建集群角色绑定资源;移除dry-run参数后向API Server提交请求,完成角色与用户的授权绑定
root@master30:~# kubectl create clusterrolebinding cyw-pod-role --clusterrole=pod-role --user=cyw

# 查询集群角色绑定基础信息;查看指定绑定的名称、关联角色与存活时长,验证创建结果
root@master30:~# kubectl get clusterrolebinding cyw-pod-role
NAME             ROLE                   AGE
cyw-pod-role   ClusterRole/pod-role   35s     # 输出说明:绑定名称、关联的集群角色、资源已创建35秒

# 查看集群角色绑定详细配置;describe输出完整的角色引用与授权主体明细
root@master30:~# kubectl describe clusterrolebinding cyw-pod-role
Name:         cyw-pod-role     # 绑定资源名称
Labels:       <none>           # 资源标签,当前未配置
Annotations:  <none>           # 资源注解,当前未配置
Role:                           # 关联角色信息
  Kind:  ClusterRole            # 角色类型为集群角色
  Name:  pod-role               # 关联的角色名称为pod-role
Subjects:                       # 授权主体列表
  Kind  Name   Namespace
  ----  ----   ---------
  User  cyw                     # 授权主体为用户cyw,集群级绑定无命名空间限制

# client节点使用cyw用户测试权限;指定自定义kubeconfig文件,验证RBAC授权是否生效
root@client:~# kubectl get pod -n kube-system --kubeconfig=config
NAME                                        READY   STATUS    RESTARTS   AGE
calico-kube-controllers-6dfcd885bf-lq4n5    1/1     Running   6          53d
calico-node-44cf4                           1/1     Running   6          53d
......
# 验证结果:可正常查看kube-system命名空间的Pod,集群级角色权限跨命名空间生效

# 测试default命名空间Pod查看权限;验证全命名空间的Pod读取权限均已正常授权
root@client:~# kubectl get pod -n default  --kubeconfig=config
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   1          15h
# 验证结果:可正常查看default命名空间的Pod,RBAC集群角色授权生效

clusterrole 回收
root@master30:~# kubectl delete clusterrolebinding cyw-pod-role
删除 clusterrole
root@master30:~# kubectl delete clusterrole pod-reader

服务账户

学习参考:管理服务账号、配置服务账号

服务账户概述

Service Account,即服务账户,pod 使用 Service Account 身份运行容器。赋予Service Account相应角色,则使用该Service Account身份运行的pod中进程将具有对应Service Account的权限,进而有权限管理Kubernetes集群。

在每个namespace中都有一个名称为default的Service Account,创建的pod都会以 Service Account-default身份运行。

root@master30:~# kubectl get sa
NAME      SECRETS   AGE
default   1         53d

# 创建一个pod,验证Service Account信息
root@master30:~# kubectl run web --image hub.cyw.cloud/library/httpd --image-pull-policy IfNotPresent
root@master30:~# kubectl get pod web -o yaml|grep serviceAccount
  serviceAccount: default
  serviceAccountName: default
      - serviceAccountToken:

服务账号与用户账号比较

Kubernetes 区分用户账号和服务账号的概念,主要基于以下原因:

类别用户账号服务账号
使用主体针对人针对Pod, Pod 中的应用程序通过服务账号访问集群。
范围集群范围,集群中的用名称必须唯一。命名空间范围,两个不同的名字空间可以包含具有相同名称的服务账号。
轻量程度重量,通过认证模块配置。轻量,用户为了具体的任务按需创建服务账号。将服务账户与用户分离开来, 使工作负载更易于遵从权限最小化原则。

服务账号令牌卷机制

当 Pod 调度到节点,kubelet 启动容器前:

  1. 根据 spec.serviceAccountName 在当前命名空间查找 SA;
  2. 自动获取该 SA 对应的 Secret(ServiceAccount Token);

K8s 1.24+ 默认不再自动创建永久 Secret,改用 Bound Service Account Token(短期轮换 Token)

  1. 将 Token、ca.crt、namespace 文件,以 Volume 形式自动挂载到容器内默认路径:/var/run/secrets/kubernetes.io/serviceaccount/
root@master30:~# kubectl get pod web -o yaml
...
# Pod 容器内的卷挂载配置;将服务账号凭证卷挂载到容器指定路径,供应用读取后访问 Kubernetes API
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount  # 容器内挂载路径;Kubernetes 标准服务账号凭证目录,官方客户端 SDK 默认从该路径自动读取认证信息
      name: kube-api-access-sjffr  # 挂载的卷名称;与下方 volumes 定义的卷名一一对应,名称后缀为系统随机生成的唯一标识
      readOnly: true  # 只读挂载;强制凭证文件不可修改,保障凭据安全,防止篡改令牌与证书
...

# Pod 级别的数据卷定义;使用 projected 投影卷类型,将多种不同来源的凭证与元数据合并投影到同一个挂载目录
  volumes:
  - name: kube-api-access-sjffr  # 数据卷名称;供容器挂载点引用,与上方 volumeMounts 的 name 字段对应
    projected:  # 投影卷类型;可将多个不同类型的数据源合并输出到同一目录下,无需分别挂载多个独立卷
      sources:  # 投影数据源列表;多个来源的内容会共同出现在同一个挂载目录中
        - serviceAccountToken:  # 数据源1:服务账号令牌;生成绑定当前 Pod 的短期 JWT 令牌,用于访问 API Server 时的身份认证
            path: token # 投影后的文件名;挂载后目录下生成名为 token 的文件,存储 JWT 令牌内容,必须与应用所预期的路径匹配
        - configMap:  # 数据源2:ConfigMap;注入集群根 CA 证书,用于容器内验证 API Server 的 TLS 证书合法性
            items:  # 指定从 ConfigMap 中提取的键值与投影后的文件名映射关系
              - key: ca.crt  # ConfigMap 中的数据键名;存储集群根 CA 证书的原始内容
                path: ca.crt  # 投影后的文件名;挂载后目录下生成名为 ca.crt 的证书文件
            name: kube-root-ca.crt  # 引用的 ConfigMap 名称;每个命名空间下默认存在该系统 ConfigMap,统一存放集群根 CA
        - downwardAPI:  # 数据源3:向下 API;将 Pod 自身的元数据信息以文件形式注入到容器内
            items:  # 指定要注入的元数据字段与投影后的文件名
              - fieldRef:  # 字段引用;从 Pod 的元数据中提取指定字段的值
                  apiVersion: v1  # 字段所属的 API 版本
                  fieldPath: metadata.namespace  # 元数据路径;提取 Pod 当前所在的命名空间名称
                path: namespace  # 投影后的文件名;挂载后目录下生成名为 namespace 的文件,内容为 Pod 所在命名空间

该清单片段定义了由三个数据源组成的投射卷。在当前场景中,每个数据源也代表该卷内的一条独立路径。这三个数据源是:

  • serviceAccountToken 数据源,包含 kubelet 从 kube-apiserver 获取的令牌。 kubelet 使用 TokenRequest API 获取有时间限制的令牌**。为 TokenRequest 服务的这个令牌会在 Pod 被删除或定义的生命周期(默认为 1 小时)结束之后过期。**该令牌绑定到特定的 Pod, 并将其 audience(受众)设置为与 kube-apiserver 的 audience 相匹配。 这种机制取代了之前基于 Secret 添加卷的机制,之前 Secret 代表了针对 Pod 的 ServiceAccount 但不会过期。
  • **configMap 数据源。**ConfigMap 包含一组证书颁发机构数据。 Pod 可以使用这些证书来确保自己连接到集群的 kube-apiserver(而不是连接到中间件或意外配置错误的对等点上)。
  • downwardAPI 数据源,用于查找包含 Pod 的名字空间的名称, 并使该名称信息可用于在 Pod 内运行的应用程序代码。

Pod 内挂载这个特定卷的所有容器都可以访问上述信息。

root@master30:~# kubectl exec -it web -- bash
root@web:/usr/local/apache2# ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt  namespace  token
root@web:/usr/local/apache2# cat /var/run/secrets/kubernetes.io/serviceaccount/token 
eyJhbGciOiJSUzI1NiIsI......
root@web:/usr/local/apache2# cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 
auth

Pod 内应用(client-go/kubectl 等)访问 kube-apiserver 鉴权流程:

  1. 读取容器内 /var/run/secrets/kubernetes.io/serviceaccount/token;
  2. 在 HTTP 请求头带上:Authorization: Bearer <token>;
  3. 请求发送给 apiserver;
  4. apiserver 验证 Token 合法性,解析出对应的 ServiceAccount(ns + sa 名称);
  5. apiserver 查找所有绑定到此 SA 的 RoleBinding / ClusterRoleBinding;
  6. 根据 RBAC 规则判断:是否允许本次操作;
  7. 返回允许 / 拒绝结果。

服务账户管理

SA 创建
root@master30:~# kubectl create sa sa1
root@master30:~# kubectl get sa sa1
NAME   SECRETS   AGE
sa1    1         9s
SA 授权
root@master30:~# kubectl create clusterrolebinding auth-sa1-cluster-admin --clusterrole=cluster-admin --serviceaccount=auth:sa1
clusterrolebinding.rbac.authorization.k8s.io/auth-sa1-cluster-admin created
# 选项--serviceaccoun指明Service Account时,格式为namespace:Service Account Name
SA 使用
# 删除原有web Pod实例;清理旧Pod,确保重建后的Pod能加载新的服务账号身份凭证
root@master30:~# kubectl delete pod web

# 生成Pod配置模板文件;kubectl run快速生成标准Pod清单,--dry-run=client本地生成不提交集群,-o yaml输出YAML格式,重定向保存到web.yaml文件
root@master30:~# kubectl run web --image=docker.io/library/httpd --image-pull-policy=IfNotPresent --dry-run=client -o yaml > web.yaml

# 编辑Pod配置文件;添加服务账号配置,指定Pod使用自定义服务账号访问集群API
root@master30:~# vim web.yaml
apiVersion: v1     # Pod所属核心API组版本
kind: Pod          # 资源类型,Pod是Kubernetes最小调度与运行单元
metadata:          # 元数据区块,定义Pod标识属性
  creationTimestamp: null     # 创建时间戳;模板生成时置空,实际创建到集群后由API Server自动填充
  labels:          # Pod标签集合,用于分类筛选与服务匹配
    run: web
  name: web        # Pod名称,命名空间内唯一标识
spec:              # Pod核心规格配置区块
  containers:      # 容器列表,定义Pod内运行的容器实例
  - image: httpd   # 容器运行的httpd业务镜像
    imagePullPolicy: IfNotPresent     # 镜像拉取策略;本地存在镜像则不拉取,加快启动速度
    name: web      # 容器名称,Pod内唯一标识
    resources: {}  # 资源配额;当前未配置CPU与内存的请求值和上限值
  dnsPolicy: ClusterFirst     # DNS策略;ClusterFirst表示优先使用集群CoreDNS解析域名,解析失败再转发到节点宿主机DNS
  restartPolicy: Always       # 重启策略;Always表示容器异常退出时总是自动重启,是无状态服务的默认配置
  # 添加以下任一记录
  serviceAccount: sa1         # 服务账号旧字段(已弃用);指定Pod使用的服务账号名称,当前版本与serviceAccountName功能等价,官方不推荐继续使用
  serviceAccountName: sa1     # 服务账号名称(标准推荐字段);指定Pod关联的服务账号,Pod会自动挂载该服务账号的API访问令牌、根CA证书等凭证,容器内应用可使用该身份访问Kubernetes API,权限由对应服务账号的RBAC绑定决定
status: {}          # 状态字段;模板生成时为空,Pod运行后由系统自动填充运行状态、节点、IP等实时信息

# 应用Pod配置到集群;创建关联了sa1服务账号的web Pod实例
root@master30:~# kubectl apply -f web.yaml

# 查看Pod完整配置信息;-o yaml输出完整YAML格式,验证服务账号配置是否正常生效
root@master30:~# kubectl get pod web -o yaml
......
spec:
......
  serviceAccount: sa1
  serviceAccountName: sa1
# 验证说明:两个字段均已同步填充,服务账号sa1成功关联到Pod,Pod内会自动挂载对应服务账号的访问凭证,替代默认的default服务账号

重要:虽然 pod/web 中 httpd 进程具有 clusterrole/cluster-admin 角色,但是它只是用来提供httpd服务,不会做其他操作。

回收权限
root@master30:~# kubectl delete clusterrolebindings auth-sa1-cluster-admin 
clusterrolebinding.rbac.authorization.k8s.io "auth-sa1-cluster-admin" deleted
使用案例

集群 dashboard 中 pod 使用服务账户管理集群。

手动管理服务账号 token

  • v1.22 之前的 Kubernetes 版本会自动创建凭据访问 Kubernetes API。 这种机制是:先创建令牌 Secret,然后将其挂载到正运行的 Pod 中。
  • 在包括 Kubernetes v1.28 在内最近的几个版本中,使用 TokenRequest API 直接获得 API 凭据, 并使用投射卷挂载到 Pod 中。这种方法获得的令牌具有绑定的生命周期, 当挂载的 Pod 被删除时这些令牌将自动失效。
创建临时令牌
root@master30:~# kubectl create sa sa1
root@master30:~# kubectl create token sa1 
eyJhbGciOiJSUzI1NiIsImt......

# 注意:服务账号属性中是看不到关联的token的。
root@master30:~# kubectl get sa sa1 -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2023-11-01T04:05:03Z"
  name: sa1
  namespace: cyw
  resourceVersion: "11548"
  uid: 4944f75b-43ae-43fc-abfd-f2d20b7375f1
创建永久令牌

创建一个带有特殊注解 kubernetes.io/service-account.name 的 Secret 对象。一旦你手动创建一个 Secret 并将其关联到 ServiceAccount, Kubernetes 控制平面就会自动将令牌填充到该 Secret 中。

# 编辑服务账号静态令牌Secret配置;手动声明专属类型的Secret,触发控制器为sa1服务账号生成长期有效的API访问令牌。Kubernetes 1.24+默认不再自动为服务账号创建令牌Secret,需通过该方式手动生成
root@master30:~# vim sa1-token.yaml
apiVersion: v1     # Secret所属核心API组版本,Secret属于核心v1原生资源
kind: Secret       # 资源类型,Secret用于加密存储敏感凭据数据,如令牌、证书、密码等
metadata:          # 元数据区块,定义Secret的标识属性与特殊控制注解
  name: sa1-secret # Secret资源名称,命名空间内唯一标识
  annotations:     # 资源注解;通过系统保留注解告知令牌控制器该Secret的关联归属
    kubernetes.io/service-account.name: sa1     # 服务账号关联注解;指定该令牌Secret归属的服务账号名称,控制器识别到该注解后,会自动生成对应服务账号的访问令牌并填充到Secret数据中
type: kubernetes.io/service-account-token     # Secret专属类型;服务账号令牌类型,系统会自动在Secret中生成并填充三项数据:token(JWT身份令牌)、ca.crt(集群根CA证书)、namespace(当前命名空间),用于客户端以该服务账号身份访问Kubernetes API

# 应用令牌Secret配置到集群;创建完成后,集群令牌控制器会自动生成凭据并写入Secret,可通过kubectl get secret sa1-secret -o yaml查看生成的令牌内容
root@master30:~# kubectl apply -f sa1-token.yaml

当你删除一个与某 Secret 相关联的 ServiceAccount 时,Kubernetes 的控制面会自动清理该 Secret 中长期有效的令牌。

root@master30:~# kubectl delete sa sa1 

#等10syan'z
root@master30:~# kubectl get secrets 
No resources found in cyw namespace.

说明: 尽管存在手动创建长久 ServiceAccount 令牌的机制,但还是推荐使用 TokenRequest 获得短期的 API 访问令牌。

思考

**问题:**Kubernetes 为什么不提供用户管理和身份认证功能?

Kubernetes 采用 RBAC 模型 管理用户(User)和用户组(Group)权限。但是Kubernetes中找不到真正的用户以及用户组信息,甚至连对应的User Resource以及Group Resource都没有,Kubernetes无法列出可信任的User列表以及Group列表。

换句话说 Kubernetes 并没有提供用户管理和身份认证功能,除了Service Account外,所有的用户信息都依赖外部的用户管理系统来存储,因此通过api-serever根本无法列出User和Group。

**解答:**这其实挺符合UNIX设计哲学的,即 Do One Thing and Do It Well。

Kubernetes只专注于做应用编排,其他的功能则提供接口集成,除了认证和鉴权,我们发现网络、存储也都如此。

这样做的好处也显而易见,用户账户信息与Kubernetes集群松耦合,便于集成企业已有的身份认证系统,如AD、LDAP、Keycloak等。

环境清理

root@master30:~# kubectl delete ns auth
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐