K8S安全框架深度解析-从认证到RBAC实战完全指南

K8S安全框架深度解析:从认证到RBAC实战完全指南

导读 :Kubernetes 的安全体系是生产环境的基石。一个配置不当的集群,可能因为权限滥用、匿名访问或认证绕过导致严重的安全事故。本文从 API Server 的角度发,逐步拆解 认证 → 鉴权 → 准入控制 三层防线,并通过 静态令牌认证、X509 证书签发、RBAC 角色绑定、ServiceAccount 授权 四个递进式实战,帮你彻底掌握 K8S 安全框架。


一、API Server 访问控制全貌

Kubernetes API Server 是集群的唯一入口 ,所有对集群资源的操作(无论是 kubectl 命令、客户端 SDK 还是 Dashboard)最终都是向 API Server 发送 HTTPS 请求。因此,API Server 内置了一套插件化的访问控制机制,分为三层:

复制代码
客户端请求 ──→认证(Authentication) ──→鉴权(Authorization) ──→ 准入控制(Admission) ──→ etcd
                身份是谁?             能做什么操作?             操作内容合规吗?
层级 作用 逻辑 说明
认证 核验请求者身份 逻辑(任一插件成功即通过) 回答"你是谁"
鉴权 核验操作是否被许可 逻辑(任一插件授权即通过) 回答"你能做什么"
准入控制 检查操作内容合规性 逻辑(所有插件都必须通过) 回答"操作内容合规吗",仅对写请求有效

1.1 认证(Authentication)

认证过程回答的是 "你是谁" 的问题。K8S 支持多种认证方式,任何一个认证插件成功后即停止后续验证(或逻辑 )。如果所有插件都失败,请求将以匿名用户 system:anonymous 身份继续。

支持的主要认证策略:

认证方式 适用场景 说明
X.509 客户端证书 各组件间通信、管理员访问 双向 TLS,CN=用户名,O=用户组
静态令牌文件 测试、简单场景 --token-auth-file 加载 CSV 文件
Bootstrap 令牌 节点加入集群 kubeadm token 管理
ServiceAccount 令牌 Pod 内进程访问 API Server 自动挂载,内置启用
OIDC 令牌 企业统一认证 类似 OAuth2(微信/支付宝登录)
Webhook 令牌 外部认证集成 支持 LDAP、钉钉等
匿名请求 开发测试 生产环境建议禁用

1.2 鉴权(Authorization)

认证通过后,鉴权层判断该用户是否有权限执行请求的操作。K8S 同样采用或逻辑------任一授权插件允许即通过。

主要鉴权模式:

模式 说明
RBAC(推荐) 基于角色的访问控制,1.8+ 默认启用,本文重点
ABAC 基于属性的访问控制,维护成本高
Webhook 通过外部 HTTP 服务进行授权回调
Node 专门为 kubelet 设计的授权模式

1.3 准入控制(Admission Control)

准入控制在数据写入 etcd 之前做最后的检查,仅对写请求生效,分为两类:

  • Validating(校验):检查字段类型、值是否合法
  • Mutating(变更):自动补全或修正默认字段(如自动注入 Sidecar)

准入控制遵循与逻辑,所有插件都必须通过。


二、Kubernetes 用户体系

理解 K8S 的用户体系是掌握安全框架的前提。K8S 中的"用户"分为三类:

复制代码
┌─────────────────────────────────────────────────┐
│              Kubernetes 用户体系                   │
├──────────────────┬──────────────────────────────┤
│  Service Account │  Pod 内进程访问 API Server    │
│  (服务账号)       │  引用格式: system:serviceaccount│
│                  │  :<NS>:<SA_NAME>              │
├──────────────────┼──────────────────────────────┤
│  User Account    │  人(管理员/开发者)访问集群    │
│  (用户账号)       │  信息保存在 kubeconfig 文件中  │
│                  │  CN=用户名, O=用户组           │
├──────────────────┼──────────────────────────────┤
│  Anonymous       │  未提供认证信息的请求者         │
│  (匿名账号)       │  system:anonymous             │
│                  │  生产环境建议禁用               │
└──────────────────┴──────────────────────────────┘

关键区别 :ServiceAccount 是 K8S 内置的资源类型,可以通过 kubectl 创建和管理;而 UserAccount 不是资源对象,其信息存储在外部文件(kubeconfig)或外部认证系统中。


三、实战一:静态令牌文件认证

静态令牌认证是最直观的认证方式,适合理解 K8S 认证流程。我们将创建一个 CSV 格式的令牌文件,配置 API Server 加载它,并通过令牌访问集群。

3.1 生成 Token

