Skip to content
0

访问控制

在 Kubernetes 中,访问控制是确保集群安全的重要机制,主要通过 RBAC(基于角色的权限控制)实现。本文档将详细介绍如何创建仅允许 get 和 create Pod 操作的账号,并深入解释 Kubernetes 中的 API 对象结构和 RBAC 权限模型。

RBAC 概述

管理员可以通过 Kubernetes API 动态配置策略来启用 RBAC,需要在 kube-apiserver 中添加参数 --authorization-mode=RBAC。如果使用 kubeadm 安装的集群,RBAC 通常是默认开启的,可以通过查看 Master 节点上 apiserver 的静态 Pod 定义文件来确认:

bash
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 组织形式:

bash
kubectl get --raw /

输出会显示所有可用的 API 路径,例如:

json
{
  "paths": [
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
    "/version"
  ]
}

还可以查看特定 API 组下的资源,例如查看批处理 API:

bash
kubectl get --raw /apis/batch/v1 | python -m json.tool

这将显示该 API 组下可用的所有资源类型及其支持的操作,例如:

json
{
    "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 的更简便访问:

bash
kubectl proxy

启动后,可以通过浏览器或 curl 命令访问 http://localhost:8001/ 来浏览 Kubernetes API。这种方式特别适合于开发和调试场景。

bash
curl http://127.0.0.1:8001/apis/batch/v1

创建用户案例:只能在 default 空间执行特定的 pod 操作

核心概念说明

在操作前需明确关键组件的作用,避免权限配置错误:

组件作用
Service Accountk8s 内部服务(如 Pod)的身份标识,需绑定证书才能通过 API Server 认证。
证书(x509)用于身份认证,由 k8s 集群的 CA(证书颁发机构)签名,确保身份合法性。
Role定义 命名空间内 的细粒度权限(如仅允许 Pod 的 get/create 操作)。
RoleBinding将 Role 与 Service Account 绑定,使账号获得 Role 定义的权限。

前提条件

已安装 kubectl 并配置集群管理员权限(能执行 kubectl cluster-info 验证)。

集群 CA 证书文件存在(默认路径:/etc/kubernetes/pki/,包含 ca.crtca.key,需 root 权限访问)。

已安装 openssl 工具(用于生成证书签名请求 CSR)。

分步操作流程

步骤 1:创建 Service Account

Service Account 的必要性

Service Account 在 Kubernetes 访问控制中扮演着基础且关键的角色,是实现精细化权限管理的核心载体:

  1. 身份标识:为 Pod、应用或自动化工具提供在集群中的唯一身份
  2. 权限绑定载体:作为 RBAC(Role-Based Access Control)权限模型中的主体(Subject),是权限分配的基本单位
  3. 自动化令牌管理:系统会自动为 Service Account 创建和管理访问令牌(Token),并可选择自动注入到 Pod 中
  4. 权限隔离:通过为不同应用创建独立的 Service Account,实现应用间的权限隔离
  5. 审计追踪:所有通过 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 绑定,主要有以下原因:

  1. 权限模型一致性:保持与 Kubernetes 原生 RBAC 权限模型的一致性,便于集中管理权限
  2. 审计可追踪性:所有操作都可关联到具体的 Service Account,便于审计和问题追溯
  3. 集群功能集成:部分集群功能(如网络策略、资源配额)依赖于 Service Account 身份
不同场景下的最佳实践
场景推荐方案优势
常规 Pod 内应用访问 API自动令牌(默认 Service Account 或自定义 SA)配置简单,自动轮换,无需额外管理
外部系统长期访问集群 APIService Account + 手动证书 + 证书轮换机制长期有效,可自定义权限范围
临时自动化脚本或 CI/CD 访问自动令牌 + 显式指定过期时间安全可控,避免长期凭证泄露

首先在目标命名空间(此处以 default 为例,可替换为自定义命名空间,如 dev)创建 Service Account,命名为 pod-reader-creator

bash
# 在 default 命名空间创建 Service Account
kubectl create sa pod-reader-creator -n default

验证创建结果:

bash
# 查看 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(需妥善保管,避免泄露):

bash
openssl genrsa -out pod-reader-creator.key 2048
2.2 生成 CSR 文件

CSR 需包含 Service Account 的身份信息(CN 为用户名,O 为用户组),k8s 中 Service Account 的默认用户组为 system:serviceaccounts:<命名空间>

bash
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 资源定义:

bash
# 将 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  # 证书用途:客户端认证(必须包含)
EOF
3.2 提交 CSR 并审批
bash
# 提交 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-csr
3.3 提取签名后的证书

审批通过后,k8s CA 会生成证书,需将其提取为本地文件 pod-reader-creator.crt

bash
kubectl get csr pod-reader-creator-csr -o jsonpath='{.status.certificate}' | base64 -d > pod-reader-creator.crt
3.4 查看证书有效期
bash
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 的 listgetcreate 操作。

创建 Role YAML 文件 pod-get-create-role.yaml

bash
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:

bash
kubectl apply -f pod-get-create-role.yaml

验证 Role:

bash
kubectl get role pod-get-create-role -n default
# 输出类似:NAME                  CREATED AT
#          pod-get-create-role   2025-xx-xxTxx:xx:xxZ
ClusterRole

ClusterRole 是 集群级 资源,允许在所有命名空间内定义权限。与 Role 不同,ClusterRole 不绑定到特定命名空间,而是全局生效。

创建 Role YAML 文件 pod-get-create-clusterrole.yaml

bash
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:

bash
kubectl apply -f pod-get-create-clusterrole.yaml

验证 ClusterRole:

bash
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

bash
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:

bash
kubectl apply -f pod-reader-creator-rb.yaml

验证 RoleBinding:

bash
kubectl get rolebinding pod-reader-creator-rb -n default
# 输出类似:NAME                      ROLE                        AGE
#          pod-reader-creator-rb   Role/pod-get-create-role   10s
ClusterRoleBinding

ClusterRoleBinding 将 Service Account pod-reader-creator 与 ClusterRole pod-get-create-clusterrole 绑定,使账号获得权限。

创建 ClusterRoleBinding YAML 文件 pod-reader-creator-clusterrolebinding.yaml

bash
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:

bash
kubectl apply -f pod-reader-creator-clusterrolebinding.yaml

验证 ClusterRoleBinding:

bash
kubectl get clusterrolebinding pod-reader-creator-clusterrolebinding
# 输出类似:NAME                              ROLE                        AGE
#          pod-reader-creator-clusterrolebinding   ClusterRole/pod-get-create-clusterrole   10s

验证权限

为确保权限配置正确,需模拟 pod-reader-creator 账号执行操作,验证仅允许 getcreate Pod,拒绝其他操作(如 deletelist)。

使用 kubectl --certificate-authority 模拟账号

通过本地证书、私钥和 CA 证书,直接以 pod-reader-creator 身份调用 API Server:

bash
# 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"

命令行参数验证遇到的错误

bash
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 文件,避免与默认配置冲突:

bash
# 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中:

bash
# 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文件可以独立使用,无需依赖外部证书文件

清理资源(可选)

若测试完成后需删除创建的资源,执行以下命令:

bash
# 删除测试 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

参考

最近更新