前言
在告别硬编码:手把手教你用Secrets保护CronJob的阿里云AK/SK这篇文章 中,已经通过 Secret 存储敏感信息,避免敏感信息硬编码,但在文中最后也提到,Secret 的内容通常是以 Base64 编码存储的,并不是 安全的,因为 Base64 编码后的字符串可以被反向解码,从而获取到原始的敏感信息。所以,要提高安全性,这里先启用 RBAC 控制。
最终还是会通过改造已经部署好的监控服务费用的 CronJob ,从实战角度讲解 RBAC(基于角色的访问控制)。
RBAC 基础概念
RBAC (Role-Based Access Control) 是 Kubernetes 中用于控制谁可以访问哪些资源的授权机制。它由以下核心对象组成:
- ServiceAccount (SA) :代表应用程序或用户的身份
- Role/ClusterRole :定义一组权限规则(能做什么)
- RoleBinding/ClusterRoleBinding :将角色绑定到主体(谁有这个权限)
RBAC 使用步骤
RBAC 的概念比较复杂,但是使用起来还是比较简单的,主要分为以下几个步骤:
- 在集群中创建一些角色,并为这些角色赋予相应的权限
- 将创建的角色绑定到某个账号上
- 将账号赋予 pod 使用
在 k8s 中控制角色的对象是 Role/ClusterRole,账号是 ServiceAccount,负责将角色和账号进行绑定的动作定义对象是 RoleBinding/ClusterRoleBinding。 Role 和 ClusterRole 的区别在于 Role 对象只在某个命名空间下生效,ClusterRole 对象在整个集群范围内生效。RoleBinding 和 ClusterRoleBinding 也是 一样。
案例改造
建议结合Kubernetes CronJob 详解:配置、原理与实践指南 和 告别硬编码:手把手教你用Secrets保护CronJob的阿里云AK/SK 这两篇文章阅读,本案例是在此基础上,进行改造。
当前配置分析
当前的 CronJob 配置使用了 Secret 来存储阿里云凭证,但想通过 RBAC 加强安全性。让看看现有配置:
yaml
env:
- name: ALIYUN_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aliyun-credentials
key: access_key_id
- name: ALIYUN_ACCESS_KEY_SECRET
valueFrom:
secretKeyRef:
name: aliyun-credentials
key: access_key_secret
这从名为 aliyun-credentials
的 Secret 中获取凭证,但没有限制哪些 Pod/SA 可以访问这个 Secret。
创建专用 ServiceAccount
首先,为这个 CronJob 创建专用 ServiceAccount:
lua
kubectl create serviceaccount serverguard-sa -n kube-ops
创建访问 Secret 的 Role
接下来,定义一个 Role,该角色将允许特定的 ServiceAccount 访问某些资源。 在这里,我们要创建一个 Role,定义谁可以访问 aliyun-credentials
Secret。
secret-reader-role.yaml 文件如下:
yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: kube-ops
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["aliyun-credentials"]
verbs: ["get"]
- Role 对象一定要在 metadata 中声明名字空间
- apiGroups: [""]:填写对象所属的 group,"" 表示核心组。
- resources: ["secrets"]:填写具体对象,这里指定角色可以操作 secrets 资源。
- resourceNames: ["aliyun-credentials"]:仅限于访问名为 aliyun-credentials 的 Secret。
- verbs: ["get"]:指定角色可以执行的操作,这里是获取 Secret。
应用这个 Role:
kubectl apply -f secret-reader-role.yaml
将 Role 绑定到 ServiceAccount
RoleBinding 用来将角色和服务账户绑定在一起,授权该服务账户执行与角色相关的操作。下面是 secret-reader-binding.yaml 的配置文件:
yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-secrets
namespace: kube-ops
subjects:
- kind: ServiceAccount
name: serverguard-sa
namespace: kube-ops
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
- subjects:指定哪个 ServiceAccount 需要被授予访问权限。这里是 serverguard-sa 服务账户。
- roleRef:指定绑定的角色,这里是 secret-reader 角色,允许读取 aliyun-credentials Secret。
应用绑定:
kubectl apply -f secret-reader-binding.yaml
更新 CronJob 使用 ServiceAccount
为了让 CronJob 使用我们刚才创建的 ServiceAccount,需要在 CronJob 配置文件中指定 serviceAccountName:
yaml
spec:
jobTemplate:
spec:
template:
spec:
serviceAccountName: serverguard-sa # 添加这行
containers:
- name: serverguard
image: /server-guard:latest
# ... 其他配置不变 ...
- serviceAccountName: serverguard-sa:指定该 CronJob 使用我们创建的 serverguard-sa 服务账户。
验证
检查 ServiceAccount 是否存在
arduino
kubectl get sa serverguard-sa -n kube-ops -o yaml
通过这个命令,可以确认 serverguard-sa ServiceAccount 是否已经成功创建,并查看它的详细配置
验证权限
csharp
# 检查 SA 是否能获取 secret
kubectl auth can-i get secret/aliyun-credentials \
--as=system:serviceaccount:kube-ops:serverguard-sa -n kube-ops
- kubectl auth can-i:这个命令用于验证当前用户或指定服务账户是否有权限执行某个操作。它是用来测试 RBAC 配置是否有效的非常有用的工具。
- get secret/aliyun-credentials:指定你要验证的操作,这里是验证 serverguard-sa 是否能够执行 get 操作,访问 aliyun-credentials Secret。
- --as=system:serviceaccount:kube-ops:serverguard-sa:通过 --as 参数,指定以 serverguard-sa 服务账户的身份进行验证。system:serviceaccount:kube-ops:serverguard-sa 是该 ServiceAccount 的完全限定名,表示这是在 kube-ops 命名空间中的 serverguard-sa 服务账户。
- -n kube-ops:指定命名空间 kube-ops,确保验证操作是在正确的命名空间下进行的。 这个命令的作用是验证 serverguard-sa 服务账户是否有权限访问 aliyun-credentials Secret。 它将返回 "yes" 或 "no" 作为结果。如果返回 "yes",则说明权限配置正确;如果返回 "no",则可能是 RBAC 配置有问题,可能需要检查角色或角色绑定的配置。
到这里就完成了,总结一下:
创建了一个专用的 ServiceAccount,并通过 Role 和 RoleBinding 配置了权限管理,确保只有指定的 ServiceAccount 能 访问敏感的 Secret。接着,更新 CronJob 配置以确保它使用正确的 ServiceAccount,这样该 CronJob 就可以安全地访问 Secret。
RBAC 解析
Role vs ClusterRole
特性 | Role | ClusterRole |
---|---|---|
作用范围 | 特定命名空间 | 整个集群 |
适用场景 | 命名空间内资源权限控制 | 集群级别资源或跨命名空间 |
绑定方式 | RoleBinding | ClusterRoleBinding |
权限规则详解
每个 Rule 包含三个关键部分:
-
apiGroups :资源所属的 API 组
- 核心组:
""
(如 pods, services, secrets) - 其他组:
"apps"
,"batch"
等
- 核心组:
-
resources :资源类型(复数形式)
- pods, deployments, secrets 等
-
verbs :允许的操作
- get, list, watch, create, update, delete
示例:
makefile
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
主体 (Subjects) 类型
RBAC 可以授权给三种主体:
-
ServiceAccount (最常见)
yamlsubjects: - kind: ServiceAccount name: serverguard-sa namespace: kube-ops
-
User (外部用户)
yamlsubjects: - kind: User name: "alice@example.com" apiGroup: rbac.authorization.k8s.io
-
Group (用户组)
yamlsubjects: - kind: Group name: system:serviceaccounts:kube-ops apiGroup: rbac.authorization.k8s.io
授予 kube-ops 命名空间下的所有 ServiceAccount 权限
最后
到这里就完成了前言部分提到的需求,最后再总结一下,完整的 RBAC 增强方案应该是:
- 为 serverguard 创建专用 SA
- 创建最小权限 Role 只允许访问需要的 Secret
- 绑定 Role 到 SA
- 更新 CronJob 使用这个 SA
- 定期审计这些配置
这样即使攻击者获取了 Pod 执行权限,也只能访问你明确授权的资源,实现了纵深防御。