Kubernetes如同容器世界里的交通警察,当你在集群里同时运行银行系统和休闲小游戏时,得确保不会出现"特权容器越狱后给游戏充值"的尴尬场面。今天咱们就深入聊聊Pod安全策略(PSP)和SecurityContext这对安全组合拳(技术栈:Kubernetes 1.25 + containerd运行时)。
一、Pod安全策略PSP:集群级的入场安检
虽然PSP在1.25版本已废弃(由PSA替代),但仍有超过30%的生产集群仍在使用。我们先看经典场景:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: baseline-restrictive
spec:
privileged: false # 关掉特权模式的口子
allowPrivilegeEscalation: false # 防止权限升级
runAsUser:
rule: MustRunAsNonRoot # 掐灭root用户的火苗
seLinux:
rule: RunAsAny # 允许不同团队的SELinux策略
supplementalGroups:
rule: RunAsAny
volumes:
- configMap # 允许的业务配置类型
- secret
- emptyDir
绑定到特定服务账号后,这个策略会像机场安检员一样检查所有Pod:
# 创建名为game-server的服务账号
kubectl create serviceaccount game-sa
# 通过ClusterRoleBinding绑定策略
kubectl create clusterrolebinding psp-game \
--clusterrole=psp:baseline-restrictive \
--serviceaccount=default:game-sa
这时如果用户用此账号启动特权Pod:
apiVersion: v1
kind: Pod
metadata:
name: test-breaker
spec:
serviceAccountName: game-sa
containers:
- name: hacker
image: nginx
securityContext:
privileged: true # 触发死亡红线
等待你的将是类似这样的报错:Pod "test-breaker" is forbidden: violates PodSecurityPolicy "baseline-restrictive": privileged
二、PodSecurityContext:给每个Pod上的电子镣铐
如果说PSP是集群级防御,那么SecurityContext就是每个Pod自带的智能手铐。看这个三层防护配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-gateway
spec:
replicas: 3
template:
spec:
securityContext: # 第一层:Pod全局设定
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000 # 文件系统组权限
containers:
- name: payment-processor
image: alipay:v2.3
securityContext: # 第二层:容器级加强
allowPrivilegeEscalation: false
capabilities:
add: ["NET_ADMIN"] # 仅开放必要网络权限
drop: ["ALL"]
volumeMounts:
- name: tmp-vol
mountPath: /tmp
initContainers:
- name: vault-init
image: vault-configurator
securityContext: # 第三层:初始化容器特殊处理
runAsUser: 0 # 允许临时使用root初始化
readOnlyRootFilesystem: true
这个配置的巧妙之处在于:
- 用fsGroup=2000确保日志文件可写入
- 主容器丢弃所有Linux能力仅保留网络管理
- init容器虽短暂获取root但限制文件系统只读
三、必须知道的关联技术
Seccomp配置实例(Kubernetes 1.19+默认启用):
securityContext:
seccompProfile:
type: RuntimeDefault # 使用运行时默认配置
配合PSP的安全策略使用,能拦截99%的非常规系统调用
AppArmor实战步骤:
- 在节点加载配置文件:
apparmor_parser -q <<EOF
#include <tunables/global>
profile payment-app flags=(attach_disconnected) {
# 禁止二进制文件修改
deny /usr/bin/** wl,
}
EOF
- Pod配置注解激活:
metadata:
annotations:
container.apparmor.security.beta.kubernetes.io/main: localhost/payment-app
四、六大应用场景实战分析
场景1:金融系统的"金库"防护
# 财务处理服务配置
securityContext:
runAsNonRoot: true
capabilities:
drop: ["SETUID", "SETGID"] # 防止提权操作
seccompProfile:
type: Localhost
localhostProfile: finance-seccomp.json # 定制财务专用策略
场景2:AI训练集群的GPU控制
securityContext:
runAsUser: 1001
capabilities:
add: ["SYS_RAWIO"] # GPU直通需要裸I/O权限
privileged: false
allowPrivilegeEscalation: false
五、技术选型的双刃剑
优势对比表:
维度 | PSP优势 | SecurityContext优势 |
---|---|---|
生效粒度 | 集群级统一管控 | Pod级灵活调整 |
维护成本 | 集中管理更方便 | 无需额外RBAC配置 |
防御纵深 | 拦截恶意部署动作 | 防止容器运行时突破 |
兼容性 | 支持旧版本集群 | 适配所有Kubernetes版本 |
典型缺陷警报:
- PSP启用后如果忘记设置默认策略,会导致所有Pod创建失败(报错Forbidden)
- SecurityContext的fsGroup改动可能导致已有文件权限紊乱
- 启用readOnlyRootFilesystem后未挂载emptyDir会导致日志写入失败
六、采坑指南与最佳实践
致命陷阱一:用户ID冲突 某电商曾因多个服务都使用runAsUser=1000导致共享存储的权限混乱。正确做法是通过类似下面的自动化分配:
# 基于namespace生成用户ID范围
USER_ID=$((20000 + $(kubectl get ns $NAMESPACE -o jsonpath='{.metadata.uid}' | tr -dc '0-9' | cut -c1-4)))
审计技巧:
# 快速定位安全隐患Pod
kubectl get pods --all-namespaces -o json | \
jq '.items[] | select(.spec.securityContext.privileged == true) | .metadata.name'
七、总结
通过PSP和SecurityContext的组合拳,我们可以实现从集群入口到容器内部的立体防御。但安全就像洋葱,永远需要叠加其他措施(网络策略、镜像扫描等)。在即将全面转向PSA的过渡期,建议同时配置:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
spec:
paramKind:
group: apps.example.com
kind: PodSecurityDefaults
rules:
- condition: "!object.metadata.namespace.matchLabels['security-level'] == 'high'"
expression: "!object.spec.containers.securityContext.privileged"