Skip to content

Docker安全最佳实践

🎯 学习目标

  • 深入理解Docker安全模型和威胁向量
  • 掌握容器和镜像的安全配置
  • 学会使用安全扫描和监控工具
  • 了解生产环境的安全防护策略

📚 Docker安全概述

1. 安全模型和威胁分析

javascript
// Docker安全威胁模型
const dockerSecurityModel = {
  threat_vectors: {
    container_escape: {
      description: '容器逃逸攻击',
      risks: ['访问宿主机', '提权攻击', '横向移动'],
      mitigations: ['最小权限原则', 'seccomp配置', 'AppArmor/SELinux']
    },
    
    image_vulnerabilities: {
      description: '镜像漏洞',
      risks: ['恶意代码执行', '数据泄露', '系统入侵'],
      mitigations: ['漏洞扫描', '最小基础镜像', '定期更新']
    },
    
    privilege_escalation: {
      description: '权限提升',
      risks: ['获取root权限', '系统控制', '数据窃取'],
      mitigations: ['非root用户', '只读文件系统', '能力限制']
    },
    
    network_attacks: {
      description: '网络攻击',
      risks: ['流量劫持', '中间人攻击', '服务拒绝'],
      mitigations: ['网络隔离', 'TLS加密', '防火墙规则']
    },
    
    data_exposure: {
      description: '数据暴露',
      risks: ['敏感信息泄露', '配置泄露', '密钥暴露'],
      mitigations: ['secrets管理', '数据加密', '访问控制']
    }
  },
  
  defense_layers: [
    '主机安全',
    'Docker守护进程安全',
    '镜像安全',
    '容器运行时安全',
    '网络安全',
    '数据安全'
  ],
  
  compliance_frameworks: [
    'CIS Docker Benchmark',
    'NIST Container Security',
    'PCI DSS',
    'SOC 2',
    'ISO 27001'
  ]
};

console.log('Docker安全模型:', dockerSecurityModel);

2. 安全检查清单

bash
#!/bin/bash
# docker-security-check.sh

echo "🔒 Docker安全检查清单"
echo "===================="

echo ""
echo "1. 🐳 Docker守护进程安全:"
echo "   - Docker版本是否最新:"
docker version --format '{{.Server.Version}}'

echo "   - 是否启用了用户命名空间:"
docker info | grep -i "userns"

echo "   - 监听端口配置:"
ps aux | grep dockerd | grep -o "\-H [^[:space:]]*"

echo ""
echo "2. 📦 镜像安全:"
echo "   - 检查基础镜像版本:"
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.CreatedAt}}"

echo ""
echo "3. 🏃 运行容器安全:"
echo "   - 运行为root的容器:"
docker ps --format "table {{.Names}}\t{{.Image}}" --filter "label=user=root"

echo "   - 特权容器:"
docker ps --format "table {{.Names}}\t{{.Image}}" --filter "label=privileged=true"

echo ""
echo "4. 🌐 网络安全:"
echo "   - 暴露的端口:"
docker ps --format "table {{.Names}}\t{{.Ports}}"

echo ""
echo "5. 💾 数据安全:"
echo "   - 挂载的敏感目录:"
docker inspect $(docker ps -q) | grep -E "(\"Source\"|\"Destination\")" | grep -E "(/etc|/var|/root|/home)"

🛡️ 镜像安全

1. 安全的基础镜像选择

dockerfile
# ❌ 不安全的做法
FROM ubuntu:latest  # 使用latest标签,版本不确定
USER root          # 使用root用户
RUN apt-get update # 不清理apt缓存

# ✅ 安全的做法
FROM ubuntu:20.04  # 使用具体版本标签

# 更好的选择:使用官方minimal镜像
FROM ubuntu:20.04-minimal

# 最佳选择:使用distroless镜像
FROM gcr.io/distroless/java:11

# 或者使用Alpine Linux(更小更安全)
FROM alpine:3.16

