Access control 访问控制

Kubernetes 对 API 访问提供了三种安全访问控制措施:Authentication、Authorization 和 Admission Control。认证解决用户是谁的问题,授权解决用户能做什么的问题,Admission Control 则是资源管理方面的作用。通过合理的权限管理,能够保证系统的安全可靠。

Kubernetes 集群的所有操作基本上都是通过 kube-apiserver 这个组件进行的,它提供 HTTP RESTful 形式的 API 供集群内外客户端调用。需要注意的是:认证授权过程只存在 HTTPS 形式的 API 中。也就是说,如果客户端使用 HTTP 连接到 kube-apiserver,那么是不会进行认证授权的。所以说,可以这么设置,在集群内部组件间通信使用 HTTP,集群外部就使用 HTTPS,这样既增加了安全性,也不至于太复杂。

可以使用 kubectl、客户端库方式对REST API的访问,Kubernetes 的 user 和 service accounts 都可以实现授权访问 API。API的请求会经过多个阶段的访问控制才会被接受处理,其中包含认证、授权以及准入控制(Admission Control)等。

image-20220112173700467

Authentication 认证

开启 TLS 时,所有的请求首先需要认证(如图步骤1)。Kubernetes 支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。如果认证成功,则用户的username 会传入授权模块做进一步授权验证;对于认证失败的请求则返回 HTTP 401。

Kubernetes 不直接管理用户

虽然 Kubernetes 认证和授权用到了 user 和 group,但 Kubernetes 并不直接管理用户,不能创建 user 对象,也不存储 user。

目前,Kubernetes 支持以下认证插件:

Authorization 授权

在通过第一步的认证之后,我们已经知道请求的用户是谁了,那么下一步就需要判断该用户是否对请求的资源有相应的权限(如图步骤 2)。

请求必须包含请求者的用户名,请求的操作以及受该操作影响的对象,如果策略已经声明用户具有完成请求的权限,则该请求将被授权。

跟认证类似,Kubernetes 也支持多种授权机制,并支持同时开启多个授权插件(只要有一个验证通过即可)。如果授权成功,则用户的请求会发送到准入控制模块做进一步的请求验证;对于授权失败的请求则返回 HTTP 403。

Kubernetes 授权仅处理以下的请求属性

  • user - 认证期间提供的user字符串
  • group - 认证用户所属的组名列表
  • “extra” - 由认证层提供的任意字符串键到字符串值的映射
  • API - 指示请求是否为API resource
  • Request path - 到其他非request端点的路径,如/api或/healthz。
  • API request verb - API verbs get,list,create,update,patch,watch,proxy,redirect,delete,和deletecollection用于请求resource。要确定resource API端点的请求verbs 。
  • HTTP request verb - HTTP verbs get,post,put,和delete用于非资源请求
  • Resource -被访问(仅用于resource 请求)的resource 的ID或名字- *对于使用resource 的请求get,update,patch,和delete,必须提供resource 名称。
  • Subresource - 正在访问的subresource (仅用于请求resource )
  • Namespace - 正在访问对象的命名空间(仅针对命名空间的请求资源)
  • API group - 正在访问的API组(仅用于请求资源)。空字符串指定核心API组。

目前,Kubernetes 支持以下授权插件:

  • ABAC:基于属性的访问控制(ABAC)模式允许你 使用本地文件配置策略。
  • RBAC:基于角色的访问控制(RBAC)模式允许你使用 Kubernetes API 创建和存储策略。
  • Webhook:WebHook 是一种 HTTP 回调模式,允许你使用远程 REST 端点管理鉴权。
  • Node:节点鉴权是一种特殊用途的鉴权模式,专门对 kubelet 发出的 API 请求执行鉴权。

AlwaysDeny 和 AlwaysAllow

Kubernetes 还支持 AlwaysDeny 和 AlwaysAllow 模式,其中 AlwaysDeny 仅用来测试,而 AlwaysAllow 则 允许所有请求(会覆盖其他模式)。

调试小技巧

kubectl 客户端有一个子命令是 auth can-i 可以快速检查执行者是否有对应的 API 权限,该命令使用 SelfSubjectAccessReview API 来确定当前用户是否可以执行给定的操作,并且无论使用何种授权模式都可以工作。

kubectl auth can-i create deployments --namespace dev

输出是 yes 证明有权限,否则就是 no。

管理员可以将此与 user impersonation 结合使用,以确定其他用户可以执行的操作。

伪装成用户 dave 来探测是否有相应的权限。

kubectl auth can-i list secrets --namespace dev --as dave

类似地,检查名字空间 dev 里的 dev-sa 服务账号是否可以列举名字空间 target 里的 Pod。

kubectl auth can-i list pods \
    --namespace target \
    --as system:serviceaccount:dev:dev-sa

除了伪装 User,还可以伪装 ServiceAccount,当然也可以伪装 Group,如使用 --as-group=system:masters

除了上面使用命令探测外,也可以通过创建普通的 Kubernetes 资源来查询这些 API,其中返回对象的响应 "status" 字段是查询的结果。

kubectl create -f - -o yaml << EOF
apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
spec:
  resourceAttributes:
    group: apps
    name: deployments
    verb: create
    namespace: dev
EOF

生成的 SelfSubjectAccessReview 为(在阿里云的 AKS 中操作):

apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
metadata:
  creationTimestamp: null
spec:
  resourceAttributes:
    group: apps
    name: deployments
    namespace: dev
    verb: create
status:
  allowed: true
  reason: 'RBAC: allowed by ClusterRoleBinding "212335916464555765-cluster-admin-clusterrolebinding"
    of ClusterRole "cluster-admin" to User "212335916464555765-1639030041"'

Admission control 准入控制

准入控制模块是可以修改或拒绝请求的软件模块。 除授权模块可用的属性外,准入控制模块还可以访问正在创建或修改的对象的内容。

准入控制器对创建、修改、删除或(通过代理)连接对象的请求进行操作。 准入控制器不会对仅读取对象的请求起作用。 有多个准入控制器被配置时,服务器将依次调用它们。

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

与身份认证和鉴权模块不同,如果任何准入控制器模块拒绝某请求,则该请求将立即被拒绝。

除了拒绝对象之外,准入控制器还可以为字段设置复杂的默认值。

可用的准入控制模块在准入控制器中进行了描述。

请求通过所有准入控制器后,将使用检验例程检查对应的 API 对象,然后将其写入对象存储(如步骤 4 所示)。

API 服务器端口和 IP

前面的讨论适用于发送到 API 服务器的安全端口的请求(典型情况)。 API 服务器实际上可以在 2 个端口上提供服务:

默认情况下,Kubernetes API 服务器在 2 个端口上提供 HTTP 服务:

  1. localhost端口:
    • 用于测试和引导,以及 master 节点上的其他组件(scheduler, controller-manager)与 API 通信
    • 没有 TLS
    • 默认为端口 8080
    • 默认 IP 为 localhost,使用 --insecure-bind-address 进行更改
    • 请求 绕过 身份认证和鉴权模块
    • 由 admission control 模块处理的请求
    • 受需要访问主机的保护
  2. “Secure port”:
    • 尽可能使用
    • 使用 TLS。 用 --tls-cert-file 设置证书,用 --tls-private-key-file 设置密钥
    • 默认端口 6443,使用 --secure-port 更改
    • 默认 IP 是第一个非本地网络接口,使用 --bind-address 更改
    • 请求须经身份认证和鉴权组件处理
    • 请求须经准入控制模块处理
    • 身份认证和鉴权模块运行

参考文档:https://kubernetes.io/docs/reference/using-api/api-concepts/