访问控制
在 Kubernetes 中,访问控制是确保集群安全的重要机制,主要通过 RBAC(基于角色的权限控制)实现。本文档将详细介绍如何创建仅允许 get 和 create Pod 操作的账号,并深入解释 Kubernetes 中的 API 对象结构和 RBAC 权限模型。
RBAC 概述
管理员可以通过 Kubernetes API 动态配置策略来启用 RBAC,需要在 kube-apiserver 中添加参数 --authorization-mode=RBAC。如果使用 kubeadm 安装的集群,RBAC 通常是默认开启的,可以通过查看 Master 节点上 apiserver 的静态 Pod 定义文件来确认:
cat /etc/kubernetes/manifests/kube-apiserver.yaml在输出中查找以下配置:
--authorization-mode=Node,RBAC如果是二进制方式搭建的集群,添加这个参数后,需要重启 kube-apiserver 服务使配置生效。
API 对象详解
在深入了解 RBAC 之前,我们需要先理解 Kubernetes 集群中的 API 对象结构。Kubernetes API 是一个以 JSON 为主要序列化方式的 HTTP 服务,也支持 Protocol Buffers 序列化方式(主要用于集群内部组件间的通信)。
API 版本与稳定性
为了可扩展性,Kubernetes 在不同的 API 路径(如 /api/v1 或 /apis/batch)下支持了多个 API 版本,不同的 API 版本意味着不同级别的稳定性和支持:
- Alpha 级别(例如
v1alpha1):默认情况下是被禁用的,可以随时删除对功能的支持,慎用 - Beta 级别(例如
v2beta1):默认情况下是启用的,表示代码已经经过了很好的测试,但是对象的语义可能会在随后的版本中以不兼容的方式更改 - 稳定级别(例如
v1):表示已经是稳定版本了,也会出现在后续的很多版本中
API 对象的组织结构
在 Kubernetes 集群中,一个 API 对象在 Etcd 里的完整资源路径,是由 Group(API 组)、Version(API 版本) 和 Resource(API 资源类型) 三个部分组成的。
Kubernetes 的 API 对象可以想象成一个大型图书馆的书架结构,我们可以用树形图来理解它:
顶层分类:就像图书馆的主要分区,Kubernetes API 有几个顶层路径
/api/v1:这里存放着最核心、最基础的 API 对象(如 Pod、Service、Namespace 等),这是一个特殊的情况/apis/:这里存放着按功能分组的其他 API 对象- 还有一些系统级别的特殊路径,如
/metrics(用于监控数据)
为什么核心组路径特殊? 这是 Kubernetes 发展过程中的一个历史遗留问题。早期版本的 Kubernetes 只有最基础的 API 对象,它们都放在
/api/v1下。后来随着功能扩展,Kubernetes 引入了 API 组的概念,但为了保持向后兼容,核心对象仍然保留在原来的位置,而没有按照新规则移动到/apis/core/v1下。其他功能组:除了核心组外,其他 API 对象都按照功能分组存放在
/apis/下面,路径格式为/apis/$NAME/$VERSION。例如:/apis/apps/v1:存放应用相关的对象(如 Deployment、StatefulSet 等)/apis/batch/v1:存放批处理相关的对象(如 Job、CronJob 等)/apis/rbac.authorization.k8s.io/v1:存放权限控制相关的对象(如 Role、RoleBinding 等)
这样的组织结构让 Kubernetes 的 API 既保持了历史兼容性,又能灵活地扩展新功能。
查看集群 API 组织形式
可以通过以下命令查看集群中的 API 组织形式:
kubectl get --raw /输出会显示所有可用的 API 路径,例如:
{
"paths": [
"/api",
"/api/v1",
"/apis",
"/apis/",
"/version"
]
}还可以查看特定 API 组下的资源,例如查看批处理 API:
kubectl get --raw /apis/batch/v1 | python -m json.tool这将显示该 API 组下可用的所有资源类型及其支持的操作,例如:
{
"apiVersion": "v1",
"groupVersion": "batch/v1",
"kind": "APIResourceList",
"resources": [
{
"categories": [
"all"
],
"kind": "CronJob",
"name": "cronjobs",
"namespaced": true,
"shortNames": [
"cj"
],
"singularName": "",
"storageVersionHash": "sd5LIXh4Fjs=",
"verbs": [
"create",
"delete",
"deletecollection",
"get",
"list",
"patch",
"update",
"watch"
]
},
// 更多资源...
]
}通过 kubectl proxy 访问 API Server
除了使用 kubectl get --raw 命令外,还可以通过 kubectl proxy 命令来开启对 apiserver 的更简便访问:
kubectl proxy启动后,可以通过浏览器或 curl 命令访问 http://localhost:8001/ 来浏览 Kubernetes API。这种方式特别适合于开发和调试场景。
curl http://127.0.0.1:8001/apis/batch/v1创建用户案例:只能在 default 空间执行特定的 pod 操作
核心概念说明
在操作前需明确关键组件的作用,避免权限配置错误:
| 组件 | 作用 |
|---|---|
| Service Account | k8s 内部服务(如 Pod)的身份标识,需绑定证书才能通过 API Server 认证。 |
| 证书(x509) | 用于身份认证,由 k8s 集群的 CA(证书颁发机构)签名,确保身份合法性。 |
| Role | 定义 命名空间内 的细粒度权限(如仅允许 Pod 的 get/create 操作)。 |
| RoleBinding | 将 Role 与 Service Account 绑定,使账号获得 Role 定义的权限。 |
前提条件
已安装 kubectl 并配置集群管理员权限(能执行 kubectl cluster-info 验证)。
集群 CA 证书文件存在(默认路径:/etc/kubernetes/pki/,包含 ca.crt 和 ca.key,需 root 权限访问)。
已安装 openssl 工具(用于生成证书签名请求 CSR)。
分步操作流程
步骤 1:创建 Service Account
Service Account 的必要性
Service Account 在 Kubernetes 访问控制中扮演着基础且关键的角色,是实现精细化权限管理的核心载体:
- 身份标识:为 Pod、应用或自动化工具提供在集群中的唯一身份
- 权限绑定载体:作为 RBAC(Role-Based Access Control)权限模型中的主体(Subject),是权限分配的基本单位
- 自动化令牌管理:系统会自动为 Service Account 创建和管理访问令牌(Token),并可选择自动注入到 Pod 中
- 权限隔离:通过为不同应用创建独立的 Service Account,实现应用间的权限隔离
- 审计追踪:所有通过 Service Account 进行的操作都可被审计系统追踪,便于问题排查和合规性检查
Service Account 与证书的关联机制
Kubernetes 中,Service Account 与证书存在两种主要的关联方式:
1. 自动关联机制(内置令牌)
- 系统会自动为每个 Service Account 创建一个包含令牌(token)和 CA 证书的 Secret
- 当 Pod 引用 Service Account 时,这些认证信息会自动挂载到 Pod 的
/var/run/secrets/kubernetes.io/serviceaccount/目录 - 内置令牌有固定的过期时间(默认 1 小时),但 kubelet 会自动刷新轮换
2. 手动关联机制(本文示例)
- 通过创建 CSR(Certificate Signing Request)并由集群 CA 签名,生成客户端证书
- 证书中必须正确编码身份信息:CN=system:serviceaccount:<命名空间>:<SA名称>,O=system:serviceaccounts:<命名空间>
- 手动创建的证书不会自动轮换,需要额外的管理机制
为什么手动证书仍需绑定 Service Account?
即使手动创建的证书不会自动轮换,仍建议与 Service Account 绑定,主要有以下原因:
- 权限模型一致性:保持与 Kubernetes 原生 RBAC 权限模型的一致性,便于集中管理权限
- 审计可追踪性:所有操作都可关联到具体的 Service Account,便于审计和问题追溯
- 集群功能集成:部分集群功能(如网络策略、资源配额)依赖于 Service Account 身份
不同场景下的最佳实践
| 场景 | 推荐方案 | 优势 |
|---|---|---|
| 常规 Pod 内应用访问 API | 自动令牌(默认 Service Account 或自定义 SA) | 配置简单,自动轮换,无需额外管理 |
| 外部系统长期访问集群 API | Service Account + 手动证书 + 证书轮换机制 | 长期有效,可自定义权限范围 |
| 临时自动化脚本或 CI/CD 访问 | 自动令牌 + 显式指定过期时间 | 安全可控,避免长期凭证泄露 |
首先在目标命名空间(此处以 default 为例,可替换为自定义命名空间,如 dev)创建 Service Account,命名为 pod-reader-creator。
# 在 default 命名空间创建 Service Account
kubectl create sa pod-reader-creator -n default验证创建结果:
# 查看 default 命名空间下的 Service Account
kubectl get sa pod-reader-creator -n default步骤 2:生成证书签名请求
Service Account 需通过证书认证,需先生成 私钥 和 CSR 文件,再由集群 CA 签名。
2.1 生成私钥
使用 openssl 生成 2048 位 RSA 私钥,保存为 pod-reader-creator.key(需妥善保管,避免泄露):
openssl genrsa -out pod-reader-creator.key 20482.2 生成 CSR 文件
CSR 需包含 Service Account 的身份信息(CN 为用户名,O 为用户组),k8s 中 Service Account 的默认用户组为 system:serviceaccounts:<命名空间>:
openssl req -new -key pod-reader-creator.key -out pod-reader-creator.csr \
-subj "/CN=system:serviceaccount:default:pod-reader-creator/O=system:serviceaccounts:default"CN(Common Name):必须为system:serviceaccount:<命名空间>:<SA名称>,否则 API Server 无法识别为 Service Account。O(Organization):必须为system:serviceaccounts:<命名空间>,对应 Service Account 的默认用户组。
步骤 3:通过 k8s API 提交 CSR 并审批
将 CSR 转换为 k8s 可识别的 YAML 资源,提交后由集群管理员审批(此处用 kubectl certificate approve 自动审批)。
3.1 创建 CSR YAML 文件
通过 base64 编码 CSR 文件内容,生成 k8s CSR 资源定义:
# 将 CSR 文件 base64 编码(需去除换行符)
CSR_BASE64=$(cat pod-reader-creator.csr | base64 | tr -d '\n')
# 生成 CSR YAML
cat > pod-reader-creator-csr.yaml << EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: pod-reader-creator-csr # CSR 资源名称,需唯一
spec:
request: ${CSR_BASE64}
signerName: kubernetes.io/kube-apiserver-client # 签名者(固定为集群 API Server 客户端签名)
usages:
- client auth # 证书用途:客户端认证(必须包含)
EOF3.2 提交 CSR 并审批
# 提交 CSR 资源
kubectl apply -f pod-reader-creator-csr.yaml
# 查看 CSR 状态(初始为 Pending)
kubectl get csr pod-reader-creator-csr
# 输出类似:NAME AGE SIGNERNAME REQUESTOR CONDITION
# pod-reader-creator-csr 5s kubernetes.io/kube-apiserver-client kubernetes-admin Pending
# 审批 CSR(仅管理员可执行)
kubectl certificate approve pod-reader-creator-csr
# 再次查看,状态变为 Approved,Issued
kubectl get csr pod-reader-creator-csr3.3 提取签名后的证书
审批通过后,k8s CA 会生成证书,需将其提取为本地文件 pod-reader-creator.crt:
kubectl get csr pod-reader-creator-csr -o jsonpath='{.status.certificate}' | base64 -d > pod-reader-creator.crt3.4 查看证书有效期
openssl x509 -in pod-reader-creator.crt -noout -dates
# notBefore=Sep 25 04:06:19 2025 GMT
# notAfter=Sep 25 04:06:19 2026 GMT步骤 4:创建 Role
Role 是 命名空间级 资源,仅允许在指定命名空间内定义权限。此处创建 Role pod-get-create-role,仅包含 Pod 的 list、get 和 create 操作。
创建 Role YAML 文件 pod-get-create-role.yaml:
cat > pod-get-create-role.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-get-create-role # Role 名称,需唯一
namespace: default # 角色所在命名空间,与 Service Account 一致
rules:
- apiGroups: [""] # 核心 API 组
resources: ["pods"] # 资源类型为 Pod
verbs: ["list", "get", "create"] # 操作权限:list、get 和 create
EOF应用 Role:
kubectl apply -f pod-get-create-role.yaml验证 Role:
kubectl get role pod-get-create-role -n default
# 输出类似:NAME CREATED AT
# pod-get-create-role 2025-xx-xxTxx:xx:xxZClusterRole
ClusterRole 是 集群级 资源,允许在所有命名空间内定义权限。与 Role 不同,ClusterRole 不绑定到特定命名空间,而是全局生效。
创建 Role YAML 文件 pod-get-create-clusterrole.yaml:
cat > pod-get-create-clusterrole.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-get-create-clusterrole # Role 名称,需唯一
rules:
- apiGroups: [""] # 核心 API 组
resources: ["pods"] # 资源类型为 Pod
verbs: ["list", "get", "create"] # 操作权限:list、get 和 create
EOF应用 ClusterRole:
kubectl apply -f pod-get-create-clusterrole.yaml验证 ClusterRole:
kubectl get clusterrole pod-get-create-clusterrole
# 输出类似:NAME CREATED AT
# pod-get-create-clusterrole 2025-xx-xxTxx:xx:xxZ步骤 5:创建 RoleBinding
RoleBinding 将 Service Account pod-reader-creator 与 Role pod-get-create-role 绑定,使账号获得权限。
创建 RoleBinding YAML 文件 pod-reader-creator-rb.yaml:
cat > pod-reader-creator-rb.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-creator-rb # RoleBinding 名称
namespace: default # 与 Role、SA 同命名空间
subjects:
- kind: ServiceAccount
name: pod-reader-creator # 绑定的 Service Account 名称
namespace: default # Service Account 所在命名空间
roleRef:
kind: Role
name: pod-get-create-role # 绑定的 Role 名称
apiGroup: rbac.authorization.k8s.io # RBAC API 组(固定)
EOF应用 RoleBinding:
kubectl apply -f pod-reader-creator-rb.yaml验证 RoleBinding:
kubectl get rolebinding pod-reader-creator-rb -n default
# 输出类似:NAME ROLE AGE
# pod-reader-creator-rb Role/pod-get-create-role 10sClusterRoleBinding
ClusterRoleBinding 将 Service Account pod-reader-creator 与 ClusterRole pod-get-create-clusterrole 绑定,使账号获得权限。
创建 ClusterRoleBinding YAML 文件 pod-reader-creator-clusterrolebinding.yaml:
cat > pod-reader-creator-clusterrolebinding.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-reader-creator-clusterrolebinding # ClusterRoleBinding 名称
subjects:
- kind: ServiceAccount
name: pod-reader-creator # 绑定的 Service Account 名称
namespace: default # Service Account 所在命名空间
roleRef:
kind: ClusterRole
name: pod-get-create-clusterrole # 绑定的 ClusterRole 名称
apiGroup: rbac.authorization.k8s.io # RBAC API 组(固定)
EOF应用 ClusterRoleBinding:
kubectl apply -f pod-reader-creator-clusterrolebinding.yaml验证 ClusterRoleBinding:
kubectl get clusterrolebinding pod-reader-creator-clusterrolebinding
# 输出类似:NAME ROLE AGE
# pod-reader-creator-clusterrolebinding ClusterRole/pod-get-create-clusterrole 10s验证权限
为确保权限配置正确,需模拟 pod-reader-creator 账号执行操作,验证仅允许 get 和 create Pod,拒绝其他操作(如 delete、list)。
使用 kubectl --certificate-authority 模拟账号
通过本地证书、私钥和 CA 证书,直接以 pod-reader-creator 身份调用 API Server:
# 1. 尝试创建 Pod(应成功)
kubectl run test-pod --image=nginx:alpine \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--client-certificate=pod-reader-creator.crt \
--client-key=pod-reader-creator.key \
-n default
# 2. 尝试查询 Pod(应成功)
kubectl get pods test-pod \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--client-certificate=pod-reader-creator.crt \
--client-key=pod-reader-creator.key \
-n default
# 3. 尝试删除 Pod(应失败,提示权限不足)
kubectl delete pod test-pod \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--client-certificate=pod-reader-creator.crt \
--client-key=pod-reader-creator.key \
-n default
# 预期错误:Error from server (Forbidden): pods "test-pod" is forbidden: User "system:serviceaccount:default:pod-reader-creator" cannot delete resource "pods" in API group "" in the namespace "default"命令行参数验证遇到的错误
Error in configuration:
* client-cert-data and client-cert are both specified for kubernetes-admin. client-cert-data will override.
* client-key-data and client-key are both specified for kubernetes-admin; client-key-data will override因为 kubectl 同时检测到了两种证书配置方式(配置文件中的 client-cert-data/client-key-data 和命令行指定的 --client-certificate/--client-key),导致冲突。
为这个专用账号创建独立的 kubeconfig 文件,避免与默认配置冲突:
# 1. 生成专用 kubeconfig 文件(使用证书文件路径)
kubectl config --kubeconfig=pod-reader-creator.kubeconfig set-cluster kubernetes \
--server=https://127.0.0.1:6443 \ # 替换为你的外部访问 API Server 地址
--certificate-authority=/etc/kubernetes/pki/ca.crt
# 2. 设置客户端证书(使用证书文件路径)
kubectl config --kubeconfig=pod-reader-creator.kubeconfig set-credentials pod-reader-creator \
--client-certificate=./pod-reader-creator.crt \
--client-key=./pod-reader-creator.key
# 3. 设置上下文
kubectl config --kubeconfig=pod-reader-creator.kubeconfig set-context pod-reader-creator-context \
--cluster=kubernetes \
--user=pod-reader-creator \
--namespace=default
# 4. 设置当前上下文为 pod-reader-creator-context
kubectl config --kubeconfig=pod-reader-creator.kubeconfig use-context pod-reader-creator-context
# 5. 使用该配置文件执行命令
kubectl --kubeconfig=pod-reader-creator.kubeconfig get pod如果你希望直接在kubeconfig中嵌入证书内容而不是引用文件路径,可以使用Kubernetes 提供的--embed-certs参数,可以直接将引用的证书文件内容嵌入到kubeconfig中:
# 1. 生成专用 kubeconfig 文件并嵌入证书
kubectl config --kubeconfig=pod-reader-creator.kubeconfig set-cluster kubernetes \
--server=https://127.0.0.1:6443 \ # 替换为你的外部访问 API Server 地址
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true
# 2. 设置客户端证书并嵌入证书内容
kubectl config --kubeconfig=pod-reader-creator.kubeconfig set-credentials pod-reader-creator \
--client-certificate=./pod-reader-creator.crt \
--client-key=./pod-reader-creator.key \
--embed-certs=true
# 3. 设置上下文
kubectl config --kubeconfig=pod-reader-creator.kubeconfig set-context pod-reader-creator-context \
--cluster=kubernetes \
--user=pod-reader-creator \
--namespace=default
# 4. 设置当前上下文为 pod-reader-creator-context
kubectl config --kubeconfig=pod-reader-creator.kubeconfig use-context pod-reader-creator-context
# 5. 使用该配置文件执行命令
kubectl --kubeconfig=pod-reader-creator.kubeconfig get pod说明:
--embed-certs=true参数会自动将引用的证书文件内容进行Base64编码并嵌入到kubeconfig中- 默认情况下
--embed-certs=false,即只保留证书文件路径引用 - 嵌入证书后,kubeconfig文件可以独立使用,无需依赖外部证书文件
清理资源(可选)
若测试完成后需删除创建的资源,执行以下命令:
# 删除测试 Pod
kubectl delete pod test-pod -n default
# 删除 RoleBinding、Role、Service Account
kubectl delete rolebinding pod-reader-creator-rb -n default
kubectl delete role pod-get-create-role -n default
kubectl delete sa pod-reader-creator -n default
# 删除 CSR 资源和本地证书文件
kubectl delete csr pod-reader-creator-csr
rm -f pod-reader-creator.key pod-reader-creator.csr pod-reader-creator.crt