Kubernetes API 访问控制机制简介
前言
介绍API访问控制之前,先了解一下Kubernetes API中的设计,在Kubernetes中,API对象完整资源路径是由:Group(API 组)、Version(API 版本)和 Resource(API资源类型)三个部分组成的。通过这样的结构,整个 Kubernetes 里的所有 API 对象,实际上就可以用如下的树形结构表示出来:
用户使用 kubectl、客户端或构造 REST 请求来访问 Kubernetes API。所有的请求都可以被鉴权访问 API。当请求到达 API 时,它会经历多个阶段,如下图所示:
Kubernetes 对 API 访问提供了三种安全访问控制措施:认证、鉴权和准入控制。认证解决用户是谁的问题,授权解决用户能做什么的问题,准入控制则是资源管理方面的作用。通过合理的权限管理,能够保证系统的安全可靠。
一、认证
如上图步骤 1 所示,建立 TLS 后, HTTP请求将进入认证(Authentication)步骤。集群创建脚本或者集群管理员配置 API 服务器,使之运行一个或多个身份认证组件。认证步骤的输入整个 HTTP请求;但是,通常组件只检查头部和客户端证书。认证模块包含客户端证书、密码、普通令牌、引导令牌和 JSON Web 令牌(JWT,用于服务账户)。可以指定多个认证模块,在这种情况下,服务器依次尝试每个验证模块,直到其中一个成功。
如果请求认证不通过,服务器将以 HTTP 状态码 401 拒绝该请求。反之,该用户被认证为特定的 username,并且该用户名可用于后续步骤以在其决策中使用。
二、鉴权
如上图的步骤 2 所示,将请求验证为来自特定的用户后,这个请求必须被授权。一个请求必须包含请求者的用户名、请求的行为以及受该操作影响的对象。如果现有策略声明用户有权完成请求的操作,那么该请求被鉴权通过。
例1,如果用户bob有以下策略,那么他只能在 projectCaribou 名称空间中读取 Pod。
{
"apiVersion": "abac.authorization.kubernetes.io/v1beta1",
"kind": "Policy",
"spec": {
"user": "bob",
"namespace": "projectCaribou",
"resource": "pods",
"readonly": true
}
}
例2,如果用户bob发送这样一个请求,他可以被成功授权,因为他读取命名空间projectCaribou里的对象信息的动作是被允许的:
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"spec": {
"resourceAttributes": {
"namespace": "projectCaribou",
"verb": "get",
"group": "unicorn.example.org",
"resource": "pods"
}
}
}
如果Bob发送往 projectCaribou命名空间写(create 或者 update)对象信息的请求, 那么他会被拒绝授权。如果发送从一个不同的命名空间,比如projectFish 读取(get)对象信息的请求,那么他的授权也会被拒绝。
Kubernetes的授权要求你和已存在的组织范畴或者云供应商范畴的访问控制系统进行交互时,要使用通用的REST属性。使用REST的格式是非常重要的, 因为这些控制系统也可能会和包括Kubernetes API在内的其它API进行交互。
Kubernetes支持多个授权模块,例如ABAC模式(基于属性的访问控制),RBAC模式(基于角色的访问控制),Webhook模式(基于web事件查询外部的REST服务)。当一个管理员创建了集群,他们会配置API server会启用哪些授权模块。如果配置了多个鉴权模块,则 Kubernetes会检查每个模块,任意一个模块鉴权该请求,请求即可继续,如果所有模块拒绝了该请求,请求将会被拒绝(HTTP 状态码返回403)。
Kubernetes 审查的API 请求属性:
用户 - 身份验证期间提供的 user 字符串。
组 - 经过身份验证的用户所属的组名列表。
额外信息 - 由身份验证层提供的任意字符串键到字符串值的映射。
API - 指示请求是否针对 API 资源。
请求路径 - 各种非资源端点的路径,如 /api 或 /healthz。
API 请求动词 - API 动词get、list、create、update、patch、watch、 proxy、redirect、delete和 deletecollection 用于资源请求。要确定资源 API 端点的请求动词,请参阅 确定请求动词。
HTTP 请求动词 - HTTP 动词get、post、put 和 delete 用于非资源请求。
Resource - 正在访问的资源的 ID 或名称(仅限资源请求)- 对于使用 get、update、patch 和 delete 动词的资源请求,你必须提供资源名称。
子资源 - 正在访问的子资源(仅限资源请求)。
名字空间 - 正在访问的对象的名称空间(仅适用于名字空间资源请求)。
API 组 - 正在访问的 API 组(仅限资源请求)
三、准入控制
准入控制模块是可以修改或拒绝请求的软件模块。除鉴权模块可用的属性外,准入控制模块还可以访问正在创建或修改的对象的内容。
准入控制器对创建、修改、删除或(通过代理)连接对象的请求进行操作。准入控制器不会对仅读取对象的请求起作用。有多个准入控制器被配置时,服务器将依次调用它们。
这一操作如上图的步骤 3 所示。与认证和鉴权模块不同,如果任何准入控制器模块拒绝某请求,则该请求将立即被拒绝。除了拒绝对象之外,准入控制器还可以为字段设置复杂的默认值。
一旦一个请求通过了所有的准则控制器的批准,那么这个请求会被对应的API对象验证程序证实为有效请求, 然后会被写入到对象存储里(如上图步骤 4所示)
四、API 服务器端口和 IP
默认情况下,Kubernetes API 服务器在 2 个端口上提供 HTTP 服务:
localhost 端口:
用于测试和引导,以及主控节点上的其他组件(调度器,控制器管理器)与 API 通信
没有 TLS
默认为端口 8080,使用--insecure-port 更改
默认 IP 为localhost,使用 --insecure-bind-address 进行更改
请求绕过身份认证和鉴权模块
由准入控制模块处理的请求
没有主机访问权限不能访问
安全端口:
官方推荐使用安全端口
使用 TLS。用--tls-cert-file 设置证书,用 --tls-private-key-file 设置密钥
默认端口 6443,使用--secure-port 更改
默认 IP 是第一个非本地网络接口,使用 --bind-address 更改
请求须经身份认证和鉴权组件处理
请求须经准入控制模块处理
身份认证和鉴权模块运行
五、总结
如果没有合理的配置验证和权限,那么攻击者通过直接访问未授权的8080端口,可以读写kube-apiserver的api,创建挂载根目录的特权DaemonSet实现控制集群,所以在生产环境中,一定要开启Kubernetes API访问控制,提高集群的安全性。
往期推荐
2021-10-29
2021-10-26
2021-10-08
2021-09-14