Kubernetes 是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它提供了丰富的功能,如服务发现、负载均衡、自动缩放等。随着 Kubernetes 在云原生领域的广泛应用,「有效管理谁可以对 Kubernetes 集群执行何种操作变得至关重要」。本文将简要介绍 Kubernetes的认证与授权体系以及RBAC授权原理。通过实际案例展示RBAC管理不当可能导致的安全风险,然后向大家分享RBAC安全研发与运维的最佳实践,以及我们在字节跳动内部的安全防护和治理经验。
背景知识❝
如果您对相关背景知识比较了解,可直接跳转到“RBAC 安全风险剖析”、“RBAC 安全研发与运维最佳实践” 章节阅读。
❞
本章节将对 Kubernetes 的认证和授权体系进行概述,了解这些机制的原理有助于理解不同场景下集群权限的安全风险。特别是那些能够被轻易利用的未授权访问漏洞,以及那些容易被忽视的权限提升与横向移动攻击风险。
Kubernetes 认证与授权体系Kubernetes 的认证与授权体系主要用于满足对关键服务 API(API Server、Kubelet Server)的访问控制。在经过多年的发展后,Kubernetes 已经实现了一套比较完善的认证与授权机制,可以满足用户大多数场景的使用需求。
「API Server」
Kubernetes 是一个以容器技术为基础,以声明式 API Server 为核心的分布式容器编排系统。Kubernetes 几乎所有的功能都通过 API Server 对外暴露。而 API Server 支持了多种认证机制,内置了多种授权模式和准入控制器,允许用户根据需要灵活配置和使用。
简单来说,当一个用户访问 Kubernetes 的 API Server 时,API Server 会使用启用的认证器依次对请求进行身份认证,API Server 使用第一个成功认证的身份来标识请求者;然后再使用启用的授权器依次对请求进行授权策略的检查,当有任意一个授权器显式地允许、拒绝一个请求时,则立刻返回当前授权结果(如果没有授权器显式地授权,那么请求也将被拒绝)。除此之外,在 API Server 真正处理请求前,它还会使用启用的准入控制器对请求进一步变异和验证。只有所有的准入控制器都验证通过后,请求才会被真正处理。
❝
注意:API Server 不保证认证器和准入控制器的执行顺序,但会按照授权模式的配置顺序进行鉴权。
❞
「Kubelet Server」
Kubernetes 中还有一个非常重要的组件,那就是 Kubelet。它充当了分布式系统中的 Agent 角色,并使用节点专属的用户证书访问 API Server,管理节点上的资源。但 Kubelet 自身也会作为服务端,对外提供服务。从而实现在容器内执行命令、获取指标信息、容器日志、宿主机日志等功能。
Kubernetes 也为 Kubelet Server 提供了多种认证和授权模式。值得一提的是其中的 webhook 认证和 webhook 授权,它们本质上是向 API Server 发送 TokenReview 和 SubjectAccessReview 请求,对客户端的身份进行认证与授权。
「小结」
Kubernetes 为 API Server 和 Kubelet Server 支持了多种认证机制、授权机制、准入控制器,以及灵活的自定义接口。这些机制虽然能够满足各种用户需求,但也给用户带来了困扰。因为如果不了解这些机制的原理和负面影响,就很容易为集群引入安全风险和入侵检测盲点。特别是那些能够被轻易利用的未授权访问漏洞,以及那些容易被忽视的提权与横向移动攻击风险。
请参见附录和参考文献,了解更多 API Server 和 Kubelet Server 的认证、授权、准入控制的技术细节。
Kubernetes RBAC 授权原理RBAC 是 Kubernetes 默认启用的授权机制,也是 Kubernetes 核心组件所使用的授权机制。用户在使用集群时,往往需要使用 RBAC 授权机制来为其用户账号授权,以便部署、运维工作负载及所需的各种资源。各类云原生应用的 Operator、Controller 往往也需要利用 RBAC 授权机制来为其服务账户授权,以确保它们能够访问必要的资源,从而实现其功能。
下面的示意图展示了用户账号和服务账号访问 API Server 时的认证、授权、准入控制过程。
在 Kubernetes 的 RBAC 授权体系中,引入了以下几种概念:
「Subject」在 Kubernetes 环境中有三类 Subject 可以被授予 RBAC 角色权限。「Rule」用于在 Role, ClusterRole 内部定义具体权限,每一个 rule 都可以通过 apiGroups, resources, resourcesName, verbs, nonResourceURLs 来定义允许对什么资源(API 组,资源类型,资源名称 )执行什么操作(动词)。注意:rule中的apiGroups, resources, resourcesNames, verbs, nonResourceURLs 支持使用通配符「Role & ClusterRole」Role 用来定义当前命名空间范围内资源的角色,它通过 Rules 显式地定义权限。ClusterRole 用来定义集群范围内资源的角色,它通过 Rules 显式地定义权限。「Role & ClusterRoleBinding」RoleBinding 将某个 ClusterRole 或当前命名空间中的某个 Role 绑定到 subjects,使 subjects 获得当前命名空间中的 ClusterRole、Role所定义的角色权限,例如可以在命名空间 A 中创建 RoleBinding,将命名空间 A 中的 Role 与命名空间 B 中的 ServiceAccount 绑定。那么命名空间 B 中的 ServiceAccount 将获得命名空间 A 中的 Role 定义的权限。ClusterRoleBinding 将某个 ClusterRole 绑定到 subjects,使 subjects 获得 ClusterRole 所定义的角色权限。由以上可知,Role 和 ClusterRole 内的 rules 代表一系列显式授予的权限,遵从 Deny-by-Default 安全模型。由于不支持 "deny" 规则,因而不支持显式的排除某些权限。
这一特点使得某些应用场景无法利用 RBAC 授权机制实现:在授予所有已知、未知 CRD 资源操作权限的同时,显式地排除某些敏感权限。但我们可以借助 ABAC、Webhook 授权模式,结合准入控制器来为此类场景的服务账号进行权限管理,从而缓解这类问题。
下面是一个通过 RBAC 授权机制为 ServiceAccount 绑定权限的示例:
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: example-clusterrole namespace: example-nsrules:- apiGroups: - apps resources: - daemonsets - deployments - replicasets - statefulsets resourcesNames: - test verbs: - '*'- nonResourceURLs: - /healthz - /healthz/* verbs: - get---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: example-rolebinding namespace: example-nsroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: example-clusterrolesubjects:- kind: ServiceAccount name: example-sa namespace: example-nsRBAC 安全风险剖析Kubernetes 是一个分布式的容器编排系统。除了要确保 Kubernetes 基础组件的配置安全(例如 API Server、Kubelet Server 基本的认证授权配置等,对应 CIS Kubernetes Benchmark 中的第一至第四章中的要求)外,我们还需要对其 RBAC 授权配置进行精细化管理。
正确的授予主体 RBAC 权限能够避免为集群引入不必要的稳定性 & 安全性风险,而不恰当的权限设置可能导致敏感数据泄露、资源滥用、权限提升,甚至威胁整个集群的安全。接下来我们将借助文献和案例来进一步说明其安全风险。
概述在 Kubernetes 中,可以通过对资源的操作来实现信息窃取、权限提升、横向移动等攻击。例如可以利用 pods/exec 资源的 create 权限通过 API Server 在指定容器内执行任意命令,也可以利用 nodes/proxy 资源的 create 权限直接访问 Kubelet Server 在指定容器内执行任意命令,还可以利用 pods 的 create 权限创建具有安全风险的容器、利用 pods 的 patch 权限在指定 Pod 的容器内执行代码......「随着 Kubernetes 的广泛使用,此类风险在云厂商、PaaS平台、云原生应用、SaaS产品中愈演愈烈,轻则被用于后渗透入侵,重则会给产品引入安全漏洞。」
Palo Alto Networks 的安全研究员深入分析了 Kubernetes 中的所有敏感权限,并根据其危害类型将其分类和分级[2](严重等级请参考开源项目 rbac-police 的风险权限扫描策略集[3])。如下图所示,在这些敏感权限中,有许多都可以被攻击者用于信息泄漏、权限提升、横向移动等攻击,最终实现整个集群的接管。
Palo Alto Networks 的研究结果表明,在针对主流公有云、CNI 厂商的分析中,有将近 50% 的厂商存在容器逃逸后轻易导致集群沦陷的安全问题。另外有 25% 的厂商存在容器逃逸后在一定条件下导致集群沦陷的安全风险[2]。
公开案例RBAC Buster:来自 Aqua Sec 的研究者通过蜜罐首次捕获到利用 Kubernetes 的 RBAC 配置漏洞进行攻击的行为,黑客通过创建后门访问集群,导致未授权访问和数据泄露的风险。详见 First-Ever Attack Leveraging Kubernetes RBAC to Backdoor Clusters[5]Sys:All:研究团队 The Orca Research Pod 扫描了 250,000 个 GKE 集群(约总数的 2%),发现其中 1300 个集群存在错误配置的角色绑定,其中有 108 个集群允许攻击者使用任何有效的谷歌帐号接管集群。详见:How A Simple Loophole in Google Kubernetes Engine Puts Clusters at Risk of Compromise[6] & GCP-2024-003 security-bulletins[7]在 OWASP Kubernetes Top 10 安全风险中,RBAC 配置错误导致的“权限过多”问题排名第三,可能引发未授权操作和权限提升。详见 OWASP Kubernetes Top 10[8]风险示例下面的示例演示了攻击者可以利用任意 secrets 的 create 权限,来获取了包含敏感权限的 ServiceAccount(这里以窃取 prometheus-agent SA 的 token 为例)的 token。对此,我们建议使用专用命名空间中的 Role 来定义所需权限,从而与 kube-system 等敏感命名空间隔离。
下面的示例演示了攻击者可以利用任意 secrets 的 get 权限,来爆破获取保存 SA token 的 secrets。虽然爆破 SA token 需要较长时间(爆破一个拥有 5 个随机字符串的 SA token 最多需要 27^5 次),但此权限也可能被用于窃取其他已知名称的 secrets 资源。对此,我们建议使用 Role 定义角色,或者通过 resourceNames 对 secrets 的权限范围进行约束,而非授予全部命名空间中任意 secrets 的 get 权限。
以上数据和案例表明,Kubernetes RBAC 权限管理已成为一个必须认真对待并及时采取有效防御措施的安全问题。
RBAC 安全研发与运维最佳实践基于我们在字节跳动内部的安全实践,我们为 RBAC 授权配置总结了如下原则,以指引大家进行 Kubernetes RBAC 权限管理,从而降低由此为集群引入的安全风险。
遵循最小权限原则在 RBAC 角色中分配权限时,请遵循最小权限原则授予执行任务所需的最低权限。例如:
优先使用 Role, RoleBinding 授予一个、多个特定命名空间中的权限。定义 rule 时,使用明确的 apiGroups, resources, verbs 以及 resourceNames 来限定权限范围。❝
注意:
如果设置了 resourceNames 字段,那么请求权限不能是 list、watch、create、deletecollection,否则请求将不会被允许(「当使用 resourceNames 限制 list、watch 权限范围时,客户端必须在请求参数中指定 fieldSelector=metadata.name%3D{RESOURCENAME} 用于通过授权」)。但当 resourceNames 字段中包含 "" 时,将允许 list 请求。
虽然 RBAC 授权模式不支持通过 resourceNames 来约束 create、deletecollection 权限,但仍然建议通过 resourceNames 来约束 update、patch、get 等权限。
❞
RBAC 权限最小化不应被视作“非黑即白”,哪怕组件的某些敏感权限无法收敛,最小化权限仍然对降低风险、增加入侵检测的机率有重要作用。
避免使用默认角色/用户/用户组一般情况下,Kubernetes 和基于 Kubernetes 的 PaaS 平台会自动将一些默认角色绑定到默认用户和用户组,以保证系统的正常运行。如需查看 Kubernetes 创建的默认角色和绑定的完整列表,请参阅 Default roles and role bindings。
常见的默认角色有:cluster-admin, system:node, system:controller:daemon-set-controller ...常见的系统用户有:system:anonymous, system:kube-controller-manager, system:kube-scheduler, system:kube-proxy, system:serviceaccounts:NAMESPACE:default ...常见的系统用户组:system:unauthenticated, system:authenticated, system:serviceaccounts, system:nodes, system:monitoring, system:masters ...大部分默认角色(例如 cluster-admin, edit, system:node 等)都会被授予较广泛的权限。因此,我们「不建议」将默认角色绑定到服务账号,除非您知道并接受由此带来的安全风险。用户可以根据实际需要将其绑定到用户账号上。
除此之外,我们「应当避免」为系统用户(例如 system:anonymous, system:serviceaccounts:NAMESPACE:default 等)、系统用户组(例如 system:authenticated, system:serviceaccounts 等)绑定额外的角色,这会导致权限的非预期扩散,引入严重的安全风险。
避免为 default 服务账号授予权限在附录 1 的“准入控制机制”一节中,我们提到了默认启用的 ServiceAccount 准入控制器。创建 Pod 时如果未指定 ServiceAccount,那么 ServiceAccount 准入控制器会将命名空间内名为 default 的 ServiceAccount 分配给 Pod。
因此,我们「应当避免」为 default 服务账号授予权限,这会导致非预期的权限泄露。
尽量避免使用通配符* 字符是一个适用于所有内容的通配符,「应尽量避免」在规则中使用通配符。这容易造成授权范围过大,除非您明确知晓并接受此行为可能引入的安全风险。建议您在 RBAC 规则中明确指定 API 组(apiGroups)、资源(resources)、动词(verbs),甚至是资源名称(resourceNames)。
例如,在 verbs 字段中指定 * 将授予 get、list、watch、patch、update、deletecollection 和 delete 等权限。下表举例说明了如何避免在规则中使用通配符。
尽量避免使用敏感权限设计角色前,请先仔细评估存在权限提升、命令执行、信息泄漏等安全风险的权限。例如 secrets 的操作权限、证书签发权限、pods/exec 访问权限等,更多请参考 Kubernetes RBAC - privilege escalation risks[9] 和 风险权限扫描策略集[3]。
为应用服务、控制组件授予敏感权限会给整个集群引入安全风险。在系统设计和开发时,「应尽量避免」使用它们,并配合其他手段进行安全编排、安全加固和入侵检测。
尽量使用单独规则对特定资源授予权限规划规则时,建议您尝试以下简要步骤,在每个角色中采用更高效、可读、易于维护的规则设计[4]:
为主体需要访问的每项资源上的动词草拟单独的 RBAC 规则。草拟规则后,分析规则,以检查多条规则是否具有相同的 verbs 列表。将这些规则合并为一条规则。请将其余的所有规则彼此分散。这种方法可实现更有条理的规则设计,将对多个资源授予相同动词的规则组合起来,将为资源授予不同动词的规则彼此分散[4]。
例如,如果您的工作负载需要获取 deployments 资源的权限,但需要 daemonsets 资源的 list 和 watch 权限,则您应该在创建角色是使用单独规则。当您将 RBAC 角色绑定到工作负载时,该角色将无法对 deployments 资源进行 watch 操作[4]。
再举一例,如果您的工作负载需要 pods 资源和 daemonsets 资源的 get 和 watch 权限,您可以将它们组合成一条规则,因为工作负载需要在这两个资源上使用相同的动词[4]。
在下表中,这两种规则设计均有效,但拆分规则会根据需要更精细地限制资源访问权限[4]。
安全编排与其它有些场景下,业务需求可能与安全要求产生冲突。例如一些应用必需某些敏感权限才可以正常运行或提供必要功能。对此,我们建议您考虑采取以下安全编排、纵深防御策略来尽量降低风险。
❝
注意:如果您的组件是 DaemonSet 类型且必需某些敏感权限,我们强烈建议您对其进行重构或缓解(例如通过webhook准入控制器进行校验等)。否则当出现节点沦陷的事件时,整个集群都将遭受威胁。
❞
「使用专用命名空间」如果应用仅需命名空间范围内的权限,那么我们「强烈建议」将其部署在专用命名空间中,而非 kube-system 命名空间、default 命名空间、业务负载所在的命名空间,从而避免不必要的权限扩散。例如某控制组件的 SA 会被授予所在命名空间 secrets 的 list & watch 权限用于维护 ssl 密钥对。我们可以将其部署在专用命名空间(而非 kube-system 命名空间、业务负载所在的命名空间)来降低 SA token 泄漏后的能够带来的安全风险。如果应用需要所有全局范围内的敏感权限,那么「不建议」将其部署在 default 命名空间、业务负载所在的命名空间,从而避免潜在的权限扩散。「制定特殊调度策略」如果某些组件需要全局范围内的敏感权限,那么「建议」制定合适的调度策略(通过节点污点、准入控制策略等确保调度策略不会被绕过),将此类组件强制调度到专用节点池或使用弹性容器部署组件,从而实现将包含敏感权限的控制组件与业务负载分离。避免业务负载所在节点沦陷后,敏感权限 SA token 泄漏带来的安全风险。「单独部署敏感组件」您也可以将需要敏感权限的组件部署到独立的控制面,从而解决此类安全风险。「建设纵深防御」在实际业务场景中,不是所有的敏感权限都能够被消除。尤其是那些风险等级较高,但业务又强依赖的权限。因此,除权限最小化、安全编排外,我们强烈建议您引入主机、Kubernetes 层面的威胁管理与入侵检测能力。从而及时发现并管理风险,告警并响应潜在的入侵行为。RBAC 安全防护与治理实践在许多企业中,往往会因为安全意识不足、云原生安全建设开展较晚、使用开源云原生应用等原因,已经为系统引入了大量 RBAC 权限风险。但由于涉及基础设施,并且缺乏相应的知识和手段,针对这类风险的防护和治理往往充满挑战。接下来笔者将向大家介绍我们在字节跳动内部的一些经验和实践,抛砖引玉供大家参考。
整体思路通过公开案例和红蓝演练等方式,向研发团队展示 K8s RBAC 错误配置对生产环境安全性和稳定性造成的危害。与 DevOps 团队在风险认知上达成一致,从而自上而下对齐治理目标。在开展治理工作前,应根据企业的实际情况制定合理的计划。同时,安全团队应提供治理所需的知识库、工具和系统,与 Ops 团队构建合适的治理流程,以确保治理工作顺利推进。此外,安全团队还应持续加强反入侵能力建设,为 K8s RBAC 等安全风险提供兜底保障。
制定计划制定切实可行的计划,以及提供必要的工具与系统,是收敛 K8s RBAC 安全风险的重要前提和保障。
「数据驱动」我们建议以数据驱动的方式开展防护和治理工作。通过持续的安全扫描来识别风险、评估风险严重性、明确优先级。通过定位风险引入的原因,来定位责任人和卡点,从而对症下药。❝
需要指出的是,虽然“RBAC 安全风险剖析”一章已经指出 Kubernetes 中有大量权限存在安全风险,但面对各种场景和现实因素,我们很可能无法要求业务避免使用所有的敏感权限。这需要我们在安全防护与业务需求之间取得平衡。
❞
「明确优先级」我们结合 RBAC 风险权限的可利用性、严重等级,以及影响范围等,将其划分成五个优先级(风险权限及其安全扫描策略请参考 风险权限扫描策略集[3]),以此来推进 K8s RBAC 的权限评估和治理。在完成风险评估和治理前后,我们还需借助入侵检测等机制来进行持续监控与兜底。「增量管控 & 存量整改」通过在企业的 PaaS 平台、K8s 集群内集成准入控制机制,以此来实现增量管控。建议提供必要的白名单机制,为无法立刻整改的应用进行临时豁免。然后根据定期扫描结果来推动责任人进行存量组件的整改、灰度测试、全量更新。防护与治理框架在字节内部,我们构建了如下图所示的安全防护和治理框架,并推进了权限治理工作。
在开发与集成阶段,我们借助最佳安全实践来指导研发部门进行安全的 RBAC 权限设计和开发。并在部分 CI/CD 流水线中集成了安全扫描,对存在危险 RBAC 配置的 chart 产物进行拦截、告警和记录。
在部署阶段,我们通过与 PaaS 平台集成的准入控制机制、K8s 准入控制器来对非法的应用和资源进行增量管控。并指导关键业务通过安全编排等手段来降低具有敏感权限的控制组件的安全风险。这里我们基于开源项目 Kyverno 的策略引擎,实现了 Policy as Code。从而在流水线安全扫描、准入控制中实现策略兼容,降低了安全策略的维护成本。
在运行阶段,我们通过定期扫描(基于开源项目 rbac-police)来持续识别风险。此外,我们还设计实现了针对服务账号和用户账号的行为建模能力。此能力基于账户行为来生成最小权限的角色定义,为组件的权限收敛提供参考。由于不是所有的敏感权限都能得到整改,因此,在实践中我们会基于 K8s 的审计日志进行入侵检测,从而发现潜在的攻击行为。
通过以上机制,我们构建了针对 K8s RBAC 安全风险的防护和治理框架,为字节内部大规模生产集群的 RBAC 安全治理和防护提供了必要能力。
总结RBAC 是 Kubernetes 中的一项重要的授权机制,正确地配置 RBAC 对于保障基于 Kubernetes 的系统安全至关重要。在设计中,我们应遵循最小权限原则进行权限设计,并理解敏感权限的安全风险,为其引入必要的防护能力。在开发中,我们要注意避免过度授权、权限混乱等问题。在安全防护和运营中,我们还要平衡安全要求和业务需求,持续收敛安全风险,建立纵深防御体系。
希望本文能让大家更好地理解 Kubernetes 的权限体系,了解 RBAC 授权模式的安全风险和最佳安全实践,从而指导系统的安全设计、开发和防护,最终构建更加安全可靠的系统。
参考文献https://kubernetes.io/docs/reference/access-authn-authzhttps://www.paloaltonetworks.com/apps/pan/public/downloadResource?pagePath=/content/pan/en_US/resources/whitepapers/kubernetes-privilege-escalation-excessive-permissions-in-popular-platformshttps://github.com/PaloAltoNetworks/rbac-police/tree/main/libhttps://cloud.google.com/kubernetes-engine/docs/best-practices/rbachttps://www.aquasec.com/blog/leveraging-kubernetes-rbac-to-backdoor-clustershttps://orca.security/resources/blog/sys-all-google-kubernetes-engine-riskhttps://cloud.google.com/kubernetes-engine/security-bulletins#gcp-2024-003https://owasp.org/www-project-kubernetes-top-tenhttps://kubernetes.io/docs/concepts/security/rbac-good-practices/#privilege-escalation-risks「通过“容器安全防护平台”审计K8s RBAC错误配置」
火山引擎容器安全防护平台的“RBAC洞察”功能支持定期自动扫描 K8s RBAC 错误配置,帮助您高效收敛攻击面。
同时支持自定义审计规则,满足企业个性化风险治理诉求。
附录 1:API Server 认证与授权Kubernetes 是一个以容器技术为基础,以声明式 API Server 为核心的分布式容器编排系统。作为 Kubernetes 对外服务的唯一接口,API Server 具备多种认证、授权、准入控制机制。
认证机制认证器将对请求者进行身份识别,识别出对应的 Username, Groups, UID, Extra fields。所有认证通过的用户都会位于 system:authenticated 用户组中。
❝
注意:当用户使用 AlwaysAllow 以外的授权器时,将默认开启匿名访问。认证失败的用户将位于 system:unauthenticated 用户组,其 Username 则为 system:anonymous。
❞
Kubernetes 支持多种认证机制,可用于不同场景下的客户端身份认证。
「证书认证」UserAccount 使用 x509 客户端证书访问 API Server 时,API Server 会使用 CA 证书对其进行身份认证。如果认证通过,则使用 Common Name 作为 Username,使用 Organization 作为 Group。Kubernetes 还支持用户配置 Authenticating Proxy,可以使用独立的 CA 对符合请求头条件的请求进行身份认证。更多请参见 authenticating proxy。「Token 认证」Static Token:Kubernetes 允许用户通过 API Server 的 --token-auth-file 参数来设置一个保存用户信息和 token 的 csv 文件。由于 token 无法动态吊销,因此不鼓励用户使用。Bootstrap Token:这是一类特殊的 bearer token,被用于创建新集群、在集群中添加新节点时,为节点 Kubelet 签发证书。ServiceAccount Token:这是一类特殊的 bearer token,它使用 JSON Web Token (JWT) 作为令牌格式,主要用于容器内应用与 API Server 通信时进行身份认证。当开启 ServiceAccount 准入控制器后,默认情况下 API Server 会为 Pod 自动创建并关联 ServiceAccount 并将 token 挂载到容器内。虽然 ServiceAccount Token 可以用于从集群外访问 API Server,但从安全角度不建议这样使用,这会给安全管理、审计与监控引入风险。Webhook Token:Kubernetes 还支持用户配置 webhook 认证来扩展认证能力。即通过向远程 webhook server 发送 TokenReview 认证请求来验证 bearer token。OpenID Connect Tokens:Kubernetes 支持使用 OIDC 来进行用户和服务账户的身份认证。OIDC 是一个基于 OAuth 2.0 协议的身份验证层,允许用户使用外部身份提供商进行身份验证。OIDC 也使用 JSON Web Tokens (JWT) 作为令牌格式。主流公有云提供商的容器托管服务,例如 EKS,GKE,AKS 均支持使用 OIDC 进行身份认证。授权机制Node 授权模式:此授权模式仅用于对 Kubelet 的账号进行授权,它基于调度到所在节点的 pods 为 Kubelet 授予相关权限,从而确保 Pod 能够正常运行。所有 Kubelet 账号的用户名格式为system:node:[NODE_NAME],并且都位于 system:nodes 用户组。RBAC 授权模式:此授权模式可基于用户角色对 Kubernetes 内资源进行细粒度访问控制。Kubernetes 的一大特点是将底层基础设施及其关系抽象为不同类型的资源对象,并通过声明式 API 暴露出来。而 RBAC 则是被广泛使用的授权模式,它允许用户通过管理 rbac.authorization.k8s.io API 组内资源对象的方式来进行灵活的权限管理。更多请参见“Kubernetes RBAC 授权原理”一章。ABAC 授权模式:此授权模式提供了基于属性的访问控制 (ABAC) 机制,允许用户通过结合属性的策略向用户授予资源的访问权限。用户需要以 JSON 形式定义访问控制策略,并且每次更新策略都需要重启 API Server,因而不常使用。Webhook 授权模式:此授权模式支持用户配置 Webhook Server 来扩展 Kubernetes 的授权能力。AlwaysAllow 授权模式:此授权模式将允许所有的用户请求。❝注意:当开启 API Server 的 --anonymous-auth=true 后,匿名用户也可以访问 Kubernetes 的所有资源。❞AlwaysDeny 授权模式:此授权模式将拦截所有的用户请求。准入控制机制Kubernetes 内置了大量准入控制器,它们可以在 API Server 处理 create, delete, modify 请求之前,对请求进行变异(Mutating)、验证(Validating),从而实现强制修改资源、访问控制等功能。Kubernetes 内置了如下准入控制器:
AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, ClusterTrustBundleAttest, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyServiceExternalIPs, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurity, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionPolicy, ValidatingAdmissionWebhook.Kubernetes 默认启用的准入控制器如下所示:
NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, ClusterTrustBundleAttest, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionPolicy, ValidatingAdmissionWebhook, ResourceQuota接下来简要介绍如下几个常用的准入控制器
ServiceAccount:此准入控制器用来为 Pod 自动配置 ServiceAccount。若创建 Pod 时未指定 ServiceAccount,那么准入控制器会将命名空间内名为 default 的 ServiceAccount 分配给 Pod。通常情况下,此准入控制器默认启用。NodeRestriction:此准入控制器用于对 Kubelet 的账户权限进行限制,限制 Kubelet 可以修改的 Node 和 Pod 对象。开启此准入控制器后,Kubelet 只被允许修改与其对应的 Node 对象,并且其修改范围也会受到严格限制,避免被攻击者利用。与此同时,Kubelet 也只被允许修改被调度到当前节点的 Pod 对象。PodSecurity:此准入控制器用于替代 PodSecurityPolicy,它能够基于 Pod Security Standards 在 namespace 级别对 Pod 资源进行准入控制、审计、提醒。MutatingAdmissionWebhook:Kubernetes 允许用户通过 MutatingWebhookConfiguration 资源来灵活配置自定义的 Webhook 对请求进行变异,向用户提供了较高的可扩展性。ValidatingAdmissionWebhook:Kubernetes 允许用户通过 ValidatingWebhookConfiguration 资源来灵活配置自定义的 Webhook 对请求进行验证,向用户提供了较高的可扩展性。附录 2:Kubelet Server 认证与授权Kubelet 作为 Kubernetes 的 Agent 运行在集群中的每个节点上,它主要通过监控集群资源、本地资源的变化来完成 pods/containers 的创建、secrets/configmap 同步等工作。除此之外,Kubelet 还会通过本地端口对外提供服务。其中 10250 端口提供了多个接口,对外提供容器内命名执行、容器端口转发、获取容器和节点日志、获取节点状态、获取指标信息等功能。
对此 Kubernetes 也为 Kubelet Server 提供了多种认证和授权机制。
认证机制匿名认证:Kubelet 默认启用匿名访问,匿名请求的认证结果是:username 为 system:anonymous,groups 为 system:unauthenticated(kubeadm 创建的集群默认关闭匿名认证)。证书认证:可以通过为 Kubelet Server 配置的 CA 证书对客户端身份进行认证。在许多场景下,它往往与 API Server 使用相同的 CA 证书。Webhook 认证:Kubelet Server 将以 Kubelet 的身份向 API Server 发起认证请求(通过 TokenReview API),对请求 Kubelet Server 的客户端身份进行认证。因此任何能被 API Server 验证的证书、服务 token,均可被用来访问 Kubelet Server。授权机制AlwaysAllow 授权模式:任何通过认证(注:也包括匿名用户)的用户都可以得到授权。Webhook 授权模式:Kubelet Server 将以 Kubelet 的身份向 API Server 发起授权校验请求(通过 SubjectAccessReview API),从而对请求 Kubelet Server 的客户端身份进行权限校验。所需权限跟所访问的接口有关,例如 node/proxy, nodes/log 资源访问权限的 get, create 权限等。下图以 kubectl exec 命令的背后逻辑为例,展示 Kubelet Server 对客户端进行认证和授权的整个过程。
执行 kubectl exec 后都发生了什么?