Docker 安全最佳实践
本章将深入讲解 Docker 的安全配置和最佳实践,帮助你构建安全的容器化应用,防范常见的安全威胁。
Docker 安全概述
容器安全的重要性
容器技术虽然提供了应用隔离,但与传统虚拟机相比,容器共享主机内核,因此需要特别关注安全配置:
- 内核共享风险:所有容器共享主机内核
- 权限提升:不当配置可能导致容器逃逸
- 镜像安全:恶意镜像可能包含后门或漏洞
- 网络暴露:不当的网络配置可能暴露内部服务
- 数据泄露:敏感数据可能通过容器泄露
Docker 安全模型
┌─────────────────────────────────────────────────────────┐
│ 主机操作系统 │
├─────────────────────────────────────────────────────────┤
│ Docker 守护进程 │
├─────────────────────────────────────────────────────────┤
│ 容器 1 │ 容器 2 │ 容器 3 │
│ ┌───────────┐ │ ┌───────────┐ │ ┌───────────┐ │
│ │ 应用 │ │ │ 应用 │ │ │ 应用 │ │
│ │ Namespace │ │ │ Namespace │ │ │ Namespace │ │
│ │ Cgroups │ │ │ Cgroups │ │ │ Cgroups │ │
│ │ Capabilities│ │ │Capabilities│ │ │Capabilities│ │
│ └───────────┘ │ └───────────┘ │ └───────────┘ │
└─────────────────────────────────────────────────────────┘镜像安全
使用可信的基础镜像
dockerfile
# ✅ 使用官方镜像
FROM node:16-alpine
# ✅ 使用具体版本标签
FROM nginx:1.21.6-alpine
# ❌ 避免使用 latest 标签
FROM ubuntu:latest
# ✅ 使用镜像摘要确保完整性
FROM nginx@sha256:10d1f5b58f74683ad34eb29287e07dab1e90f10af243f151bb50aa5dbb4d62ee
# ✅ 使用最小化镜像
FROM alpine:3.16
FROM scratch # 空镜像,适用于静态编译的程序镜像漏洞扫描
bash
# 使用 Docker 内置扫描
docker scan nginx:latest
# 使用 Trivy 扫描
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image nginx:latest
# 使用 Clair 扫描
docker run -d --name clair-db postgres:latest
docker run -d --name clair --link clair-db:postgres \
quay.io/coreos/clair:latest
# 使用 Anchore 扫描
docker run -d --name anchore-db postgres:latest
docker run -d --name anchore-engine --link anchore-db:anchore-db \
anchore/anchore-engine:latest构建安全的镜像
dockerfile
# 多阶段构建,减少攻击面
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:16-alpine AS runtime
# 创建非特权用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
# 只复制必要文件
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --chown=nextjs:nodejs . .
# 删除不必要的包
RUN apk del .build-deps
# 使用非 root 用户
USER nextjs
# 设置只读根文件系统
# 运行时使用: docker run --read-only myapp镜像签名和验证
bash
# 启用 Docker Content Trust
export DOCKER_CONTENT_TRUST=1
# 推送签名镜像
docker push myregistry/myapp:v1.0
# 拉取时自动验证签名
docker pull myregistry/myapp:v1.0
# 使用 Notary 管理签名
notary init myregistry/myapp
notary publish myregistry/myapp容器运行时安全
用户和权限管理
bash
# ✅ 使用非 root 用户运行
docker run -u 1000:1000 nginx
# ✅ 在 Dockerfile 中创建用户
FROM alpine
RUN adduser -D -s /bin/sh appuser
USER appuser
# ✅ 删除不必要的权限
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
# ✅ 禁用新权限获取
docker run --security-opt no-new-privileges nginx
# ❌ 避免特权模式
docker run --privileged nginx # 危险!Linux Capabilities 管理
bash
# 查看默认 capabilities
docker run --rm -it alpine sh -c 'apk add libcap && capsh --print'
# 删除所有 capabilities
docker run --cap-drop=ALL alpine
# 只添加必要的 capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
# 常用 capabilities
# NET_BIND_SERVICE: 绑定特权端口 (<1024)
# SYS_TIME: 修改系统时间
# NET_ADMIN: 网络管理
# SYS_ADMIN: 系统管理(危险)资源限制
bash
# 内存限制
docker run -m 512m nginx
# CPU 限制
docker run --cpus="1.5" nginx
# 进程数限制
docker run --pids-limit 100 nginx
# 文件描述符限制
docker run --ulimit nofile=1024:1024 nginx
# 磁盘 I/O 限制
docker run --device-read-bps /dev/sda:1mb nginx文件系统安全
bash
# 只读根文件系统
docker run --read-only nginx
# 只读根文件系统 + 临时文件系统
docker run --read-only --tmpfs /tmp --tmpfs /var/run nginx
# 禁用 suid/sgid 程序
docker run --security-opt no-new-privileges nginx
# 使用 AppArmor 配置文件
docker run --security-opt apparmor:docker-default nginx
# 使用 SELinux 标签
docker run --security-opt label:type:container_t nginx网络安全
网络隔离
bash
# 创建隔离网络
docker network create --internal backend-network
# 运行在隔离网络中
docker run --network backend-network postgres
# 禁用网络
docker run --network none alpine
# 使用主机网络(谨慎使用)
docker run --network host nginx端口和服务暴露
bash
# ✅ 只暴露必要端口
docker run -p 127.0.0.1:8080:80 nginx # 只绑定本地接口
# ✅ 使用非标准端口
docker run -p 8080:80 nginx
# ❌ 避免暴露所有端口
docker run -P nginx # 可能暴露不必要的端口
# ✅ 使用防火墙规则
iptables -A INPUT -p tcp --dport 8080 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROPTLS 和加密
yaml
# docker-compose.yml 中配置 TLS
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./ssl/cert.pem:/etc/nginx/ssl/cert.pem:ro
- ./ssl/key.pem:/etc/nginx/ssl/key.pem:ro
- ./nginx-ssl.conf:/etc/nginx/nginx.conf:ro
environment:
- SSL_CERT_PATH=/etc/nginx/ssl/cert.pem
- SSL_KEY_PATH=/etc/nginx/ssl/key.pem秘密信息管理
避免在镜像中存储秘密
dockerfile
# ❌ 不要在镜像中硬编码秘密
ENV API_KEY=secret123
COPY secret.key /app/
# ✅ 使用运行时注入
# 通过环境变量或挂载文件传递使用 Docker Secrets
bash
# 创建 secret
echo "mysecretpassword" | docker secret create db_password -
# 在服务中使用 secret
docker service create \
--name myapp \
--secret db_password \
myapp:latest
# 在容器中访问 secret(位于 /run/secrets/)
cat /run/secrets/db_password使用外部秘密管理
yaml
# 使用 HashiCorp Vault
version: '3.8'
services:
app:
image: myapp:latest
environment:
- VAULT_ADDR=https://vault.company.com
- VAULT_TOKEN_FILE=/run/secrets/vault_token
secrets:
- vault_token
command: |
sh -c '
export VAULT_TOKEN=$$(cat /run/secrets/vault_token)
export DB_PASSWORD=$$(vault kv get -field=password secret/db)
exec myapp
'
secrets:
vault_token:
external: true日志和监控安全
安全日志配置
bash
# 配置日志驱动
docker run --log-driver=syslog \
--log-opt syslog-address=tcp://logserver:514 \
--log-opt tag="{{.Name}}" \
nginx
# 限制日志大小
docker run --log-driver=json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx
# 发送到集中日志系统
docker run --log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag="docker.{{.Name}}" \
nginx安全监控
yaml
# 使用 Falco 进行运行时安全监控
version: '3.8'
services:
falco:
image: falcosecurity/falco:latest
privileged: true
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- /dev:/host/dev
- /proc:/host/proc:ro
- /boot:/host/boot:ro
- /lib/modules:/host/lib/modules:ro
- /usr:/host/usr:ro
- /etc:/host/etc:ro
command: falco --modern-bpfDocker 守护进程安全
守护进程配置
json
// /etc/docker/daemon.json
{
"icc": false, // 禁用容器间通信
"userland-proxy": false, // 禁用用户态代理
"no-new-privileges": true, // 禁用新权限
"selinux-enabled": true, // 启用 SELinux
"userns-remap": "default", // 启用用户命名空间
"live-restore": true, // 守护进程重启时保持容器运行
"log-driver": "json-file", // 配置日志驱动
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2", // 使用安全的存储驱动
"tls": true, // 启用 TLS
"tlscert": "/etc/docker/cert.pem",
"tlskey": "/etc/docker/key.pem",
"tlsverify": true,
"tlscacert": "/etc/docker/ca.pem"
}TLS 配置
bash
# 生成 CA 私钥
openssl genrsa -aes256 -out ca-key.pem 4096
# 生成 CA 证书
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# 生成服务器私钥
openssl genrsa -out server-key.pem 4096
# 生成服务器证书签名请求
openssl req -subj "/CN=docker-host" -sha256 -new -key server-key.pem -out server.csr
# 签名服务器证书
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -out server-cert.pem
# 生成客户端私钥和证书
openssl genrsa -out key.pem 4096
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -out cert.pem
# 启动带 TLS 的 Docker 守护进程
dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376安全扫描和审计
容器安全扫描
bash
# 使用 Docker Bench Security
git clone https://github.com/docker/docker-bench-security.git
cd docker-bench-security
sudo sh docker-bench-security.sh
# 使用 Lynis 系统审计
docker run --rm -v /:/rootfs:ro --pid=host cisofy/lynis audit system
# 使用 OpenSCAP 合规性检查
docker run --rm -v /:/host:ro --privileged \
quay.io/compliance-operator/openscap:latest \
oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_docker \
/usr/share/xml/scap/ssg/content/ssg-rhel7-ds.xml运行时安全监控
yaml
# 使用 Sysdig Falco
version: '3.8'
services:
falco:
image: falcosecurity/falco:latest
privileged: true
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- /dev:/host/dev
- /proc:/host/proc:ro
- /boot:/host/boot:ro
- /lib/modules:/host/lib/modules:ro
- /usr:/host/usr:ro
- /etc:/host/etc:ro
- ./falco_rules.yaml:/etc/falco/falco_rules.local.yaml
environment:
- FALCO_GRPC_ENABLED=true
- FALCO_GRPC_BIND_ADDRESS=0.0.0.0:5060合规性和标准
CIS Docker Benchmark
bash
# 下载 CIS Docker Benchmark
wget https://www.cisecurity.org/cis-benchmarks/
# 主要检查项目:
# 1. 主机配置
# 2. Docker 守护进程配置
# 3. Docker 守护进程配置文件
# 4. 容器镜像和构建文件
# 5. 容器运行时
# 6. Docker 安全操作NIST 容器安全指南
遵循 NIST SP 800-190 容器安全指南:
- 镜像安全:使用可信镜像源,定期扫描漏洞
- 注册表安全:保护镜像注册表,使用访问控制
- 编排器安全:配置 Kubernetes/Swarm 安全策略
- 容器安全:最小权限原则,资源限制
- 主机安全:加固主机操作系统
实战安全配置
生产环境安全配置
yaml
version: '3.8'
services:
web:
image: myapp:v1.0
user: "1000:1000"
read_only: true
tmpfs:
- /tmp
- /var/run
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
- apparmor:docker-default
networks:
- frontend
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
db:
image: postgres:13-alpine
user: "999:999"
read_only: true
tmpfs:
- /tmp
- /var/run/postgresql
volumes:
- db_data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
networks:
- backend
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
db_data:
driver: local
secrets:
db_password:
external: true安全检查清单
镜像安全:
- [ ] 使用官方或可信的基础镜像
- [ ] 使用具体版本标签,避免 latest
- [ ] 定期扫描镜像漏洞
- [ ] 使用多阶段构建减少攻击面
- [ ] 不在镜像中存储秘密信息
容器运行时安全:
- [ ] 使用非 root 用户运行容器
- [ ] 启用只读根文件系统
- [ ] 删除不必要的 Linux capabilities
- [ ] 设置资源限制
- [ ] 禁用新权限获取
网络安全:
- [ ] 使用自定义网络隔离服务
- [ ] 只暴露必要的端口
- [ ] 使用 TLS 加密通信
- [ ] 配置防火墙规则
数据安全:
- [ ] 使用 Docker secrets 管理敏感信息
- [ ] 加密静态数据
- [ ] 定期备份重要数据
- [ ] 实施访问控制
监控和审计:
- [ ] 配置安全日志记录
- [ ] 实施运行时安全监控
- [ ] 定期进行安全审计
- [ ] 建立事件响应流程
本章小结
本章全面介绍了 Docker 安全的各个方面:
关键要点:
- 镜像安全:使用可信镜像,定期扫描漏洞
- 运行时安全:最小权限原则,资源限制
- 网络安全:网络隔离,TLS 加密
- 秘密管理:避免硬编码,使用专门工具
- 监控审计:实时监控,定期审计
安全原则:
- 最小权限原则
- 深度防御策略
- 定期更新和扫描
- 持续监控和审计
- 事件响应准备
在下一章中,我们将学习 Docker 的性能优化,包括镜像优化、容器性能调优和资源管理。