字数:约4200字 | 阅读时间:12分钟
“Kubernetes安全不是加一把锁,而是建立纵深防御体系。”
在Kubernetes集群中,Pod是最小的调度单位,也是安全攻击的首要目标。无论是容器逃逸、横向移动还是数据窃取,攻击者的最终目的往往落脚在Pod层面。Kubernetes 1.29引入了多项安全增强,但很多团队对这些能力的理解还停留在”听说过”的阶段。
本文从实战角度出发,深入讲解Pod Security Standards、网络策略与入站出站流量的精细控制,结合真实案例与代码示例,帮助你构建真正可落地的容器安全体系。
一、Pod Security Standards:你的Pod是否符合最低要求?
Kubernetes 1.29延续了Pod Security admission(PSA,正式毕业成为GA特性),提供了三种预置策略级别:
| 级别 |
说明 |
privileged |
完全放开,不做任何限制(仅用于系统组件) |
baseline |
最小安全基线,防止已知特权提升 |
restricted |
严格限制,要求生产级安全标准 |
1.1 快速验证你的Namespace
1 2 3 4 5 6 7
| kubectl get namespace <namespace> -o yaml | grep -A 5 pod-security.kubernetes.io
kubectl label --overwrite ns <namespace> \ pod-security.kubernetes.io/enforce=baseline \ pod-security.kubernetes.io/enforce-version=v1.29
|
1.2 baseline vs restricted:差异在哪里?
baseline级别允许一些危险能力,但要求必须显式声明;restricted则完全禁止。
1 2 3 4 5 6 7 8 9 10
| securityContext: capabilities: add: ["NET_ADMIN"]
|
实战建议:先从baseline开始,验证无误后逐步迁移到restricted。直接用restricted会遇到大量Pod无法调度的麻烦。
1.3 多命名空间批量应用
生产环境中往往有几十个命名空间,逐个配置费时费力。使用Kustomize可以批量处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - namespace.yaml patches: - patch: | apiVersion: v1 kind: Namespace metadata: name: production labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: v1.29 pod-security.kubernetes.io/warn: restricted pod-security.kubernetes.io/warn-version: v1.29 target: kind: Namespace name: production
|
二、网络策略:Pod级别的防火墙
Pod默认情况下可以自由通信,这意味着某个被攻陷的Pod可以探测整个集群的内网。NetworkPolicy是Kubernetes的网络隔离机制,相当于Pod级别的”白名单防火墙”。
2.1 默认拒绝:先禁后放
网络策略的第一原则:默认拒绝所有入站流量。
1 2 3 4 5 6 7 8 9 10 11
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: production spec: podSelector: {} policyTypes: - Ingress - Egress
|
这个策略创建后,namespace内的所有Pod都无法收发流量。必须为需要通信的Pod添加允许规则。
2.2 允许特定Pod之间的通信
最常见的场景:Web层可以访问Backend层,但禁止Backend主动访问Web层。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-web-to-backend namespace: production spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: web ports: - protocol: TCP port: 8080
|
2.3 限制出站流量:DNS是特殊案例
出站流量中最容易被忽略的是DNS。Pod需要DNS才能解析Service地址,因此必须单独允许。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-dns-egress namespace: production spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 - protocol: TCP port: 53 - to: - podSelector: {} ports: - protocol: TCP port: 80 port: 443 - to: - podSelector: {} ports: - protocol: TCP port: 1-65535
|
2.4 使用CIDR限制IP段访问
对于需要访问特定IP段的服务(如云数据库):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-db-egress namespace: production spec: podSelector: matchLabels: app: database-client policyTypes: - Egress egress: - to: - ipBlock: cidr: "10.0.0.0/8" except: - 10.0.0.0/16 ports: - protocol: TCP port: 5432
|
三、安全上下文:Pod和容器的权限控制
Security Context决定了容器运行时具有哪些权限。设置得当可以大幅降低容器逃逸的风险。
3.1 Pod级别与容器级别的区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| apiVersion: v1 kind: Pod metadata: name: secure-pod spec: securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault sysctls: - name: net.ipv4.ping_group_range value: "1 1000" containers: - name: app image: myapp:latest securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL add: - NET_BIND_SERVICE seccompProfile: type: RuntimeDefault
|
3.2 常用能力(Capabilities)说明
| Capability |
含义 |
生产环境建议 |
| NET_BIND_SERVICE |
允许绑定低于1024的端口 |
按需添加 |
| NET_ADMIN |
允许网络管理 |
禁止 |
| SYS_ADMIN |
超级管理员权限 |
禁止 |
| SYS_MODULE |
加载内核模块 |
禁止 |
| DAC_READ_SEARCH |
绕过文件权限检查 |
禁止 |
黄金法则:所有容器都应该drop: [ALL],然后按需add最小集。
3.3 验证安全上下文是否生效
1 2 3 4 5 6 7 8 9
| kubectl get pod <pod-name> -o jsonpath='{.spec.securityContext}'
kubectl exec <pod-name> -- cat /proc/self/status | grep Cap
kubectl exec <pod-name> -- id
|
四、ServiceAccount与RBAC:最小权限原则
Pod通过ServiceAccount与Kubernetes API交互。默认情况下,每个Pod都绑定了defaultServiceAccount,具有查看cluster信息的权限,这是安全隐患。
4.1 不再使用的SA权限立即收回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| apiVersion: v1 kind: ServiceAccount metadata: name: myapp-sa namespace: production automountServiceAccountToken: false ---
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: myapp-read-configmaps namespace: production rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list"] resourceNames: ["myapp-config"] ---
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: myapp-sa-read-configmaps namespace: production subjects: - kind: ServiceAccount name: myapp-sa namespace: production roleRef: kind: Role name: myapp-read-configmaps apiGroup: rbac.authorization.k8s.io ---
apiVersion: v1 kind: Pod metadata: name: myapp-pod namespace: production spec: serviceAccountName: myapp-sa ...
|
4.2 ClusterRoleBinding的最小化
很多集群管理员习惯给SA绑定cluster-admin角色,这是极度危险的。以下是正确做法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| subjects: - kind: ServiceAccount name: default namespace: production roleRef: kind: ClusterRole name: cluster-admin
subjects: - kind: ServiceAccount name: myapp-sa namespace: production roleRef: kind: Role name: myapp-specific-permissions
|
五、实战案例:生产环境Nginx安全加固
以下是一个完整的生产级Nginx Pod配置,涵盖前面讲到的所有安全维度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| apiVersion: v1 kind: Pod metadata: name: nginx-secure namespace: production labels: app: nginx environment: production spec: serviceAccountName: nginx-sa securityContext: runAsNonRoot: true runAsUser: 101 fsGroup: 101 seccompProfile: type: RuntimeDefault containers: - name: nginx image: nginx:1.27-alpine ports: - containerPort: 80 name: http - containerPort: 443 name: https securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "128Mi" cpu: "200m" volumeMounts: - name: nginx-config mountPath: /etc/nginx/conf.d readOnly: true - name: nginx-cache mountPath: /var/cache/nginx - name: nginx-run mountPath: /var/run volumes: - name: nginx-config configMap: name: nginx-config - name: nginx-cache emptyDir: medium: Memory sizeLimit: "32Mi" - name: nginx-run emptyDir: medium: Memory sizeLimit: "1Mi"
|
六、安全检查清单
| 检查项 |
命令 |
期望结果 |
| 不以root运行 |
kubectl get pod -o jsonpath='{.spec.securityContext.runAsNonRoot}' |
true |
| 不允许权限提升 |
kubectl get pod -o jsonpath='{.spec.containers[*].securityContext.allowPrivilegeEscalation}' |
false |
| 删除所有Capabilities |
kubectl get pod -o jsonpath='{.spec.containers[*].securityContext.capabilities.drop}' |
[ALL] |
| 只读根文件系统 |
kubectl get pod -o jsonpath='{.spec.containers[*].securityContext.readOnlyRootFilesystem}' |
true |
| 启用Seccomp |
kubectl get pod -o jsonpath='{.spec.securityContext.seccompProfile.type}' |
RuntimeDefault |
| NetworkPolicy存在 |
kubectl get networkpolicy |
列出至少一个策略 |
| Pod使用专属SA |
kubectl get pod -o jsonpath='{.spec.serviceAccountName}' |
非default |
七、总结
Kubernetes安全不是单点配置,而是纵深防御体系:
- Pod Security Standards:通过
baseline→restricted的渐进式迁移,确保Pod满足最小权限要求
- NetworkPolicy:以
default-deny-all为起点,按业务需要显式放行,控制Pod间通信
- Security Context:从容器级别限制权限,以
drop: [ALL]为起点,按需add最小能力集
- RBAC:ServiceAccount最小权限原则,禁止使用
cluster-admin,精确到资源级别
下一篇文章我们将深入讲解Kubernetes的Secret管理、Pod加密存储、以及在多租户场景下的安全隔离策略。
延伸阅读