容器运行时安全加固实战:containerd镜像扫描与Kubernetes Pod安全策略配置

容器运行时安全威胁模型

容器化部署中,安全威胁来自三个层面:镜像层(基础镜像含已知漏洞、植入恶意后门)、运行时层(容器逃逸、权限提升)、编排层(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/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