
容器安全:Docker 与 Kubernetes 加固
安全的 Dockerfile 最佳实践
# 使用最小基础镜像
FROM node:20-alpine3.19 # 不要使用 node:latest 或 node:20
# 以非 root 用户运行
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 不要复制不必要的文件
COPY --chown=appuser:appgroup package*.json ./
RUN npm ci --only=production # 不包含 devDependencies
COPY --chown=appuser:appgroup src/ ./src/
# 尽可能使用只读文件系统
RUN mkdir -p /tmp/uploads && chmod 770 /tmp/uploads
# 丢弃 capabilities
# 在运行时通过 --cap-drop ALL --cap-add NET_BIND_SERVICE 处理
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost:3000/health || exit 1
# 不要在 ENV 或 ARG 中存放密钥
# ENV DATABASE_URL=... <- 永远不要这样做
EXPOSE 3000
CMD ["node", "src/server.js"]

镜像漏洞扫描
# Trivy - 全面扫描器
trivy image myapp:v1.0 --severity HIGH,CRITICAL
# 如果发现严重漏洞则 CI 失败
trivy image myapp:v1.0 --exit-code 1 --severity CRITICAL
# 扫描文件系统
trivy fs . --severity HIGH,CRITICAL
# 为 GitHub Actions 生成 SARIF 报告
trivy image myapp:v1.0 --format sarif --output trivy-results.sarif
# GitHub Actions 集成
# - uses: aquasecurity/trivy-action@master
# with:
# image-ref: 'myapp:v1.0'
# format: 'sarif'
# severity: 'CRITICAL,HIGH'
# exit-code: '1'
# Grype 替代方案
grype myapp:v1.0 --fail-on high

Kubernetes Pod 安全
# Pod 安全标准 - Restricted
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/warn: restricted
---
# 安全的 Pod 模板
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault # 使用默认 seccomp 配置
containers:
- name: myapp
image: myapp:v1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL # 丢弃所有 capabilities
add:
- NET_BIND_SERVICE # 仅当绑定到小于 1024 的端口时需要
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
volumeMounts:
- name: tmp
mountPath: /tmp # 只读文件系统下用于可写临时目录
volumes:
- name: tmp
emptyDir: {}
automountServiceAccountToken: false # 除非需要,否则禁用

RBAC 最小权限
# 具有最小权限的 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-sa
namespace: production
---
# Role - 仅包含所需权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: myapp-role
namespace: production
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"] # 只读
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["myapp-secret"] # 仅限特定 Secret
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myapp-rolebinding
namespace: production
subjects:
- kind: ServiceAccount
name: myapp-sa
roleRef:
kind: Role
name: myapp-role
apiGroup: rbac.authorization.k8s.io
使用 Falco 进行运行时安全
# falco-rules.yaml - 自定义规则
- rule: Unexpected Network Connection
desc: 检测来自容器的意外出站连接
condition: >
outbound and
container.name startswith "myapp" and
not fd.net in (allowed_networks)
output: >
来自 %container.name 的意外连接
(目标=%fd.net.sport 用户=%user.name 命令=%proc.cmdline)
priority: WARNING
- rule: Shell in Container
desc: 在生产容器中启动 shell
condition: >
spawned_process and
container.name startswith "myapp" and
proc.name in (shell_binaries)
output: >
容器 %container.name 中启动了 shell
(用户=%user.name shell=%proc.name)
priority: CRITICAL
- rule: Write to Sensitive File
desc: 写入敏感文件路径
condition: >
write_to_sensitive_file and
container.name startswith "myapp"
priority: HIGH
容器安全清单
| 领域 |
控制措施 |
| 镜像 |
最小基础镜像,非 root,扫描漏洞 |
| 运行时 |
只读文件系统,丢弃 capabilities |
| 网络 |
网络策略,不使用 hostNetwork |
| RBAC |
最小权限 SA,不使用 cluster-admin |
| 密钥 |
外部密钥管理,不使用环境变量 |
| 监控 |
Falco 运行时监控,审计日志 |