AI容器安全不是配个NetworkPolicy就完事了——镜像被投毒、容器被逃逸、配置有缺陷,任何一个短板都能让整个集群沦陷。
目录
一、你的AI容器真的安全吗?
二、第一道防线:镜像签名与验证——让"假镜像"无处遁形
2.1 为什么需要镜像签名?
2.2 主流工具对比:Cosign vs Notation
2.3 实战:Cosign Keyless 签名 + 验签
2.4 实战:Notation + 企业CA签名
2.5 准入控制:在K8s层面强制验签
三、第二道防线:镜像扫描——在"出事之前"把漏洞揪出来
3.1 镜像扫描解决什么问题
3.2 主流工具:Trivy vs Grype
3.3 实战:Trivy全量扫描 + CI集成
3.4 准入控制:Trivy Operator 在K8s层自动扫描
四、第三道防线:RuntimeClass安全沙箱——用硬件隔离兜底
4.1 为什么还需要沙箱?
4.2 RuntimeClass + 安全沙箱方案
4.3 实战:配置Kata Containers RuntimeClass
4.4 gVisor配置参考
五、第四道防线:PodSecurity标准——从"凭感觉"到"按标准"
5.1 PodSecurity的进化史
5.2 实战:Enforce + Warn + Audit 三模式部署
5.3 AI容器的Restricted配置示例
六、分层防御总览:四道防线如何协同工作
每一层的职责
攻击路径与防御矩阵
七、生产级完整YAML清单
八、落地避坑指南
8.1 不要一上来就全量推行
8.2 关于性能损耗
8.3 别忘了运行时监控
九、总结
一、你的AI容器真的安全吗?
先问一个扎心的问题:你公司用的AI推理镜像,是谁打的?从哪个仓库拉的?打完有没有被人改过?
如果你回答不上来,那恭喜你——你已经踩进了容器安全最致命的坑。
2025年的AI工程化浪潮里,几乎每家公司都在抢着上Kubernetes跑AI负载。模型推理用Pod拉起,训练用Job分布,数据预处理用CronJob定时执行——看起来很美好对吧?
但现实是,AI容器比普通业务容器更容易成为攻击目标:
⚠️镜像投毒:AI镜像动辄几个GB到十几GB,基础镜像里塞个挖矿脚本、改个Python依赖,很难被发现。2024年就爆出过PyPI上的torch包被投毒事件,那些镜像如果被CI/CD流水线拉下来直接推生产……
⚠️逃逸攻击:AI推理需要GPU直通、需要挂载大容量存储,权限难免放宽。一旦有攻击者通过模型文件注入触发容器逃逸,宿主机的GPU显存数据、模型权重文件全暴露。
⚠️配置缺陷:大部分AI团队focus在模型精度上,写出来的K8s YAML就俩字——奔放。privileged: true、hostNetwork、hostPath——比你家大门还敞亮。
我见过一个真实的案例:某AI公司的推理Pod直接用root跑,挂载了宿主机的docker.sock,结果一个模型输入层面的RCE就让攻击者拿到整个集群的控制权——代价是全公司的模型参数被勒索,损失七位数。
所以容器安全,从来不是"配一个NetworkPolicy就完事"那么简单。
今天这篇,咱们就聊聊AI容器安全的四道纵深防线——从镜像供应链到运行时隔离,从Pod准入到策略管控,每一道都是一层过滤网,层层递进、环环相扣。
二、第一道防线:镜像签名与验证——让"假镜像"无处遁形
2.1 为什么需要镜像签名?
很多人觉得:“镜像我都是从官方仓库拉的,能有什么问题?”
问得好,那我再问一句:你能保证从拉取到部署的整个链条上,没人动过这个镜像吗?
Docker Hub上的镜像是没有天然防篡改能力的。你拉下来的镜像是"一个tar包推上去的",中间经过的镜像仓库是否可信?镜像Tag是否被覆盖过?CI/CD流水线的构建机如果被攻破,推送的镜像是否被篡改?
镜像签名的本质:用私钥对镜像的digest签名,任何人只要有公钥就能验证镜像的完整性和来源可靠性。谁签的名、镜像内容变没变、什么时间签的——三个问题一次性回答。
2.2 主流工具对比:Cosign vs Notation
目前镜像签名领域,两个主流工具二选一:
| 维度 | Cosign | Notation |
|---|---|---|
| 缔造者 | Sigstore 社区 | CNCF Notary 项目 |
| 签名载体 | OCI 镜像仓库的 Tag 或 Referrers | OCI Artifact / Referrers |
| Key管理 | 支持 Keyless(OIDC 免密钥)+ 传统 Key | 传统 Key + 证书链模式 |
| 认证集成 | 原生支持 GitHub/GitLab OIDC | 支持 x509 证书 |
| 策略引擎 | Cosign Policy 内置 | Ratify 独立组件 |
| 企业友好度 | ⭐⭐⭐ Keyless 模式降低门槛 | ⭐⭐⭐⭐ 证书链适合企业CA体系 |
| 社区活跃度 | 非常高,Sigstore 社区主力 | 较高,CNCF 赛道 |
💡选型建议:如果你在GitHub/GitLab上的CI/CD用的是OIDC认证,强烈建议走Cosign的Keyless模式。这东西是真的省心——连密钥管理都省了,OIDC令牌本身就是你的身份凭证。
如果贵司有严格的PKI体系(比如基于企业CA签发的证书),Notation会更适合。
2.3 实战:Cosign Keyless 签名 + 验签
先说Keyless模式——这是Cosign最大的亮点:
# 安装 Cosign # Mac brew install cosign # Linux # 这里走 VERSION 变量指定版本 VERSION=$(curl -s https://api.github.com/repos/sigstore/cosign/releases/latest | jq -r .tag_name | sed 's/^v//') curl -LO "https://github.com/sigstore/cosign/releases/download/v${VERSION}/cosign_${VERSION}_amd64.deb" sudo dpkg -i cosign_${VERSION}_amd64.deb # 构建并推送镜像 docker build -t registry.example.com/ai-inference:v1 . docker push registry.example.com/ai-inference:v1 # 签名(Keyless模式,不用管理任何密钥!) cosign sign registry.example.com/ai-inference:v1 # 触发浏览器OIDC认证,或通过环境变量指配CI的OIDC token # COSIGN_EXPERIMENTAL=1 cosign sign ... # 完成后签名信息作为OCI Tag或Referrers存储在镜像仓库中验证签名:
# 验证签名 cosign verify \ --certificate-identity-regexp 'https://github.com/myorg/.*' \ --certificate-oidc-issuer-regexp 'https://token.actions.githubusercontent.com' \ registry.example.com/ai-inference:v1⚠️关键配置点:--certificate-identity-regexp和--certificate-oidc-issuer-regexp定义了"谁的签名我认"。这里必须精确匹配你组织的CI系统,否则任何人都能用Cosign签你的镜像——那就失去意义了。
2.4 实战:Notation + 企业CA签名
# 安装 Notation # Mac brew install notation # Linux curl -LO https://github.com/notaryproject/notation/releases/latest/download/notation_1.1.0_linux_amd64.tar.gz tar -xzf notation_*.tar.gz sudo mv notation /usr/local/bin/ # 导入企业CA签发的证书 notation cert add --type ca --file ca.pem --name my-enterprise-ca notation cert add --type signing --file signer-cert.pem --key signer-key.pem \ --name ai-team-key # 签名 notation sign registry.example.com/ai-inference:v1 \ --signature-format cose \ --key ai-team-key # 本地验证 notation verify registry.example.com/ai-inference:v12.5 准入控制:在K8s层面强制验签
光签名没有任何意义,只有在部署时强制验证才有用。
用Ratify(Notation的策略执行引擎)或Kyverno做准入控制:
💡核心逻辑:在K8s的Admission Webhook里拦截所有Pod创建请求,检查镜像是否有有效签名。没有签名 → 直接拒绝创建。
# Kyverno 策略:强制所有Pod必须包含已验证签名的镜像 apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-image-signature spec: validationFailureAction: Enforce background: false rules: - name: check-cosign-signature match: any: - resources: kinds: - Pod verifyImages: - imageReferences: - "registry.example.com/*" mutateDigest: true verifyDigest: true required: true attestors: - count: 1 entries: - keys: publicKeys: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE... -----END PUBLIC KEY-----💡为什么不推荐用 Admission Controller 手动写Webhook?因为Kyverno/ Ratify/ OPA Gatekeeper 已经封装了镜像签名验证的完整逻辑,没必要再重复造轮子。而且它们支持热更新策略规则,不需要重启APIServer。
三、第二道防线:镜像扫描——在"出事之前"把漏洞揪出来
3.1 镜像扫描解决什么问题
镜像签名解决的是"这个镜像有没有被篡改",而镜像扫描解决的是"这个镜像本身有没有漏洞"。
⚠️这是两道完全不同的防线。签名保证完整性,扫描保证安全性。少了任何一个,你的供应链安全都有窟窿。
3.2 主流工具:Trivy vs Grype
| 维度 | Trivy | Grype |
|---|---|---|
| 开发商 | Aqua Security | Anchore |
| 漏洞库 | 自家 + NVD + RedHat + Alpine 等14个源 | 自家 + NVD + RedHat + Ubuntu 等 |
| 扫描速度 | ⭐⭐⭐⭐ 非常快 | ⭐⭐⭐ 较快 |
| SBOM支持 | CycloneDX + SPDX | CycloneDX + SPDX |
| 策略引擎 | 内置 Cosign + 配置策略 | 需要 + Syft 配合 |
| 容器镜像层缓存 | ✅ | ❌(当前不支持) |
| K8s 集成 | Trivy Operator(CRD + 准入) | 社区方案 |
💡我的推荐:日常开发用Trivy就够了。理由很直接——Trivy Operator可以做成CRD扫描K8s集群中所有Pod的镜像,跟K8s生态绑定最紧密,不用额外运维一套扫描系统。
3.3 实战:Trivy全量扫描 + CI集成
# 安装 Trivy # Mac brew install trivy # Linux curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh # 扫描单个镜像 trivy image registry.example.com/ai-inference:v1 # 扫描并输出JSON供后续处理 trivy image --format json --output scan-result.json \ registry.example.com/ai-inference:v1 # 只扫描 HIGH / CRITICAL 级别(建议CI用这种模式) trivy image --severity HIGH,CRITICAL \ --exit-code 1 \ --ignore-unfixed \ registry.example.com/ai-inference:v1⚠️必配参数说明:
--exit-code 1:发现漏洞时让CI失败,阻止有问题的镜像进入仓库--ignore-unfixed:忽略没有修复方案的漏洞(很多OS包漏洞确实没有补丁,扫出来也没用,白白阻塞流水线)--severity HIGH,CRITICAL:只关心中高风险,LOW/MEDIUM级别的漏洞阈值下可以放过
3.4 准入控制:Trivy Operator 在K8s层自动扫描
Trivy Operator是精品——它作为Operator运行在集群内,自动发现并扫描所有Pod的镜像,同时提供Admission Controller+准入Webhook,在Pod创建前自动扫描:
# 安装 Trivy Operator helm repo add aqua https://aquasecurity.github.io/helm-charts helm repo update helm install trivy-operator aqua/trivy-operator \ --namespace trivy-system \ --create-namespace \ --set="trivy.ignoreUnfixed=true" \ --set="trivy.severity=CRITICAL,HIGH"然后Trivy Operator会自动创建VulnerabilityReportCRD,每个Pod都会有一个对应的扫描报告:
# 查看所有漏洞报告 kubectl get vulnerabilityreports -A # 查看某个Pod的详细漏洞 kubectl get vulnerabilityreport pod-ai-inference-xxxxx -o yaml如果再配合准入Webhook,所有新创建的Pod如果不满足漏洞阈值,直接拒绝:
# 准入策略:拒绝包含CRITICAL漏洞的镜像 apiVersion: aquasecurity.github.io/v1alpha1 kind: ClusterConfigAuditReport ... # 这里实际上是通过Trivy Operator的ConfigMap配置策略 # 在 trivy-operator 命名空间修改配置即可 kubectl edit configmap trivy-operator -n trivy-system四、第三道防线:RuntimeClass安全沙箱——用硬件隔离兜底
4.1 为什么还需要沙箱?
前两道防线解决的是供应链安全——镜像是否可信、是否有漏洞。但它们解决不了运行时逃逸的问题。
只要你的容器和宿主机共享Linux内核(这是Docker和runc的默认模式),就有逃逸的可能——CVE-2022-0185(Linux内核越界漏洞)、CVE-2024-21626(runc文件描述符泄露)……每年的逃逸漏洞轮着来。
⚠️AI容器的特殊性:AI推理Pod需要挂载GPU、请求巨量显存、可能挂载额外的模型存储。这些"特权"操作天然增加了逃逸攻击面。
4.2 RuntimeClass + 安全沙箱方案
K8s的RuntimeClass机制就是为解决这个问题的——让不同的Pod跑在不同的容器运行时上。
核心思路:高风险的AI推理Pod跑在轻量级VM沙箱里,跟宿主机完全隔离。
| 维度 | Kata Containers | gVisor |
|---|---|---|
| 隔离级别 | 轻量级VM(硬件虚拟化) | 用户态内核(应用层拦截) |
| 性能损耗 | ~5-10%(接近原生) | ~15-40%(系统调用越多越慢) |
| GPU支持 | ✅ 完整支持(GPU passthrough) | ❌ 不支持GPU直通 |
| 兼容性 | ⭐⭐⭐⭐⭐ 所有系统调用都支持 | ⭐⭐⭐ 部分系统调用不兼容 |
| 启动速度 | 较慢(需启动VM) | 很快(进程级) |
| 安全等级 | 更高(硬件隔离) | 较高(软件隔离) |
| 适用场景 | AI推理、GPU负载、高风险Pod | 通用Web服务、低风险Pod |
💡AI场景的明确建议:
- AI推理Pod用Kata Containers——GPU passthrough是刚需,没有替代方案。损失5-10%的性能,换的是完整的硬件隔离。
- Web服务 / 数据处理Pod用gVisor——不需要GPU,系统调用模式简单,gVisor足够。
- 管理面Pod(kube-system下的组件)用默认runc——改运行时可能导致兼容性问题。
4.3 实战:配置Kata Containers RuntimeClass
# 1. 安装Kata Containers(选择一个节点做测试) # Ubuntu sudo apt-get update && sudo apt-get install -y kata-containers # 2. 配置 containerd 支持 Kata # 编辑 /etc/containerd/config.toml 添加: cat >> /etc/containerd/config.toml << EOF [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata] runtime_type = "io.containerd.kata.v2" privileged_without_host_devices = true EOF # 重启 containerd sudo systemctl restart containerd # 3. 创建 RuntimeClass cat <<'EOF' | kubectl apply -f - apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: kata-qemu handler: kata scheduling: nodeSelector: katacontainers.io/kata-runtime: "true" EOF # 4. 标记kata节点 kubectl label node <ai-node-name> katacontainers.io/kata-runtime=true # 5. 在AI推理Pod中指定 runtimeClassName apiVersion: v1 kind: Pod metadata: name: ai-inference-safe spec: runtimeClassName: kata-qemu containers: - name: inference image: registry.example.com/ai-inference:v1 resources: requests: nvidia.com/gpu: 1 limits: nvidia.com/gpu: 1 volumeMounts: - name: model-storage mountPath: /models volumes: - name: model-storage persistentVolumeClaim: claimName: model-pvc⚠️注意事项:
- 启用Kata的节点建议打上taint,只调度安全Pod,避免非安全Pod也跑到Kata节点上(浪费资源)
- GPU passthrough需要节点支持SR-IOV或直通,不是所有硬件都支持
- Kata对存储有额外的Overhead,建议用local SSD而非网络存储
4.4 gVisor配置参考
# 安装 gVisor runsc curl -LO https://storage.googleapis.com/gvisor/releases/release/latest/x86_64/runsc sudo mv runsc /usr/local/bin/ sudo chmod +x /usr/local/bin/runsc # 配置 containerd cat >> /etc/containerd/config.toml << EOF [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc] runtime_type = "io.containerd.runsc.v1" EOF sudo systemctl restart containerd # 创建 RuntimeClass cat <<'EOF' | kubectl apply -f - apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: gvisor handler: runsc EOF五、第四道防线:PodSecurity标准——从"凭感觉"到"按标准"
5.1 PodSecurity的进化史
PodSecurity Policies(PSP)那会儿是真的反人类——一个PSP写200行YAML是常事,而且逻辑复杂到连K8s大佬都配不对。
好在K8s v1.21开始引入PodSecurity Admission,v1.25正式GA,把PSP替代了。
PodSecurity标准只有三个等级,但覆盖了95%以上的容器安全配置:
| 等级 | 说明 | 典型限制 |
|---|---|---|
| Privileged | 不受限——啥都能干 | 没有额外限制 |
| Baseline | 最小受限——防已知特权升级 | 禁止privileged、禁止hostNetwork、禁止hostPID/IPC、限制Seccomp等 |
| Restricted | 强受限——遵循Pod安全最佳实践 | Baseline基础上+强制non-root、限制capabilities、限制SELinux等 |
💡实际建议:你的集群中90%的Pod都应该用Restricted,只有那些实在不兼容的特殊Pod(比如网络插件、监控agent)才放宽到Baseline或Privileged。
5.2 实战:Enforce + Warn + Audit 三模式部署
PodSecurity采用三种模式而非一刀切,让你可以渐进式落地:
# 命名空间级别配置 apiVersion: v1 kind: Namespace metadata: name: ai-inference-prod labels: # Enforce:直接拒绝不符合Restricted的Pod pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: latest # Warn:不符合的Pod创建时给警告,但不会拒绝 pod-security.kubernetes.io/warn: baseline pod-security.kubernetes.io/warn-version: latest # Audit:不符合的在审计日志记录,但没有任何用户可见影响 pod-security.kubernetes.io/audit: baseline pod-security.kubernetes.io/audit-version: latest --- # 集群级默认值 apiVersion: apiserver.config.k8s.io/v1 kind: AdmissionConfiguration plugins: - name: PodSecurity configuration: apiVersion: pod-security.admission.config.k8s.io/v1 kind: PodSecurityConfiguration defaults: enforce: "restricted" enforce-version: "latest" audit: "baseline" audit-version: "latest" warn: "baseline" warn-version: "latest" exemptions: # 豁免kube-system等系统命名空间 namespaces: ["kube-system", "gatekeeper-system", "trivy-system"] # 豁免特定运行时类 runtimeClasses: ["kata-qemu", "gvisor"]5.3 AI容器的Restricted配置示例
apiVersion: apps/v1 kind: Deployment metadata: name: ai-inference-secure namespace: ai-inference-prod spec: replicas: 3 selector: matchLabels: app: ai-inference template: metadata: labels: app: ai-inference spec: # 使用Kata运行时——第三道防线 runtimeClassName: kata-qemu securityContext: # 关键:Pod级别的安全上下文 runAsNonRoot: true runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 seccompProfile: type: RuntimeDefault containers: - name: inference image: registry.example.com/ai-inference:v1 securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL # AI推理可能需要CAP_SYS_PTRACE,按需添加 # add: ["SYS_PTRACE"] readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 1000 seccompProfile: type: RuntimeDefault resources: requests: memory: "8Gi" cpu: "4" nvidia.com/gpu: 1 limits: memory: "16Gi" cpu: "8" nvidia.com/gpu: 1 volumeMounts: - name: tmp mountPath: /tmp - name: models mountPath: /models readOnly: true volumes: - name: tmp emptyDir: {} - name: models persistentVolumeClaim: claimName: ai-models-pvc readOnly: true⚠️常见踩坑点:
readOnlyRootFilesystem: true会导致应用在根目录写临时文件失败。必须声明emptyDir来挂载/tmp和/var/tmp等写目录。runAsNonRoot: true+runAsUser: 1000必须确保镜像内的进程是用1000uid跑的。如果Dockerfile里用root启动,这里直接创建失败。- AI推理框架(如Triton Server)有自己的进程管理逻辑,要注意这些框架的安全配置兼容性。
六、分层防御总览:四道防线如何协同工作
下面的图展示了AI容器从提交到运行的完整防御链路:
flowchart TD subgraph "开发者侧" A[代码提交] --> B[CI流水线] B --> C[Trivy镜像扫描] C --> D{漏洞达标?} D -->|否| E[阻断-返回修复] D -->|是| F[Cosign/Notation签名] F --> G[推送镜像到仓库] end subgraph "K8s集群侧" H[创建Pod请求] --> I[Admission Webhook] I --> J[Ratify/Kyverno验签] J --> K{签名有效?} K -->|否| L[拒绝Pod创建] K -->|是| M[PodSecurity校验] M --> N{符合Restricted?} N -->|否| O[Warn/Reject] N -->|是| P[Pod调度] P --> Q{Schedule调度策略} Q -->|AI推理Pod| R[RuntimeClass:kata-qemu] Q -->|Web服务Pod| S[RuntimeClass:gvisor] Q -->|系统组件| T[默认runc] end subgraph "运行时" R --> U[Kata轻量级VM隔离] S --> V[gVisor用户态内核] T --> W[标准容器] U --> X{运行时监控} V --> X W --> X X --> Y[Falco/告警] end每一层的职责
| 防线 | 防御对象 | 生命周期阶段 | 核心工具 | 绕过成本 |
|---|---|---|---|---|
| ①镜像签名与验证 | 镜像篡改、供应链攻击 | 构建→部署 | Cosign/Notation + Ratify/Kyverno | 攻破私钥/CA或绕过Admission |
| ②镜像扫描 | 已知漏洞、恶意依赖 | 构建时 + 运行时持续 | Trivy/Grype + Trivy Operator | 漏洞不上报或掩盖特征 |
| ③RuntimeClass沙箱 | 容器逃逸、内核漏洞 | 运行时 | Kata Containers / gVisor | 逃出VM或突破Seccomp |
| ④PodSecurity标准 | 配置缺陷、过度特权 | 部署准入 | PodSecurity Admission | 找到豁免条件或利用不兼容点 |
攻击路径与防御矩阵
下面的Mermaid图直观展示了四类典型攻击分别会被哪道防线拦截——红色划线表示被拦截,绿色勾表示可绕过(需要更上游防线兜底):
flowchart LR subgraph 攻击向量 A1[恶意镜像投毒] A2[供应链依赖篡改] A3[内核漏洞逃逸] A4[容器过度特权] end subgraph 防线拦截 L1[①镜像签名验证] L2[②漏洞扫描] L3[③RuntimeClass沙箱] L4[④PodSecurity标准] end subgraph 拦截结果 R1[❌ 拦截 - 签名不匹配] R2[❌ 拦截 - CVE超阈值] R3[❌ 拦截 - VM隔离] R4[❌ 拦截 - Restricted策略] R5[⚠️ 需要⑤运行时监控兜底] end A1 -->|镜像digest不一致| L1 L1 -->|验签失败| R1 A2 -->|依赖含已知漏洞| L2 L2 -->|CRITICAL漏洞| R2 A3 -->|利用内核syscall| L3 L3 -->|Kata硬件虚拟机| R3 A3 -.->|突破沙箱| R5 A4 -->|特权操作被限制| L4 L4 -->|非root+只读FS| R4| 攻击类型 | 绕过第一道 | 绕过第二道 | 绕过第三道 | 绕过第四道 |
|---|---|---|---|---|
| 恶意镜像投毒 | ❌ 签名验证 | ❌ 漏洞扫描 | ✅ 无法阻止 | ✅ 无法阻止 |
| 供应链依赖篡改 | ❌ 签名验证 | ❌ 漏洞扫描 | ✅ 无法阻止 | ✅ 无法阻止 |
| 内核漏洞逃逸 | ✅ 签名有效即可 | ✅ 能过扫描 | ❌ Kata VM隔离 | ✅ 非内核级问题 |
| 容器过度特权 | ✅ 签名有效即可 | ✅ 能过扫描 | ❌ 缩小攻击面 | ❌ Restricted策略 |
| 宿主文件访问 | ✅ 签名有效即可 | ✅ 能过扫描 | ❌ Kata文件系统隔离 | ❌ 只读根文件系统 |
| 网络横向移动 | ✅ 签名有效即可 | ✅ 能过扫描 | ✅ 沙箱内仍可网络通信 | ✅ 无直接防御 |
七、生产级完整YAML清单
下面是一份可以直接用于生产环境的完整配置组合:
# 文件1:RuntimeClass 定义 --- apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: kata-qemu handler: kata scheduling: nodeSelector: katacontainers.io/kata-runtime: "true" tolerations: - effect: NoSchedule key: kata operator: Exists --- apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: gvisor handler: runsc --- # 文件2:命名空间级PodSecurity配置 apiVersion: v1 kind: Namespace metadata: name: ai-inference-prod labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: latest pod-security.kubernetes.io/warn: baseline pod-security.kubernetes.io/warn-version: latest --- apiVersion: v1 kind: Namespace metadata: name: ai-training labels: # Training可能用GPU集合通信,放宽到baseline pod-security.kubernetes.io/enforce: baseline pod-security.kubernetes.io/enforce-version: latest --- # 文件3:Kyverno镜像签名验证策略 apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-image-signature spec: validationFailureAction: Enforce background: false rules: - name: check-signature match: any: - resources: kinds: - Pod verifyImages: - imageReferences: - "registry.example.com/*" mutateDigest: true verifyDigest: true required: true attestors: - count: 1 entries: - keys: publicKeys: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEX... -----END PUBLIC KEY----- --- # 文件4:生产级AI推理Deployment(完整安全配置) apiVersion: apps/v1 kind: Deployment metadata: name: ai-inference-secure namespace: ai-inference-prod labels: app.kubernetes.io/name: ai-inference app.kubernetes.io/component: inference-server security-tier: restricted spec: replicas: 3 selector: matchLabels: app: ai-inference template: metadata: labels: app: ai-inference annotations: # 显式声明容器运行时 container.apparmor.security.beta.kubernetes.io/inference: runtime/default seccomp.security.alpha.kubernetes.io/pod: runtime/default spec: runtimeClassName: kata-qemu serviceAccountName: inference-sa securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 seccompProfile: type: RuntimeDefault containers: - name: inference image: registry.example.com/ai-inference:v1 imagePullPolicy: Always ports: - containerPort: 8000 protocol: TCP env: - name: MODEL_PATH value: /models/current - name: LOG_LEVEL value: info securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 1000 seccompProfile: type: RuntimeDefault resources: requests: cpu: "4" memory: "8Gi" nvidia.com/gpu: 1 limits: cpu: "8" memory: "16Gi" nvidia.com/gpu: 1 volumeMounts: - name: tmp mountPath: /tmp - name: model-storage mountPath: /models readOnly: true livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 8000 initialDelaySeconds: 5 periodSeconds: 5 volumes: - name: tmp emptyDir: medium: Memory sizeLimit: 1Gi - name: model-storage persistentVolumeClaim: claimName: ai-models-pvc readOnly: true --- # 文件5:最小RBAC apiVersion: v1 kind: ServiceAccount metadata: name: inference-sa namespace: ai-inference-prod automountServiceAccountToken: false --- # 文件6:NetworkPolicy apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: inference-network-policy namespace: ai-inference-prod spec: podSelector: matchLabels: app: ai-inference policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: ai-gateway ports: - port: 8000 protocol: TCP egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system ports: - port: 53 protocol: UDP - port: 53 protocol: TCP - to: - podSelector: matchLabels: app: model-registry ports: - port: 50051 protocol: TCP八、落地避坑指南
8.1 不要一上来就全量推行
我见过太多团队:“我们在所有命名空间强制enforce: restricted!” 然后……所有人都被阻塞了,然后……策略被回滚了。
💡建议的落地节奏:
- 第1周:所有命名空间用
audit模式,观察哪些Pod不满足 - 第2周:对不满足的Pod逐个评估,要么改代码适应Restricted,要么确认豁免
- 第3周:核心业务命名空间切到
enforce: restricted - 第4周:全量切
enforce: restricted,保留warn: baseline作为新风向标
8.2 关于性能损耗
⚠️不要无脑对所有Pod启用Kata Containers。
Kata的VM启动开销在5-20秒之间,对于水平扩展频繁匹配Pod的应用,这个延迟是不可接受的。而且不是所有CPU都支持Kata需要的虚拟化扩展(Intel VT-x/AMD-V)。
合理策略:
- 高风险AI推理Pod → Kata(安全 > 性能)
- 批处理/离线任务 → Kata(可接受额外启动时间)
- 在线Web服务 → gVisor(启动快,隔离够用)
- kube-system组件 → runc(不改运行时)
8.3 别忘了运行时监控
四道防线都配好了,但你以为就完事了?
💡运行时监控是第五道防线(可选增强):
# Falco 运行时安全(作为补充监控) helm repo add falcosecurity https://falcosecurity.github.io/charts helm install falco falcosecurity/falco \ --namespace falco \ --create-namespace \ --set falco.driver.kind=ebpfFalco可以检测:容器内执行shell、读取敏感文件、创建网络连接等等——即使攻击者突破了Kata沙箱,Falco还能在宿主机层给你报警。
九、总结
AI容器安全不是选一个工具就能解决的。四道防线,缺一不可:
- 镜像签名(Cosign/Notation)→ 解决"镜像被篡改"的问题
- 镜像扫描(Trivy/Grype)→ 解决"镜像有漏洞"的问题
- RuntimeClass沙箱(Kata/gVisor)→ 解决"逃逸攻击"的问题
- PodSecurity标准(Restricted/Baseline)→ 解决"配置缺陷"的问题
配置从来不是为了阻止"绝对不会出事"——而是为了提高攻击成本,让攻击者觉得"不值得攻破你"。
今天花半天配好这四道防线,明天省下的可能是一个七位数的安全事件。
📌 推荐阅读:
- Cosign 官方文档
- Trivy Operator 项目
- Kata Containers 架构说明
- K8s PodSecurity 标准
如果你也在做AI容器安全,欢迎留言交流👇 你觉得哪道防线最难落地?
标签:容器安全镜像签名RuntimeClassPodSecurityKata ContainersCosignTrivy