保护 Kubernetes 集群的 RBAC 基本最佳实践
Kubernetes 已成为容器编排的既定标准,使组织能够以前所未有的效率部署和扩展应用程序。然而,能力越大,责任越大,尤其是在安全性方面。Kubernetes 中最关键的安全机制之一是基于角色的访问控制 (RBAC),它允许管理员精确定义集群内谁可以做什么。
本文深入探讨了 Kubernetes RBAC 的基本概念,并概述了保护生产环境的基本最佳实践。我们将探讨如何实施最小权限原则,指导您完成角色 (Role) 和集群角色 (ClusterRole) 的创建、绑定和细致管理,以最大限度地减少潜在的安全漏洞。通过理解和应用这些策略,您可以显著增强 Kubernetes 集群的安全性,保护您宝贵的应用程序和数据。
理解 Kubernetes RBAC 基础知识
Kubernetes 中的 RBAC 是一种授权机制,它根据个人用户或服务帐户的角色来管理对 Kubernetes 资源的访问权限。它是防御的一个关键层,确保只有授权实体才能对特定资源执行特定操作。
其核心是,RBAC 依赖于四种主要的 Kubernetes 对象类型:
Role(角色):Role是一组权限,适用于特定的命名空间。它定义了可以对哪些资源(如pods、deployments、services、secrets)执行哪些操作(如get、list、create、update、delete等动词)。例如,一个Role可能会授予在development命名空间中读取pods和deployments的权限。ClusterRole(集群角色): 与Role类似,但ClusterRole定义的权限适用于整个集群或非命名空间资源(例如nodes、persistentvolumes)。ClusterRole还可以定义跨所有命名空间的命名空间资源的权限。例如,一个ClusterRole可能会允许列出集群中的所有nodes。RoleBinding(角色绑定):RoleBinding将Role(或应用于命名空间的ClusterRole)中定义的权限授予用户、组或服务帐户。它始终在特定的命名空间内操作。ClusterRoleBinding(集群角色绑定):ClusterRoleBinding将ClusterRole中定义的权限授予用户、组或服务帐户,将这些权限应用于整个集群。
这些对象共同使管理员能够构建一个健壮且精细的访问控制系统。当用户或应用程序(由服务帐户表示)尝试执行操作时,Kubernetes 会评估现有的 RoleBindings 和 ClusterRoleBindings 以确定是否允许所请求的操作。
使用 RBAC 实施最小权限原则
信息安全的一个中心原则是最小权限原则 (PoLP)。该原则规定,用户、程序或进程应仅被授予执行其工作所需的最低权限集。在 Kubernetes 中,遵守 PoLP 对安全至关重要。权限过多的角色是常见的攻击媒介,因为它们允许攻击者在攻陷一个帐户后获得比预期更广泛的访问权限。
定义精细的权限
在设计 RBAC 策略时,请考虑所需的精确操作和资源:
- 动词 (Verbs): 不要授予
*(所有动词),而是明确指定所需的操作(get、list、watch、create、update、delete、patch)。 - 资源 (Resources): 明确指定资源(
pods、deployments、secrets、configmaps)。除非绝对必要且有充分理由,否则避免对资源授予*访问权限。 - 资源名称 (Resource Names): 对于像
secrets这样非常敏感的资源,您甚至可以限制对资源类型内特定resourceNames的访问。 - API 组 (API Groups): 大多数 Kubernetes 资源都属于一个 API 组(例如
apps、rbac.authorization.k8s.io,核心资源为"")。指定正确的 API 组以进一步缩小范围。
命名空间范围限定
对于大多数应用程序和开发团队,权限应限制在特定的命名空间内。这种隔离可确保一个应用程序或团队环境的泄露不会自动导致集群范围的访问。只要有可能,始终优先使用 Role 和 RoleBinding 而不是 ClusterRole 和 ClusterRoleBinding。
实际 RBAC 实施:示例
让我们通过一些创建和绑定 RBAC 策略的实际示例。
示例 1:开发人员对特定命名空间的访问权限
假设一名开发人员需要在其专用的 dev-team-a 命名空间中管理部署和查看日志。他们不应访问其他命名空间或集群范围的资源。
首先,在 dev-team-a 命名空间中为该开发人员定义一个 Role:
# dev-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev-team-a
name: dev-deployer
rules:
- apiGroups: ["apps"] # 用于 Deployments
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "delete", "patch"]
- apiGroups: ["core"] # 用于 Pods 和 Pod 日志
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
应用此角色:
kubectl apply -f dev-role.yaml
接下来,将此 Role 绑定到特定用户(例如,通过外部身份提供者的 [email protected])或 dev-team-a 命名空间内的服务帐户:
# dev-role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: dev-team-a
name: john-dev-deployer-binding
subjects:
- kind: User
name: [email protected] # 名称区分大小写
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: dev-deployer
apiGroup: rbac.authorization.k8s.io
应用此绑定:
kubectl apply -f dev-role-binding.yaml
现在,[email protected] 只能在 dev-team-a 命名空间内管理部署和查看日志。例如,他们不能在 kube-system 中创建 Secret 或列出所有节点。
示例 2:应用程序服务帐户访问 Secret
以 ServiceAccount 身份运行的应用程序需要在其自己的命名空间中读取特定的 Secret。
首先,确保服务帐户存在或创建一个:
# app-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: my-app-namespace
name: my-app-service-account
应用此服务帐户:
kubectl apply -f app-sa.yaml
接下来,定义一个允许读取特定 Secret 的 Role:
# secret-reader-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: my-app-namespace
name: secret-reader
rules:
- apiGroups: ["core"]
resources: ["secrets"]
resourceNames: ["my-app-db-credentials"]
verbs: ["get"]
应用此角色:
kubectl apply -f secret-reader-role.yaml
最后,将此 Role 绑定到 my-app-service-account:
# app-secret-reader-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: my-app-namespace
name: my-app-secret-reader-binding
subjects:
- kind: ServiceAccount
name: my-app-service-account
namespace: my-app-namespace
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
应用此绑定:
kubectl apply -f app-secret-reader-binding.yaml
该应用程序现在将只能读取指定的 Secret,仅此而已。
示例 3:集群管理员角色(需谨慎)
集群范围的管理员角色应极其谨慎地授予。以下是一个 ClusterRole 的示例,用于列出所有节点,这可能是监控工具需要的。
# node-viewer-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-viewer
rules:
- apiGroups: ["core"]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
应用此 ClusterRole:
kubectl apply -f node-viewer-clusterrole.yaml
然后,使用 ClusterRoleBinding 将其绑定到监控服务帐户:
# monitoring-node-viewer-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitoring-node-viewer-binding
subjects:
- kind: ServiceAccount
name: monitoring-sa
namespace: monitoring
roleRef:
kind: ClusterRole
name: node-viewer
apiGroup: rbac.authorization.k8s.io
应用此绑定:
kubectl apply -f monitoring-node-viewer-binding.yaml
警告: 对人类用户使用 ClusterRole 和 ClusterRoleBinding 时要极其小心。将其使用限制为真正的集群管理员和特定的基础设施服务帐户。
关键 RBAC 最佳实践
遵循这些最佳实践将显著提高您集群的安全性:
-
实施最小权限原则 (PoLP):
- 只授予最少必要的权限。仔细审查每项权限。
- 尽可能避免在
resources和verbs中使用通配符 (*)。如果使用,请说明理由并尝试将其范围尽可能缩小。 - 通过在角色中使用
resourceNames来限制对敏感资源(如secrets)的访问。
-
使用命名空间进行隔离:
- 将您的应用程序和团队组织到不同的命名空间中。
- 默认情况下,在这些命名空间内授予权限时使用
Role和RoleBinding。
-
优先使用 Role 而不是 ClusterRole:
- 仅当权限确实需要在集群范围内生效时(例如节点管理、自定义资源定义、特定监控代理),才使用
ClusterRole和ClusterRoleBinding。 - 大多数特定于应用程序的权限应命名空间化。
- 仅当权限确实需要在集群范围内生效时(例如节点管理、自定义资源定义、特定监控代理),才使用
-
定期审计和审查 RBAC 策略:
- RBAC 策略可能会随时间推移而漂移。定期审查谁拥有什么访问权限。
- 使用
kubectl auth can-i等工具来测试特定用户/服务帐户的权限。
```bash
检查 '[email protected]' 是否可以在 'dev-team-a' 中获取 pod
kubectl auth can-i get pods --namespace=dev-team-a [email protected]
检查 'monitoring-sa' 是否可以列出节点(集群范围)
kubectl auth can-i list nodes --as=system:serviceaccount:monitoring:monitoring-sa
```
* 考虑使用第三方工具或自定义脚本进行全面的 RBAC 审计。 -
分离管理员角色:
- 绝不向开发人员或应用程序服务帐户授予
cluster-admin权限。 - 创建具有必要提升权限的特定管理
ClusterRoles(例如cluster-reader、node-reader)。
- 绝不向开发人员或应用程序服务帐户授予
-
利用服务帐户进行应用程序管理:
- 在集群内部运行的应用程序应使用
ServiceAccounts与 Kubernetes API 交互。 - 每个应用程序或微服务理想情况下都应拥有自己的专用
ServiceAccount及其最少权限。 - 对于不需要 API 访问的 Pod,确保在 Pod 规约或服务帐户定义中将
automountServiceAccountToken设置为false,仅在必要时设置为true。
- 在集群内部运行的应用程序应使用
-
集成外部身份管理:
- 对于人类用户,将 Kubernetes 与外部身份提供者(例如 OIDC、LDAP、Active Directory)集成以进行身份验证和组管理。
- 将外部组映射到 Kubernetes
RoleBindings或ClusterRoleBindings以便于管理。
-
使用 GitOps 自动化 RBAC 管理:
- 将 RBAC 策略视为代码。将其存储在版本控制的存储库 (Git) 中。
- 使用 GitOps 原则管理和部署 RBAC 配置,确保一致性、可追溯性和更轻松的回滚。
-
通过审计日志监控 RBAC 事件:
- 启用并配置 Kubernetes 审计日志,以跟踪 API 请求,包括谁、何时执行了什么操作。
- 定期审查审计日志,以检测与 RBAC 相关的未经授权的访问尝试或可疑活动。
-
定期更新 Kubernetes:
- 及时了解 Kubernetes 版本,以受益于安全补丁和改进,包括 RBAC 增强功能。
常见陷阱及规避方法
- 权限过大的通配符:授予
apiGroups: ["*"]、resources: ["*"]或verbs: ["*"]是重大的安全风险。始终明确指定。 - 默认使用
cluster-admin:绝不要将system:masters组或cluster-adminClusterRole用于日常操作,也不要将其分配给非管理员用户。这是通往您整个集群的后门。 - 忽略
automountServiceAccountToken:默认情况下,每个 Pod 都会挂载一个服务帐户令牌。如果 Pod 不需要与 Kube API 交互,请在 Pod 规约或服务帐户定义中设置automountServiceAccountToken: false,以减少其攻击面。 - 缺乏审计:如果没有定期审查,随着集群需求的演变,RBAC 策略可能会过时或权限过度。实施审查流程。
- 混淆
Role和ClusterRole:对范围的误解可能导致在只需要命名空间访问时授予了集群范围的访问权限。
结论
保护您的 Kubernetes 集群是一项持续的旅程,而 RBAC 是您安全工具库中不可或缺的工具。通过严格应用最小权限原则、使用命名空间进行访问隔离、仔细定义角色和绑定以及维护严格的审计流程,您可以构建一个强大的安全基础。请记住,RBAC 不是一个“设置好就不用管”的解决方案;随着集群和应用程序的发展,它需要持续的关注和适应。采纳这些最佳实践,以确保您的 Kubernetes 环境能够抵御未经授权的访问和潜在威胁。