容器运行时安全威胁模型
容器化部署中,安全威胁来自三个层面:镜像层(基础镜像含已知漏洞、植入恶意后门)、运行时层(容器逃逸、权限提升)、编排层(RBAC配置不当、敏感信息泄露)。容器运行时安全加固需要在这三个层面分别建立防护措施,形成纵深防御体系。
镜像层的安全基线是:所有生产镜像经过漏洞扫描、不使用latest标签、Dockerfile遵循最小权限原则。运行时层的安全基线是:禁止特权模式、只读根文件系统、限制Linux capabilities、启用Seccomp和AppArmor。编排层的安全基线是:启用Pod Security Standards、网络策略隔离、RBAC最小授权、Secret加密存储。
Trivy镜像漏洞扫描集成
Trivy是Aqua Security开源的容器镜像漏洞扫描工具,支持OS包漏洞、语言依赖漏洞和配置文件检查。安装后可直接扫描本地或远程镜像:
# 安装Trivy
apt-get install trivy
# 扫描镜像漏洞
trivy image nginx:1.27-alpine
# 输出JSON格式,集成到CI/CD
trivy image --format json -o scan-result.json nginx:1.27-alpine
# 只报告HIGH和CRITICAL级别漏洞
trivy image --severity HIGH,CRITICAL nginx:1.27-alpine
# 扫描本地文件系统中的Dockerfile配置问题
trivy config ./Dockerfile
在GitLab CI/CD中集成Trivy扫描,构建阶段自动拦截高危镜像:
# .gitlab-ci.yml
stages:
- scan
- build
trivy-scan:
stage: scan
image: aquasec/trivy:latest
script:
- trivy image --severity HIGH,CRITICAL --exit-code 1 --ignore-unfixed $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
rules:
- if: $CI_COMMIT_BRANCH == "main"
--exit-code 1设置发现高危漏洞时CI流水线失败,阻止漏洞镜像进入生产环境。--ignore-unfixed过滤尚未有修复方案的漏洞,减少误报干扰。
Dockerfile安全编写规范
Dockerfile的安全问题集中在三个方面:基础镜像选择、用户权限和文件权限。
# 安全的Dockerfile示例
FROM node:22-alpine AS builder
# 创建非root用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 先复制依赖文件,利用层缓存
COPY package*.json ./
RUN npm ci --production
# 复制源码
COPY . .
# 构建产物
RUN npm run build
# 运行阶段使用最小化基础镜像
FROM node:22-alpine
# 创建非root用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 安装最小依赖
RUN apk add --no-cache dumb-init tini
WORKDIR /app
# 仅复制构建产物
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
# 切换非root用户
USER appuser
# 设置只读根文件系统友好的目录
RUN mkdir -p /tmp/app && chown appuser:appgroup /tmp/app
ENV TMPDIR=/tmp/app
EXPOSE 3000
# 使用tini作为init进程,正确处理信号
ENTRYPOINT ["tini", "--"]
CMD ["node", "dist/server.js"]
关键安全实践:USER appuser确保容器进程以非root用户运行,即使容器逃逸也限制攻击者权限。使用--chown在COPY时设置正确文件属主,避免运行时chmod操作。tini作为PID 1进程处理SIGTERM信号,确保容器优雅停止。
Kubernetes Pod Security Standards配置
Kubernetes 1.25移除了PodSecurityPolicy,以Pod Security Standards(PSS)替代。PSS定义三种安全级别:privileged(无限制)、baseline(最小限制,禁止已知危险配置)、restricted(严格限制,符合安全最佳实践)。
# 命名空间级别启用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/audit-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
三个标签的作用:enforce拒绝创建不符合策略的Pod;audit在审计日志中记录不合规Pod但不阻止创建;warn在kubectl创建时返回警告信息。生产环境建议同时设置三个标签,enforce确保强制执行,audit和warn提供可观测性。
restricted级别要求Pod必须满足以下条件:
# 符合restricted策略的Deployment示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
namespace: production
spec:
template:
spec:
# 必须设置securityContext
securityContext:
runAsNonRoot: true # 禁止root运行
runAsUser: 10001 # 指定非0用户UID
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault # 使用默认Seccomp配置
containers:
- name: app
image: registry.example.com/app:v1.2.3
securityContext:
allowPrivilegeEscalation: false # 禁止权限提升
readOnlyRootFilesystem: true # 只读根文件系统
runAsNonRoot: true
capabilities:
drop:
- ALL # 丢弃所有Linux capabilities
add:
- NET_BIND_SERVICE # 仅保留必要capability
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/.cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir:
medium: Memory # tmpfs存储敏感缓存
readOnlyRootFilesystem: true使容器根文件系统只读,攻击者无法写入恶意文件或篡改配置。需要写入的目录通过emptyDir挂载,medium: Memory使用tmpfs将缓存存储在内存中,避免写入磁盘。
网络策略隔离与Secret管理
默认情况下Kubernetes集群中所有Pod可以互相通信。网络策略(NetworkPolicy)按标签选择器控制Pod间流量:
# 默认拒绝所有入站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 选择命名空间内所有Pod
policyTypes:
- Ingress
---
# 仅允许前端调用后端API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Secret管理方面,禁止在镜像中硬编码密钥。使用Kubernetes Secret挂载环境变量或文件,并通过外部密钥管理系统(如HashiCorp Vault、External Secrets Operator)动态获取。启用etcd加密确保Secret在持久化存储中不以明文保存:
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {} # 兜底方案
配置后重启kube-apiserver,新创建的Secret将以AES-CBC加密存储在etcd中。已有Secret需执行kubectl get secrets --all-namespaces -o yaml | kubectl replace -f -重新加密。定期轮换加密密钥,旧密钥保留用于解密历史数据,新数据使用新密钥加密。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rong-qi-yun-xing-shi-an-quan-jia-gu-shi-zhan-containerd/