保护您的 Kubernetes 集群的 RBAC 必备最佳实践

学习 Kubernetes RBAC 最佳实践、最小权限 Role 示例、服务账户范围界定以及集群安全审计检查。

保护 Kubernetes 集群的 RBAC 最佳实践

Kubernetes RBAC 决定了谁能在集群中执行哪些操作。一个单一的宽泛绑定就可能让被攻破的账户读取密钥、修改工作负载或接管集群资源。

本指南将解释核心 RBAC 对象,展示实际示例,并提供审查习惯,以防止权限随时间发生漂移。

理解 Kubernetes RBAC 基础

Kubernetes 中的 RBAC 是一种授权机制,它根据单个用户或服务账户的角色来调节对 Kubernetes 资源的访问。这是一个关键的安全层,确保只有授权实体才能对特定资源执行特定操作。

其核心是,RBAC 依赖于四种主要的 Kubernetes 对象:

  • RoleRole 是一组权限,适用于特定命名空间内。它定义了可以对哪些资源(如 podsdeploymentsservicessecrets)执行哪些操作(动词如 getlistcreateupdatedelete)。例如,一个 Role 可能授予在 development 命名空间中读取 podsdeployments 的权限。
  • ClusterRole:类似于 Role,但 ClusterRole 定义的权限适用于集群范围或非命名空间资源(例如 nodespersistentvolumes)。ClusterRole 也可以为所有命名空间中的命名空间资源定义权限。例如,一个 ClusterRole 可能允许列出集群中的所有 nodes
  • RoleBindingRoleBindingRole(或应用于命名空间的 ClusterRole)中定义的权限授予用户、组或服务账户。它始终在特定命名空间内操作。
  • ClusterRoleBindingClusterRoleBindingClusterRole 中定义的权限授予用户、组或服务账户,并将这些权限应用于整个集群

这些对象共同使管理员能够构建一个健壮且细粒度的访问控制系统。当用户或应用程序(由服务账户代表)尝试执行操作时,Kubernetes 会评估现有的 RoleBindingsClusterRoleBindings,以确定是否允许请求的操作。

使用 RBAC 实施最小权限原则

信息安全的一个核心原则是最小权限原则。用户、程序或进程只应获得完成其工作所需的权限。在 Kubernetes 中,过于宽松的角色是导致小问题演变成集群范围问题的常见原因。

定义细粒度权限

在制定 RBAC 策略时,请考虑所需的精确操作和资源:

  • 动词:不要授予 *(所有动词),而是明确指定需要哪些操作(getlistwatchcreateupdatedeletepatchexec)。
  • 资源:具体指定资源(podsdeploymentssecretsconfigmaps)。除非绝对必要且有充分理由的管理角色,否则避免授予对资源的 * 访问权限。
  • 资源名称:对于像 secrets 这样非常敏感的资源,你可以将某些动词(如 get)限制在资源类型中的特定 resourceNames 上。不要依赖 resourceNames 来实现列表式访问,因为 listwatch 不能以相同方式限定到单个命名对象。
  • API 组:大多数 Kubernetes 资源都属于一个 API 组(例如 appsrbac.authorization.k8s.io,核心资源为 "")。指定正确的 API 组可以进一步缩小范围。

命名空间范围界定

对于大多数应用程序和开发团队,权限应限制在特定命名空间内。这种隔离确保一个应用程序或团队环境中的泄露不会自动导致集群范围的访问。只要可能,始终优先使用 RoleRoleBinding,而不是 ClusterRoleClusterRoleBinding

实际 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

警告:对于人类用户,使用 ClusterRoleClusterRoleBinding 要极其谨慎。将其使用限制在真正的集群管理员和特定的基础设施服务账户。

基本 RBAC 最佳实践

遵循这些最佳实践将显著提高集群的安全态势:

  1. 强制执行最小权限原则 (PoLP)

    • 仅授予必要的最低权限。仔细审查每个权限。
    • 尽可能避免对 resourcesverbs 使用通配符 (*)。如果使用,请证明其合理性,并尽量缩小其范围。
    • 通过在角色中使用 resourceNames 来限制对敏感资源(如 secrets)的访问。
  2. 使用命名空间进行隔离

    • 将应用程序和团队组织到不同的命名空间中。
    • 默认使用 RoleRoleBinding 在这些命名空间内授予权限。
  3. 优先使用 Roles 而非 ClusterRoles

    • 仅在权限确实需要集群范围时(例如节点管理、自定义资源定义、特定监控代理)才使用 ClusterRoleClusterRoleBinding
    • 大多数特定于应用程序的权限应该是命名空间范围的。
  4. 定期审计和审查 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 审计。
  5. 分离管理角色

    • 切勿授予开发人员或应用程序服务账户 cluster-admin 权限。
    • 创建具有必要提升权限的特定管理 ClusterRoles(例如 cluster-readernode-reader)。
  6. 为应用程序利用服务账户

    • 在集群内运行的应用程序应使用 ServiceAccounts 与 Kubernetes API 交互。
    • 理想情况下,每个应用程序或微服务应拥有自己专用的 ServiceAccount,并具有最小权限。
    • 对于不需要 Kubernetes API 访问的 Pod,在 Pod 或服务账户上设置 automountServiceAccountToken: false
  7. 与外部身份管理集成

    • 对于人类用户,将 Kubernetes 与外部身份提供商(例如 OIDC、LDAP、Active Directory)集成以进行身份验证和组管理。
    • 将外部组映射到 Kubernetes RoleBindingsClusterRoleBindings,以便于管理。
  8. 使用 GitOps 自动化 RBAC 管理

    • 将 RBAC 策略视为代码。将它们存储在版本控制仓库 (Git) 中。
    • 使用 GitOps 原则来管理和部署 RBAC 配置,确保一致性、可追溯性和更简单的回滚。
  9. 通过审计日志监控 RBAC 事件

    • 启用并配置 Kubernetes 审计日志记录,以跟踪 API 请求,包括谁在何时执行了什么操作。
    • 定期审查审计日志,以检测未经授权的访问尝试或与 RBAC 相关的可疑活动。
  10. 定期更新 Kubernetes

    • 保持使用最新的 Kubernetes 版本,以受益于安全补丁和改进,包括 RBAC 增强。

常见陷阱及如何避免

  • 过于宽松的通配符:授予 apiGroups: ["*"]resources: ["*"]verbs: ["*"] 是一个主要的安全风险。始终要明确。
  • 默认使用 cluster-admin:不要在日常操作中使用 system:masters 组或 cluster-admin ClusterRole,也不要将其分配给非管理员用户。两者都赋予对集群的广泛控制权。
  • 忽略 automountServiceAccountToken:在许多集群中,除非你禁用自动挂载,否则 Pod 会收到一个服务账户令牌。如果 Pod 不需要与 Kubernetes API 交互,请在 Pod 规范或服务账户定义中设置 automountServiceAccountToken: false,以减少其攻击面。
  • 缺乏审计:如果没有定期审查,RBAC 策略可能会随着集群需求的变化而过时或过于宽松。实施审查流程。
  • 混淆 RoleClusterRole:误解范围可能导致在只需要命名空间范围访问时授予了集群范围的访问权限。

要点

RBAC 的最佳效果是保持其简单和具体:为应用程序团队使用命名空间角色,狭窄的服务账户权限,未经审查不使用通配符,以及定期的 kubectl auth can-i 检查。将每个绑定视为生产代码,因为在 Kubernetes 集群中,它确实就是。