bash 复制代码
# 方式一:openssl 随机生成
echo "$(openssl rand -hex 3).$(openssl rand -hex 8)"
# 输出示例:01b202.d5c4210389cbff08

# 方式二:kubeadm 生成
kubeadm token generate
# 输出示例:jvt496.ls43vufojf45q73i

3.2 创建 Token CSV 文件

bash 复制代码
cat > /etc/kubernetes/pki/token.csv <<EOF
01b202.d5c4210389cbff08,test01,10001,k8s
497804.9fc391f505052952,test02,10002,k8s
8fd32c.0868709b9e5786a8,test03,10003,k3s
EOF

CSV 格式说明token,用户名,用户ID,用户组,共四个字段,用户组可选。

3.3 修改 API Server 加载 Token 文件

编辑 /etc/kubernetes/manifests/kube-apiserver.yaml,添加启动参数和卷挂载:

yaml 复制代码
spec:
  containers:
  - command:
    - kube-apiserver
    - --token-auth-file=/etc/kubernetes/pki/token.csv    # 添加此行
    ...
    volumeMounts:
    - mountPath: /etc/kubernetes/pki/token.csv            # 添加挂载
      name: static-token-file
      readOnly: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/pki/token.csv
      type: File
    name: static-token-file

通过移动 YAML 文件触发 Pod 重建来重启 API Server:

bash 复制代码
mv /etc/kubernetes/manifests/kube-apiserver.yaml /opt/
mv /opt/kube-apiserver.yaml /etc/kubernetes/manifests/

# 等待 30s+,确认 API Server 就绪
kubectl get pods -n kube-system -l component=kube-apiserver -o wide

3.4 使用 Token 认证访问集群

bash 复制代码
# 场景1:使用有效 Token 认证(已通过认证,但未授权 → 403 Forbidden)
kubectl --server=https://10.0.0.231:6443 \
  --certificate-authority=/etc/kubernetes/pki/ca.crt \
  --token=01b202.d5c4210389cbff08 get nodes
# Error from server (Forbidden): User "test01" cannot list resource "nodes"

# 场景2:使用无效 Token(未通过认证 → 401 Unauthorized)
kubectl --server=https://10.0.0.231:6443 \
  --certificate-authority=/etc/kubernetes/pki/ca.crt \
  --token=invalid.token get nodes
# error: You must be logged in to the server (Unauthorized)

# 场景3:不提供任何认证信息(匿名用户 → 403 Forbidden)
kubectl --server=https://10.0.0.231:6443 \
  --certificate-authority=/etc/kubernetes/pki/ca.crt get nodes
# Error from server (Forbidden): User "system:anonymous" cannot list resource "nodes"

关键理解:这三个场景完美演示了认证与鉴权的区别。场景1认证通过(用户身份已识别为 test01),但鉴权失败(无权限);场景2认证未通过(Token 不存在);场景3被识别为匿名用户。

3.5 curl 基于 Token 的认证测试

bash 复制代码
# 有效 Token(认证通过,但无权限)
curl -k -H "Authorization: Bearer 01b202.d5c4210389cbff08" \
  https://10.0.0.231:6443/api/v1/pods
# 返回 403 Forbidden

# 无效 Token
curl -k -H "Authorization: Bearer invalid.token" \
  https://10.0.0.231:6443/api/v1/pods
# 返回 401 Unauthorized

# 无认证信息
curl -k https://10.0.0.231:6443
# 返回 403 Forbidden (system:anonymous)

四、实战二:X509 证书认证

X509 证书认证是 K8S 生产环境最常用的认证方式。通过自签名证书,将证书中的 CN 字段映射为用户名、O 字段映射为用户组。

4.1 认证流程

复制代码
客户端                          Master 节点
  │                                │
  ├─ 1.生成私钥 (openssl genrsa)    │
  ├─ 2.生成证书签发请求 CSR          │
  │    (CN=用户名, O=用户组)        │
  ├─ 3.CSR 进行 base64 编码 ───────→ 4.创建 CSR 资源
  │                                5.管理员批准 CSR
  │    ←──── 6.导出签发的证书 ─────  7.base64 解码证书
  │                                │
  ├─ 8.配置 kubeconfig 使用证书     │
  ├─ 9.kubectl 访问集群             │

4.2 客户端创建证书签发请求

bash 复制代码
# 1. 生成私钥
openssl genrsa -out test.key 2048

# 2. 生成 CSR(CN=用户名,O=用户组)
openssl req -new -key test.key -out test.csr \
  -subj "/CN=test/O=group"

# 3. 对 CSR 进行 base64 编码
cat test.csr | base64 | tr -d '\n'

