引言
Kubernetes 已经成为云原生时代的基础设施标准。但随着集群规模的扩大和部署场景的复杂化,Kubernetes 的安全问题也日益突出。CNCF 的调查显示,超过 60% 的受访者将安全列为采用容器和 Kubernetes 时的主要担忧。
本文从攻击面分析入手,逐层讲解 K8s 集群的纵深防御策略。
Kubernetes 的攻击面全景
一个典型的 K8s 集群包含控制面节点、工作节点、etcd、网络插件等多个组件,攻击面分布在各个层面:
控制面攻击面
API Server 是整个集群的入口,也是攻击者的首要目标。以下几类风险最为常见:
- 未授权访问:API Server 暴露在公网且未配置认证授权
- 匿名请求:
--anonymous-auth=false未设置 - RBAC 配置不当:过度宽松的 ClusterRole 绑定
工作节点攻击面
- kubelet 未认证:kubelet 的 10250 端口暴露且未配置认证
- 容器逃逸:privileged 容器、hostPath 挂载、–privileged 参数
- Seccomp/AppArmor 未配置:容器缺乏系统调用限制
etcd 攻击面
etcd 存储了集群的全部状态,包括 Secret。如果 etcd 未启用 TLS 认证,攻击者拿到 etcd 的访问权限就等于拿到了集群的"核弹按钮"。
配置加固:CIS Benchmark 实践
CIS Kubernetes Benchmark 是最权威的集群安全基线。核心检查项包括:
控制面加固
# 1. API Server 强制认证
--anonymous-auth=false
--enable-admission-plugins=NodeRestriction,PodSecurity,AlwaysPullImages
--audit-log-path=/var/log/k8s-audit.log
--audit-log-maxage=30
--profiling=false
# 2. etcd 加密
--encryption-provider-config=/etc/k8s/encryption.yaml
--peer-client-cert-auth=true
--peer-auto-tls=false
etcd 数据加密
Kubernetes 默认将 Secret 以 Base64 编码存储在 etcd 中——这不是加密。启用加密是等保合规的硬性要求:
# encryption.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <BASE64_ENCODED_32_BYTE_KEY>
- identity: {}
工作节点加固
# kubelet 配置
--authentication.anonymous.enabled=false
--authorization.mode=Webhook
--read-only-port=0 # 关闭只读端口
--protect-kernel-defaults=true
Pod 安全标准
Kubernetes 从 v1.23 开始使用 Pod Security Standards 替代了废弃的 PSP。三个等级的安全策略:
| 等级 | 说明 | 适用场景 |
|---|---|---|
| Privileged | 不受限制 | 系统组件、监控 Agent |
| Baseline | 最小限制 | 大多数工作负载 |
| Restricted | 严格限制 | 高安全要求的多租户场景 |
Restricted 策略禁止的行为包括:privileged 容器、hostPID/hostNetwork、capabilities 添加、root 文件系统写权限等。
# 命名空间级别强制 Restricted
apiVersion: v1
kind: Namespace
metadata:
name: secure-workloads
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
网络安全
网络策略
默认情况下,K8s 允许所有 Pod 之间互相通信。通过 NetworkPolicy 可以实现微隔离:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-deny-all
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
---
# 只允许来自前端 Pod 的入站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-frontend
spec:
podSelector:
matchLabels:
app: api-server
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080
服务网格 mTLS
对于跨 Pod 通信的加密需求,服务网格(Istio、Linkerd)可以提供透明的 mTLS 加密,无需修改应用代码。服务网格的工作原理是在每个 Pod 中注入 Sidecar 代理,所有进出流量都由代理处理。
运行时安全:从 Seccomp 到 Falco
Seccomp 配置
限制容器可以执行的系统调用是减少攻击面的有效手段。从 K8s v1.19 开始,Seccomp 默认配置已 GA:
securityContext:
seccompProfile:
type: RuntimeDefault
RuntimeDefault 会应用 Docker 或 containerd 自带的 seccomp 策略,禁用了大约 50 个高危系统调用(如 mount、reboot、acct 等)。
Falco 运行时检测
Falco 是 CNCF 孵化的运行时安全项目,利用 eBPF 技术监控系统调用,检测异常行为。
以下是常见的告警规则场景:
- 容器内执行 Shell:攻击者进入容器后通常会启动 Shell
- 敏感文件读取:读取
/etc/shadow、kubelet 凭证等 - 异常网络连接:容器发起对外部的异常连接
- 提权操作:setuid/setgid 文件的执行
镜像供应链安全
镜像安全是整个容器安全链的起点。实践中常用的手段:
- 镜像签名:使用 cosign 对镜像进行签名和验证
- 镜像扫描:集成 Trivy 或 Grype 扫描漏洞
- 基础镜像最小化:使用 distroless 或 scratch 基础镜像
- SBOM 生成:生成软件物料清单,追踪组件依赖
# 使用 cosign 签名镜像
cosign sign --key cosign.key ghcr.io/secshu/app:v1.0.0
# 验证签名
cosign verify --key cosign.pub ghcr.io/secshu/app:v1.0.0
审计日志
开启 API Server 的审计日志是事件溯源的关键。审计日志记录了谁、在什么时间、对什么资源做了什么操作:
# --audit-policy-file=/etc/k8s/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 记录所有 Secret 的读写
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
# 记录元数据变更
- level: Metadata
verbs: ["create", "delete", "patch", "update"]
# 只读请求默认不记录
- level: None
verbs: ["get", "list", "watch"]
审计日志应集中采集到 SIEM 系统或对象存储中,保留时间建议不少于 180 天。
总结
Kubernetes 安全不是单一维度的配置问题,而是贯穿集群生命周期、从镜像构建到运行时监控的全链路防护。按优先级排序的实践建议:
- 先做配置基线:CIS Benchmark 核心项,20% 的配置覆盖 80% 的风险
- 控制网络平面:NetworkPolicy + 服务网格 mTLS
- 准入控制:Pod Security Standards + OPA/Gatekeeper
- 运行时检测:Falco 异常行为监控
- 供应链安全:镜像签名 + 漏洞扫描
安全是一个持续改进的过程,不存在"配置完就安全"的状态。建立自动化的安全巡检机制,比一次性的安全整改更有价值。