K8S(十二)—— Kubernetes安全机制深度解析与实践:从认证到RBAC授权
文章目录
- 前言
- 一、Kubernetes安全机制概述
- 1.1 核心设计原则
- 1.2 安全访问流程
- 二、认证(Authentication):确认“你是谁”
- 2.1 支持的认证方式
- 2.2 需要认证的访问类型
- 2.3 端口与证书安全规范
- 2.4 证书颁发方式
- 2.5 kubeconfig:认证信息的载体
- 2.5.1 kubeconfig核心组成
- 2.5.2 常用操作
- 2.6 Service Account(SA):Pod的身份标识
- 2.6.1 SA的核心特性
- 2.7 Secret与SA的关联
- 2.7.1 Secret的核心类型
- 2.7.2 SA与Secret的自动挂载
- 2.7.3 验证挂载结果
- 三、鉴权(Authorization):确认“你能做什么”
- 3.1 常见鉴权策略对比
- 3.1.1 RBAC的核心优势
- 3.2 RBAC的核心资源对象
- 3.3 角色定义:Role与ClusterRole
- 3.3.1 Role:命名空间级角色
- 3.3.2 ClusterRole:集群级角色
- 3.4 角色绑定:RoleBinding与ClusterRoleBinding
- 3.4.1 RoleBinding:命名空间级绑定
- 示例1:绑定Role到用户
- 示例2:绑定ClusterRole到用户
- 3.4.2 ClusterRoleBinding:集群级绑定
- 示例:绑定ClusterRole到用户组
- 3.5 主体(Subject)与JWT
- 3.5.1 主体类型
- 3.5.2 JWT与SA认证
- 3.6 资源(Resources)与操作:RBAC权限的细粒度控制
- 3.6.1 子资源的权限控制
- 3.6.2 常用权限配置速查
- 四、准入控制(Admission Control):确认“请求是否合规”
- 4.1 准入插件的核心作用
- 4.2 推荐准入插件列表(生产环境)
- 4.3 核心插件功能说明
- 五、实战:创建仅管理指定命名空间的用户
- 5.1 步骤1:创建系统用户
- 5.2 步骤2:生成HTTPS证书与kubeconfig
- 5.2.1 安装证书生成工具
- 5.2.2 生成证书签名请求(CSR)
- 5.2.3 执行脚本生成证书
- 5.2.4 生成kubeconfig文件
- 5.3 步骤3:创建命名空间与分发kubeconfig
- 5.3.1 创建目标命名空间`yjs0805`
- 5.3.2 执行脚本生成kubeconfig
- 5.3.3 分发kubeconfig到`zhangsan`用户目录
- 5.4 步骤4:配置RBAC授权(Role + RoleBinding)
- 5.4.1 创建RBAC配置文件`rbac.yaml`
- 5.4.2 应用RBAC配置并验证
- 5.5 步骤5:验证用户权限
- 5.5.1 验证允许的操作(创建与查看Pod)
- 5.5.2 验证拒绝的操作(访问其他资源或命名空间)
- 5.6 步骤6:管理员侧验证权限生效
- 5.7 可选:授予命名空间管理员权限
- 总结
- 附:官方文档参考
前言
在云原生时代,Kubernetes作为分布式集群的核心管理平台,其安全性直接决定了整个集群的稳定与数据安全。Kubernetes的安全设计围绕API Server展开——作为内部组件通信的中介与外部控制的唯一入口,所有客户端(如kubectl
、Pod、组件)对集群资源的操作,都必须通过API Server的三重安全校验。
本文将从认证-鉴权-准入控制
三道核心关卡切入,系统讲解Kubernetes安全机制的原理,并通过实战案例演示如何创建仅具备指定命名空间权限的用户,帮助开发者和运维人员构建更安全的K8s集群环境。
一、Kubernetes安全机制概述
Kubernetes 作为分布式集群的管理工具,Kubernetes安全的核心目标是确保只有合法主体能对集群资源执行合规操作,其安全流程通过API Server的三层校验实现,任何一层校验失败,请求都会被直接拒绝。
1.1 核心设计原则
Kubernetes安全机制遵循最小权限
与“分层防御”原则:
- 最小权限:每个主体(用户、组件、Pod)仅获得完成其工作所需的最小权限;
- 分层防御:通过
认证-鉴权-准入控制
三层校验,形成递进式安全屏障,避免单一环节失效导致整体安全突破。
1.2 安全访问流程
当客户端(如kubectl
、Pod)向API Server发起资源请求时,需依次通过以下三层校验:
- 认证(Authentication):验证“请求者是谁”,确认请求者的身份合法性;
- 鉴权(Authorization):验证“请求者能做什么”,判断身份是否有权执行请求的操作;
- 准入控制(Admission Control):验证“请求是否符合集群规则”,对请求进行变更或拦截(如配额校验、命名空间合法性校验)。
二、认证(Authentication):确认“你是谁”
认证是Kubernetes安全的第一道关卡,用于识别请求者的身份。API Server支持多种认证方式,不同场景下可选择适配的认证方案。
2.1 支持的认证方式
API Server通过启动参数配置认证插件,常见认证方式如下:
- HTTP Token认证:客户端在HTTP请求头中携带一个长字符串Token,API Server通过内置或外部存储的“Token-用户名”映射关系验证身份;优点是实现简单,缺点是Token易泄露且无过期机制;
- HTTP Basic认证:客户端将“用户名:密码”通过Base64编码后,放入
Authorization
请求头;优点是配置简单,缺点是Base64编码可逆,安全性较低,仅适用于测试环境; - HTTPS证书认证(推荐):基于CA根证书签名的双向TLS认证,是Kubernetes最严格的认证方式。客户端需携带CA签名的证书,API Server同时验证客户端证书与自身证书,确保双向身份合法。
注意:Token认证与Basic认证仅支持“服务端对客户端”的单向认证,无法验证服务端身份;HTTPS证书认证可实现双向认证,是生产环境的首选方案。
2.2 需要认证的访问类型
Kubernetes集群中,所有访问API Server的主体都需通过认证,主要分为两类:
- Kubernetes组件访问:包括
kubectl
(命令行工具)、kubelet
(节点代理)、kube-proxy
(网络代理)、Controller Manager
(控制器管理器)、Scheduler
(调度器); - Pod访问:包括以Pod形式运行的集群内部组件(如
coredns
、dashboard
),这类访问需通过“Service Account”实现身份认证。
2.3 端口与证书安全规范
API Server默认提供两个端口,对应不同的安全级别:
- 非安全端口(8080):仅用于集群内部同机组件通信(如
Controller Manager
、Scheduler
与API Server同机部署时),不对外暴露,无需认证; - 安全端口(6443):对外暴露的唯一端口,所有外部访问(如
kubectl
、kubelet
、kube-proxy
)必须通过HTTPS双向认证,是生产环境的核心访问端口。
2.4 证书颁发方式
HTTPS证书的颁发分为“手动签发”与“自动签发”两种,适配不同部署场景:
- 手动签发:二进制部署Kubernetes时,需通过CA根证书手动为API Server、
kubectl
等组件签发证书;优点是可控性高,缺点是操作繁琐,不适用于动态组件(如Pod); - 自动签发:
kubelet
首次访问API Server时,先通过Token临时认证;认证通过后,由Controller Manager
自动为其签发长期证书,后续kubelet
将使用该证书进行认证;优点是适配动态组件,减少人工操作。
2.5 kubeconfig:认证信息的载体
kubeconfig
是Kubernetes客户端(如kubectl
、kubelet
)连接API Server的配置文件,包含集群信息、客户端认证信息与上下文参数,是认证流程的核心载体。
2.5.1 kubeconfig核心组成
- 集群参数:CA根证书(用于验证API Server身份)、API Server地址;
- 客户端参数:客户端证书与私钥(用于API Server验证客户端身份);
- 上下文参数:默认集群名、用户名、命名空间(指定客户端默认操作的集群与命名空间)。
- 通过指定不同 kubeconfig,组件(如
kubelet
、kube-proxy
)可切换不同集群并连接到 API Server。- 既是集群描述,也是认证信息的载体。
kubectl
默认位置:~/.kube/config
。
2.5.2 常用操作
kubectl
默认读取~/.kube/config
路径的kubeconfig文件,可通过--kubeconfig
参数指定自定义配置文件:
# 使用自定义kubeconfig文件访问集群
kubectl get pods --kubeconfig /path/to/your/kubeconfig
2.6 Service Account(SA):Pod的身份标识
由于Pod是动态创建与销毁的,无法为每个Pod手动签发证书,因此Kubernetes引入Service Account(SA),专门用于Pod访问API Server的身份认证。
2.6.1 SA的核心特性
- 每个命名空间默认创建一个
default
SA; - 创建Pod时,若未显式指定SA,Pod将自动使用所属命名空间的
default
SA; - SA的认证信息通过Secret挂载到Pod内部,供容器使用。
2.7 Secret与SA的关联
Kubernetes通过Secret存储SA的认证信息,其中与SA直接关联的是service-account-token
类型的Secret。
2.7.1 Secret的核心类型
- service-account-token:存储SA的认证Token、CA根证书与命名空间信息,用于Pod访问API Server;
- Opaque:存储用户自定义的敏感信息(如密码、密钥),需手动创建与挂载。
2.7.2 SA与Secret的自动挂载
创建Pod后,Kubernetes会自动将SA关联的service-account-token
Secret挂载到Pod的/var/run/secrets/kubernetes.io/serviceaccount/
路径下,挂载内容包括:
ca.crt
:CA根证书,用于Pod验证API Server身份;namespace
:SA所属的命名空间;token
:SA的认证Token,用于API Server验证Pod身份。
这也是Service Account 的三个组成部分
/var/run/secrets/kubernetes.io/serviceaccount/├─ ca.crt├─ namespace└─ token
2.7.3 验证挂载结果
通过以下命令可查看Pod内挂载的SA认证信息:
# 1. 查看命名空间下的SA
kubectl get sa
# 输出示例(default命名空间默认SA)
NAME SECRETS AGE
default 1 6d21h# 2. 查看kube-system命名空间的kube-proxy Pod
kubectl get po -n kube-system
# 示例输出
NAME READY STATUS RESTARTS AGE
kube-proxy-hgghd 1/1 Running 0 6d21h
kube-proxy-hsc69 1/1 Running 4 6d21h
kube-proxy-vwxc6 1/1 Running 0 6d21h# 3. 查看挂载的SA认证文件
kubectl exec -it kube-proxy-xxxx -n kube-system sh -- ls /var/run/secrets/kubernetes.io/serviceaccount/
# 输出:ca.crt namespace token
三、鉴权(Authorization):确认“你能做什么”
鉴权是Kubernetes安全的第二道关卡,在认证通过后,判断请求者是否有权执行目标操作(如“查看Pod”“创建Deployment”)。API Server通过--authorization-mode
参数配置鉴权策略,其中RBAC(基于角色的访问控制) 是Kubernetes 1.6+版本的默认且推荐的鉴权方案。
3.1 常见鉴权策略对比
Kubernetes支持多种鉴权策略,不同策略的适用场景差异较大:
鉴权策略 | 核心逻辑 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
AlwaysDeny | 拒绝所有请求 | 实现简单 | 无实际业务价值 | 测试环境(验证拒绝逻辑) |
AlwaysAllow | 允许所有请求 | 无需配置 | 完全无安全防护 | 测试环境(快速部署) |
ABAC(属性基) | 基于用户、资源、操作的属性配置静态规则 | 规则细粒度高 | 配置繁琐,修改需重启API Server | 复杂且固定的权限场景 |
Webhook | 调用外部REST服务判断权限 | 权限逻辑与集群解耦 | 依赖外部服务,增加延迟与故障点 | 跨集群统一权限管理 |
RBAC(角色基) | 基于“角色-权限-用户”的动态绑定 | 动态调整、细粒度高、无需重启API Server | 需理解角色与绑定关系 | 生产环境(默认推荐) |
3.1.1 RBAC的核心优势
RBAC成为生产环境首选的原因在于其三大特性:
- 覆盖全场景:支持对
资源型对象
(如Pod、Service)与非资源型对象
(如集群状态、元信息)的权限控制; - 方便管理:权限通过Kubernetes
API资源对象
(Role、RoleBinding等)定义,可用kubectl
/API 管理; - 动态调整:可通过
kubectl
或API实时修改,无需重启API Server(ABAC 需重启);
3.2 RBAC的核心资源对象
RBAC通过4个顶级API资源对象实现权限管理,分为“角色定义”与“角色绑定”两类:
- 角色定义对象:定义“有哪些权限”;
- Role:命名空间级角色,权限仅作用于所属命名空间;
- ClusterRole:集群级角色,权限可作用于全集群或跨命名空间;
- 角色绑定对象:定义“谁拥有这些权限”;
- RoleBinding:命名空间级绑定,将Role/ClusterRole的权限赋予指定主体(用户、用户组、SA),权限仅作用于所属命名空间;
- ClusterRoleBinding:集群级绑定,将ClusterRole的权限赋予指定主体,权限作用于全集群。
关键注意点:若用RoleBinding绑定ClusterRole,权限仍受RoleBinding所属命名空间限制;仅当用ClusterRoleBinding绑定ClusterRole时,权限才作用于全集群。
3.3 角色定义:Role与ClusterRole
角色的核心是“权限规则(Rules)”,规则由apiGroups
(API组)、resources
(资源类型)、verbs
(操作类型)三部分组成。
注意点:
- 权限仅能累加(白名单),不存在“先有很多再减少”的黑名单模型。
- Role 只能定义在 某个命名空间 内;跨命名空间请使用 ClusterRole。
3.3.1 Role:命名空间级角色
Role仅作用于其所属的命名空间,无法对跨命名空间资源生效。以下示例定义一个在default
命名空间中“读取Pod”的Role:
apiVersion: rbac.authorization.k8s.io/v1 # RBAC API组与版本
kind: Role # 资源类型为Role
metadata:namespace: default # 作用于default命名空间name: pod-reader # Role名称
rules: # 权限规则列表
- apiGroups: [""] #""表示 apiGroups 和 apiVersion 使用相同的 core API 组,即 rbac.authorization.k8s.ioresources: ["pods"] # 资源类型为Podverbs: ["get", "watch", "list"] # 允许的操作:获取、监听、列出Pod#以上配置的意义是,如果把 pod-reader 这个 Role 赋予给一个用户,那么这个用户将在 default 命名空间中具有对 Pod 资源对象 进行 get(获取)、watch(监听)、list(列出)这三个操作权限。
3.3.2 ClusterRole:集群级角色
ClusterRole不受命名空间限制,可作用于全集群,支持对“集群级资源”(如Node)、“跨命名空间资源”(如Secret)的权限定义。以下示例定义一个“读取全集群Secret”的ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole # 资源类型为ClusterRole
metadata:name: secret-reader # ClusterRole名称(无namespace字段)
rules:
- apiGroups: [""]resources: ["secrets"] # 资源类型为Secretverbs: ["get", "watch", "list"] # 允许的操作:获取、监听、列出Secret
3.4 角色绑定:RoleBinding与ClusterRoleBinding
角色绑定的核心是“将角色的权限赋予主体”,主体(Subject)包括User(用户)、Group(用户组)、ServiceAccount(服务账号)三类。
3.4.1 RoleBinding:命名空间级绑定
RoleBinding仅在其所属命名空间内生效,可绑定Role或ClusterRole(绑定ClusterRole时,权限仍受命名空间限制)。
示例1:绑定Role到用户
将default
命名空间的pod-reader
Role赋予用户zhangsan
,使其仅能在default
命名空间读取Pod:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: read-pods # RoleBinding名称namespace: default # 作用于default命名空间
subjects: # 主体列表(被授权者)
- kind: User # 主体类型为用户name: zhangsan # 用户名apiGroup: rbac.authorization.k8s.io # 主体所属API组
roleRef: # 引用的角色(授权来源)kind: Role # 引用的角色类型为Rolename: pod-reader # 引用的Role名称apiGroup: rbac.authorization.k8s.io # 角色所属API组#将 default 命名空间的 pod-reader Role 授予 zhangsan 用户,此后 zhangsan 用户在 default 命名空间中将具有 pod-reader 的权限。
示例2:绑定ClusterRole到用户
通过RoleBinding引用secret-reader
ClusterRole,将“读取Secret”的权限赋予用户lisi
,但仅作用于kube-public
命名空间:
# RoleBinding 同样可以引用 ClusterRole 来对当前 namespace 内 User、Group 或 ServiceAccount 进行授权
# 这种操作允许集群管理员在整个集群内定义一些通用的 ClusterRole,然后在不同的 namespace 中使用 RoleBinding 来引用。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: read-secrets # RoleBinding名称namespace: kube-public # 作用于kube-public命名空间
subjects:
- kind: Username: lisiapiGroup: rbac.authorization.k8s.io
roleRef:kind: ClusterRole # 引用的角色类型为ClusterRolename: secret-reader # 引用的ClusterRole名称apiGroup: rbac.authorization.k8s.io
注意:尽管
secret-reader
ClusterRole本身具备全集群读取Secret的权限,但RoleBinding的namespace: kube-public
限制了lisi
仅能在kube-public
命名空间读取Secret。
3.4.2 ClusterRoleBinding:集群级绑定
ClusterRoleBinding作用于全集群,仅能绑定ClusterRole,将权限赋予主体后,主体可在所有命名空间执行对应操作。
示例:绑定ClusterRole到用户组
将secret-reader
ClusterRole赋予manager
用户组,使其所有成员能在全集群读取Secret:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: read-secrets-global # ClusterRoleBinding名称
subjects:
- kind: Group # 主体类型为用户组name: manager # 用户组名称apiGroup: rbac.authorization.k8s.io
roleRef:kind: ClusterRolename: secret-readerapiGroup: rbac.authorization.k8s.io#以上 ClusterRoleBinding 授权 manager 组内所有用户在全部命名空间中对 secrets 进行访问。
3.5 主体(Subject)与JWT
3.5.1 主体类型
RBAC支持三类主体(Subject),覆盖所有访问集群的场景:
- User(用户):由外部系统管理(如LDAP、证书CN字段),Kubernetes不提供内置用户管理功能;
- Group(用户组):用于批量授权,如
system:masters
组(默认集群管理员组); - ServiceAccount(服务账号):用于Pod访问API Server,由Kubernetes自动管理。
注意:
system:
前缀为Kubernetes系统保留前缀,普通用户/用户组应避免使用,以防与系统权限冲突。- Pod 使用
SA
认证时,其service-account-token
中的JWT
保存用户信息;结合Role/ClusterRole + (Cluster)RoleBinding
完成权限绑定。
3.5.2 JWT与SA认证
Pod使用SA认证时,其挂载的token
文件是一个JWT(JSON Web Token),包含以下核心信息:
- 主体身份(SA名称与命名空间);
- 签发者(API Server);
- 过期时间。
API Server验证JWT的签名(通过自身私钥)后,提取主体信息,再结合Role/ClusterRole与绑定关系判断权限。
3.6 资源(Resources)与操作:RBAC权限的细粒度控制
RBAC的权限规则通过“资源(resources)”与“操作(verbs)”定义,支持对资源的细粒度控制,包括“子资源”(如Pod的log
)。
API 中对 Pod 日志的请求 URL 样例如下:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
3.6.1 子资源的权限控制
部分资源包含“子资源”,如Pod的log
(日志)、exec
(执行命令),需通过资源/子资源
格式定义权限。以下示例定义一个“读取Pod与Pod日志”的Role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: defaultname: pod-and-pod-logs-reader
rules:
- apiGroups: [""]resources: ["pods", "pods/log"] # 同时授权Pod与Pod的log子资源verbs: ["get", "list"] # 允许获取Pod与Pod日志
3.6.2 常用权限配置速查
类别 | 常用值 |
---|---|
verbs(操作) | get (获取)、list (列出)、watch (监听)、create (创建)、update (更新)、delete (删除)、exec (执行命令) |
resources(资源) | pods 、services 、secrets 、configmaps 、deployments 、daemonsets 、nodes 、namespaces |
apiGroups(API组) | "" (核心组)、apps (Deployment/StatefulSet所属组)、autoscaling (HPA所属组)、batch (CronJob所属组) |
四、准入控制(Admission Control):确认“请求是否合规”
准入控制是Kubernetes安全的第三道关卡,通过一组“准入插件(Admission Controller)”对请求进行校验与修改。请求通过认证与鉴权后,将依次经过所有准入插件的校验,任何一个插件拒绝请求,整个请求都会被驳回。
4.1 准入插件的核心作用
准入插件分为两类:
- 验证型插件(Validating):仅校验请求是否合规(如配额是否充足、命名空间是否存在),不修改请求;
- 修改型插件(Mutating):在请求合规的前提下,自动修改请求内容(如为Pod自动注入SA、设置默认存储类)。
4.2 推荐准入插件列表(生产环境)
Kubernetes官方推荐的准入插件组合(不同版本略有差异)如下,可通过API Server启动参数--enable-admission-plugins
配置:
NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,NodeRestriction
4.3 核心插件功能说明
插件名称 | 类型 | 核心功能 |
---|---|---|
NamespaceLifecycle | 验证型 | 管理命名空间生命周期:拒绝在不存在的命名空间创建资源;禁止删除系统命名空间;删除命名空间时级联清理资源 |
LimitRanger | 验证/修改型 | 基于LimitRange 配置,为Pod设置默认资源限制(如CPU/内存);拒绝超过限制的资源请求 |
ServiceAccount | 修改型 | 为未指定SA的Pod自动注入所属命名空间的default SA;自动挂载SA关联的Secret |
DefaultStorageClass | 修改型 | 为未指定存储类的PVC自动设置默认存储类 |
ResourceQuota | 验证型 | 基于ResourceQuota 配置,限制命名空间的总资源使用(如最大Pod数量、总CPU配额);拒绝超过配额的请求 |
NodeRestriction | 验证型 | 限制Node组件的权限,仅允许Node修改自身相关资源(如Node、Pod绑定),防止Node越权 |
官方文档参考:https://kubernetes.io/zh/docs/reference/access-authn-authz/admission-controllers/
五、实战:创建仅管理指定命名空间的用户
本节通过实战演示如何创建用户zhangsan
,使其仅能在yjs0805
命名空间对Pod执行get/watch/list/create
操作,深入理解RBAC的权限控制逻辑。
5.1 步骤1:创建系统用户
首先在集群控制节点创建Linux系统用户zhangsan
(Kubernetes的User需与系统用户关联):
# 1. 创建系统用户zhangsan
useradd zhangsan# 2. 设置用户密码(按提示输入密码)
passwd zhangsan# 3. 切换到zhangsan用户,尝试访问集群(此时未配置认证信息,访问会失败)
su - zhangsan
kubectl get pods# 预期输出(失败):
# The connection to the server localhost:8080 was refused - did you specify the right host or port?
5.2 步骤2:生成HTTPS证书与kubeconfig
Kubernetes通过证书识别User身份(证书的CN
字段为用户名,O
字段为用户组),需先为zhangsan
生成证书,再创建对应的kubeconfig文件。
5.2.1 安装证书生成工具
使用cfssl
工具生成证书,需先下载并安装:
# 1. 下载cfssl工具(切换到root用户执行)
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl_1.6.4_linux_amd64 -O /usr/local/bin/cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssljson_1.6.4_linux_amd64 -O /usr/local/bin/cfssljson
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl-certinfo_1.6.4_linux_amd64 -O /usr/local/bin/cfssl-certinfo# 或者
传证书工具至 /usr/local/bin:cfssl、cfssljson、cfssl-certinfo# 2. 赋予执行权限
chmod +x /usr/local/bin/cfssl*
5.2.2 生成证书签名请求(CSR)
创建证书申请文件,指定用户名(CN: zhangsan
)与用户组(O: k8s
):
# 1. 创建工作目录(root用户执行)
mkdir -p /opt/zhangsan && cd /opt/zhangsan# 2. 创建证书申请脚本user-cert.sh
vim user-cert.sh
脚本内容如下(CN
为用户名,O
为用户组,需与后续RBAC绑定的主体一致):
#! /bin/bash
# 生成证书签名请求(CSR)配置文件
cat > zhangsan-csr.json <<EOF
{"CN": "zhangsan", # 用户名(Kubernetes User)"hosts": [], # 证书生效的主机列表,空表示所有主机"key": {"algo": "rsa", # 密钥算法"size": 2048 # 密钥长度},"names": [{"C": "CN", # 国家"ST": "BeiJing", # 省份"L": "BeiJing", # 城市"O": "k8s", # 用户组(Kubernetes Group)"OU": "System" # 组织单元}]
}
EOF
#API Server 会把客户端证书的 CN 字段作为 User,把 names.O 字段作为 Group
# 使用集群CA根证书签发用户证书(CA证书默认路径为/etc/kubernetes/pki/)
cd /etc/kubernetes/pki/
cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /opt/zhangsan/zhangsan-csr.json | cfssljson -bare zhangsan======================================================================================
#! /bin/bash
cat > zhangsan-csr.json <<EOF
{"CN": "zhangsan","hosts": [],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","ST": "BeiJing","L": "BeiJing","O": "k8s","OU": "System"}]
}
EOF
#API Server 会把客户端证书的 CN 字段作为 User,把 names.O 字段作为 Group
cd /etc/kubernetes/pki/
cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /opt/zhangsan/zhangsan-csr.json | cfssljson -bare zhangsan
5.2.3 执行脚本生成证书
# 1. 赋予脚本执行权限
chmod +x user-cert.sh# 2. 执行脚本生成证书
./user-cert.sh#/etc/kubernetes/pki/ 目录中会生成 zhangsan-key.pem、zhangsan.pem、
# 3. 查看生成的证书文件(在/etc/kubernetes/pki/目录下)
ls /etc/kubernetes/pki/zhangsan*
# 预期输出:zhangsan.csr(证书签名请求)、zhangsan-key.pem(用户私钥)、zhangsan.pem(用户证书)
5.2.4 生成kubeconfig文件
创建kubeconfig脚本,为zhangsan
配置集群信息、客户端认证信息与默认上下文:
# 1. 在/opt/zhangsan目录创建kubeconfig脚本rbac-kubeconfig.sh
cd /opt/zhangsan
vim rbac-kubeconfig.sh
脚本内容如下(需将192.168.10.14
替换为你的API Server地址):
#!/bin/bash
# 接收API Server地址作为参数(如./rbac-kubeconfig.sh 192.168.10.14)
APISERVER=$1# 设置集群参数(指定CA证书与API Server地址)
export KUBE_APISERVER="https://$APISERVER:6443"
kubectl config set-cluster kubernetes \--certificate-authority=/etc/kubernetes/pki/ca.crt \--embed-certs=true \--server=${KUBE_APISERVER} \--kubeconfig=zhangsan.kubeconfig# 设置客户端认证参数(指定用户证书与私钥)
kubectl config set-credentials zhangsan \--client-key=/etc/kubernetes/pki/zhangsan-key.pem \--client-certificate=/etc/kubernetes/pki/zhangsan.pem \--embed-certs=true \--kubeconfig=zhangsan.kubeconfig# 设置上下文参数(默认集群、用户、命名空间)
kubectl config set-context kubernetes \--cluster=kubernetes \--user=zhangsan \--namespace=yjs0805 \--kubeconfig=zhangsan.kubeconfig# 激活上下文(设置默认使用的上下文)
kubectl config use-context kubernetes --kubeconfig=zhangsan.kubeconfig
5.3 步骤3:创建命名空间与分发kubeconfig
5.3.1 创建目标命名空间yjs0805
# root用户执行,创建命名空间
kubectl create namespace yjs0805# 验证命名空间是否创建成功
kubectl get ns yjs0805
# 预期输出:NAME STATUS AGE
# yjs0805 Active 10s
5.3.2 执行脚本生成kubeconfig
# 1. 赋予脚本执行权限
chmod +x rbac-kubeconfig.sh# 2. 执行脚本(替换192.168.10.14为你的API Server地址)
./rbac-kubeconfig.sh 192.168.10.14# 3. 查看生成的kubeconfig文件
ls zhangsan.kubeconfig
# 预期输出:zhangsan.kubeconfig
5.3.3 分发kubeconfig到zhangsan
用户目录
将生成的zhangsan.kubeconfig
文件复制到zhangsan
用户的默认kubeconfig路径(~/.kube/config
):
# 1. 为zhangsan用户创建.kube目录
mkdir -p /home/zhangsan/.kube# 2. 复制kubeconfig文件
cp zhangsan.kubeconfig /home/zhangsan/.kube/config# 3. 修改文件权限(确保zhangsan用户拥有读写权限)
chown -R zhangsan:zhangsan /home/zhangsan/.kube/# 4. 查看 kubeconfig
cat zhangsan-kubeconfig
5.4 步骤4:配置RBAC授权(Role + RoleBinding)
创建Role定义“yjs0805
命名空间的Pod操作权限”,再通过RoleBinding将Role赋予zhangsan
用户。
5.4.1 创建RBAC配置文件rbac.yaml
# root用户执行,创建rbac.yaml文件
vim rbac.yaml
文件内容如下:
# 定义Role:在yjs0805命名空间对Pod执行get/watch/list/create操作
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: yjs0805 # 作用于yjs0805命名空间name: pod-reader # Role名称
rules:
- apiGroups: [""]resources: ["pods"] # 资源类型为Podverbs: ["get", "watch", "list", "create"] # 允许的操作
---
# 定义RoleBinding:将pod-reader Role赋予zhangsan用户
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: read-pods # RoleBinding名称namespace: yjs0805 # 作用于yjs0805命名空间
subjects:
- kind: User # 主体类型为用户name: zhangsan # 用户名(与证书CN字段一致)apiGroup: rbac.authorization.k8s.io
roleRef:kind: Role # 引用的角色类型为Rolename: pod-reader # 引用的Role名称apiGroup: rbac.authorization.k8s.io
======================================================================================
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: yjs0805name: pod-reader
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get", "watch", "list", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: read-podsnamespace: yjs0805
subjects:
- kind: Username: zhangsanapiGroup: rbac.authorization.k8s.io
roleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io
5.4.2 应用RBAC配置并验证
# 1. 应用RBAC配置
kubectl apply -f rbac.yaml# 2. 验证Role与RoleBinding是否创建成功
kubectl get role,rolebinding -n yjs0805
# 预期输出:
# role.rbac.authorization.k8s.io/pod-reader 2025-10-18T08:20:12Z
# rolebinding.rbac.authorization.k8s.io/read-pods Role/pod-reader 37s
5.5 步骤5:验证用户权限
切换到zhangsan
用户,验证其权限是否符合预期(仅能在yjs0805
命名空间操作Pod,无其他权限)。
5.5.1 验证允许的操作(创建与查看Pod)
# 1. 切换到zhangsan用户
su - zhangsan# 2. 创建测试Pod的配置文件pod-test.yaml
cat > pod-test.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:name: pod-test
spec:containers:- name: nginximage: nginx # 使用nginx镜像
YAML# 3. 在yjs0805命名空间创建Pod(允许)
kubectl create -f pod-test.yaml# 4. 查看yjs0805命名空间的Pod(允许)
kubectl get pods -o wide
# 预期输出:
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# pod-test 1/1 Running 0 2m 10.244.2.2 node02 <none> <none>
5.5.2 验证拒绝的操作(访问其他资源或命名空间)
# 1. 尝试查看yjs0805命名空间的Service(拒绝,无Service权限)
kubectl get svc
# 预期输出(失败):
# Error from server (Forbidden): services is forbidden: User "zhangsan" cannot list resource "services" in API group "" in the namespace "yjs0805"# 2. 尝试查看default命名空间的Pod(拒绝,无跨命名空间权限)
kubectl get pods -n default
# 预期输出(失败):
# Error from server (Forbidden): pods is forbidden: User "zhangsan" cannot list resource "pods" in API group "" in the namespace "default"
5.6 步骤6:管理员侧验证权限生效
切换到root
用户(集群管理员),验证zhangsan
创建的Pod仅存在于yjs0805
命名空间:
# 1. 切换到root用户
exit # 退出zhangsan用户,回到root用户# 2. 查看全集群的Pod
kubectl get pods --all-namespaces -o wide
# 预期输出(仅yjs0805命名空间有pod-test):
# NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
# yjs0805 pod-test 1/1 Running 0 5m 10.244.2.2 node02
5.7 可选:授予命名空间管理员权限
若需让zhangsan
具备yjs0805
命名空间的“管理员权限”(可操作所有资源),可通过RoleBinding引用Kubernetes内置的admin
ClusterRole:
# root用户执行,将admin ClusterRole赋予zhangsan用户(仅作用于yjs0805命名空间)
kubectl create rolebinding zhangsan-admin-binding \--clusterrole=admin \--user=zhangsan \--namespace=yjs0805# 验证绑定结果
kubectl get rolebinding -n yjs0805
# 预期输出:
# NAME ROLE AGE
# read-pods Role/pod-reader 10m
# zhangsan-admin-binding ClusterRole/admin 30s
总结
Kubernetes的安全机制通过“认证-鉴权-准入控制”三层防御,构建了从“身份验证”到“权限控制”再到“请求合规”的完整安全体系:
- 认证:通过证书、Token等方式确认“请求者是谁”,是安全的基础;
- 鉴权:通过RBAC实现“细粒度权限控制”,确保主体仅能执行必要操作,是安全的核心;
- 准入控制:通过插件链对请求进行“合规校验与自动修改”,是安全的补充屏障。
在实际生产环境中,需重点关注以下几点:
- 优先使用HTTPS证书认证,避免Token或Basic认证;
- 基于RBAC配置最小权限,避免过度授权(如不随意将
cluster-admin
权限赋予普通用户); - 启用官方推荐的准入插件,尤其是
ResourceQuota
(配额控制)与NodeRestriction
(Node权限限制); - 定期轮换证书与Token,避免长期泄露导致安全风险。
通过本文的理论讲解与实战演示,相信你已掌握Kubernetes安全机制的核心原理与配置方法,可根据实际业务需求构建更安全、更可靠的K8s集群。
附:官方文档参考
- Kubernetes RBAC官方文档
- Kubernetes准入控制器官方文档
- Kubernetes证书管理官方文档