4.3 Master 节点签发证书

yaml 复制代码
# csr-test.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: test-csr
spec:
  # 将 base64 编码的 CSR 内容粘贴到这里
  request: LS0tLS1CRUdJTi...(base64编码的CSR内容)
  # 签名者类型
  signerName: kubernetes.io/kube-apiserver-client
  # 证书有效期(单位:秒,86400 = 24小时)
  expirationSeconds: 86400
  # 密钥用途
  usages:
  - client auth
bash 复制代码
# 创建 CSR 资源
kubectl apply -f csr-test.yaml
kubectl get csr
# NAME        AGE   SIGNERNAME                            REQUESTOR          CONDITION
# test-csr   4s    kubernetes.io/kube-apiserver-client   kubernetes-admin   Pending

# 管理员批准 CSR
kubectl certificate approve test-csr
kubectl get csr
# test-csr   47s   kubernetes.io/kube-apiserver-client   Approved,Issued

# 导出签发的证书
kubectl get csr test-csr -o jsonpath='{.status.certificate}' \
  | base64 -d > test.crt

4.4 CSR 签名者类型说明

K8S 支持三种 CSR 签名者类型:

signerName 用途 自动批准
kubernetes.io/kube-apiserver-client 客户端证书(如管理员) 不自动批准
kubernetes.io/kube-apiserver-client-kubelet Kubelet 客户端证书 可自动批准
kubernetes.io/kubelet-serving Kubelet 服务端证书 不自动批准

4.5 配置 kubeconfig 使用证书

将签发的证书和私钥配置到 kubeconfig 中:

bash 复制代码
# 设置集群信息
kubectl config set-cluster my-cluster \
  --server=https://10.0.0.231:6443 \
  --certificate-authority=/etc/kubernetes/pki/ca.crt \
  --kubeconfig=/root/test-kubeconfig \
  --embed-certs

# 设置用户凭证(使用签发的证书和私钥)
kubectl config set-credentials test \
  --client-certificate=/root/test.crt \
  --client-key=/root/test.key \
  --kubeconfig=/root/test-kubeconfig \
  --embed-certs

# 设置上下文
kubectl config set-context test-context \
  --cluster=my-cluster \
  --user=test \
  --kubeconfig=/root/test-kubeconfig

# 切换当前上下文
kubectl config use-context test-context \
  --kubeconfig=/root/test-kubeconfig

测试访问:

bash 复制代码
# 认证成功(CN 被识别为用户名 "test",O 被识别为用户组 "group")
kubectl --kubeconfig=/root/test-kubeconfig get nodes
# Error from server (Forbidden): User "test" cannot list resource "nodes"
# 注意:此时虽然认证通过,但鉴权尚未配置,所以返回 403

要点:证书中的 CN 字段会被识别为用户名,O 字段会被识别为用户组。这个映射关系是 RBAC 鉴权的基础。


五、RBAC 授权机制详解

RBAC(Role-Based Access Control)是 K8S 1.8 之后默认启用且推荐的授权模式。它的核心思想是:不直接给用户授权,而是将权限绑定到角色上,再将角色绑定给用户

5.1 RBAC 四大资源

复制代码
┌──────────────────────────────────────────────────┐
│                    RBAC 资源模型                    │
│                                                  │
│   Role ──────┐                                   │
│              ├──→ RoleBinding ──→ (User/Group/SA)│
│   ClusterRole┼                                   │
│              ├──→ ClusterRoleBinding → (User/...) │
│              │                                   │
│              └──→ RoleBinding ──→ (User/Group/SA) │
│                 (ClusterRole 降级使用)             │
└──────────────────────────────────────────────────┘
资源 作用范围 说明
Role 命名空间级别 定义在某个命名空间内的权限
ClusterRole 集群级别 定义集群范围的权限,也可用于命名空间
RoleBinding 命名空间级别 将 Role 或 ClusterRole 绑定到用户/组/SA
ClusterRoleBinding 集群级别 将 ClusterRole 绑定到用户/组/SA

关键区别 :Role + RoleBinding = 命名空间级权限;ClusterRole + ClusterRoleBinding = 集群级权限。但 ClusterRole 也可以通过 RoleBinding 绑定,此时 ClusterRole 的权限会被限制在 RoleBinding 所在的命名空间内。

5.2 K8S 内置的 ClusterRole

K8S 自带了几个常用的系统级 ClusterRole:

ClusterRole 权限范围 典型用途
cluster-admin 超级管理员,所有权限 集群管理员
admin 命名空间管理员(不含资源配额) 命名空间负责人
edit 命名空间内读写权限(不含角色/绑定) 开发者
view 命名空间内只读权限 只读用户

