Kubernetes 安全涉及多个层面:API 访问控制、工作负载安全、网络隔离、密钥管理和审计追溯。构建纵深防御体系,是保障集群免受攻击和数据泄露的核心。
目录
- 1. API 访问控制链路
- 2. RBAC:基于角色的访问控制
- 3. ServiceAccount 与 Token
- 4. Pod 安全标准(PSS/PSA)
- 5. NetworkPolicy 网络隔离
- 6. Admission Controller 准入控制
- 7. Secret 与静态加密
- 8. 审计日志
- 9. 安全加固 Checklist
1. API 访问控制链路
当用户或 Pod 访问 Kubernetes API 时,请求经过以下安全检查:
请求 → 认证(Authentication)→ 授权(Authorization)→ 准入控制(Admission)→ 执行
│ │ │
│ 验证你是谁 │ 验证你能做什么 │ 验证请求内容合法
│ │ │
X.509 证书 RBAC/ABAC/Node PodSecurity
Bearer Token Webhook ResourceQuota
OIDC (SSO) AlwaysAllow Mutating Webhook
ServiceAccount Token AlwaysDeny Validating Webhook
认证方式优先级(同时提供多种凭据时):
- X.509 客户端证书
- Bearer Token(或 OIDC JWT)
- HTTP Basic Auth(已弃用)
2. RBAC:基于角色的访问控制
核心对象
RBAC 通过四个对象定义权限:
# Role:Namespace 级别的权限规则
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""] # "" 表示核心 API 组
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"]
---
# RoleBinding:将 Role 绑定到用户/组/ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: production
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: ci-bot
namespace: ci-system
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Role vs ClusterRole:
| 对象 | 作用域 | 适用场景 |
|---|---|---|
| Role | 单个 Namespace | 应用团队权限、CI/CD 权限 |
| ClusterRole | 整个集群 | 节点管理、跨 Namespace 资源、非命名空间资源(Node、PV、Namespace) |
常用权限模板
只读权限(适合开发):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer-readonly
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "services", "deployments", "configmaps", "jobs"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
部署权限(适合 CI/CD):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer
rules:
- apiGroups: ["", "apps"]
resources: ["pods", "services", "deployments", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "rollback"]
集群管理员(谨慎授予):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: restricted-admin
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "list", "watch"] # 仅只读
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch", "patch"] # 允许 Cordon/Drain
权限最小化原则
# 查询用户/SA 的权限
kubectl auth can-i create pods --as=alice -n production
# 检查 ServiceAccount 权限
kubectl auth can-i '*' '*' --as=system:serviceaccount:default:default
# 列出某 Role 的所有规则
kubectl describe role pod-reader -n production
3. ServiceAccount 与 Token
ServiceAccount 机制
每个 Pod 默认挂载关联 ServiceAccount 的 Token,用于访问 K8s API:
# 查看 Pod 挂载的 ServiceAccount
kubectl get pod <pod> -o jsonpath='{.spec.serviceAccountName}'
# 查看 Secret 中的 Token
kubectl get secret <sa-token> -o jsonpath='{.data.token}' | base64 -d
Token 安全问题
旧版 Token(K8s <1.24):ServiceAccount 自动生成永不过期的 Secret Token,泄露后风险无限期存在。
新版 Token(K8s 1.24+):
- ServiceAccount 不再自动生成 Secret
- Token 通过 TokenRequest API 按需生成短期 Token(默认 1 小时)
- 可创建手动管理的长期 Token(但不推荐)
# 启用新的短期 Token
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
automountServiceAccountToken: true # Pod 自动挂载 Token
---
# 或禁用自动挂载(不需要 K8s API 访问时)
apiVersion: v1
kind: ServiceAccount
metadata:
name: public-app
automountServiceAccountToken: false
Token 过期配置:
apiVersion: v1
kind: ServiceAccount
metadata:
name: short-lived
secrets: [] # K8s 1.24+ 不再自动生成
---
# 手动创建短期 Token(1小时)
kubectl create token short-lived --duration=1h
Pod 级别禁用 Token 挂载
apiVersion: v1
kind: Pod
spec:
automountServiceAccountToken: false # 不挂载任何 Token
containers:
- name: app
image: myapp:v1
推荐:绝大多数业务 Pod 不需要访问 K8s API,应禁用 automountServiceAccountToken。
4. Pod 安全标准(PSS/PSA)
Pod Security Standards(PSS)
K8s 1.25+ 内置三个安全级别:
| 级别 | 策略 | 说明 |
|---|---|---|
| Privileged | 无限制 | 适用于系统管理员、需要完整权限的工作负载 |
| Baseline | 最小限制 | 禁止已知的高危配置(特权容器、主机命名空间等) |
| Restricted | 严格限制 | 遵循 Pod 加固最佳实践(非 root、只读根文件系统等) |
Pod Security Admission(PSA)
PSA 是 K8s 1.25+ 内置的准入控制器,替代已弃用的 PodSecurityPolicy(PSP)。
在 Namespace 级别生效:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# 实施级别
pod-security.kubernetes.io/enforce: restricted # 违规 Pod 被拒绝
pod-security.kubernetes.io/audit: restricted # 违规记录审计日志
pod-security.kubernetes.io/warn: baseline # 违规返回用户警告(但不阻止)
三种模式:
| 模式 | 行为 | 用途 |
|---|---|---|
enforce | 阻止不符合策略的 Pod 创建 | 生产环境强制安全 |
audit | 允许创建,但记录审计日志 | 过渡期评估影响 |
warn | 允许创建,返回警告给用户 | 开发环境提醒 |
Restricted 策略要求
要满足 restricted 级别,Pod 必须:
spec:
securityContext:
runAsNonRoot: true # 禁止 root 用户
seccompProfile:
type: RuntimeDefault # 使用默认 seccomp 配置
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false # 禁止特权提升
readOnlyRootFilesystem: true # 根文件系统只读
capabilities:
drop: ["ALL"] # 丢弃所有 capabilities
runAsUser: 1000 # 指定非 root UID
Restricted 禁止项:
- 特权容器(
privileged: true) - 主机命名空间共享(PID、IPC、Network)
- 主机路径挂载(
hostPath) - 以 root 运行
- 未限制 capabilities
- Seccomp 未启用
5. NetworkPolicy 网络隔离
默认开放的网络
K8s 集群默认没有任何网络隔离:所有 Pod 之间、所有 Namespace 之间都可以自由通信。
默认拒绝 + 按需开放
第一步:创建默认拒绝所有入站流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 选中所有 Pod
policyTypes:
- Ingress
# ingress 规则为空 = 拒绝所有入站
第二步:按需开放特定流量:
# 允许 ingress-nginx 访问 web 服务
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-nginx
namespace: production
spec:
podSelector:
matchLabels:
app: web-server
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx # 只允许 ingress-nginx namespace
ports:
- protocol: TCP
port: 8080
---
# 允许 frontend 访问 backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # 同一 namespace 的 frontend
ports:
- protocol: TCP
port: 8080
跨 Namespace 策略
# 允许 monitoring namespace 的 Prometheus 抓取 metrics
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-prometheus
namespace: production
spec:
podSelector:
matchLabels:
prometheus.io/scrape: "true"
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring # monitoring namespace
- podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
Egress 策略(出站控制)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-egress
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
# 允许访问数据库
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# 允许 DNS 查询
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# 允许访问外部 API(特定 CIDR)
- to:
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24 # 排除敏感网段
ports:
- protocol: TCP
port: 443
NetworkPolicy 限制
- NetworkPolicy 只是声明,实际执行依赖 CNI 插件(Flannel 不支持,Calico/Cilium 支持)
- 只能控制 Pod 级别的规则,不支持 FQDN(域名过滤)
- 规则是白名单 + 默认拒绝模式
- 不支持日志和审计(Cilium NetworkPolicy 支持)
6. Admission Controller 准入控制
两类 Admission Controller
Mutating(变形):修改请求内容后放行
Validating(验证):仅验证不修改
内置准入控制器
# kube-apiserver 启动参数
--enable-admission-plugins=\
NamespaceLifecycle,\
LimitRanger,\
ServiceAccount,\
ResourceQuota,\
PodSecurity,\
NodeRestriction
| 控制器 | 类型 | 作用 |
|---|---|---|
| PodSecurity | Validating | 执行 Pod Security Standards |
| ResourceQuota | Validating | 限制 Namespace 资源总量 |
| LimitRange | Mutating + Validating | 设置默认值和限制 |
| NodeRestriction | Validating | 限制 Node 只能修改自己的资源 |
| ServiceAccount | Mutating | 自动注入 ServiceAccount 和 Token |
自定义 Admission Webhook
用动态准入控制实现自定义策略:
# MutatingWebhookConfiguration:修改请求
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: pod-mutator
webhooks:
- name: mutator.security.example.com
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
clientConfig:
service:
name: webhook-service
namespace: security-system
path: "/mutate"
caBundle: <CA_BUNDLE>
admissionReviewVersions: ["v1"]
sideEffects: None
Mutating Webhook 常见用途:
- 自动注入 Sidecar(Istio、vault-agent)
- 自动添加资源限制(若未指定则补充默认值)
- 自动挂载 ConfigMap/Secret
- 添加标准标签和注解
Validating Webhook 常见用途:
- 强制镜像来源白名单(只允许内部仓库)
- 禁止 latest 标签
- 强制安全配置(securityContext 必须设置)
- 限制特权容器
OPA/Gatekeeper 策略即代码
OPA(Open Policy Agent)提供更灵活的策略定义:
# Gatekeeper ConstraintTemplate
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredprobes
spec:
crd:
spec:
names:
kind: K8sRequiredProbes
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredprobes
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.livenessProbe
not container.readinessProbe
msg := sprintf("Container %s must have liveness or readiness probe", [container.name])
}
7. Secret 与静态加密
etcd 加密配置
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
- ingresses.extensions
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {} # 未加密数据的回退读取
配置后重启 kube-apiserver。新写入的 Secret 自动加密,已有的 Secret 在下次更新时重加密。
外部密钥管理
| 方案 | 原理 | 适用场景 |
|---|---|---|
| Vault + External Secrets | Vault 存储密钥,External Secrets Operator 同步到 K8s Secret | 企业级密钥管理 |
| Sealed Secrets | 用集群公钥加密 Secret,安全存入 Git | GitOps 工作流 |
| SOPS | 用 Age/GPG 加密 YAML,Flux 部署时解密 | 多环境配置管理 |
| 云厂商密钥管理服务 | AWS Secrets Manager / Azure KV / 阿里云 KMS | 云原生部署 |
8. 审计日志
审计策略配置
# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 记录所有变更操作
- level: RequestResponse
verbs: ["create", "update", "patch", "delete"]
resources:
- group: ""
resources: ["pods", "secrets", "configmaps"]
# 记录 auth 相关的只读操作
- level: Metadata
resources:
- group: "rbac.authorization.k8s.io"
# 忽略健康检查(减少噪音)
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: ""
resources: ["endpoints", "services"]
# 默认记录元数据
- level: Metadata
omitStages:
- RequestReceived
kube-apiserver 审计参数
--audit-log-path=/var/log/kubernetes/audit.log
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
审计日志分析
# 查找某用户的操作
jq '. | select(.user.username=="alice")' /var/log/kubernetes/audit.log
# 查找失败的认证尝试
jq '. | select(.responseStatus.code>=400)' /var/log/kubernetes/audit.log
9. 安全加固 Checklist
集群层面
- API Server 禁用匿名认证(–anonymous-auth=false)
- kubelet 启用认证和授权(–authentication-token-webhook –authorization-mode=Webhook)
- etcd 启用 TLS(peer/client 双向认证)
- etcd 数据加密(EncryptionConfiguration)
- 启用审计日志
- 定期轮换证书(使用 kubeadm 的 cert renew)
RBAC 层面
- 遵循最小权限原则
- 禁用默认 SA 的自动 Token 挂载
- 定期审计 Role/ClusterRole 权限
- 使用 impersonation 进行权限测试
工作负载层面
- Namespace 启用 restricted Pod Security Standard
- 容器以非 root 用户运行
- 启用 readOnlyRootFilesystem
- 丢弃所有 capabilities
- 使用 distroless/Alpine 最小镜像
- 镜像签名验证(Sigstore/cosign)
网络层面
- 所有 Namespace 默认拒绝 NetworkPolicy
- 按需开放白名单
- 敏感服务不暴露 NodePort/LoadBalancer
总结
| 层面 | 安全机制 | 核心要点 |
|---|---|---|
| API 访问 | 认证 + RBAC | TLS/Token/OIDC 认证,最小权限原则 |
| 工作负载 | PSS/PSA | Restricted 级别,非 root、只读根文件系统 |
| 网络 | NetworkPolicy | 默认拒绝,白名单开放,CNI 必须支持 |
| 密钥 | Secret 加密 | etcd 静态加密 + 外部密钥管理 |
| 审计 | Audit Log | 全量记录变更操作,定期分析 |
| 准入 | Admission Controller | 内置 + Webhook + OPA/Gatekeeper |
安全是持续的过程,而非一次性配置。定期审计、最小权限、纵深防御——这三个原则贯穿 K8s 安全体系的始终。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。