2.9. 认证与安全
Kubernetes 的安全模型是分层的:先证明你是谁,再判断你能做什么,最后在准入阶段拦截不合规的请求。任何一层缺失,后面的隔离都不可靠。
- 层级:
L2 · 核心
- 难度:
进阶
- 预计:
55 分钟
- 前置:
架构与对象模型、网络
2.9.1. 你将学到
认证、授权、准入、审计四层模型
用户与 ServiceAccount 的区别
RBAC 的 Role / ClusterRole / Binding 与最小权限
SecurityContext 与 Pod Security Standards
用 CSR API 手工签发客户端证书
用 ResourceQuota、LimitRange 与准入 Webhook 做命名空间级策略
Secret、NetworkPolicy、镜像安全的基本边界
2.9.2. 四层模型
图:API Server 的请求处理链。任何一层拒绝,请求都不会落库。
层 |
解决的问题 |
常见机制 |
|---|---|---|
认证 |
身份是否可信 |
客户端证书、Bearer Token、OIDC、Webhook |
授权 |
是否有权限 |
RBAC、ABAC、Node、Webhook |
准入 |
是否符合策略 |
Mutating / Validating Webhook、PSA、配额 |
审计 |
谁做了什么 |
Audit Policy + 后端 |
2.9.3. 用户与 ServiceAccount
维度 |
普通用户 |
ServiceAccount |
|---|---|---|
管理方式 |
外部(证书 / OIDC) |
Kubernetes 对象 |
作用范围 |
集群 |
命名空间 |
用途 |
人 |
Pod 内的进程 |
凭证 |
kubeconfig |
自动挂载的 Token / 投影卷 |
Kubernetes 不存储普通用户对象。你用证书或 OIDC 登录,API Server 只认证书里的 CN/O 或 Token 里的 claims。
查看当前身份:
kubectl auth whoami
kubectl config view --minify
2.9.3.1. ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: reader
namespace: demo
automountServiceAccountToken: false
Pod 使用:
spec:
serviceAccountName: reader
automountServiceAccountToken: false
最佳实践:
每个应用一个 SA,不要共用
default;不需要访问 API 的应用关闭自动挂载;
需要 Token 时用投影卷,设置过期时间与 audience。
2.9.4. RBAC
RBAC 由四个对象组成:
对象 |
作用域 |
作用 |
|---|---|---|
Role |
namespace |
定义一组权限 |
ClusterRole |
集群 |
定义集群级权限,或可复用的权限集 |
RoleBinding |
namespace |
把 Role/ClusterRole 绑给主体 |
ClusterRoleBinding |
集群 |
把 ClusterRole 绑给主体 |
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: demo
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: demo
subjects:
- kind: ServiceAccount
name: reader
namespace: demo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
验证:
kubectl auth can-i get pods -n demo \
--as=system:serviceaccount:demo:reader
kubectl auth can-i delete pods -n demo \
--as=system:serviceaccount:demo:reader
kubectl auth can-i --list -n demo \
--as=system:serviceaccount:demo:reader
2.9.4.1. 常用 verbs
verb |
含义 |
|---|---|
|
读取单个资源 |
|
列出资源 |
|
监听变化 |
|
创建 |
|
更新 |
|
局部更新 |
|
删除 |
|
批量删除 |
get 与 list 是不同权限。只给 get 时,kubectl get pods(列表)仍会被拒绝。
2.9.4.2. 最小权限原则
优先用 Role,不用 ClusterRoleBinding;
不要给
*资源或*verbs;需要读日志时单独给
pods/log;定期审计
system:masters、cluster-admin的绑定;用
kubectl auth reconcile管理 RBAC 变更。
警告
cluster-admin 不是万能钥匙
给应用绑定 cluster-admin,等于把整个集群交给它。一旦容器被攻破,攻击者可以直接创建特权 Pod、读取所有 Secret。生产环境应使用命名空间级 Role。
2.9.5. SecurityContext
Pod 级与容器级的安全配置:
apiVersion: v1
kind: Pod
metadata:
name: secure-demo
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.27
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
volumes:
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
字段 |
作用 |
建议 |
|---|---|---|
|
禁止 root 用户 |
开启 |
|
禁止提权 |
false |
|
根文件系统只读 |
开启,需挂可写目录 |
|
去掉 Linux capabilities |
至少 drop ALL |
|
系统调用过滤 |
RuntimeDefault |
2.9.6. Pod Security Standards
Kubernetes 内置三档 Pod 安全标准:
级别 |
限制 |
适用 |
|---|---|---|
|
几乎不限制 |
系统组件 |
|
禁止特权、hostNetwork 等 |
一般业务 |
|
强制非 root、只读根、drop caps |
高安全业务 |
用命名空间标签启用:
kubectl label namespace demo \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
enforce 拒绝不合规 Pod,audit 记录,warn 返回警告。已有 Pod 不会因为打标签而被删除,但重建时会受限。
2.9.7. 准入控制与 Dashboard
认证回答“你是谁”,授权回答“你能做什么”,准入控制则回答“这个请求是否允许落库”。它位于授权之后、持久化之前,是集群策略的最后一道闸门。
2.9.7.1. 准入链
一个写请求通常经过:
Mutating Admission:修改请求,例如注入 sidecar、补默认资源、加标签;
Object Schema Validation:字段类型、必填项、枚举值;
Validating Admission:只读校验,例如配额、安全标准、镜像白名单;
持久化到 etcd。
内置准入控制器包括 ServiceAccount、LimitRanger、ResourceQuota、PodSecurity、DefaultStorageClass 等。外部策略通常通过 MutatingWebhookConfiguration / ValidatingWebhookConfiguration 接入,例如 Kyverno、OPA Gatekeeper、cert-manager。
Kubernetes 1.30+ 还提供 ValidatingAdmissionPolicy(CEL),不依赖外部 Webhook 就能表达“禁止 latest 标签”“必须设置 resources”等策略。
2.9.7.2. 实验:ResourceQuota 与 LimitRange
apiVersion: v1
kind: ResourceQuota
metadata:
name: demo-quota
namespace: demo
spec:
hard:
pods: "2"
requests.cpu: "1"
requests.memory: 1Gi
---
apiVersion: v1
kind: LimitRange
metadata:
name: demo-limits
namespace: demo
spec:
limits:
- type: Container
default:
cpu: 200m
memory: 128Mi
defaultRequest:
cpu: 100m
memory: 64Mi
kubectl create namespace demo
kubectl apply -f quota-and-limitrange.yaml
kubectl run p1 --image=nginx:1.27 -n demo
kubectl run p2 --image=nginx:1.27 -n demo
kubectl run p3 --image=nginx:1.27 -n demo # 预期被 ResourceQuota 拒绝
kubectl describe resourcequota demo-quota -n demo
LimitRange 负责给未写 requests/limits 的容器补默认值,ResourceQuota 负责限制命名空间总量。两者经常一起使用:没有 LimitRange 时,未设置 requests 的 Pod 可能绕过配额计算。
2.9.7.3. Dashboard 的认证与最小权限
Kubernetes Dashboard 不是“装了就能用”的匿名面板。推荐流程:
kubectl create serviceaccount dashboard-readonly -n kubernetes-dashboard
kubectl create clusterrolebinding dashboard-readonly \
--clusterrole=view \
--serviceaccount=kubernetes-dashboard:dashboard-readonly
TOKEN=$(kubectl create token dashboard-readonly -n kubernetes-dashboard)
把 Token 粘贴到 Dashboard 登录页。只给 view 权限,避免使用 cluster-admin 的长期 Token。Dashboard 的部署与 Ingress 示例见 集群面板。
警告
准入控制器不是“可选插件”
Pod Security、ResourceQuota、LimitRange 都是内置准入能力;关闭它们会让命名空间隔离形同虚设。外部 Webhook 故障时,要评估 failurePolicy: Fail 是否会导致整个集群无法创建 Pod。
对应原书第 9 章的 limitrange-*.yaml、resourcequota-demo.yaml、dashboard.yaml 与 RBAC 示例。
2.9.8. CSR API:手工签发证书
仓库中的 examples/authn_and_authz/certificate-sign-request-demo 演示了这条链路。核心步骤:
openssl genrsa -out mason.key 2048
openssl req -new -key mason.key -out mason.csr -subj "/CN=mason/O=dev"
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: mason
spec:
request: <base64 编码的 CSR>
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
# 生成 base64 并替换
CSR=$(cat mason.csr | base64 | tr -d '\n')
sed "s|<base64 编码的 CSR>|${CSR}|" mason-csr.yaml | kubectl apply -f -
kubectl get csr mason
kubectl certificate approve mason
kubectl get csr mason -o jsonpath='{.status.certificate}' | base64 -d > mason.crt
配置 kubeconfig:
kubectl config set-credentials mason \
--client-certificate=mason.crt \
--client-key=mason.key
kubectl config set-context mason \
--cluster=kubernetes \
--user=mason
kubectl --context=mason auth whoami
新用户默认没有任何权限,需要额外绑定 Role。这正是「认证」与「授权」分离的体现。
备注
证书里有什么
CN 是用户名,O 是组。RBAC 的 subject 可以用 User 或 Group 匹配。不要把 O=system:masters 签给普通用户,那是超级权限组。
2.9.9. Secret 与静态加密
Secret 默认以 base64 存在 etcd。生产环境至少做三件事:
开启 etcd 静态加密(
EncryptionConfiguration);限制 Secret 的 RBAC,禁止普通用户
list;使用 External Secrets / Sealed Secrets 管理密钥来源。
检查是否有权限:
kubectl auth can-i list secrets -n demo
kubectl auth can-i get secrets -n demo
2.9.10. 网络与供应链
NetworkPolicy:默认拒绝 + 按需放行,参见 服务与网络。
镜像:使用不可变 tag / digest,启用镜像签名与漏洞扫描。
准入:用 Kyverno / OPA Gatekeeper 强制「禁止 latest」「必须设置 resources」等策略。
运行时:启用 seccomp、AppArmor,限制 hostPath 与 hostNetwork。
2.9.11. 实验:创建一个只读用户
2.9.11.1. 1. 创建 SA、Role、RoleBinding
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl apply -f serviceaccount.yaml
kubectl apply -f rbac.yaml
2.9.11.2. 2. 验证权限
kubectl auth can-i get pods -n demo --as=system:serviceaccount:demo:reader
# yes
kubectl auth can-i delete pods -n demo --as=system:serviceaccount:demo:reader
# no
2.9.11.3. 3. 用 Token 实际请求
TOKEN=$(kubectl create token reader -n demo)
kubectl get pods -n demo --token="$TOKEN" \
--server=https://k8s-master01.magedu.com:6443 \
--certificate-authority=/etc/kubernetes/pki/ca.crt
2.9.11.4. 4. 启用 restricted 策略
kubectl label namespace demo pod-security.kubernetes.io/enforce=restricted --overwrite
kubectl run bad --image=nginx:1.27 -n demo
预期被拒绝,错误信息会指出违反了哪条 restricted 规则。给 Pod 补上 runAsNonRoot、seccompProfile、drop ALL 后再试。
2.9.12. 排错表
现象 |
原因 |
处理 |
|---|---|---|
|
RBAC 未授权 |
|
|
证书/Token 无效 |
|
SA 无法访问 API |
未绑定 Role / Token 未挂载 |
|
Pod 被 PSA 拒绝 |
违反 restricted |
看错误信息,补 securityContext |
Secret 读不到 |
RBAC 限制 / 命名空间错 |
|
证书过期 |
客户端证书未轮换 |
重新签发,检查 |
|
RBAC 缺少 |
单独授权 |
2.9.13. 进阶挑战
创建一个只能
get单个 Pod(resourceNames)的 Role,验证list被拒绝。用
kubectl auth reconcile更新 RoleBinding,观察它如何合并权限。给命名空间启用
baseline,找出一个不合规的 Pod 并修复。用 CSR API 签发一个属于
dev组的证书,绑定一个只读 Role。检查集群中所有
cluster-admin绑定,判断哪些可以降级。
2.9.14. 小结
安全是分层防御:认证 → 授权 → 准入 → 审计。
RBAC 要最小权限,避免给应用
cluster-admin。SecurityContext + PSA 是 Pod 层的基线,Secret 要配合加密与外部密钥管理。
认证与授权分离:证书只证明身份,权限来自 Binding。
准入控制是策略落地的最后一道闸门,Dashboard 也必须使用最小权限 Token。
2.9.15. 延伸阅读
原仓库示例:examples/authn_and_authz
下一章:平台能力总览