六、实战三:RBAC 角色绑定

6.1 创建只读角色(Role + RoleBinding)

给用户 test 授予 kube-public 命名空间的只读权限:

yaml 复制代码
# reader-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: reader
  namespace: kube-public
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "deployments", "services"]
  verbs: ["get", "list", "watch"]
yaml 复制代码
# reader-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: reader-bind
  namespace: kube-public
subjects:
- kind: User
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: reader
  apiGroup: rbac.authorization.k8s.io
bash 复制代码
kubectl apply -f reader-role.yaml
kubectl apply -f reader-binding.yaml

测试验证:

bash 复制代码
kubectl --kubeconfig=/root/test-kubeconfig get pods -n kube-public
# 可以查看 Pod 列表(只读权限生效)

kubectl --kubeconfig=/root/test-kubeconfig delete pod <pod-name> -n kube-public
# Error from server (Forbidden): 用户无删除权限(verbs 中没有 "delete")

6.2 使用 ClusterRole(集群级权限)

创建集群级别的管理员角色:

yaml 复制代码
# admin-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: admin
rules:
- apiGroups: ["", "apps", "extensions"]
  resources: ["*"]
  verbs: ["*"]
yaml 复制代码
# admin-clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-bind
subjects:
- kind: User
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io

生产提示resources: ["*"] + verbs: ["*"] 表示对所有资源拥有所有操作权限,在生产环境中应严格控制 ,遵循最小权限原则

6.3 快捷绑定内置 ClusterRole

如果只是需要标准权限,可以直接绑定内置的 ClusterRole,无需自定义:

bash 复制代码
# 将 view 角色绑定给 test 用户(所有命名空间只读)
kubectl create clusterrolebinding test-view-binding \
  --clusterrole=view \
  --user=test

# 将 admin 角色绑定给 test 用户(所有命名空间管理)
kubectl create clusterrolebinding test-admin-binding \
  --clusterrole=admin \
  --user=test

# 将 edit 角色绑定给 ServiceAccount
kubectl create rolebinding sa-edit-binding \
  --clusterrole=edit \
  --serviceaccount=kube-public:test01 \
  --namespace=kube-public

七、实战四:ServiceAccount + RBAC

ServiceAccount 是 K8S 中为 Pod 内进程设计的身份。Pod 默认会自动挂载所在命名空间的 default ServiceAccount。

7.1 创建 ServiceAccount 并绑定权限

yaml 复制代码
# sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test01
  namespace: kube-public
yaml 复制代码
# sa-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: reader-bind
subjects:
- kind: ServiceAccount
  name: test01
  namespace: kube-public
roleRef:
  kind: ClusterRole
  name: reader
  apiGroup: rbac.authorization.k8s.io
bash 复制代码
kubectl apply -f sa.yaml
kubectl apply -f sa-rolebinding.yaml

7.2 在 Pod 中使用 ServiceAccount

yaml 复制代码
# pod-with-sa.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pods-sa
  namespace: kube-public
spec:
  serviceAccountName: test01    # 指定使用自定义 SA
  containers:
  - name: test-container
    image: nginx:1.20
    command: ["/bin/sh", "-c", "sleep 3600"]

Pod 启动后,K8S 会自动将 SA 的 Token 以文件形式挂载到容器内:

复制代码
/var/run/secrets/kubernetes.io/serviceaccount/
├── ca.crt          # API Server 的 CA 证书
├── namespace       # 当前命名空间
└── token           # SA 的 Bearer Token

7.3 在 Pod 内通过 Python SDK 访问 API Server

以下示例展示 Pod 内的进程如何使用自动挂载的 SA Token 访问 API Server:

python 复制代码
# view-k8s-resources.py
from kubernetes import client, config

# Pod 内自动使用挂载的 SA Token
config.load_incluster_config()

apps_api = client.AppsV1Api()
core_api = client.CoreV1Api()

try:
    print("###### Deployment列表 ######")
    for dp in apps_api.list_namespaced_deployment("kube-public").items:
        print(dp.metadata.name)
except:
    print("没有权限访问Deployment资源!")

try:
    print("###### Pod列表 ######")
    for po in core_api.list_namespaced_pod("kube-public").items:
        print(po.metadata.name)
except:
    print("没有权限访问Pod资源!")

将此脚本放入 Pod 中执行:

bash 复制代码
# 进入 Pod 并执行
kubectl -n kube-public exec -it <pod-name> -- python3 view-k8s-resources.py

# 输出示例(有权限时):
# ###### Deployment列表 ######
# xiuxian
# ###### Pod列表 ######
# pods-sa
# xiuxian-6ffc4f5fd7-m9tf2

