Kubernetes安全机制深度解析(二):从身份认证到资源鉴权
#作者:程宏斌
文章目录
- 鉴权上下文
- 鉴权模式
- 鉴权模式配置
- 命令行鉴权模式配置
- 使用RBAC鉴权
- API对象
- Role 和 ClusterRole
- RoleBinding 和 ClusterRoleBinding
- 使用Node鉴权
- 迁移考虑因素
- 具有无差别用户名的 kubelet
- Webhook模式
- 配置文件格式
- 使用ABAC鉴权
- 策略文件格式
- 鉴权算法
- kubectl
鉴权上下文
Kubernetes 需要 REST API 请求所共有的属性, 这意味着 Kubernetes 鉴权可与现有的组织范围或云提供商范围的访问控制系统配合使用, 这些系统可以处理除 Kubernetes API 之外的其他 API。
鉴权模式
AlwaysAllow
此模式允许所有请求,但存在安全风险, 仅当你的 API 请求不需要鉴权时(例如,用于测试),才使用此鉴权模式。
AlwaysDeny
此模式阻止所有请求。此鉴权模式仅适用于测试。
ABAC(基于属性的访问控制)
Kubernetes ABAC 模式定义了一种访问控制范例,通过使用将属性组合在一起的策略向用户授予访问权限, 策略可以使用任何类型的属性(用户属性、资源属性、对象、环境属性等)。
RBAC(基于角色的访问控制)
Kubernetes RBAC 是一种根据企业内各个用户的角色来管理其对计算机或网络资源的访问权限的方法。 在此上下文中,访问权限是单个用户执行特定任务(例如查看、创建或修改文件)的能力。 在这种模式下,Kubernetes 使用 rbac.authorization.k8s.io API 组来驱动鉴权决策, 允许你通过 Kubernetes API 动态配置权限策略。
Node
一种特殊用途的鉴权模式,根据 kubelet 计划运行的 Pod 向其授予权限。 要了解有关 Node 鉴权模式的更多信息,请参阅 Node 鉴权。
Webhook
Kubernetes 的 Webhook 鉴权模式用于鉴权,进行同步 HTTP 调用, 阻塞请求直到远程 HTTP 服务响应查询。你可以编写自己的软件来处理这种向外调用,也可以使用生态系统中的解决方案。
警告:
启用 AlwaysAllow 模式会绕过鉴权;请勿在你不信任所有潜在 API 客户端(包括你运行的工作负载)的集群上使用该模式。
鉴权机制通常返回“拒绝”或“无意见”的结果; 有关更多信息,请参阅鉴权裁决。 激活 AlwaysAllow 意味着如果所有其他鉴权组件都返回“无意见”,则允许该请求。 例如,–authorization-mode=AlwaysAllow,RBAC 与 --authorization-mode=AlwaysAllow 具有相同的效果,因为 Kubernetes RBAC 不提供否定(拒绝)访问规则。
你不应在可从公共互联网访问 API 服务器的 Kubernetes 集群上使用 AlwaysAllow 模式。
鉴权模式配置
你可以仅使用配置文件, 或使用命令行参数来配置 Kubernetes API 服务器的鉴权链。
你必须选择两种配置方法之一;不允许同时设置 --authorization-config 路径并使用 --authorization-mode 和 --authorization-webhook-* 命令行参数配置鉴权 Webhook。 如果你尝试这样做,API 服务器会在启动期间报告错误消息,然后立即退出。
命令行鉴权模式配置
你可以使用以下模式:
- –authorization-mode=ABAC(基于属性的访问控制模式)
- –authorization-mode=RBAC(基于角色的访问控制模式)
- –authorization-mode=Node(节点鉴权组件)
- –authorization-mode=Webhook(Webhook 鉴权模式)
- –authorization-mode=AlwaysAllow(始终允许请求;存在安全风险)
- –authorization-mode=AlwaysDeny(始终拒绝请求)
你可以选择多种鉴权模式;例如:–authorization-mode=Node,Webhook
Kubernetes 根据你在 API 服务器的命令行上指定鉴权模块的顺序来检查鉴权模块, 因此较早的模块具有更高的优先级来允许或拒绝请求。
你不能将 --authorization-mode 命令行参数与用于使用本地文件配置鉴权的 --authorization-config 命令行参数结合使用。
使用RBAC鉴权
基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对计算机或网络资源的访问的方法。
RBAC 鉴权机制使用 rbac.authorization.k8s.io API 组来驱动鉴权决定, 允许你通过 Kubernetes API 动态配置策略。
要启用 RBAC,在启动 API 服务器时将 --authorization-config 标志设置为包含 RBAC 授权者的文件
或者,启动 API 服务器时, 将 --authorization-mode 标志设置为包含 RBAC 的逗号分隔列表;
API对象
RBAC API 声明了四种 Kubernetes 对象:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding。你可以像使用其他 Kubernetes 对象一样, 通过类似 kubectl 这类工具描述或修补 RBAC 对象。
注意:
这些对象在设计时即实施了一些访问限制。如果你在学习过程中对集群做了更改, 请参考避免特权提升和引导一节, 以了解这些限制会以怎样的方式阻止你做出修改。
Role 和 ClusterRole
RBAC 的 Role 或 ClusterRole 中包含一组代表相关权限的规则。 这些权限是纯粹累加的(不存在拒绝某操作的规则)。
Role 总是用来在某个名字空间内设置访问权限; 在你创建 Role 时,你必须指定该 Role 所属的名字空间。
与之相对,ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和 ClusterRole) 是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的,不可两者兼具。
ClusterRole 有若干用法。你可以用它来:
- 定义对某名字空间域对象的访问权限,并将在个别名字空间内被授予访问权限;
- 为名字空间作用域的对象设置访问权限,并被授予跨所有名字空间的访问权限;
- 为集群作用域的资源定义访问权限。
如果你希望在名字空间内定义角色,应该使用 Role; 如果你希望定义集群范围的角色,应该使用 ClusterRole。
RoleBinding 和 ClusterRoleBinding
角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。 它包含若干主体(Subject)(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。 RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权。
一个 RoleBinding 可以引用同一的名字空间中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。
RoleBinding 或 ClusterRoleBinding 对象的名称必须是合法的 路径分段名称。
使用Node鉴权
节点鉴权是一种特殊用途的鉴权模式,专门对 kubelet 发出的 API 请求进行授权。
概述
节点鉴权器允许 kubelet 执行 API 操作。包括:
读取操作:
- services
- endpoints
- nodes
- pods
- 与绑定到kubelet节点的Pod相关的Secret、ConfigMap、PersistentVolumeClaim 和持久卷
当启用AuthorizeNodeWithSelectors特性(以及作为先决条件的 AuthorizeWithSelectors特性)时, kubelet 只允许读取它们自己的 Node 对象, 并且只允许读取绑定到其节点的 Pod。
写入操作:
- 节点和节点状态(启用 NodeRestriction 准入插件以限制 kubelet 只能修改自己的节点)
- Pod 和 Pod 状态(启用 NodeRestriction 准入插件以限制 kubelet 只能修改绑定到自身的 Pod)
- 事件
身份认证与鉴权相关的操作:
- 对于基于 TLS 的启动引导过程时使用的 certificationsigningrequests API 的读/写权限
- 为委派的身份验证/鉴权检查创建 TokenReview 和 SubjectAccessReview 的能力
在将来的版本中,节点鉴权器可能会添加或删除权限,以确保 kubelet 具有正确操作所需的最小权限集。
为了获得节点鉴权器的授权,kubelet 必须使用一个凭据以表示它在 system:nodes 组中,用户名为 system:node:。上述的组名和用户名格式要与 kubelet TLS 启动引导 过程中为每个 kubelet 创建的标识相匹配。
的值必须与 kubelet 注册的节点名称精确匹配。默认情况下,节点名称是由 hostname 提供的主机名,或者通过 kubelet --hostname-override 选项覆盖。 但是,当使用 --cloud-provider kubelet 选项时,具体的主机名可能由云提供商确定, 忽略本地的 hostname 和 --hostname-override 选项。有关 kubelet 如何确定主机名的详细信息,请参阅 kubelet 选项参考。
要启用 Node 鉴权器,启动 API 服务器时将 --authorization-config 参数设置为包含 Node 鉴权器的某个文件;例如:
apiVersion: apiserver.config.k8s.io/v1
kind: AuthorizationConfiguration
authorizers:
...
- type: Node
...
或者,在启动 API 服务器时将 --authorization-mode 参数设置为一个包含 Node 的逗号分隔的列表;例如:
kube-apiserver --authorization-mode=…,Node --other-options --more-options
要限制 kubelet 可以写入的 API 对象,请使用 --enable-admission-plugins=…,NodeRestriction,… 启动 API 服务器,从而启用 NodeRestriction 准入插件。
迁移考虑因素
在 system:nodes 组之外的 kubelet
system:nodes 组之外的 kubelet 不会被 Node 鉴权模式授权,并且需要继续通过当前授权它们的机制来授权。 节点准入插件不会限制来自这些 kubelet 的请求。
具有无差别用户名的 kubelet
在一些部署中,kubelet 具有 system:nodes 组的凭据, 但是无法给出它们所关联的节点的标识,因为它们没有 system:node:… 格式的用户名。 这些 kubelet 不会被 Node 鉴权模式授权,并且需要继续通过当前授权它们的任何机制来授权。
因为默认的节点标识符实现不会把它当作节点身份标识,NodeRestriction 准入插件会忽略来自这些 kubelet 的请求。
Webhook模式
WebHook 是一种 HTTP 回调:某些条件下触发的 HTTP POST 请求;通过 HTTP POST 发送的简单事件通知。一个基于 web 应用实现的 WebHook 会在特定事件发生时把消息发送给特定的 URL。
具体来说,当在判断用户权限时,Webhook 模式会使 Kubernetes 查询外部的 REST 服务。
配置文件格式
Webhook 模式需要一个 HTTP 配置文件,通过 --authorization-webhook-config-file=SOME_FILENAME 的参数声明。
配置文件的格式使用 kubeconfig。 在该文件中,“users” 代表着 API 服务器的 Webhook,而 “cluster” 代表着远程服务。
使用 HTTPS 客户端认证的配置例子:
# Kubernetes API 版本
apiVersion: v1
# API 对象种类
kind: Config
# clusters 代表远程服务
clusters:- name: name-of-remote-authz-servicecluster:# 对远程服务进行身份认证的 CAcertificate-authority: /path/to/ca.pem# 远程服务的查询 URL。必须使用 'https'。不可以包含参数。server: https://authz.example.com/authorize
# users 代表 API 服务器的 webhook 配置
users:- name: name-of-api-serveruser:client-certificate: /path/to/cert.pem # 要使用的 webhook 插件的证书client-key: /path/to/key.pem # 与证书匹配的密钥
# kubeconfig 文件必须有 context。需要提供一个给 API 服务器。
current-context: webhook
contexts:
- context:cluster: name-of-remote-authz-serviceuser: name-of-api-servername: webhook
使用ABAC鉴权
基于属性的访问控制(Attribute-based access control,ABAC)定义了访问控制范例, ABAC 通过使用将属性组合在一起的策略来向用户授予访问权限。
策略文件格式
要启用 ABAC 模式,可以在启动时指定 --authorization-policy-file=SOME_FILENAME 和 --authorization-mode=ABAC。
此文件格式是每行一个 JSON 对象,不应存在外层的列表或映射,每行应只有一个映射。
每一行都是一个“策略对象”,策略对象是具有以下属性的映射:
- 版本控制属性:
¡apiVersion,字符串类型:有效值为 abac.authorization.kubernetes.io/v1beta1,允许对策略格式进行版本控制和转换。
¡kind,字符串类型:有效值为 Policy,允许对策略格式进行版本控制和转换。 - spec 配置为具有以下映射的属性:
¡主体匹配属性:user,字符串类型;来自 --token-auth-file 的用户字符串,如果你指定 user,它必须与验证用户的用户名匹配。 - group,字符串类型;如果指定 group,它必须与经过身份验证的用户的一个组匹配, system:authenticated 匹配所有经过身份验证的请求。 system:unauthenticated 匹配所有未经过身份验证的请求。
¡资源匹配属性:
¡apiGroup,字符串类型;一个 API 组。例如:apps、networking.k8s.io - 通配符:*匹配所有 API 组。
¡namespace,字符串类型;一个命名空间。例如:kube-system - 通配符:*匹配所有资源请求。
¡resource,字符串类型;资源类型。例如:pods、deployments - 通配符:*匹配所有资源请求。
¡非资源匹配属性:
¡nonResourcePath,字符串类型;非资源请求路径。 - 例如:/version 或 /apis
- 通配符:* 匹配所有非资源请求。
- /foo/* 匹配 /foo/ 的所有子路径。
¡readonly,布尔值类型。如果为 true,则表示该策略仅适用于 get、list 和 watch 操作。 非资源匹配属性仅适用于 get 操作。
说明:
属性未设置等效于属性被设置为对应类型的零值(例如空字符串、0、false)。 然而,出于可读性考虑,应尽量选择不设置这类属性。
在将来,策略可能以 JSON 格式表示,并通过 REST 界面进行管理
鉴权算法
请求具有与策略对象的属性对应的属性。
当接收到请求时,属性是确定的。未知属性设置为其类型的零值(例如:空字符串、0、false)。
设置为 “*” 的属性将匹配相应属性的任何值。
检查属性的元组,以匹配策略文件中的每个策略。如果至少有一行匹配请求属性, 则请求被鉴权(但仍可能无法通过稍后的合法性检查)。
要允许任何经过身份验证的用户执行某些操作,请将策略组属性设置为 “system:authenticated”。
要允许任何未经身份验证的用户执行某些操作,请将策略组属性设置为 “system:unauthenticated”。
要允许用户执行任何操作,请使用设置为 “*” 的 apiGroup、namespace、resource 和 nonResourcePath 属性编写策略。
kubectl
kubectl 使用 apiserver 的 /api 和 /apis 端点来发现服务资源类型, 并使用位于 /openapi/v2 的模式信息来验证通过创建/更新操作发送到 API 的对象。
当使用 ABAC 鉴权时,这些特殊资源必须显式地通过策略中的 nonResourcePath 属性暴露出来 (参见下面的 示例):
/api,/api/,/apis 和 /apis/ 用于 API 版本协商。
/version 通过 kubectl version 检索服务器版本。
/swaggerapi/* 用于创建 / 更新操作。
要检查涉及到特定 kubectl 操作的 HTTP 调用,你可以调整详细程度:
kubectl --v=8 version