K8s 安全机制全解析
一、前言
二、Authentication(认证机制)
2.1 支持的认证方式
2.2 哪些访问需要认证
2.3 通信端口与安全性
2.4 证书的颁发方式
2.5 kubeconfig 文件结构
2.6 ServiceAccount(服务账户)
2.7 Secret 与 ServiceAccount 的关系
三、Authorization(鉴权机制)
3.1 常见授权模式对比
3.2 RBAC 四大核心对象
3.3 角色(Role/ClusterRole)示例
3.4 绑定角色权限(RoleBinding / ClusterRoleBinding)
3.5 主体(Subject)与 JWT
什么是 Subject(主体)
JWT 在 Kubernetes 中的角色
1) JWT 的结构(3 部分)
2) 常见 claim(k8s 环境)
3.6 子资源(Subresources)
四、Admission Control(准入控制)
常见 Admission 插件
五、实践案例:创建受限用户(命名空间级别权限)
Step 0:创建系统用户
Step 1:生成用户 CSR 与证书
Step 2:生成 kubeconfig
Step 3:创建命名空间与 kubeconfig 上下文
Step 4:创建 Role 与 RoleBinding(命名空间级权限)
Step 5:验证(切换到 ciallo 用户执行操作)
Step 6:管理员侧检查(确认 RBAC 生效)
可选:授予命名空间管理员(如果需要)
撤销 / 收回访问(重要)
1. 删除 RoleBinding / Role
2. 撤销用户证书(若用证书认证)
3. 删除 kubeconfig(分发到用户机器上)
审计与排错建议
查看拒绝原因(管理侧)
常见排错命令
如果 kubectl 返回 connection refused 或 The connection to the server localhost:8080 was refused:
额外补充:用 ServiceAccount 做应用访问(更常见的场景)
六、总结(Summary)
一、前言
在 Kubernetes(以下简称 K8s)集群中,安全机制是核心基础设施之一。 API Server 是整个系统的“中枢大脑”,所有控制与资源操作都要经过它。
因此,K8s 的安全体系可以理解为一套完整的“守门系统”,主要包括三层安全防线:
-
Authentication(认证):你是谁?
-
Authorization(鉴权):你能做什么?
-
Admission Control(准入控制):是否允许执行?
二、Authentication(认证机制)
在 K8s 集群中,任何访问 API Server 的请求都需要首先通过认证环节。 这一步确认请求者的身份是否可信。
2.1 支持的认证方式
类型 | 说明 | 安全等级 |
---|---|---|
HTTP Basic Auth | 使用 用户名:密码 (Base64 编码)放入 HTTP Header | 低 |
HTTP Token Auth | 通过 Header 携带 Token 进行认证(由 API Server 校验) | 中 |
HTTPS 证书认证 | 采用双向 TLS 认证,基于 CA 根证书签发 | ✅ 高(推荐) |
💡 HTTPS 证书认证是生产环境最安全、最标准的方式,可实现双向信任。
2.2 哪些访问需要认证
-
集群组件访问:如
kubectl
、kubelet
、kube-proxy
。 -
Pod 内访问:如
coredns
、dashboard
这类运行在 Pod 中的系统组件。
2.3 通信端口与安全性
组件 | 通信端口 | 是否加密 |
---|---|---|
kube-apiserver | 6443 | ✅ HTTPS(双向认证) |
controller-manager 、scheduler | 8080 | ⚠️ HTTP(非加密) |
kubectl 、kubelet | 6443 | ✅ HTTPS |
2.4 证书的颁发方式
Kubernetes 提供两种方式生成证书:
-
手动签发:在二进制部署环境中手动生成并签发 CA 与客户端证书。
-
自动签发:当 kubelet 第一次加入集群时,用 bootstrap token 认证,Controller Manager 会自动为其颁发证书。
2.5 kubeconfig 文件结构
K8s 的认证核心文件是 ~/.kube/config
,它包含三个部分:
部分 | 含义 |
---|---|
cluster | 集群信息(API Server 地址、CA 证书等) |
user | 用户凭据(客户端证书与私钥) |
context | 上下文绑定(集群 + 用户 + 命名空间) |
💡 一个 kubeconfig 可以同时包含多个上下文,实现多集群管理。
2.6 ServiceAccount(服务账户)
ServiceAccount(简称 SA) 是专为 Pod 内应用访问 API Server 设计的身份机制。
每个命名空间默认存在一个 default
SA,当创建 Pod 时系统会自动挂载认证信息:
/var/run/secrets/kubernetes.io/serviceaccount/├── ca.crt # 集群 CA 根证书├── namespace # 当前命名空间└── token # JWT 签名的访问令牌
Pod 内程序通过这个 token 与 API Server 通信,实现安全认证。 这也是为什么 Pod 内可以直接使用 kubectl
或 API 客户端访问集群的原因。
2.7 Secret 与 ServiceAccount 的关系
K8s 中的 Secret 用于存储敏感信息。与 SA 相关的 Secret 主要有两类:
类型 | 说明 |
---|---|
service-account-token | 系统自动生成,用于认证 |
Opaque | 用户自定义的密钥内容 |
每个 SA 会自动关联一个 service-account-token
类型的 Secret,其中包含:
-
token
(由 API Server 私钥签名的 Token,用于服务端认证来访主体) -
ca.crt
(CA 根证书,供客户端验证 API Server 的证书) -
namespace
(该 service-account-token 的命名空间作用域)
三、Authorization(鉴权机制)
认证通过后,K8s 需要确定用户能做什么,即权限控制阶段。 这部分由 --authorization-mode
参数控制。
3.1 常见授权模式对比
模式 | 描述 | 特点 |
---|---|---|
AlwaysDeny | 拒绝所有请求 | 测试用 |
AlwaysAllow | 允许所有请求 | 不安全 |
ABAC(Attribute-Based) | 基于属性文件的静态规则授权 | 需重启 API Server |
Webhook | 调用外部 REST 服务判断权限 | 灵活但复杂 |
✅ RBAC(Role-Based Access Control) | 基于角色的权限控制 | 官方推荐,动态可调 |
3.2 RBAC 四大核心对象
对象 | 级别 | 功能 |
---|---|---|
Role | 命名空间级 | 定义局部权限 |
ClusterRole | 集群级 | 定义全局权限 |
RoleBinding | 命名空间级 | 将角色绑定到用户/SA |
ClusterRoleBinding | 集群级 | 全局绑定角色 |
⚙️ 注意:
使用 RoleBinding 绑定 ClusterRole 时仍仅作用于当前命名空间;
使用 ClusterRoleBinding 则可全局生效。
3.3 角色(Role/ClusterRole)示例
-
权限仅能累加(白名单),不存在“先有很多再减少”的黑名单模型。
-
Role 只能定义在 某个命名空间 内;跨命名空间请使用 ClusterRole。
Role 示例(只读访问 default 命名空间的 Pods):
apiVersion: rbac.authorization.k8s.io/v1 #指定 core API 组和版本 kind: Role #指定类型为 Role metadata:namespace: default #使用默认命名空间 name: pod-reader #Role 的名称 rules: #定义规则 - apiGroups: [""] #""表示 apiGroups 和 apiVersion 使用相同的 core API 组,即 rbac.authorization.k8s.ioresources: ["pods"] #资源对象为 Pod 类型verbs: ["get", "watch", "list"] #被授予的操作权限#以上配置的意义是,如果把 pod-reader 这个 Role 赋予给一个用户,那么这个用户将在 default 命名空间中具有对 Pod 资源对象 进行 get(获取)、watch(监听)、list(列出)这三个操作权限。
ClusterRole 示例(读取所有命名空间的 Secrets):
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata:# "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制name: secret-reader rules: - apiGroups: [""]resources: ["secrets"]verbs: ["get", "watch", "list"]
3.4 绑定角色权限(RoleBinding / ClusterRoleBinding)
-
RoleBinding:在命名空间内将 Role/ClusterRole 赋予 User/Group/ServiceAccount。
-
ClusterRoleBinding:在全集群范围将 ClusterRole 赋予 User/Group/ServiceAccount。
(1)RoleBinding 示例(在 default
内授予用户 cy
读取 Pods 的 Role)
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata:name: read-podsnamespace: default subjects: - kind: Username: cyapiGroup: rbac.authorization.k8s.io roleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io#将 default 命名空间的 pod-reader Role 授予 cy 用户,此后 cy 用户在 default 命名空间中将具有 pod-reader 的权限--------------------------------------------------------------- #示例2,在 `kube-public` 内给用户 `qh` 引用 ClusterRole `secret-reader`apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata:name: read-secretsnamespace: kube-public subjects: - kind: Username: qhapiGroup: rbac.authorization.k8s.io roleRef:kind: ClusterRolename: secret-readerapiGroup: rbac.authorization.k8s.io#以上 RoleBinding 引用了一个 ClusterRole,这个 ClusterRole 具有整个集群内对 secrets 的访问权限;但是其授权用户 qh 只能访问 kube-public 空间中的 secrets(因为 RoleBinding 定义在 kube-public 命名空间)
(2)ClusterRoleBinding 示例
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata:name: read-secrets-global subjects: - kind: Groupname: managerapiGroup: rbac.authorization.k8s.io roleRef:kind: ClusterRolename: secret-readerapiGroup: rbac.authorization.k8s.io#以上 ClusterRoleBinding 授权 manager 组内所有用户在全部命名空间中对 secrets 进行访问。
3.5 主体(Subject)与 JWT
什么是 Subject(主体)
在 RBAC 的世界里,Subject 表示“谁将被授予权限”。Subject 有三类:
-
User
:外部或系统用户(通常是证书 CN、外部身份提供者中的用户名)。 -
Group
:用户组(便于把权限授予一组用户)。 -
ServiceAccount
:Kubernetes 内部的服务账户(用于 Pod 内部进程访问 API Server)。
示例(RoleBinding 中的 subjects):
subjects: - kind: Username: aliceapiGroup: rbac.authorization.k8s.io - kind: Groupname: dev-teamapiGroup: rbac.authorization.k8s.io - kind: ServiceAccountname: myappnamespace: app-namespace
注意:
-
ServiceAccount
需要namespace
字段(如果跨命名空间引用 SA,必须写明)。 -
User
/Group
的名字按照认证系统决定(证书的CN
、OIDC 的sub
/preferred_username
等)。 -
system:
前缀为系统保留,如system:masters
是集群管理员组,普通用户勿滥用。
JWT 在 Kubernetes 中的角色
Kubernetes 使用 JWT(JSON Web Token)作为一种常见的 token 格式 —— 尤其体现在 ServiceAccount 的 token(早期是长期有效的 secret token,现代推荐用短期绑定 token / TokenRequest)。
1) JWT 的结构(3 部分)
JWT = header.payload.signature
(都使用 base64url 编码):
-
header:算法(如
alg: RS256
)和类型typ: JWT
。 -
payload(声明 claims):包含
iss
(issuer)、sub
(subject)、aud
(audience)、exp
(过期时间)、iat
(签发时间)、以及 k8s 自定义字段(例如kubernetes.io/serviceaccount/namespace
、kubernetes.io/serviceaccount/secret.name
等)。 -
signature:由签名密钥对 header+payload 计算得到,保证不可篡改。
2) 常见 claim(k8s 环境)
-
iss
:token 的颁发者(例如kubernetes/serviceaccount
或 API Server)。 -
sub
:主体(如system:serviceaccount:namespace:name
)。 -
aud
:受众(token 能被哪些服务器接受,如kubernetes.default.svc.cluster.local
)。 -
exp
:过期时间(UNIX 时间)。 -
k8s 特有:
kubernetes.io/serviceaccount/namespace
,kubernetes.io/serviceaccount/secret.name
,kubernetes.io/serviceaccount/service-account.name
等。常见 verbs / resources / apiGroups 速查
-
verbs:
get
、list
、watch
、create
、update
、patch
、delete
、exec
-
resources(示例):
services
、endpoints
、pods
、secrets
、configmaps
、crontabs
、deployments
、jobs
、nodes
、rolebindings
、clusterroles
、daemonsets
、replicasets
、statefulsets
、horizontalpodautoscalers
、replicationcontrollers
、cronjobs
-
apiGroups:
""
(core)、apps
、autoscaling
、batch
-
3.6 子资源(Subresources)
有些资源有子资源,例如获取 Pod 日志:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
RBAC 可对其精确控制:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata:namespace: defaultname: pod-and-pod-logs-reader rules: - apiGroups: [""]resources: ["pods", "pods/log"]verbs: ["get", "list"]
四、Admission Control(准入控制)
通过认证与鉴权后,请求仍需经过 Admission Controller 检查。 它是一系列插件链,用于验证、修改或拒绝请求。
常见 Admission 插件
插件 | 功能 |
---|---|
NamespaceLifecycle | 管理命名空间生命周期 |
LimitRanger | 控制资源限制 |
ServiceAccount | 自动为 Pod 注入 SA |
ResourceQuota | 命名空间配额管理 |
NodeRestriction | 限制 Node 的注册与权限 |
Mutating/ValidatingWebhook | 动态策略验证(如 OPA/Gatekeeper) |
五、实践案例:创建受限用户(命名空间级别权限)
目标:创建一个名为 ciallo
的用户,仅能在 yozusoft
命名空间管理 Pods。
Step 0:创建系统用户
useradd ciallo passwd ciallo# 切换为该用户尝试访问 su - ciallo kubectl get pods # The connection to the server localhost:8080 was refused - did you specify the right host or port?
Step 1:生成用户 CSR 与证书
ciallo-csr.json
(注意 CN 将作为 k8s User 名称,names[].O 会作为 Group):
# 下载最新版本(根据需要可去 GitHub 查看最新版本) wget https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssl_1.6.5_linux_amd64 wget https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssljson_1.6.5_linux_amd64# 添加执行权限 chmod +x cfssl_1.6.5_linux_amd64 cfssljson_1.6.5_linux_amd64# 移动到 /usr/local/bin sudo mv cfssl_1.6.5_linux_amd64 /usr/local/bin/cfssl sudo mv cfssljson_1.6.5_linux_amd64 /usr/local/bin/cfssljsonmkdir -p /opt/ciallo && cd /opt/ciallo ------------------------------------------------------------ vim user-cert.sh ####################### cat > ciallo-csr.json <<EOF {"CN": "ciallo","hosts": [],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","ST": "BeiJing","L": "BeiJing","O": "k8s","OU": "System"}] } EOF ------------------------------------------------------------------ cd /etc/kubernetes/pki/ cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /opt/ciallo/ciallo-csr.json | cfssljson -bare ciallo (报错就先执行下面的命令,然后再重新执行该命令) ------------------------------------------------------------------ chmod +x user-cert.sh ./user-cert.sh
Step 2:生成 kubeconfig
借助 kubectl config
创建专属 kubeconfig(示例脚本):
cd /opt/ciallovim rbac-kubeconfig.sh APISERVER=$1 # 设置集群参数 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=ciallo.kubeconfig# 设置客户端认证参数 kubectl config set-credentials ciallo \--client-key=/etc/kubernetes/pki/ciallo-key.pem \--client-certificate=/etc/kubernetes/pki/ciallo.pem \--embed-certs=true \--kubeconfig=ciallo.kubeconfig# 设置上下文参数 kubectl config set-context kubernetes \--cluster=kubernetes \--user=ciallo \--namespace=yozusoft \--kubeconfig=ciallo.kubeconfig# 使用上下文参数生成 ciallo.kubeconfig 文件 kubectl config use-context kubernetes --kubeconfig=ciallo.kubeconfig
Step 3:创建命名空间与 kubeconfig 上下文
kubectl create namespace yozusoft chmod +x rbac-kubeconfig.sh ./rbac-kubeconfig.sh 192.168.10.10# 分发 kubeconfig mkdir -p /home/ciallo/.kube cp ciallo.kubeconfig /home/ciallo/.kube/config chown -R ciallo:ciallo /home/ciallo/.kube/# 查看 kubeconfig cat ciallo.kubeconfig
Step 4:创建 Role 与 RoleBinding(命名空间级权限)
rbac.yaml
:
vim rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata:namespace: yozusoftname: pod-reader rules: - apiGroups: [""]resources: ["pods"]verbs: ["get", "watch", "list", "create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata:name: read-podsnamespace: yozusoft subjects: - kind: Username: cialloapiGroup: rbac.authorization.k8s.io roleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io
应用:
kubectl apply -f rbac.yaml kubectl get role,rolebinding -n yozusoft # role.rbac.authorization.k8s.io/pod-reader 32s # rolebinding.rbac.authorization.k8s.io/read-pods 32s
Step 5:验证(切换到 ciallo 用户执行操作)
su - ciallo# 创建 Pod(允许) cat > pod-test.yaml <<'YAML' apiVersion: v1 kind: Pod metadata:name: pod-test spec:containers:- name: nginximage: nginx YAMLkubectl create -f pod-test.yaml kubectl get pods -o wide # NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES # pod-test 1/1 Running 0 114s 10.244.2.2 node02 <none> <none># 访问 svc(拒绝) kubectl get svc # Error from server (Forbidden): services is forbidden: User "ciallo" cannot list resource "services" in API group "" in the namespace "kgc"# 访问 default 命名空间(拒绝) kubectl get pods -n default # Error from server (Forbidden): pods is forbidden: User "ciallo" cannot list resource "pods" in API group "" in the namespace "default"
Step 6:管理员侧检查(确认 RBAC 生效)
# root 用户查看: kubectl get pods --all-namespaces -o wide # NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE # yozusoft pod-test 1/1 Running 0 107s 10.244.2.2 node01 # ... # 可见 RoleBinding 生效:用户仅能管理指定命名空间资源。
可选:授予命名空间管理员(如果需要)
kubectl create rolebinding ciallo-admin-binding \--clusterrole=admin \--user=ciallo \--namespace=yozusoft
撤销 / 收回访问(重要)
1. 删除 RoleBinding / Role
kubectl delete rolebinding read-pods -n yozusoft kubectl delete role pod-reader -n yozusoft
2. 撤销用户证书(若用证书认证)
证书撤销在 k8s 中通常不是单条 API;常见做法:
-
从发布方(CA)撤销证书并更新信任链(更换 CA 或更新 CRL),或
-
在 API Server 端配置认证 webhook 去校验白名单(例如把该证书列入拒绝名单)。 若只是要阻止一个 kubeconfig,删除或收回 kubeconfig 是立即有效的(用户客户端失去凭证)。
3. 删除 kubeconfig(分发到用户机器上)
rm -rf /home/ciallo/.kube/config
审计与排错建议
查看拒绝原因(管理侧)
启用并查看 API Server 审计日志(若已开启 audit policy):
-
审计日志会显示
user
,verb
,resource
,namespace
,responseStatus
,便于定位被拒绝请求的主体与原因。
常见排错命令
-
查看用户信息(以 admin 身份):
kubectl auth can-i create pods --as=ciallo -n yozusoft kubectl auth can-i list services --as=ciallo -n yozusoft
-
在集群上以 target user 模拟权限检查:
kubectl auth can-i get pods --as=ciallo -n yozusoft
如果 kubectl
返回 connection refused
或 The connection to the server localhost:8080 was refused
:
-
检查 kubeconfig
server
地址是否正确(kubectl config view
)。 -
检查 API Server 是否运行并监听 6443,防火墙规则是否允许访问。
额外补充:用 ServiceAccount 做应用访问(更常见的场景)
如果目标是给应用(而不是人)授权,推荐使用 ServiceAccount 而非给 Pod 注入用户 kubeconfig:
创建 SA、Role、RoleBinding:
kubectl create sa myapp -n yozusoft # Role (pod-reader) 与 RoleBinding 绑定到 ServiceAccount kubectl apply -f - <<EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata:name: myapp-readpodsnamespace: yozusoft subjects: - kind: ServiceAccountname: myappnamespace: yozusoft roleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io EOF
Pod 使用 serviceAccountName: myapp
,并建议使用 TokenRequest / projected short-lived tokens,而不是长-lived Secrets。
六、总结(Summary)
安全层级 | 功能 | 关键组件 |
---|---|---|
认证(Authentication) | 验证用户身份 | Token / Cert / SA |
鉴权(Authorization) | 权限控制 | RBAC / Webhook |
准入控制(Admission) | 最终验证与策略控制 | Admission Plugins |
✅ 安全最佳实践建议:
使用 TLS 双向认证 确保通信安全;
启用 RBAC 实现最小权限原则;
配合 Admission Webhook 做策略审查;
为每个微服务/用户单独创建 ServiceAccount 或 kubeconfig;
搭配 NetworkPolicy / WAF / 限速 加强集群防御。