# 更新系统并清理
RUN apk update && \
    apk upgrade && \
    apk add --no-cache ca-certificates && \
    rm -rf /var/cache/apk/*

# 创建非特权用户
RUN addgroup -g 1000 -S appgroup && \
    adduser -u 1000 -S appuser -G appgroup

# 设置工作目录权限
WORKDIR /app
RUN chown -R appuser:appgroup /app

# 切换到非特权用户
USER appuser

2. 镜像构建安全实践

dockerfile
# Dockerfile.secure
FROM node:16-alpine AS base

# 更新基础镜像
RUN apk update && apk upgrade && \
    apk add --no-cache dumb-init && \
    rm -rf /var/cache/apk/*

# 创建应用用户和组
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001 -G nodejs

# 设置安全的工作目录
WORKDIR /app
RUN chown -R nextjs:nodejs /app

# 依赖安装阶段
FROM base AS deps
USER nextjs
COPY --chown=nextjs:nodejs package*.json ./
RUN npm ci --only=production && \
    npm cache clean --force && \
    rm -rf ~/.npm

# 构建阶段
FROM base AS builder
USER nextjs
COPY --chown=nextjs:nodejs package*.json ./
RUN npm ci
COPY --chown=nextjs:nodejs . .
RUN npm run build

# 生产阶段
FROM base AS runner
USER nextjs

# 只复制必要的文件
COPY --from=deps --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/api/health || exit 1

# 暴露端口
EXPOSE 3000

# 使用dumb-init处理信号
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "server.js"]

3. 镜像签名和验证

bash
# 启用Docker Content Trust
export DOCKER_CONTENT_TRUST=1

# 生成签名密钥
docker trust key generate mykey

# 为仓库添加签名者
docker trust signer add --key mykey.pub myuser myrepo

# 推送签名镜像
docker push myrepo/myimage:v1.0

# 验证镜像签名
docker trust inspect --pretty myrepo/myimage:v1.0

# 使用Notary验证(高级)
notary verify docker.io/myrepo/myimage v1.0

🏃 容器运行时安全

1. 安全运行配置

bash
# ✅ 安全的容器运行实践

# 1. 使用非root用户
docker run --user 1000:1000 myapp

# 2. 只读根文件系统
docker run --read-only --tmpfs /tmp myapp

# 3. 删除不必要的能力
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp

# 4. 使用安全计算模式
docker run --security-opt seccomp=seccomp-profile.json myapp

# 5. 限制资源使用
docker run -m 512m --cpus="1.0" --pids-limit 100 myapp

# 6. 网络安全
docker run --network none myapp  # 无网络访问
docker run --network custom-network myapp  # 自定义网络

# 7. 禁用新权限
docker run --security-opt no-new-privileges:true myapp

# 8. 设置SELinux/AppArmor标签
docker run --security-opt label=level:s0:c100,c200 myapp

# 综合安全配置
docker run -d \
  --name secure-app \
  --user 1000:1000 \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=100m \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --security-opt no-new-privileges:true \
  --security-opt seccomp=seccomp-profile.json \
  -m 512m \
  --cpus="0.5" \
  --pids-limit 50 \
  --network secure-network \
  myapp:latest

2. Seccomp安全配置

json
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": [
    "SCMP_ARCH_X86_64",
    "SCMP_ARCH_X86",
    "SCMP_ARCH_X32"
  ],
  "syscalls": [
    {
      "names": [
        "accept",
        "accept4",
        "access",
        "adjtimex",
        "alarm",
        "bind",
        "brk",
        "capget",
        "capset",
        "chdir",
        "chmod",
        "chown",
        "chown32",
        "clock_getres",
        "clock_gettime",
        "clock_nanosleep",
        "close",
        "connect",
        "copy_file_range",
        "creat",
        "dup",
        "dup2",
        "dup3",
        "epoll_create",
        "epoll_create1",
        "epoll_ctl",
        "epoll_ctl_old",
        "epoll_pwait",
        "epoll_wait",
        "epoll_wait_old",
        "eventfd",
        "eventfd2",
        "execve",
        "execveat",
        "exit",
        "exit_group",
        "faccessat",
        "fadvise64",
        "fadvise64_64",
        "fallocate",
        "fanotify_mark",
        "fchdir",
        "fchmod",
        "fchmodat",
        "fchown",
        "fchown32",
        "fchownat",
        "fcntl",
        "fcntl64",
        "fdatasync",
        "fgetxattr",
        "flistxattr",
        "flock",
        "fork",
        "fremovexattr",
        "fsetxattr",
        "fstat",
        "fstat64",
        "fstatat64",
        "fstatfs",
        "fstatfs64",
        "fsync",
        "ftruncate",
        "ftruncate64",
        "futex",
        "futimesat",
        "getcwd",
        "getdents",
        "getdents64",
        "getegid",
        "getegid32",
        "geteuid",
        "geteuid32",
        "getgid",
        "getgid32",
        "getgroups",
        "getgroups32",
        "getitimer",
        "getpeername",
        "getpgid",
        "getpgrp",
        "getpid",
        "getppid",
        "getpriority",
        "getrandom",
        "getresgid",
        "getresgid32",
        "getresuid",
        "getresuid32",
        "getrlimit",
        "get_robust_list",
        "getrusage",
        "getsid",
        "getsockname",
        "getsockopt",
        "get_thread_area",
        "gettid",
        "gettimeofday",
        "getuid",
        "getuid32",
        "getxattr",
        "inotify_add_watch",
        "inotify_init",
        "inotify_init1",
        "inotify_rm_watch",
        "io_cancel",
        "ioctl",
        "io_destroy",
        "io_getevents",
        "ioprio_get",
        "ioprio_set",
        "io_setup",
        "io_submit",
        "ipc",
        "kill",
        "lchown",
        "lchown32",
        "lgetxattr",
        "link",
        "linkat",
        "listen",
        "listxattr",
        "llistxattr",
        "_llseek",
        "lremovexattr",
        "lseek",
        "lsetxattr",
        "lstat",
        "lstat64",
        "madvise",
        "memfd_create",
        "mincore",
        "mkdir",
        "mkdirat",
        "mknod",
        "mknodat",
        "mlock",
        "mlock2",
        "mlockall",
        "mmap",
        "mmap2",
        "mprotect",
        "mq_getsetattr",
        "mq_notify",
        "mq_open",
        "mq_timedreceive",
        "mq_timedsend",
        "mq_unlink",
        "mremap",
        "msgctl",
        "msgget",
        "msgrcv",
        "msgsnd",
        "msync",
        "munlock",
        "munlockall",
        "munmap",
        "nanosleep",
        "newfstatat",
        "_newselect",
        "open",
        "openat",
        "pause",
        "pipe",
        "pipe2",
        "poll",
        "ppoll",
        "prctl",
        "pread64",
        "preadv",
        "prlimit64",
        "pselect6",
        "pwrite64",
        "pwritev",
        "read",
        "readahead",
        "readlink",
        "readlinkat",
        "readv",
        "recv",
        "recvfrom",
        "recvmmsg",
        "recvmsg",
        "remap_file_pages",
        "removexattr",
        "rename",
        "renameat",
        "renameat2",
        "restart_syscall",
        "rmdir",
        "rt_sigaction",
        "rt_sigpending",
        "rt_sigprocmask",
        "rt_sigqueueinfo",
        "rt_sigreturn",
        "rt_sigsuspend",
        "rt_sigtimedwait",
        "rt_tgsigqueueinfo",
        "sched_getaffinity",
        "sched_getattr",
        "sched_getparam",
        "sched_get_priority_max",
        "sched_get_priority_min",
        "sched_getscheduler",
        "sched_rr_get_interval",
        "sched_setaffinity",
        "sched_setattr",
        "sched_setparam",
        "sched_setscheduler",
        "sched_yield",
        "seccomp",
        "select",
        "semctl",
        "semget",
        "semop",
        "semtimedop",
        "send",
        "sendfile",
        "sendfile64",
        "sendmmsg",
        "sendmsg",
        "sendto",
        "setfsgid",
        "setfsgid32",
        "setfsuid",
        "setfsuid32",
        "setgid",
        "setgid32",
        "setgroups",
        "setgroups32",
        "setitimer",
        "setpgid",
        "setpriority",
        "setregid",
        "setregid32",
        "setresgid",
        "setresgid32",
        "setresuid",
        "setresuid32",
        "setreuid",
        "setreuid32",
        "setrlimit",
        "set_robust_list",
        "setsid",
        "setsockopt",
        "set_thread_area",
        "set_tid_address",
        "setuid",
        "setuid32",
        "setxattr",
        "shmat",
        "shmctl",
        "shmdt",
        "shmget",
        "shutdown",
        "sigaltstack",
        "signalfd",
        "signalfd4",
        "sigreturn",
        "socket",
        "socketcall",
        "socketpair",
        "splice",
        "stat",
        "stat64",
        "statfs",
        "statfs64",
        "statx",
        "symlink",
        "symlinkat",
        "sync",
        "sync_file_range",
        "syncfs",
        "sysinfo",
        "tee",
        "tgkill",
        "time",
        "timer_create",
        "timer_delete",
        "timerfd_create",
        "timerfd_gettime",
        "timerfd_settime",
        "timer_getoverrun",
        "timer_gettime",
        "timer_settime",
        "times",
        "tkill",
        "truncate",
        "truncate64",
        "ugetrlimit",
        "umask",
        "uname",
        "unlink",
        "unlinkat",
        "utime",
        "utimensat",
        "utimes",
        "vfork",
        "vmsplice",
        "wait4",
        "waitid",
        "waitpid",
        "write",
        "writev"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

3. AppArmor/SELinux配置

bash
# AppArmor配置
# /etc/apparmor.d/docker-nginx
profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>
  
  network inet tcp,
  network inet udp,
  network inet6 tcp,
  network inet6 udp,
  
  deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx,
  deny @{PROC}/sysrq-trigger rwklx,
  deny @{PROC}/mem rwklx,
  deny @{PROC}/kmem rwklx,
  deny @{PROC}/kcore rwklx,
  deny mount,
  deny /sys/[^f]*/** wklx,
  deny /sys/f[^s]*/** wklx,
  deny /sys/fs/[^c]*/** wklx,
  deny /sys/fs/c[^g]*/** wklx,
  deny /sys/fs/cg[^r]*/** wklx,
  deny /sys/firmware/efi/efivars/** rwklx,
  deny /sys/kernel/security/** rwklx,
  
  # 允许nginx访问
  /usr/sbin/nginx mrix,
  /var/log/nginx/** rw,
  /var/cache/nginx/** rw,
  /usr/share/nginx/html/** r,
  /etc/nginx/** r,
}

# 加载AppArmor配置
sudo apparmor_parser -r /etc/apparmor.d/docker-nginx

# 使用AppArmor运行容器
docker run --security-opt apparmor=docker-nginx nginx

🔐 密钥和配置管理

1. Docker Secrets

bash
# 创建secrets
echo "mysecretpassword" | docker secret create db_password -
docker secret create api_key ./api_key.txt

# 在compose中使用secrets
# docker-compose.yml
version: '3.8'

services:
  web:
    image: myapp
    secrets:
      - db_password
      - api_key
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  db_password:
    external: true
  api_key:
    file: ./api_key.txt

2. 环境变量安全

dockerfile
# ❌ 不安全的做法
ENV API_KEY=secret123
ENV DB_PASSWORD=password

# ✅ 安全的做法
# 使用ARG传递构建时密钥,运行时不保留
ARG API_KEY
RUN curl -H "Authorization: Bearer $API_KEY" api.example.com/setup && \
    unset API_KEY

# 使用多阶段构建分离密钥
FROM alpine AS secrets
ARG API_KEY
RUN echo "$API_KEY" > /tmp/api_key

FROM alpine AS runtime
COPY --from=secrets /tmp/api_key /run/secrets/api_key
RUN rm /tmp/api_key

3. 配置文件加密

bash
#!/bin/bash
# encrypt-config.sh

CONFIG_FILE="app.conf"
ENCRYPTED_FILE="app.conf.enc"
KEY_FILE="encryption.key"

# 生成加密密钥
openssl rand -base64 32 > $KEY_FILE

# 加密配置文件
openssl enc -aes-256-cbc -salt -in $CONFIG_FILE -out $ENCRYPTED_FILE -pass file:$KEY_FILE

# 在容器中解密
# COPY decrypt-and-run.sh /usr/local/bin/
# ENTRYPOINT ["/usr/local/bin/decrypt-and-run.sh"]

cat > decrypt-and-run.sh << 'EOF'
#!/bin/sh
# 从环境变量或文件获取密钥
if [ -f "/run/secrets/encryption_key" ]; then
    KEY_FILE="/run/secrets/encryption_key"
else
    echo "Encryption key not found!"
    exit 1
fi

# 解密配置文件
openssl enc -aes-256-cbc -d -in /app/app.conf.enc -out /app/app.conf -pass file:$KEY_FILE

# 启动应用
exec "$@"
EOF

chmod +x decrypt-and-run.sh

🔍 安全扫描和监控

1. 漏洞扫描工具

bash
# 使用Trivy扫描镜像
trivy image myapp:latest

# 扫描文件系统
trivy fs .

# 生成报告
trivy image --format json --output report.json myapp:latest

# 使用Clair扫描
docker run -d --name clair-db postgres:latest
docker run -d --name clair --link clair-db:postgres quay.io/coreos/clair:latest

# 使用Grype扫描
grype myapp:latest

# 使用Snyk扫描
snyk test --docker myapp:latest

# 自动化扫描脚本
#!/bin/bash
# security-scan.sh

IMAGE_NAME=$1
REPORT_DIR="./security-reports"

mkdir -p $REPORT_DIR

echo "🔍 开始安全扫描: $IMAGE_NAME"

# Trivy扫描
echo "📋 Trivy扫描..."
trivy image --format json --output "$REPORT_DIR/trivy-report.json" $IMAGE_NAME
trivy image --format table $IMAGE_NAME

# 检查高危漏洞
HIGH_VULNS=$(trivy image --format json $IMAGE_NAME | jq '.Results[].Vulnerabilities[] | select(.Severity=="HIGH" or .Severity=="CRITICAL") | .VulnerabilityID' | wc -l)

if [ $HIGH_VULNS -gt 0 ]; then
    echo "⚠️ 发现 $HIGH_VULNS 个高危漏洞"
    exit 1
else
    echo "✅ 未发现高危漏洞"
fi

2. 运行时安全监控

bash
# 使用Falco进行运行时监控
# falco-rules.yaml
- rule: Unexpected container behavior
  desc: Detect unexpected behavior in containers
  condition: >
    spawned_process and container and
    (proc.name in (nc, netcat, ncat, nmap, dig, nslookup, tcpdump))
  output: >
    Unexpected process spawned in container
    (user=%user.name command=%proc.cmdline container_id=%container.id 
     container_name=%container.name image=%container.image.repository)
  priority: WARNING

- rule: Container with sensitive mount
  desc: Detect containers with sensitive mounts
  condition: >
    container and container.mounts intersects (/proc, /var/run/docker.sock, /etc)
  output: >
    Container with sensitive mount detected
    (container_id=%container.id container_name=%container.name 
     image=%container.image.repository mounts=%container.mounts)
  priority: WARNING

# 启动Falco
docker run --rm -i -t \
  --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 \
  -v $PWD/falco-rules.yaml:/etc/falco/local_rules.yaml \
  falcosecurity/falco:latest

3. 安全监控脚本

bash
#!/bin/bash
# security-monitor.sh

echo "🔒 Docker安全监控"
echo "=================="

echo ""
echo "1. 🔍 容器权限检查:"
docker ps --format "table {{.Names}}\t{{.Image}}" | while read name image; do
    if [ "$name" != "NAMES" ]; then
        privileged=$(docker inspect $name 2>/dev/null | jq '.[0].HostConfig.Privileged' 2>/dev/null)
        user=$(docker inspect $name 2>/dev/null | jq -r '.[0].Config.User' 2>/dev/null)
        readonly=$(docker inspect $name 2>/dev/null | jq '.[0].HostConfig.ReadonlyRootfs' 2>/dev/null)
        
        echo "  容器: $name"
        echo "    特权模式: ${privileged:-unknown}"
        echo "    运行用户: ${user:-root}"
        echo "    只读根文件系统: ${readonly:-false}"
        echo ""
    fi
done

echo "2. 🌐 网络暴露检查:"
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep -E "0\.0\.0\.0|:::"

echo ""
echo "3. 💾 敏感挂载检查:"
docker inspect $(docker ps -q) 2>/dev/null | \
jq -r '.[] | select(.Mounts != null) | .Name + ": " + (.Mounts[] | select(.Source | test("/etc|/var|/root|/home|/proc|/sys")) | .Source)' 2>/dev/null

echo ""
echo "4. 🔑 Capabilities检查:"
docker ps -q | xargs -I {} docker inspect {} 2>/dev/null | \
jq -r '.[] | .Name + ": " + (.HostConfig.CapAdd // [] | join(","))' 2>/dev/null

echo ""
echo "5. 📊 资源限制检查:"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" 2>/dev/null

📋 安全配置模板

1. 安全的Compose配置

yaml
# docker-compose.secure.yml
version: '3.8'

services:
  web:
    image: myapp:latest
    user: "1000:1000"
    read_only: true
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=100m
      - /var/cache:rw,noexec,nosuid,size=50m
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    security_opt:
      - no-new-privileges:true
      - seccomp:./seccomp-profile.json
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
    networks:
      - frontend
    secrets:
      - api_key
      - db_password
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  db:
    image: postgres:13
    user: "999:999"
    read_only: true
    tmpfs:
      - /tmp:rw,noexec,nosuid
      - /var/run/postgresql:rw,noexec,nosuid
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend
    secrets:
      - db_password
    environment:
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password

networks:
  frontend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16
  backend:
    driver: bridge
    internal: true

volumes:
  db-data:
    driver: local

secrets:
  api_key:
    external: true
  db_password:
    external: true

2. CI/CD安全检查

yaml
# .github/workflows/security.yml
name: Security Checks

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Build image
      run: docker build -t test-image .
    
    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: 'test-image'
        format: 'sarif'
        output: 'trivy-results.sarif'
    
    - name: Upload Trivy scan results
      uses: github/codeql-action/upload-sarif@v2
      with:
        sarif_file: 'trivy-results.sarif'
    
    - name: Run Hadolint
      uses: hadolint/hadolint-action@v2.0.0
      with:
        dockerfile: Dockerfile
    
    - name: Security hardening check
      run: |
        docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
          docker/docker-bench-security

📝 下一步

现在您已经掌握了Docker安全配置,接下来学习:

  1. Docker生产环境部署 - 学习生产部署策略
  2. Docker监控与日志 - 掌握监控和日志管理

🎯 本章要点

  • ✅ 理解Docker安全威胁模型和防护策略
  • ✅ 掌握镜像和容器的安全配置
  • ✅ 学会使用安全扫描和监控工具
  • ✅ 了解密钥管理和访问控制
  • ✅ 掌握安全配置模板和最佳实践

继续深入学习Docker生产环境部署!🐳