7.4 验证权限回收

删除 RoleBinding 后,Pod 内的访问将被拒绝:

bash 复制代码
# 删除绑定
kubectl delete clusterrolebinding reader-boy-bind

# 再次在 Pod 内执行脚本
kubectl -n kube-public exec -it <pod-name> -- python3 view-k8s-resources.py
# ###### Deployment列表 ######
# 没有权限访问Deployment资源!
# ###### Pod列表 ######
# 没有权限访问Pod资源!

权限即时生效:RBAC 的权限变更在 API Server 层面即时生效,无需重启 Pod。删除 RoleBinding 后,使用该 SA 的 Pod 立即失去相应权限。


八、生产环境最佳实践

8.1 安全配置检查清单

检查项 推荐做法 命令
禁用匿名访问 --anonymous-auth=false 检查 API Server 启动参数
启用 RBAC --authorization-mode=RBAC K8S 1.8+ 默认启用
启用准入控制 --enable-admission-plugins=NodeRestriction,... 按需启用
审计日志 --audit-log-path=/var/log/audit.log 记录所有 API 请求
最小权限原则 按需分配 Role,避免 resources: ["*"] 定期审查 RoleBinding
SA 自动挂载 对不需要访问 API Server 的 Pod 设为 false automountServiceAccountToken: false

8.2 RBAC 权限设计原则

  1. 最小权限原则:只授予完成工作所需的最小权限集
  2. 命名空间隔离:不同环境的资源分命名空间管理,通过 Role 控制边界
  3. 使用内置角色优先view/edit/admin 覆盖大多数场景
  4. 定期审计:检查是否存在过度授权的 ClusterRoleBinding
  5. 命名规范:Role 和 RoleBinding 的命名应能体现其用途

8.3 禁用 Pod 默认 SA 的 API 访问

对于不需要访问 API Server 的 Pod(如纯计算任务),应禁用 SA Token 自动挂载:

yaml 复制代码
apiVersion: v1
kind: ServiceAccount
metadata:
  name: no-api-access
  namespace: production
automountServiceAccountToken: false    # 禁用自动挂载
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
spec:
  template:
    spec:
      serviceAccountName: no-api-access
      automountServiceAccountToken: false    # Pod 级别也可设置

8.4 多集群管理方案

在生产环境中,通常需要管理多套 K8S 集群。kubectl 天然支持通过 kubeconfig 管理多集群:

bash 复制代码
# 配置多集群的 kubeconfig
kubectl config set-cluster cluster-a --server=https://10.0.0.231:6443 ...
kubectl config set-cluster cluster-b --server=https://10.0.0.240:8443 ...

# 创建上下文
kubectl config set-context ctx-a --cluster=cluster-a --user=user-a
kubectl config set-context ctx-b --cluster=cluster-b --user=user-b

# 切换集群
kubectl config use-context ctx-a
kubectl get nodes

kubectl config use-context ctx-b
kubectl get nodes

常用多集群管理工具:

工具 特点
kubectl 官方 CLI,通过 kubeconfig 管理多集群
Kuboard 免费 Web UI,最多 3 个集群
KubeSphere 功能全面的国产管理平台
Rancher 企业级多集群管理
云平台 ACK/TKE/CCE 等托管服务

十、总结

K8S 安全框架是一个分层防御体系:

  1. 认证层确认"你是谁"(X509/Token/SA)
  2. 鉴权层判断"你能做什么"(RBAC:Role → RoleBinding → Subject)
  3. 准入控制层检查"操作合规吗"(Validating/Mutating)

生产环境中,建议按照最小权限原则设计 RBAC 策略,禁用匿名访问,定期审计权限配置,并使用专用 ServiceAccount 替代默认 SA。掌握这些内容,你就能构建一个安全、可控的 K8S 集群。

相关推荐
运维开发故事1 天前
基于 Arthas 的多集群在线诊断系统设计与实现
kubernetes
Flynt1 天前
npm v12 来了:allowScripts 默认关闭,我的项目差点跑不起来
安全·npm·node.js
Patrick_Wilson3 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
探索云原生3 天前
K8s 1.36 这个 GA 特性,把 initContainer 拉模型的 hack 干掉了
ai·云原生·kubernetes
云恒要逆袭3 天前
运行你的第一个Docker容器
后端·docker·容器
Java之美4 天前
一次k8s升级引发的DevicePlugin注册失败
云原生·kubernetes
程序员老赵5 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程
冬奇Lab6 天前
Skill 系列(02):Skill 安全风险——三类攻击面的实战测试
人工智能·安全·开源
武子康8 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple