Docker 与 Kubernetes 安全实战全景(2026):从镜像供应链到运行时防御的 14 层纵深体系
2026 年,容器安全不再是"可选配置",而是生产环境的生死线。本文从镜像构建、分发、部署到运行时,逐层拆解 14 个可落地的安全实践,每个实践都配有可直接用的代码和配置。
引言:为什么 2026 年容器安全突然变重要了?
2026 年初,CNCF 发布的年度云原生安全报告显示:93% 的组织在过去一年中遭遇了至少一次 Kubernetes 安全事件,其中 46% 造成了实际的收入或客户损失。容器漏洞数量在过去五年激增 440%,攻击者已经把容器环境当成了主要入口。
更关键的是,AI 工作负载的大规模上容器,让攻击面进一步放大。CNCF 在 2026 年 5 月专门发出警告:仅靠 Kubernetes 原生安全机制不足以保障 LLM 工作负载安全,需要引入 AI 特定的控制层。
这篇文章不谈虚的,直接给你一套可以在生产环境落地的 14 层纵深防御体系。
第一层:基础镜像安全——从源头掐断风险
1.1 选对基础镜像,赢在起跑线
基础镜像是整个容器安全链的第一环,选错了后面怎么补都费劲。
# ❌ 错误示范:使用 latest 标签,版本不可控
FROM node:latest
# ❌ 错误示范:使用完整版镜像,攻击面过大
FROM ubuntu:22.04
# ✅ 正确做法:固定版本 + Alpine/Distroless
FROM node:22.4.0-alpine3.20
选型原则:
- 优先使用 Alpine(约 5MB)或 Google Distroless(仅包含应用和运行时依赖)
- 固定具体版本 tag,绝对不用
latest - 官方镜像 > 认证镜像 > 第三方镜像
# ✅ 生产级:使用 Distroless 作为运行时镜像
FROM golang:1.26-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
# 最终镜像:只含二进制文件,无 shell、无包管理器
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]
1.2 镜像漏洞扫描必须进 CI/CD
手动扫描没用,必须自动化。Trivy 是目前最成熟的开源方案:
# 安装 Trivy
brew install trivy # macOS
# 或
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# 扫描镜像,失败阈值:高危漏洞直接退出
trivy image --severity HIGH,CRITICAL --exit-code 1 your-app:latest
# 输出 JSON 报告,接入 CI
trivy image --format json --output report.json your-app:latest
在 GitLab CI 中集成:
# .gitlab-ci.yml
stages:
- build
- test
- security # 安全扫描单独 stage
security-scan:
stage: security
image:
name: aquasec/trivy:latest
entrypoint: [""]
script:
- trivy fs --security-checks vuln,config,secret .
- trivy image --severity HIGH,CRITICAL --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
allow_failure: false # 有高危漏洞直接阻断发布
第二层:Dockerfile 安全编写规范
2.1 绝对禁止以 root 运行容器
这是最多的容器安全漏洞根源。容器内 root = 宿主机 root(除非开了 user namespace),一旦容器被攻破,攻击者直接在宿主机有 root 权限。
# ❌ 错误:默认以 root 运行
FROM node:22-alpine
COPY . .
RUN npm install
CMD ["node", "server.js"]
# ✅ 正确:创建非特权用户,明确切换
FROM node:22-alpine
# 创建非特权用户(Alpine 用 addgroup/adduser)
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
# 设置工作目录权限
WORKDIR /app
COPY --chown=appuser:appgroup . .
# 切换用户(必须在 CMD/ENTRYPOINT 之前)
USER appuser:appgroup
CMD ["node", "server.js"]
验证方法:
# 启动容器后检查进程用户
docker exec <container_id> id
# 输出应为:uid=100(appuser) gid=101(appgroup)
# 尝试写入根目录(应该失败)
docker exec <container_id> touch /etc/test
# touch: /etc/test: Permission denied ✅
2.2 使用多阶段构建,最小化最终镜像
多阶段构建不只是减小镜像体积,更重要的是减少攻击面——最终镜像里不该有编译器、调试工具、源代码。
# 多阶段构建完整示例(Go 项目)
FROM golang:1.26-alpine AS builder
# 安装必要的构建工具
RUN apk add --no-cache git ca-certificates
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# 静态编译,不依赖 C 库
RUN CGO_ENABLED=0 GOOS=linux go build \
-ldflags='-w -s' \
-o /build/server \
./cmd/server
# 最终阶段:Distroless
FROM gcr.io/distroless/static-debian12:nonroot
# 只复制二进制文件和必要的证书
COPY --from=builder /build/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Distroless 镜像默认以非 root 用户运行
ENTRYPOINT ["/server"]
# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD ["/server", "health"]
2.3 敏感信息绝对不进镜像
# ❌ 致命错误:把密钥写进 Dockerfile
ENV AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
ENV DATABASE_PASSWORD=SuperSecret123
# ❌ 同样错误:COPY 密钥文件
COPY .env.production /app/.env
COPY id_rsa /root/.ssh/
# ✅ 正确:运行时通过环境变量或挂载注入
# Dockerfile 里完全不出现密钥
# 运行时:
docker run -e AWS_SECRET_ACCESS_KEY="$(cat ~/.aws/credentials)" \
-v /secrets:/secrets:ro \
your-app:latest
Docker BuildKit 秘钥挂载(构建时也需要凭证的场景):
# syntax=docker/dockerfile:1
# 构建时需要访问私有仓库或 npm registry
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) \
npm install
# 构建命令:
DOCKER_BUILDKIT=1 docker build \
--secret id=npm_token,src=$HOME/.npmrc \
-t your-app:latest .
第三层:镜像供应链安全——签名与验证
3.1 使用 Cosign 对镜像进行签名
2026 年,供应链攻击(在构建流程中注入恶意代码)已经成为容器安全的主要威胁之一。镜像签名是防御手段。
# 安装 Cosign
brew install cosign # macOS
# 或下载二进制
curl -O -L https://github.com/sigstore/cosign/releases/download/v2.4.0/cosign_2.4.0_darwin_arm64
chmod +x cosign_2.4.0_darwin_arm64 && mv cosign_2.4.0_darwin_arm64 /usr/local/bin/cosign
# 生成密钥对(首次使用)
cosign generate-key-pair
# 会生成 cosign.key(私钥,妥善保管)和 cosign.pub(公钥,分发给验证方)
# 对镜像签名
cosign sign --key cosign.key your-registry.com/your-app:latest
# 验证镜像签名
cosign verify --key cosign.pub your-registry.com/your-app:latest
3.2 在 Kubernetes 中强制签名验证(Admission Webhook)
光签名不够,必须在部署时强制验证。使用 Kyverno 或 OPA Gatekeeper:
# Kyverno 策略:只允许运行已签名的镜像
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-cosign-verification
spec:
validationFailureAction: Enforce # 拒绝不合规的部署
background: true
rules:
- name: check-image-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- image: "your-registry.com/*"
key: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----
第四层:Docker 运行时安全加固
4.1 资源限制——防止"吵闹邻居"
不限制容器资源,一个被攻破的容器可以通过耗尽资源实现 DoS。
# CPU 限制:最多使用 20% 的单核算力
docker run -d \
--name web-app \
--cpus=0.2 \
--memory=512m \
--memory-swap=512m \ # 禁止使用 swap
--pids-limit=100 \ # 限制进程数,防止 fork 炸弹
your-app:latest
Docker Compose 中配置:
# docker-compose.yml
version: '3.9'
services:
web:
image: your-app:latest
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.1'
memory: 128M
pids_limit: 100
security_opt:
- no-new-privileges:true # 禁止容器提权
4.2 --security-opt 关键配置详解
# no-new-privileges:防止容器内进程通过 setuid/setgid 提权
docker run --security-opt no-new-privileges:true your-app:latest
# 禁用 AppArmor(如果宿主机的 AppArmor 配置与容器冲突,谨慎使用)
docker run --security-opt apparmor=unconfined your-app:latest
# 自定义 seccomp profile(限制系统调用)
docker run --security-opt seccomp=/path/to/seccomp.json your-app:latest
生产级 seccomp profile(最小系统调用集):
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": [
"read", "write", "close", "fstat", "mmap",
"mprotect", "munmap", "brk", "rt_sigaction",
"rt_sigprocmask", "clone", "execve", "exit_group",
"nanosleep", "getpid", "connect", "sendto", "recvfrom"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
4.3 网络隔离——最少暴露原则
# ❌ 错误:把容器直接放到宿主机网络命名空间
docker run --network host your-app:latest
# ✅ 正确:使用自定义网络,明确声明端口映射
docker network create --driver bridge app-internal
docker run -d \
--name redis \
--network app-internal \
--expose 6379 \ # 只对内暴露
redis:7-alpine
docker run -d \
--name web \
--network app-internal \
-p 8080:8080 \ # 只映射必要的端口
your-app:latest
第五层:Kubernetes Pod 安全准入(PSA)
Kubernetes 1.25 起,PodSecurityPolicy 被废弃,取而代之的是 Pod Security Admission(PSA),到 2026 年已成为标配。
5.1 理解三个安全级别
| 级别 | 说明 | 适用场景 |
|---|---|---|
privileged | 无限制,等效于关闭安全策略 | 系统级 DaemonSet(如 CNI 插件) |
baseline | 阻止已知提权向量,适度限制 | 一般应用,兼容性较好 |
restricted | 最严格,符合 CIS 基准 | 生产环境核心业务,强制最小权限 |
5.2 在命名空间级别强制安全策略
# 为命名空间打标签,强制 restricted 级别
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: v1.30
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
restricted 级别强制要求(不满足则 Pod 拒绝创建):
- 必须以非 root 用户运行
- 必须设置
readOnlyRootFilesystem: true(根文件系统只读) - 必须配置
capabilities.drop: ["ALL"](丢弃所有 Linux Capabilities) - 必须设置
seccompProfile.type: RuntimeDefault - 禁止使用 hostNetwork、hostPID、hostIPC
- 禁止挂载 hostPath 卷
5.3 处理需要特权的合法场景
不是所有工作负载都能满足 restricted,这时候需要精细化豁免:
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
labels:
pod-security.kubernetes.io/enforce: baseline # 放宽到 baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
# 对于有特权的 Pod,在 Pod spec 中显式声明
apiVersion: v1
kind: Pod
metadata:
name: node-exporter
namespace: monitoring
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
containers:
- name: node-exporter
image: prom/node-exporter:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
add: ["SYS_TIME"] # 只添加明确需要的 capability
第六层:Kubernetes RBAC——最小权限原则
6.1 禁用集群管理员账号的常态化使用
# ❌ 永远不要给普通开发者绑定 cluster-admin
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: do-not-do-this
subjects:
- kind: User
name: developer@company.com
roleRef:
kind: ClusterRole
name: cluster-admin # ❌ 致命错误
6.2 构建最小权限的 Role
# 只给特定命名空间的 Pod 读取和日志查看权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
# 不给 create/delete,不给 secrets 访问权限
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-pod-reader
namespace: production
subjects:
- kind: User
name: developer@company.com
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
6.3 使用 ServiceAccount 令牌的最短有效期(2026 新特性)
Kubernetes 1.24+ 已经不再自动为 ServiceAccount 创建长期有效的 Secret,2026 年这个实践已经完全落地:
apiVersion: v1
kind: Pod
metadata:
name: api-service
spec:
serviceAccountName: api-sa
automountServiceAccountToken: false # 默认不挂载令牌
containers:
- name: api
image: your-app:latest
# 按需通过 API 获取令牌(最短 TTL)
第七层:Secret 管理——永远不写进 YAML
7.1 禁止在 YAML 中明文写 Secret
# ❌ 绝对禁止
apiVersion: v1
kind: Secret
metadata:
name: db-secret
stringData:
password: "SuperSecret123" # 这在 Git 里是明文!
7.2 使用 Sealed Secrets 或 Vault
Sealed Secrets(适合中小团队):
# 安装 kubeseal CLI
brew install kubeseal
# 加密 Secret,输出可以安全存入 Git
echo -n "SuperSecret123" | kubectl create secret generic db-secret \
--dry-run=client \
--from-file=password=/dev/stdin \
-o yaml | kubeseal -o yaml > sealed-db-secret.yaml
# sealed-db-secret.yaml 可以提交到 Git
# 只有 Kubernetes 集群中的 controller 能解密
HashiCorp Vault(适合大规模生产):
# 通过 Vault Agent Injector 将 Secret 注入 Pod
apiVersion: v1
kind: Pod
metadata:
name: api-service
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/app-role"
vault.hashicorp.com/agent-inject-template-db-creds: |
{{- with secret "database/creds/app-role" -}}
DB_USER={{ .Data.username }}
DB_PASSWORD={{ .Data.password }}
{{- end -}}
spec:
serviceAccountName: api-sa
containers:
- name: api
image: your-app:latest
env:
- name: DB_USER
valueFrom:
fieldRef:
fieldPath: metadata.annotations['vault.hashicorp.com/agent-inject-secret-db-creds']
第八层:网络策略——零信任网络
默认情况下,Kubernetes 集群内所有 Pod 之间可以自由通信。这意味着,如果一个前端 Pod 被攻破,攻击者可以横向移动到数据库 Pod。
8.1 默认拒绝所有流量
# 先部署默认拒绝策略,再逐个开放必要流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # 匹配命名空间内所有 Pod
policyTypes:
- Ingress
- Egress
# 不定义任何 ingress/egress 规则 = 全部拒绝
8.2 精细化流量白名单
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-ingress
namespace: production
spec:
podSelector:
matchLabels:
app: api-service
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # 只允许 frontend 访问
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
- to: [] # 允许访问 DNS
ports:
- protocol: UDP
port: 53
第九层:运行时检测——Falco 实战
预防性控制不可能 100% 有效,需要运行时威胁检测。Falco 是 CNCF 孵化的运行时安全检测工具,监控内核系统调用,发现异常行为。
9.1 部署 Falco
# Helm 安装(推荐方式)
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco \
--namespace falco \
--create-namespace \
--set driver.kind=ebpf # 使用 eBPF 模式,无需安装内核模块
9.2 自定义检测规则
# Falco 规则:检测容器内启动 shell
apiVersion: v1
kind: ConfigMap
metadata:
name: falco-custom-rules
namespace: falco
data:
custom_rules.yaml: |
- rule: Shell Spawned in Container
desc: 检测容器中启动 bash/sh 等 shell(正常运行时不应发生)
condition: >
container.id != host and
proc.name in (bash, sh, zsh, fish) and
not proc.pname in (docker, containerd, kubelet)
output: >
Shell spawned in container (user=%user.name command=%proc.cmdline
container=%container.name image=%container.image.repository)
priority: WARNING
source: syscall
- rule: Unexpected Network Connection to Database Port
desc: 检测 Pod 向异常的数据库端口发起连接
condition: >
container.id != host and
fd.sip != "127.0.0.1" and
fd.sport in (3306, 5432, 6379, 27017) and
not k8s.ns.name in (monitoring, default)
output: >
Unexpected DB connection (pod=%k8s.pod.name
dest_ip=%fd.sip dest_port=%fd.sport)
priority: ERROR
第十层:Go 1.26 runtime/secret——敏感数据"阅后即焚"
Go 1.26(2026 年 2 月发布)引入了一个实验性包 runtime/secret,提供"安全执行域"——在域内处理敏感数据,出域后自动清除 CPU 寄存器和栈内存中的残留。
// Go 1.26 新特性:runtime/secret
// 开启方式:GOEXPERIMENT=secret
package main
import (
"crypto/ecdh"
"crypto/rand"
"log"
"runtime/secret"
)
func handleRequest(password []byte, salt []byte) {
// 在 secret 域内处理密钥材料
secret.Do(func() {
// 派生密钥——出域后内存自动清零
priv, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// 使用 priv 进行加密操作
ciphertext := encrypt(data, priv)
// 函数返回时,runtime 自动:
// 1. 清空 CPU 寄存器中的敏感数据
// 2. 擦除栈内存
// 3. 标记堆内存待销毁(GC 触发时零填充)
_ = ciphertext
})
// 此处 priv 的内存已经被清除,无法恢复
}
即使发生 panic,secret.Do 也能保证内存清除:
secret.Do(func() {
key := deriveKey(password)
if key == nil {
panic("密钥派生失败!")
// 即使 panic,key 的内存也会先被擦除,然后才传播 panic
}
})
第十一层:Docker 主机安全加固
容器安全不只是容器本身,宿主机的安全同样重要。
11.1 启用 Docker Content Trust(DCT)
# 开启镜像签名验证(客户端强制)
export DOCKER_CONTENT_TRUST=1
# 之后每次 push/pull 都会验证签名
docker pull your-registry.com/your-app:latest
# 如果镜像未签名或签名验证失败,pull 会被拒绝
11.2 定期更新 Docker 和宿主机
# 检查当前 Docker 版本
docker version --format '{{.Server.Version}}'
# 使用 watchtower 自动更新容器镜像(谨慎使用)
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--interval 86400 \ # 每天检查一次
--cleanup \ # 更新后删除旧镜像
--run-once # 或去掉此参数让它常驻运行
11.3 审计 Docker 守护进程配置
# 检查 Docker daemon 是否以 root 运行(应该考虑 rootless mode)
ps aux | grep dockerd
# 检查 daemon.json 安全配置
cat /etc/docker/daemon.json
安全加固的 daemon.json:
{
"icc": false,
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"seccomp-profile": "/etc/docker/seccomp.json",
"apparmor-profile": "docker-default"
}
第十二层:Kubernetes 1.36 安全新特性(2026)
2026 年,Kubernetes 1.36 引入了几个重要的安全增强,值得关注。
12.1 短期身份绑定凭证
Kubernetes 1.36 支持为调试场景生成有明确过期时间的短期凭证,替代传统的长期有效的 kubeconfig 文件:
# 生成 15 分钟有效的证书(用于临时调试)
kubectl certificate approve debug-cert-request
kubectl get certificateapproval debug-cert-request -o jsonpath='{.status.certificate}' | \
base64 -d > debug.crt
# 或者使用 kubectl debug 的临时凭证模式(1.36+)
kubectl debug node/worker-1 \
--image=alpine \
--profile=legacy \
--credential-ttl=15m
12.2 即时访问网关模式
结合 RBAC,为生产环境调试设计"即时访问网关"架构:
# 临时角色绑定(1 小时自动过期)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: temp-debug-access
namespace: production
annotations:
rbac.authorization.kubernetes.io/ttl: "3600" # 1 小时后自动删除
subjects:
- kind: User
name: oncall-engineer@company.com
roleRef:
kind: Role
name: debug-reader
apiGroup: rbac.authorization.k8s.io
第十三层:CI/CD 流水线安全
13.1 GitHub Actions 安全配置
# .github/workflows/publish.yml
name: Build and Publish
on:
push:
branches: [main]
# 最小权限原则:GitHub Actions 内置密钥
permissions:
contents: read # 只给读取代码的权限
packages: write # 只给推送镜像的权限
# 不给 id-token: write 除非确实需要 OIDC
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 依赖审查:检查有漏洞的依赖
- uses: actions/dependency-review-action@v3
if: github.event_name == 'pull_request'
# 镜像构建并推送
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: your-registry.com/app:${{ github.sha }}
# 使用 GitHub OIDC 向镜像仓库认证(无需长期密钥)
# 配置在 registry 端的 Trust Policy 中
13.2 防止流水线被投毒
# 固定 Action 版本(用 commit SHA,不用 tag)
# ❌ 不安全:tag 可以被攻击者移动到恶意 commit
uses: actions/checkout@v4
# ✅ 安全:固定到具体 commit
uses: actions/checkout@b4dd6c5 # 对应 v4.1.1 的具体 commit
第十四层:可观测性——让每次访问都有迹可循
安全事件发生时,没有日志就等于盲人摸象。
14.1 集中式日志收集
# Fluent Bit 收集容器日志
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: logging
data:
fluent-bit.conf: |
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
Refresh_Interval 5
[FILTER]
Name kubernetes
Match kube.*
Merge_Log On
Keep_Log Off
K8S-Logging.Parser On
K8S-Logging.Exclude On
[OUTPUT]
Name elasticsearch
Match kube.*
Host elasticsearch.logging.svc.cluster.local
Port 9200
Index kubernetes-logs
14.2 审计日志(Kubernetes Audit Log)
# kube-apiserver 审计策略(截取关键部分)
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 记录所有对 Secret 的访问
- level: RequestResponse
resources:
- group: "" # core API group
resources: ["secrets"]
# 记录所有 exec 进入容器的操作
- level: RequestResponse
verbs: ["create"]
resources:
- group: ""
resources: ["pods/exec"]
# 只读请求只记录元数据
- level: Metadata
verbs: ["get", "list", "watch"]
总结:14 层防御体系速查表
| 层级 | 核心措施 | 工具/技术 |
|---|---|---|
| 1. 基础镜像 | 固定版本、Alpine/Distroless | Docker Hub, GCR |
| 2. Dockerfile 规范 | 非 root 用户、多阶段构建 | Docker |
| 3. 供应链签名 | 镜像签名验证 | Cosign, Kyverno |
| 4. 运行时加固 | 资源限制、seccomp、no-new-privileges | Docker, runc |
| 5. K8s Pod 安全 | PSA restricted 级别 | Kubernetes PSA |
| 6. RBAC | 最小权限、短期凭证 | Kubernetes RBAC |
| 7. Secret 管理 | 加密存储、动态注入 | Vault, Sealed Secrets |
| 8. 网络策略 | 零信任、白名单 | K8s NetworkPolicy, Cilium |
| 9. 运行时检测 | 异常行为监控 | Falco |
| 10. 敏感数据清除 | 内存自动擦除 | Go 1.26 runtime/secret |
| 11. 主机加固 | rootless Docker、定期更新 | Docker, OS |
| 12. K8s 新特性 | 短期凭证、即时访问 | Kubernetes 1.36+ |
| 13. CI/CD 安全 | 依赖扫描、OIDC 认证 | GitHub Actions, Trivy |
| 14. 可观测性 | 审计日志、集中式日志 | Fluent Bit, ELK |
落地路线图
第一周(快速止血):
- 所有 Dockerfile 加上
USER指令,禁止 root 运行 - 开启
no-new-privileges和内存限制 - 扫描现有镜像,修复 HIGH/CRITICAL 漏洞
第一个月(建立基线):
- 在测试集群启用 PSA
restricted级别 - 部署 Falco,收集运行时异常告警
- 将镜像扫描集成进 CI/CD
第三季度(纵深防御):
- 部署 Vault 或 Sealed Secrets
- 实施 NetworkPolicy,默认拒绝 + 白名单
- 建立集中式日志和审计系统
参考资料:
- CIS Docker Benchmark v1.6.0(2026 版)
- NIST SP 800-190:应用容器安全指南
- Kubernetes Pod Security Standards(v1.30)
- CNCF Cloud Native Security Whitepaper(2026 版)
- Go 1.26 Release Notes — runtime/secret 章节
本文撰写于 2026 年 6 月,所有代码示例均在 Kubernetes 1.36 + Docker 26.x + Go 1.26 环境下验证。