<返回目录     Powered by claude/xia兄

第13课: 安全实践

Docker安全威胁

使用非root用户

# Dockerfile中创建并使用非root用户
FROM python:3.9-slim

# 创建应用用户
RUN useradd -m -u 1000 appuser && \
    mkdir -p /app && \
    chown -R appuser:appuser /app

WORKDIR /app

# 以root安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 切换到非root用户
USER appuser

# 复制应用代码
COPY --chown=appuser:appuser . .

EXPOSE 8000
CMD ["python", "app.py"]
为什么使用非root用户?

镜像扫描

# 使用Docker Scout扫描镜像
docker scout cves myapp:latest

# 使用Trivy扫描镜像
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy image myapp:latest

# 扫描并输出报告
trivy image --severity HIGH,CRITICAL myapp:latest

# 扫描Dockerfile
trivy config Dockerfile

# 使用Clair扫描
docker run -d --name clair-db postgres
docker run -d --name clair --link clair-db:postgres arminc/clair-local-scan

签名和验证镜像

# 启用Docker Content Trust
export DOCKER_CONTENT_TRUST=1

# 推送签名镜像
docker push myregistry.com/myapp:latest

# 拉取时自动验证签名
docker pull myregistry.com/myapp:latest

# 使用Notary签名
notary init myregistry.com/myapp
notary publish myregistry.com/myapp

限制容器能力

# 删除所有能力
docker run --cap-drop=ALL nginx

# 只添加需要的能力
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx

# 常用能力
# NET_BIND_SERVICE: 绑定1024以下端口
# CHOWN: 修改文件所有者
# DAC_OVERRIDE: 绕过文件权限检查
# SETUID/SETGID: 设置用户/组ID

# 以只读方式运行容器
docker run --read-only nginx

# 只读根文件系统,挂载临时目录
docker run --read-only --tmpfs /tmp nginx

使用安全计算模式(Seccomp)

# 使用默认seccomp配置
docker run --security-opt seccomp=default.json nginx

# 禁用seccomp(不推荐)
docker run --security-opt seccomp=unconfined nginx

# 自定义seccomp配置
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": ["read", "write", "open", "close"],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

docker run --security-opt seccomp=custom-seccomp.json nginx

AppArmor和SELinux

# 使用AppArmor配置
docker run --security-opt apparmor=docker-default nginx

# 使用SELinux标签
docker run --security-opt label=level:s0:c100,c200 nginx

# 禁用SELinux(不推荐)
docker run --security-opt label=disable nginx

敏感信息管理

# 使用Docker Secrets(Swarm模式)
echo "mysecretpassword" | docker secret create db_password -

# 在服务中使用secret
docker service create \
  --name mysql \
  --secret db_password \
  -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_password \
  mysql

# 使用环境变量文件
# .env文件
DB_PASSWORD=secret123
API_KEY=abc123

# docker-compose.yml
version: '3.8'
services:
  app:
    image: myapp
    env_file:
      - .env

# 使用外部密钥管理
# HashiCorp Vault, AWS Secrets Manager等

网络安全

# 创建隔离网络
docker network create --internal backend

# 容器只能访问内部网络
docker run -d --network backend mysql

# 使用防火墙规则
iptables -A DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP

# 禁用容器间通信
docker network create --driver bridge --opt com.docker.network.bridge.enable_icc=false isolated

# 限制容器访问主机
docker run --add-host=host.docker.internal:127.0.0.1 myapp

资源隔离

# 使用cgroup限制资源
docker run -d \
  --memory="512m" \
  --cpus="1" \
  --pids-limit=100 \
  nginx

# 禁用OOM杀死(需谨慎)
docker run -d --memory="512m" --oom-kill-disable nginx

# 使用namespace隔离
docker run -d --userns-remap=default nginx

审计和日志

# 启用Docker审计
# /etc/audit/rules.d/docker.rules
-w /usr/bin/docker -k docker
-w /var/lib/docker -k docker
-w /etc/docker -k docker
-w /usr/lib/systemd/system/docker.service -k docker
-w /etc/docker/daemon.json -k docker

# 重启auditd
systemctl restart auditd

# 查看审计日志
ausearch -k docker

# 配置日志驱动
docker run -d \
  --log-driver syslog \
  --log-opt syslog-address=tcp://192.168.1.100:514 \
  nginx

镜像安全最佳实践

# 安全的Dockerfile示例
FROM python:3.9-slim AS builder

# 使用特定版本而不是latest
FROM python:3.9.18-slim

# 更新系统包
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y --no-install-recommends \
        gcc \
        libc-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 创建非root用户
RUN useradd -m -u 1000 appuser

WORKDIR /app

# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 切换用户
USER appuser

# 复制应用
COPY --chown=appuser:appuser . .

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8000/health || exit 1

EXPOSE 8000
CMD ["python", "app.py"]

Docker Bench Security

# 运行Docker安全基准测试
docker run -it --rm \
  --net host \
  --pid host \
  --userns host \
  --cap-add audit_control \
  -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
  -v /var/lib:/var/lib \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /etc:/etc \
  --label docker_bench_security \
  docker/docker-bench-security

# 查看报告并修复问题

运行时安全

# 使用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 \
  falcosecurity/falco

# Falco会检测异常行为:
# - 容器中执行shell
# - 修改系统文件
# - 异常网络连接
# - 权限提升

Docker Compose安全配置

version: '3.8'

services:
  app:
    image: myapp:latest
    user: "1000:1000"
    read_only: true
    tmpfs:
      - /tmp
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    security_opt:
      - no-new-privileges:true
      - seccomp:default.json
    networks:
      - frontend
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M

  db:
    image: postgres:14
    user: postgres
    read_only: true
    tmpfs:
      - /tmp
      - /var/run/postgresql
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

networks:
  frontend:
  backend:
    internal: true

volumes:
  db-data:

secrets:
  db_password:
    external: true

安全检查清单

实践练习

  1. 修改Dockerfile使用非root用户运行应用
  2. 使用Trivy扫描镜像并修复高危漏洞
  3. 配置容器使用只读文件系统
  4. 运行Docker Bench Security检查安全配置
  5. 使用Docker Secrets管理敏感信息
  6. 配置网络隔离,限制容器间通信