容器已成为现代应用部署的标准载体,但容器的轻量和共享内核特性也带来了新的安全挑战。本文从镜像构建到运行时防护,系统讲解容器安全的最佳实践。
1. 容器安全生命周期
┌─────────────────────────────────────────────────────────────┐
│ 容器安全生命周期 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 开发 构建 分发 运行 销毁 │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ 依赖扫描 镜像扫描 签名验证 运行时防护 审计清理 │
│ SAST/SCA Trivy Cosign Falco 日志归档 │
│ │
└─────────────────────────────────────────────────────────────┘
2. 镜像安全
2.1 最小镜像原则
# ❌ 不安全:包含 shell、包管理器、调试工具
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3 curl
COPY app.py /app/
CMD ["python3", "/app/app.py"]
# ✅ 安全:Distroless,无 shell、无包管理器
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
FROM gcr.io/distroless/python3-debian12
WORKDIR /app
COPY --from=builder /root/.local /home/nonroot/.local
COPY app.py .
USER nonroot:nonroot
ENV PATH=/home/nonroot/.local/bin:$PATH
CMD ["app.py"]
| 基础镜像 | 大小 | Shell | 包管理器 | 适用 |
|---|---|---|---|---|
| Ubuntu/Debian | ~80MB | ✅ | ✅ | 开发调试 |
| Alpine | ~5MB | ✅ | apk | 权衡选择 |
| Distroless | ~20MB | ❌ | ❌ | 生产推荐 |
| Scratch | ~0MB | ❌ | ❌ | Go 静态编译 |
2.2 多阶段构建
# 编译阶段(包含编译工具)
FROM golang:1.21-alpine AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/app ./cmd/app
# 最终阶段(仅二进制)
FROM scratch
COPY --from=build /bin/app /app
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/app"]
2.3 镜像扫描
# Trivy 扫描
trivy image myapp:latest
# 只关注严重/高危
trivy image --severity CRITICAL,HIGH myapp:latest
# 镜像签名(Cosign)
cosign generate-key-pair
cosign sign --key cosign.key myregistry/myapp:latest
cosign verify --key cosign.pub myregistry/myapp:latest
3. Dockerfile 安全基线
# ✅ 使用官方镜像,指定具体版本
FROM python:3.11.6-slim-bookworm
# ✅ 创建非 root 用户
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
# ✅ 设置工作目录
WORKDIR /app
# ✅ 先复制依赖,利用缓存层
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# ✅ 再复制应用代码
COPY --chown=appuser:appgroup . .
# ✅ 只暴露需要的端口
EXPOSE 8080
# ✅ 切换到非 root 用户
USER appuser:appgroup
# ✅ 使用 HEALTHCHECK
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
CMD curl -f http://localhost:8080/health || exit 1
# ✅ 明确 ENTRYPOINT/CMD
ENTRYPOINT ["python"]
CMD ["app.py"]
3.1 Dockerfile 安全检查清单
| 检查项 | 说明 |
|---|---|
| 使用特定版本标签 | 不用 latest |
| 最小基础镜像 | Distroless/Alpine/Scratch |
| 非 root 运行 | USER 指令 |
| 不暴露不必要端口 | 最小化攻击面 |
| 敏感数据不入镜像 | 用 Secret/环境变量 |
| 使用 COPY 而非 ADD | ADD 会自动解压 URL |
| 多阶段构建 | 分离编译时依赖 |
| 扫描依赖漏洞 | SCA 工具 |
4. Linux 安全机制
4.1 Capabilities(能力)
# 默认 Docker 容器会 drop 大部分 capabilities
# 只保留必要的:
# 查看容器 capabilities
docker run --rm alpine:latest capsh --print
# 运行容器时移除所有 capabilities,只添加需要的
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
# Kubernetes
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
常见 Capabilities:
| 能力 | 说明 | 需要场景 |
|---|---|---|
NET_BIND_SERVICE | 绑定 < 1024 端口 | 非 root 运行 nginx |
NET_ADMIN | 网络管理 | VPN/路由 |
SYS_TIME | 修改系统时间 | NTP |
SYS_PTRACE | 进程跟踪 | 调试工具 |
4.2 seccomp(安全计算模式)
// 自定义 seccomp 配置(限制系统调用)
{
"defaultAction": "SCMP_ACT_ERRNO",
"syscalls": [
{
"names": ["accept", "bind", "connect", "listen", "socket"],
"action": "SCMP_ACT_ALLOW"
}
]
}
# Docker 使用自定义 seccomp
docker run --security-opt seccomp=custom-seccomp.json myapp
# Kubernetes
securityContext:
seccompProfile:
type: Localhost
localhostProfile: profiles/custom.json
4.3 AppArmor
# 查看当前 AppArmor 状态
sudo aa-status
# Docker 使用 AppArmor 策略
docker run --security-opt apparmor=docker-default nginx
# Kubernetes
metadata:
annotations:
container.apparmor.security.beta.kubernetes.io/nginx: runtime/default
4.4 SELinux
# Docker 使用 SELinux
docker run --security-opt label=type:container_t nginx
5. Kubernetes Pod 安全
5.1 Pod Security Standard(PSS)
Kubernetes 1.23+ 提供三种安全级别:
| 级别 | 策略 | 适用 |
|---|---|---|
| Privileged | 无限制 | 系统/管理 Pod |
| Baseline | 最小限制 | 一般应用 |
| Restricted | 最严格 | 安全敏感应用 |
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
apiVersion: v1
kind: Pod
metadata:
name: secure-app
namespace: production
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
fsGroup: 1000
containers:
- name: app
image: myapp:1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
runAsUser: 1000
runAsGroup: 1000
resources:
limits:
memory: "256Mi"
cpu: "500m"
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
5.2 Kyverno 策略引擎
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-non-root
spec:
validationFailureAction: enforce
rules:
- name: check-runasnonroot
match:
resources:
kinds:
- Pod
validate:
message: "Pod 必须设置 runAsNonRoot: true"
pattern:
spec:
securityContext:
runAsNonRoot: true
6. 运行时安全监控
6.1 Falco
# falco-rule.yaml
- rule: Terminal Shell in Container
desc: Detect shell spawned in container
condition: spawned_process and container and shell_procs
output: >
Shell spawned in container
(user=%user.name container=%container.name shell=%proc.name)
priority: WARNING
- rule: Unauthorized K8s API Access
desc: Detect access to K8s API from unexpected sources
condition: >
k8s_audit and k8s_audit_object_resource=pods
and not (ka.auth.decision=allow and authorized_user)
output: Unauthorized K8s API access
priority: CRITICAL
# 运行 Falco
docker run -d --name falco \
--privileged \
-v /var/run/docker.sock:/host/var/run/docker.sock \
-v /dev:/host/dev \
-v /proc:/host/proc:ro \
-v /boot:/host/boot:ro \
-v /lib/modules:/host/lib/modules:ro \
-v /usr:/host/usr:ro \
falcosecurity/falco:latest
6.2 运行时安全检查清单
| 检查项 | 工具/方法 |
|---|---|
| 异常进程创建 | Falco |
| 文件完整性监控 | AIDE/Tripwire |
| 网络连接异常 | Falco/Network Policy |
| 权限提升尝试 | Falco audit |
| 敏感文件访问 | Falco |
| 容器逃逸检测 | Falco + 内核审计 |
7. 总结
容器安全的 Defense in Depth:
应用层 ──► 安全编码、依赖扫描
│
镜像层 ──► 最小镜像、多阶段构建、镜像扫描、签名验证
│
编排层 ──► Pod Security Standard、Network Policy、RBAC
│
运行时 ──► seccomp、AppArmor/SELinux、Capabilities、Falco
│
主机层 ──► 主机加固、容器运行时安全、内核安全
核心原则:
- 最小权限:容器只能做必须的事
- 最小镜像:减少攻击面
- 不可变基础设施:镜像只读,配置外部化
- 持续扫描:从开发到运行全程监控
- 快速响应:漏洞发现后立即修复重建
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。