保护您的 Kubernetes 集群的 RBAC 必备最佳实践
学习 Kubernetes RBAC 最佳实践、最小权限 Role 示例、服务账户范围界定以及集群安全审计检查。
保护 Kubernetes 集群的 RBAC 最佳实践
Kubernetes RBAC 决定了谁能在集群中执行哪些操作。一个单一的宽泛绑定就可能让被攻破的账户读取密钥、修改工作负载或接管集群资源。
本指南将解释核心 RBAC 对象,展示实际示例,并提供审查习惯,以防止权限随时间发生漂移。
理解 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 实施最小权限原则
信息安全的一个核心原则是最小权限原则。用户、程序或进程只应获得完成其工作所需的权限。在 Kubernetes 中,过于宽松的角色是导致小问题演变成集群范围问题的常见原因。
定义细粒度权限
在制定 RBAC 策略时,请考虑所需的精确操作和资源:
- 动词:不要授予
*(所有动词),而是明确指定需要哪些操作(get、list、watch、create、update、delete、patch、exec)。 - 资源:具体指定资源(
pods、deployments、secrets、configmaps)。除非绝对必要且有充分理由的管理角色,否则避免授予对资源的*访问权限。 - 资源名称:对于像
secrets这样非常敏感的资源,你可以将某些动词(如get)限制在资源类型中的特定resourceNames上。不要依赖resourceNames来实现列表式访问,因为list和watch不能以相同方式限定到单个命名对象。 - API 组:大多数 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: [""] # 用于 Pods 和 Pod 日志的核心 API 组
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 中创建密钥或列出所有节点。
示例 2:应用程序服务账户访问密钥
作为 ServiceAccount 运行的应用程序需要读取其自身命名空间中的特定密钥。
首先,确保服务账户存在或创建一个:
# app-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: my-app-namespace
name: my-app-service-account
应用此服务账户:
kubectl apply -f app-sa.yaml
接下来,定义一个允许读取特定密钥的 Role:
# secret-reader-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: my-app-namespace
name: secret-reader
rules:
- apiGroups: [""]
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
现在,该应用程序将只能读取指定的密钥,而不能读取其他任何内容。
示例 3:集群管理员角色(谨慎使用)
集群范围的管理员角色应极其谨慎地授予。以下是一个 ClusterRole 示例,用于列出所有节点,监控工具可能需要此权限。
# node-viewer-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-viewer
rules:
- apiGroups: [""]
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在这些命名空间内授予权限。
优先使用 Roles 而非 ClusterRoles:
- 仅在权限确实需要集群范围时(例如节点管理、自定义资源定义、特定监控代理)才使用
ClusterRole和ClusterRoleBinding。 - 大多数特定于应用程序的权限应该是命名空间范围的。
- 仅在权限确实需要集群范围时(例如节点管理、自定义资源定义、特定监控代理)才使用
定期审计和审查 RBAC 策略:
- RBAC 策略会随时间漂移。定期审查谁拥有什么访问权限。
- 使用像
kubectl auth can-i这样的工具来测试特定用户/服务账户的权限。
# 检查 '[email protected]' 是否可以在 'dev-team-a' 中获取 pods 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,并具有最小权限。 - 对于不需要 Kubernetes API 访问的 Pod,在 Pod 或服务账户上设置
automountServiceAccountToken: false。
- 在集群内运行的应用程序应使用
与外部身份管理集成:
- 对于人类用户,将 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 不需要与 Kubernetes API 交互,请在 Pod 规范或服务账户定义中设置automountServiceAccountToken: false,以减少其攻击面。 - 缺乏审计:如果没有定期审查,RBAC 策略可能会随着集群需求的变化而过时或过于宽松。实施审查流程。
- 混淆
Role和ClusterRole:误解范围可能导致在只需要命名空间范围访问时授予了集群范围的访问权限。
要点
RBAC 的最佳效果是保持其简单和具体:为应用程序团队使用命名空间角色,狭窄的服务账户权限,未经审查不使用通配符,以及定期的 kubectl auth can-i 检查。将每个绑定视为生产代码,因为在 Kubernetes 集群中,它确实就是。