学习目标
通过本章学习,您将能够:
- 理解 Docker Swarm 安全架构和机制
- 掌握集群安全配置和加固
- 学会密钥和证书管理
- 了解访问控制和权限管理
- 掌握安全扫描和合规性检查
1. 安全架构概述
1.1 Swarm 安全模型
安全组件
# Docker Swarm 安全组件:
# 1. TLS 加密
# - 节点间通信加密
# - 客户端-服务器通信加密
# - 证书自动轮换
# 2. 相互认证
# - 节点身份验证
# - 客户端身份验证
# - 基于证书的认证
# 3. 授权机制
# - 基于角色的访问控制(RBAC)
# - 节点角色管理
# - 服务权限控制
# 4. 密钥管理
# - Docker Secrets
# - 密钥轮换
# - 加密存储
# 5. 网络安全
# - 网络隔离
# - 流量加密
# - 防火墙规则
安全架构图
# Swarm 安全架构:
┌─────────────────────────────────────────────────────────────┐
│ Docker Swarm Cluster │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Manager │ │ Manager │ │ Worker │ │
│ │ Node │◄──►│ Node │◄──►│ Node │ │
│ │ │ │ │ │ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ TLS │ │ │ │ TLS │ │ │ │ TLS │ │ │
│ │ │ Cert │ │ │ │ Cert │ │ │ │ Cert │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Encrypted Communication │ │
│ │ (TLS 1.3) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Secrets Store │ │
│ │ (Encrypted at Rest) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ External CA │
│ (Optional) │
└─────────────────┘
1.2 威胁模型分析
常见安全威胁
# Docker Swarm 面临的安全威胁:
# 1. 网络攻击
# - 中间人攻击
# - 网络窃听
# - DDoS 攻击
# - 端口扫描
# 2. 容器逃逸
# - 特权容器滥用
# - 内核漏洞利用
# - 资源限制绕过
# - 文件系统挂载攻击
# 3. 镜像安全
# - 恶意镜像
# - 漏洞镜像
# - 供应链攻击
# - 镜像篡改
# 4. 密钥泄露
# - 硬编码密钥
# - 环境变量泄露
# - 日志泄露
# - 内存转储
# 5. 权限提升
# - 容器特权滥用
# - 主机权限获取
# - 集群管理权限
# - 服务账户滥用
安全防护策略
# 多层防护策略:
# 1. 网络层防护
# - 防火墙配置
# - 网络分段
# - 流量加密
# - 入侵检测
# 2. 主机层防护
# - 操作系统加固
# - 访问控制
# - 审计日志
# - 安全更新
# 3. 容器层防护
# - 镜像扫描
# - 运行时保护
# - 资源限制
# - 安全配置
# 4. 应用层防护
# - 代码审计
# - 输入验证
# - 身份认证
# - 授权控制
# 5. 数据层防护
# - 数据加密
# - 访问控制
# - 备份保护
# - 合规性检查
2. 集群安全配置
2.1 TLS 配置
查看集群证书信息
# 查看集群 TLS 信息
docker info --format '{{.Swarm.Cluster.TLSInfo}}'
# 查看节点证书
docker node inspect self --format '{{.Description.TLSInfo}}'
# 查看证书有效期
docker swarm ca --cert-expiry 90d
# 查看 CA 证书
docker swarm ca --print
证书轮换
# 轮换集群证书
docker swarm ca --rotate
# 设置证书有效期
docker swarm ca --cert-expiry 30d
# 强制轮换节点证书
docker swarm update-ca --rotate
# 查看轮换状态
docker node ls --format "table {{.Hostname}}\t{{.Status}}\t{{.TLSStatus}}"
外部 CA 集成
# 配置外部 CA
docker swarm ca \
--external-ca protocol=cfssl,url=https://ca.example.com:8888 \
--ca-cert ca.pem \
--ca-key ca-key.pem
# 使用外部根 CA
docker swarm init \
--external-ca protocol=cfssl,url=https://ca.example.com:8888,cacert=ca.pem
# 验证外部 CA 配置
docker info --format '{{.Swarm.Cluster.Spec.CAConfig}}'
2.2 节点安全
节点加入令牌管理
# 查看加入令牌
docker swarm join-token worker
docker swarm join-token manager
# 轮换加入令牌
docker swarm join-token --rotate worker
docker swarm join-token --rotate manager
# 查看令牌信息
docker swarm join-token --quiet worker
docker swarm join-token --quiet manager
节点标签和约束
# 添加安全标签
docker node update --label-add security.zone=dmz node1
docker node update --label-add security.level=high node2
docker node update --label-add compliance.pci=true node3
# 基于安全标签部署服务
docker service create --name secure-app \
--constraint 'node.labels.security.level == high' \
--constraint 'node.labels.compliance.pci == true' \
my-secure-app:latest
# 查看节点标签
docker node inspect node1 --format '{{.Spec.Labels}}'
2.3 安全配置脚本
集群安全加固脚本
#!/bin/bash
# swarm-security-hardening.sh
# 安全配置参数
CERT_EXPIRY="30d"
LOG_LEVEL="info"
SECURITY_OPTS="no-new-privileges:true"
READ_ONLY_ROOT="true"
# 日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# 检查是否为管理节点
check_manager_node() {
if ! docker node ls > /dev/null 2>&1; then
log "ERROR: This script must be run on a manager node"
exit 1
fi
}
# 配置证书安全
configure_certificate_security() {
log "Configuring certificate security..."
# 设置证书有效期
docker swarm ca --cert-expiry $CERT_EXPIRY
# 轮换加入令牌
log "Rotating join tokens..."
docker swarm join-token --rotate worker > /dev/null
docker swarm join-token --rotate manager > /dev/null
# 检查证书状态
log "Certificate status:"
docker node ls --format "table {{.Hostname}}\t{{.Status}}\t{{.TLSStatus}}"
}
# 配置节点安全标签
configure_node_security_labels() {
log "Configuring node security labels..."
# 为每个节点添加安全标签
for node in $(docker node ls --format '{{.Hostname}}'); do
# 检查节点角色
role=$(docker node inspect $node --format '{{.Spec.Role}}')
# 添加基础安全标签
docker node update --label-add security.role=$role $node
docker node update --label-add security.hardened=true $node
docker node update --label-add security.scan.date=$(date +%Y%m%d) $node
log "Security labels added to node: $node (role: $role)"
done
}
# 配置服务安全默认值
configure_service_security_defaults() {
log "Configuring service security defaults..."
# 创建安全配置文件
cat > /tmp/secure-service-template.yml << 'EOF'
version: '3.8'
services:
secure-template:
image: placeholder
deploy:
replicas: 1
placement:
constraints:
- node.labels.security.hardened == true
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.1'
memory: 128M
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:size=100M,noexec,nosuid,nodev
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
user: "1000:1000"
EOF
log "Secure service template created at /tmp/secure-service-template.yml"
}
# 配置网络安全
configure_network_security() {
log "Configuring network security..."
# 创建加密网络
docker network create \
--driver overlay \
--opt encrypted \
--label security.encrypted=true \
secure-network
# 创建隔离网络
docker network create \
--driver overlay \
--opt encrypted \
--subnet 10.99.0.0/24 \
--label security.isolated=true \
isolated-network
log "Secure networks created"
}
# 配置密钥管理
configure_secrets_management() {
log "Configuring secrets management..."
# 创建示例密钥
echo "example-secret-$(date +%s)" | docker secret create example-secret -
# 创建 TLS 证书密钥
openssl req -new -x509 -days 365 -nodes \
-out /tmp/server.crt \
-keyout /tmp/server.key \
-subj "/C=US/ST=CA/L=SF/O=Example/CN=example.com"
docker secret create server.crt /tmp/server.crt
docker secret create server.key /tmp/server.key
# 清理临时文件
rm -f /tmp/server.crt /tmp/server.key
log "Secrets configured"
}
# 配置审计日志
configure_audit_logging() {
log "Configuring audit logging..."
# 创建审计日志配置
cat > /etc/docker/daemon.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
},
"log-level": "info",
"userland-proxy": false,
"experimental": false,
"live-restore": true
}
EOF
log "Audit logging configured (requires Docker restart)"
}
# 安全扫描
perform_security_scan() {
log "Performing security scan..."
# 检查不安全的配置
echo "\n=== Security Scan Results ==="
# 检查特权容器
echo "\nChecking for privileged containers:"
docker ps --filter "label=privileged=true" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}" || echo "No privileged containers found"
# 检查未加密网络
echo "\nChecking for unencrypted networks:"
for network in $(docker network ls --filter driver=overlay --format '{{.Name}}'); do
encrypted=$(docker network inspect $network --format '{{.Options.encrypted}}')
if [ "$encrypted" != "true" ]; then
echo " Unencrypted network: $network"
fi
done
# 检查未使用的密钥
echo "\nChecking for unused secrets:"
for secret in $(docker secret ls --format '{{.Name}}'); do
used=$(docker service ls --filter "secret=$secret" --format '{{.Name}}')
if [ -z "$used" ]; then
echo " Unused secret: $secret"
fi
done
# 检查节点安全状态
echo "\nNode security status:"
docker node ls --format "table {{.Hostname}}\t{{.Status}}\t{{.Availability}}\t{{.ManagerStatus}}"
}
# 生成安全报告
generate_security_report() {
local report_file="/tmp/swarm-security-report-$(date +%Y%m%d_%H%M%S).txt"
log "Generating security report: $report_file"
{
echo "Docker Swarm Security Report"
echo "Generated: $(date)"
echo "========================================"
echo "\nCluster Information:"
docker info --format 'Swarm: {{.Swarm.LocalNodeState}}'
docker info --format 'Nodes: {{.Swarm.Nodes}}'
docker info --format 'Managers: {{.Swarm.Managers}}'
echo "\nTLS Configuration:"
docker info --format 'TLS Info: {{.Swarm.Cluster.TLSInfo}}'
echo "\nNode Status:"
docker node ls
echo "\nNetwork Security:"
docker network ls --filter driver=overlay
echo "\nSecrets:"
docker secret ls
echo "\nServices:"
docker service ls
echo "\nSecurity Scan:"
perform_security_scan
} > $report_file
log "Security report generated: $report_file"
}
# 主函数
main() {
log "Starting Docker Swarm security hardening..."
check_manager_node
case "${1:-all}" in
"certificates")
configure_certificate_security
;;
"labels")
configure_node_security_labels
;;
"services")
configure_service_security_defaults
;;
"network")
configure_network_security
;;
"secrets")
configure_secrets_management
;;
"audit")
configure_audit_logging
;;
"scan")
perform_security_scan
;;
"report")
generate_security_report
;;
"all")
configure_certificate_security
configure_node_security_labels
configure_service_security_defaults
configure_network_security
configure_secrets_management
configure_audit_logging
perform_security_scan
generate_security_report
;;
*)
echo "Usage: $0 {certificates|labels|services|network|secrets|audit|scan|report|all}"
exit 1
;;
esac
log "Security hardening completed"
}
# 执行主函数
main "$@"
3. 密钥和证书管理
3.1 Docker Secrets
基本密钥操作
# 创建密钥
echo "my-secret-password" | docker secret create db-password -
# 从文件创建密钥
docker secret create ssl-cert ./server.crt
docker secret create ssl-key ./server.key
# 查看密钥列表
docker secret ls
# 查看密钥详情
docker secret inspect db-password
# 删除密钥
docker secret rm db-password
服务中使用密钥
# 在服务中使用密钥
docker service create --name web \
--secret ssl-cert \
--secret ssl-key \
--secret source=db-password,target=db_pass \
nginx
# 指定密钥挂载路径和权限
docker service create --name app \
--secret source=ssl-cert,target=/etc/ssl/cert.pem,mode=0400 \
--secret source=ssl-key,target=/etc/ssl/key.pem,mode=0400 \
my-app:latest
# 查看服务密钥
docker service inspect web --format '{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{.SecretName}} -> {{.File.Name}}{{end}}'
密钥轮换
# 创建新版本密钥
echo "new-secret-password" | docker secret create db-password-v2 -
# 更新服务使用新密钥
docker service update \
--secret-rm db-password \
--secret-add source=db-password-v2,target=db_pass \
web
# 删除旧密钥
docker secret rm db-password
# 重命名新密钥
docker secret create db-password-temp -
echo "final-password" | docker secret create db-password -
docker secret rm db-password-temp
3.2 密钥管理最佳实践
密钥管理脚本
#!/bin/bash
# secrets-manager.sh
SECRETS_DIR="/secure/secrets"
BACKUP_DIR="/secure/backups"
LOG_FILE="/var/log/secrets-manager.log"
# 日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
# 创建密钥
create_secret() {
local secret_name=$1
local secret_file=$2
local description=$3
if [ ! -f "$secret_file" ]; then
log "ERROR: Secret file not found: $secret_file"
return 1
fi
# 检查密钥是否已存在
if docker secret inspect $secret_name > /dev/null 2>&1; then
log "WARNING: Secret $secret_name already exists"
return 1
fi
# 创建密钥
docker secret create $secret_name $secret_file
if [ $? -eq 0 ]; then
# 添加标签
docker secret update \
--label-add description="$description" \
--label-add created=$(date +%Y%m%d) \
--label-add source-file=$(basename $secret_file) \
$secret_name
log "SUCCESS: Secret $secret_name created"
# 备份密钥元数据
docker secret inspect $secret_name > "$BACKUP_DIR/${secret_name}.json"
return 0
else
log "ERROR: Failed to create secret $secret_name"
return 1
fi
}
# 轮换密钥
rotate_secret() {
local secret_name=$1
local new_secret_file=$2
local services=$(docker service ls --filter "secret=$secret_name" --format '{{.Name}}')
if [ -z "$services" ]; then
log "WARNING: No services using secret $secret_name"
fi
log "Rotating secret: $secret_name"
log "Affected services: $services"
# 创建新版本密钥
local new_secret_name="${secret_name}-new-$(date +%s)"
docker secret create $new_secret_name $new_secret_file
if [ $? -ne 0 ]; then
log "ERROR: Failed to create new secret version"
return 1
fi
# 更新使用该密钥的服务
for service in $services; do
log "Updating service: $service"
# 获取当前密钥配置
local secret_config=$(docker service inspect $service --format '{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{if eq .SecretName "'$secret_name'"}}{{.File.Name}}:{{.File.Mode}}{{end}}{{end}}')
if [ -n "$secret_config" ]; then
local target_name=$(echo $secret_config | cut -d: -f1)
local mode=$(echo $secret_config | cut -d: -f2)
# 更新服务
docker service update \
--secret-rm $secret_name \
--secret-add source=$new_secret_name,target=$target_name,mode=$mode \
$service
if [ $? -eq 0 ]; then
log "SUCCESS: Service $service updated"
else
log "ERROR: Failed to update service $service"
fi
fi
done
# 删除旧密钥
docker secret rm $secret_name
# 重命名新密钥
docker secret create $secret_name $new_secret_file
docker secret rm $new_secret_name
log "Secret rotation completed: $secret_name"
}
# 备份密钥
backup_secrets() {
local backup_file="$BACKUP_DIR/secrets-backup-$(date +%Y%m%d_%H%M%S).tar.gz"
log "Starting secrets backup..."
mkdir -p $BACKUP_DIR
# 导出所有密钥元数据
for secret in $(docker secret ls --format '{{.Name}}'); do
docker secret inspect $secret > "$BACKUP_DIR/${secret}.json"
done
# 创建备份归档
tar czf $backup_file -C $BACKUP_DIR *.json
# 清理临时文件
rm -f $BACKUP_DIR/*.json
log "Secrets backup completed: $backup_file"
}
# 密钥审计
audit_secrets() {
log "Starting secrets audit..."
echo "\n=== Secrets Audit Report ==="
echo "Generated: $(date)"
echo "\nSecret Inventory:"
printf "%-20s %-15s %-20s %-30s\n" "NAME" "CREATED" "UPDATED" "SERVICES"
printf "%-20s %-15s %-20s %-30s\n" "----" "-------" "-------" "--------"
for secret in $(docker secret ls --format '{{.Name}}'); do
local created=$(docker secret inspect $secret --format '{{.CreatedAt}}' | cut -d'T' -f1)
local updated=$(docker secret inspect $secret --format '{{.UpdatedAt}}' | cut -d'T' -f1)
local services=$(docker service ls --filter "secret=$secret" --format '{{.Name}}' | tr '\n' ',' | sed 's/,$//')
printf "%-20s %-15s %-20s %-30s\n" "$secret" "$created" "$updated" "$services"
done
# 检查未使用的密钥
echo "\nUnused Secrets:"
for secret in $(docker secret ls --format '{{.Name}}'); do
local services=$(docker service ls --filter "secret=$secret" --format '{{.Name}}')
if [ -z "$services" ]; then
echo " - $secret"
fi
done
# 检查过期密钥(基于标签)
echo "\nExpiring Secrets (created > 90 days ago):"
for secret in $(docker secret ls --format '{{.Name}}'); do
local created_label=$(docker secret inspect $secret --format '{{.Spec.Labels.created}}')
if [ -n "$created_label" ]; then
local days_old=$(( ($(date +%s) - $(date -d $created_label +%s)) / 86400 ))
if [ $days_old -gt 90 ]; then
echo " - $secret (${days_old} days old)"
fi
fi
done
}
# 清理未使用的密钥
cleanup_unused_secrets() {
log "Cleaning up unused secrets..."
for secret in $(docker secret ls --format '{{.Name}}'); do
local services=$(docker service ls --filter "secret=$secret" --format '{{.Name}}')
if [ -z "$services" ]; then
echo "Removing unused secret: $secret"
docker secret rm $secret
log "Removed unused secret: $secret"
fi
done
}
# 主菜单
case "$1" in
"create")
if [ -n "$2" ] && [ -n "$3" ]; then
create_secret $2 $3 "$4"
else
echo "Usage: $0 create <secret-name> <secret-file> [description]"
fi
;;
"rotate")
if [ -n "$2" ] && [ -n "$3" ]; then
rotate_secret $2 $3
else
echo "Usage: $0 rotate <secret-name> <new-secret-file>"
fi
;;
"backup")
backup_secrets
;;
"audit")
audit_secrets
;;
"cleanup")
cleanup_unused_secrets
;;
*)
echo "Usage: $0 {create|rotate|backup|audit|cleanup}"
echo " create <name> <file> [desc] - Create new secret"
echo " rotate <name> <file> - Rotate existing secret"
echo " backup - Backup secrets metadata"
echo " audit - Audit secrets usage"
echo " cleanup - Remove unused secrets"
;;
esac
3.3 外部密钥管理集成
HashiCorp Vault 集成
# 部署 Vault 服务
docker service create --name vault \
--publish 8200:8200 \
--mount type=volume,source=vault-data,target=/vault/data \
--env VAULT_DEV_ROOT_TOKEN_ID=myroot \
--env VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \
vault:latest
# Vault 密钥同步脚本
cat > vault-sync.sh << 'EOF'
#!/bin/bash
VAULT_ADDR="http://vault:8200"
VAULT_TOKEN="myroot"
# 从 Vault 获取密钥并创建 Docker Secret
sync_secret_from_vault() {
local secret_path=$1
local secret_name=$2
# 从 Vault 获取密钥
secret_value=$(curl -s \
-H "X-Vault-Token: $VAULT_TOKEN" \
$VAULT_ADDR/v1/secret/data/$secret_path | \
jq -r '.data.data.value')
if [ "$secret_value" != "null" ]; then
# 创建或更新 Docker Secret
echo "$secret_value" | docker secret create $secret_name - 2>/dev/null || \
{
# 如果密钥已存在,进行轮换
echo "$secret_value" | docker secret create ${secret_name}-new -
# 这里需要更新使用该密钥的服务
docker secret rm $secret_name
echo "$secret_value" | docker secret create $secret_name -
docker secret rm ${secret_name}-new
}
echo "Secret $secret_name synced from Vault"
else
echo "Failed to retrieve secret from Vault: $secret_path"
fi
}
# 同步多个密钥
sync_secret_from_vault "database/password" "db-password"
sync_secret_from_vault "ssl/certificate" "ssl-cert"
sync_secret_from_vault "ssl/private-key" "ssl-key"
EOF
chmod +x vault-sync.sh
4. 访问控制和权限管理
4.1 基于角色的访问控制
用户和角色管理
# Docker 不直接支持用户管理,但可以通过以下方式实现:
# 1. 使用客户端证书认证
# 生成客户端证书
openssl genrsa -out client-key.pem 4096
openssl req -new -key client-key.pem -out client.csr -subj "/CN=client"
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca-key.pem -out client-cert.pem -days 365
# 2. 配置 Docker 客户端使用证书
export DOCKER_HOST=tcp://manager-node:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/path/to/certs
# 3. 测试连接
docker --tlsverify --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem -H=manager-node:2376 version
服务权限控制
# 使用约束限制服务部署
docker service create --name restricted-app \
--constraint 'node.role == worker' \
--constraint 'node.labels.security.level == high' \
--user 1000:1000 \
--cap-drop ALL \
--cap-add CHOWN \
--cap-add SETGID \
--cap-add SETUID \
--read-only \
--security-opt no-new-privileges:true \
my-app:latest
# 网络访问控制
docker service create --name isolated-app \
--network isolated-network \
--constraint 'node.labels.network.zone == isolated' \
my-isolated-app:latest
4.2 权限管理脚本
访问控制管理
#!/bin/bash
# access-control-manager.sh
CERTS_DIR="/etc/docker/certs"
USERS_DIR="/etc/docker/users"
LOG_FILE="/var/log/docker-access.log"
# 日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
# 创建用户证书
create_user_cert() {
local username=$1
local role=${2:-worker} # worker, manager, admin
local days=${3:-365}
log "Creating certificate for user: $username (role: $role)"
# 创建用户目录
local user_dir="$USERS_DIR/$username"
mkdir -p $user_dir
# 生成私钥
openssl genrsa -out $user_dir/key.pem 4096
# 生成证书请求
openssl req -new \
-key $user_dir/key.pem \
-out $user_dir/cert.csr \
-subj "/CN=$username/O=$role"
# 签发证书
openssl x509 -req \
-in $user_dir/cert.csr \
-CA $CERTS_DIR/ca.pem \
-CAkey $CERTS_DIR/ca-key.pem \
-out $user_dir/cert.pem \
-days $days \
-extensions v3_req
# 设置权限
chmod 400 $user_dir/key.pem
chmod 444 $user_dir/cert.pem
chown -R $username:$username $user_dir 2>/dev/null || true
# 创建用户配置文件
cat > $user_dir/docker-env << EOF
export DOCKER_HOST=tcp://$(hostname):2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=$user_dir
EOF
# 记录用户信息
echo "$username:$role:$(date +%Y%m%d):$days" >> $USERS_DIR/users.db
log "Certificate created for user: $username"
echo "User certificate created at: $user_dir"
echo "To use: source $user_dir/docker-env"
}
# 撤销用户证书
revoke_user_cert() {
local username=$1
log "Revoking certificate for user: $username"
local user_dir="$USERS_DIR/$username"
if [ -d "$user_dir" ]; then
# 移动到撤销目录
local revoked_dir="$USERS_DIR/revoked/$username-$(date +%Y%m%d_%H%M%S)"
mkdir -p $(dirname $revoked_dir)
mv $user_dir $revoked_dir
# 从用户数据库中移除
sed -i "/^$username:/d" $USERS_DIR/users.db
log "Certificate revoked for user: $username"
echo "Certificate moved to: $revoked_dir"
else
log "ERROR: User directory not found: $user_dir"
return 1
fi
}
# 列出用户
list_users() {
echo "=== Docker Users ==="
printf "%-15s %-10s %-12s %-10s\n" "USERNAME" "ROLE" "CREATED" "VALIDITY"
printf "%-15s %-10s %-12s %-10s\n" "--------" "----" "-------" "--------"
if [ -f "$USERS_DIR/users.db" ]; then
while IFS=':' read -r username role created days; do
printf "%-15s %-10s %-12s %-10s\n" "$username" "$role" "$created" "${days}d"
done < $USERS_DIR/users.db
fi
}
# 检查证书有效性
check_cert_validity() {
local username=$1
local user_dir="$USERS_DIR/$username"
if [ ! -f "$user_dir/cert.pem" ]; then
echo "Certificate not found for user: $username"
return 1
fi
echo "Certificate information for user: $username"
openssl x509 -in $user_dir/cert.pem -text -noout | grep -E "Subject:|Not Before:|Not After:"
# 检查是否即将过期
local expiry_date=$(openssl x509 -in $user_dir/cert.pem -enddate -noout | cut -d= -f2)
local expiry_timestamp=$(date -d "$expiry_date" +%s)
local current_timestamp=$(date +%s)
local days_until_expiry=$(( (expiry_timestamp - current_timestamp) / 86400 ))
if [ $days_until_expiry -lt 30 ]; then
echo "WARNING: Certificate expires in $days_until_expiry days"
else
echo "Certificate valid for $days_until_expiry days"
fi
}
# 更新用户角色
update_user_role() {
local username=$1
local new_role=$2
log "Updating role for user: $username to $new_role"
# 更新用户数据库
if grep -q "^$username:" $USERS_DIR/users.db; then
sed -i "s/^$username:[^:]*:/$username:$new_role:/" $USERS_DIR/users.db
log "Role updated for user: $username"
else
log "ERROR: User not found: $username"
return 1
fi
}
# 生成访问报告
generate_access_report() {
local report_file="/tmp/docker-access-report-$(date +%Y%m%d_%H%M%S).txt"
log "Generating access report: $report_file"
{
echo "Docker Access Control Report"
echo "Generated: $(date)"
echo "========================================"
echo "\nUser Summary:"
list_users
echo "\nCertificate Status:"
if [ -f "$USERS_DIR/users.db" ]; then
while IFS=':' read -r username role created days; do
echo "\nUser: $username"
check_cert_validity $username
done < $USERS_DIR/users.db
fi
echo "\nRevoked Certificates:"
if [ -d "$USERS_DIR/revoked" ]; then
ls -la $USERS_DIR/revoked/
else
echo "No revoked certificates"
fi
echo "\nAccess Log Summary (last 24 hours):"
if [ -f "$LOG_FILE" ]; then
grep "$(date -d '1 day ago' +%Y-%m-%d)" $LOG_FILE | tail -20
fi
} > $report_file
log "Access report generated: $report_file"
}
# 主菜单
case "$1" in
"create")
if [ -n "$2" ]; then
create_user_cert $2 $3 $4
else
echo "Usage: $0 create <username> [role] [days]"
fi
;;
"revoke")
if [ -n "$2" ]; then
revoke_user_cert $2
else
echo "Usage: $0 revoke <username>"
fi
;;
"list")
list_users
;;
"check")
if [ -n "$2" ]; then
check_cert_validity $2
else
echo "Usage: $0 check <username>"
fi
;;
"update")
if [ -n "$2" ] && [ -n "$3" ]; then
update_user_role $2 $3
else
echo "Usage: $0 update <username> <new-role>"
fi
;;
"report")
generate_access_report
;;
*)
echo "Usage: $0 {create|revoke|list|check|update|report}"
echo " create <user> [role] [days] - Create user certificate"
echo " revoke <user> - Revoke user certificate"
echo " list - List all users"
echo " check <user> - Check certificate validity"
echo " update <user> <role> - Update user role"
echo " report - Generate access report"
;;
esac
5. 安全扫描和合规性
5.1 镜像安全扫描
使用 Docker Scout 扫描
# 启用 Docker Scout
docker scout --help
# 扫描本地镜像
docker scout cves nginx:latest
# 扫描并显示详细信息
docker scout cves --details nginx:latest
# 扫描特定严重级别的漏洞
docker scout cves --severity critical,high nginx:latest
# 生成 SARIF 报告
docker scout cves --format sarif nginx:latest > nginx-scan.sarif
使用 Trivy 扫描
# 安装 Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# 扫描镜像
trivy image nginx:latest
# 扫描并输出 JSON 格式
trivy image --format json nginx:latest > nginx-trivy.json
# 扫描文件系统
trivy fs /path/to/project
# 扫描 Kubernetes 配置
trivy k8s cluster
5.2 安全扫描脚本
综合安全扫描工具
#!/bin/bash
# security-scanner.sh
SCAN_DIR="/tmp/security-scans"
REPORT_DIR="/var/reports/security"
LOG_FILE="/var/log/security-scanner.log"
# 日志函数
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}
# 创建目录
mkdir -p $SCAN_DIR $REPORT_DIR
# 扫描镜像漏洞
scan_image_vulnerabilities() {
local image=$1
local scan_id=$(date +%Y%m%d_%H%M%S)
local report_file="$REPORT_DIR/image-scan-${image//[:\/]/-}-$scan_id.json"
log "Scanning image vulnerabilities: $image"
# 使用 Trivy 扫描
if command -v trivy > /dev/null; then
trivy image --format json --output $report_file $image
# 提取关键信息
local critical=$(jq '.Results[]?.Vulnerabilities[]? | select(.Severity=="CRITICAL") | .VulnerabilityID' $report_file | wc -l)
local high=$(jq '.Results[]?.Vulnerabilities[]? | select(.Severity=="HIGH") | .VulnerabilityID' $report_file | wc -l)
local medium=$(jq '.Results[]?.Vulnerabilities[]? | select(.Severity=="MEDIUM") | .VulnerabilityID' $report_file | wc -l)
log "Vulnerabilities found in $image: Critical=$critical, High=$high, Medium=$medium"
# 如果有严重漏洞,发出警告
if [ $critical -gt 0 ] || [ $high -gt 0 ]; then
log "WARNING: High-risk vulnerabilities found in $image"
return 1
fi
else
log "ERROR: Trivy not installed"
return 1
fi
return 0
}
# 扫描容器配置
scan_container_config() {
local container_id=$1
log "Scanning container configuration: $container_id"
local issues=()
# 检查特权模式
local privileged=$(docker inspect $container_id --format '{{.HostConfig.Privileged}}')
if [ "$privileged" = "true" ]; then
issues+=("Privileged mode enabled")
fi
# 检查用户
local user=$(docker inspect $container_id --format '{{.Config.User}}')
if [ -z "$user" ] || [ "$user" = "root" ] || [ "$user" = "0" ]; then
issues+=("Running as root user")
fi
# 检查只读根文件系统
local readonly=$(docker inspect $container_id --format '{{.HostConfig.ReadonlyRootfs}}')
if [ "$readonly" != "true" ]; then
issues+=("Root filesystem is writable")
fi
# 检查能力
local cap_add=$(docker inspect $container_id --format '{{.HostConfig.CapAdd}}')
if [ "$cap_add" != "<no value>" ] && [ "$cap_add" != "[]" ]; then
issues+=("Additional capabilities granted: $cap_add")
fi
# 检查网络模式
local network_mode=$(docker inspect $container_id --format '{{.HostConfig.NetworkMode}}')
if [ "$network_mode" = "host" ]; then
issues+=("Using host network mode")
fi
# 报告问题
if [ ${#issues[@]} -gt 0 ]; then
log "Security issues found in container $container_id:"
for issue in "${issues[@]}"; do
log " - $issue"
done
return 1
else
log "No security issues found in container $container_id"
return 0
fi
}
# 扫描服务配置
scan_service_config() {
local service_name=$1
log "Scanning service configuration: $service_name"
local issues=()
# 检查服务约束
local constraints=$(docker service inspect $service_name --format '{{.Spec.TaskTemplate.Placement.Constraints}}')
if [ "$constraints" = "<no value>" ] || [ "$constraints" = "[]" ]; then
issues+=("No placement constraints defined")
fi
# 检查资源限制
local cpu_limit=$(docker service inspect $service_name --format '{{.Spec.TaskTemplate.Resources.Limits.NanoCPUs}}')
local mem_limit=$(docker service inspect $service_name --format '{{.Spec.TaskTemplate.Resources.Limits.MemoryBytes}}')
if [ "$cpu_limit" = "<no value>" ] || [ "$cpu_limit" = "0" ]; then
issues+=("No CPU limit defined")
fi
if [ "$mem_limit" = "<no value>" ] || [ "$mem_limit" = "0" ]; then
issues+=("No memory limit defined")
fi
# 检查网络
local networks=$(docker service inspect $service_name --format '{{range .Spec.TaskTemplate.Networks}}{{.Target}} {{end}}')
if [[ $networks == *"ingress"* ]] && [[ $networks != *"backend"* ]] && [[ $networks != *"frontend"* ]]; then
issues+=("Service only connected to ingress network")
fi
# 检查密钥使用
local secrets=$(docker service inspect $service_name --format '{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{.SecretName}} {{end}}')
local env_vars=$(docker service inspect $service_name --format '{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{.}} {{end}}')
if [[ $env_vars == *"PASSWORD"* ]] || [[ $env_vars == *"SECRET"* ]] || [[ $env_vars == *"KEY"* ]]; then
issues+=("Sensitive data in environment variables")
fi
# 报告问题
if [ ${#issues[@]} -gt 0 ]; then
log "Security issues found in service $service_name:"
for issue in "${issues[@]}"; do
log " - $issue"
done
return 1
else
log "No security issues found in service $service_name"
return 0
fi
}
# 扫描网络配置
scan_network_config() {
log "Scanning network configuration..."
local issues=()
# 检查未加密的 overlay 网络
for network in $(docker network ls --filter driver=overlay --format '{{.Name}}'); do
local encrypted=$(docker network inspect $network --format '{{.Options.encrypted}}')
if [ "$encrypted" != "true" ]; then
issues+=("Unencrypted overlay network: $network")
fi
done
# 检查默认网络使用
for service in $(docker service ls --format '{{.Name}}'); do
local networks=$(docker service inspect $service --format '{{range .Spec.TaskTemplate.Networks}}{{.Target}} {{end}}')
if [[ $networks == *"ingress"* ]] && [ $(echo $networks | wc -w) -eq 1 ]; then
issues+=("Service $service only uses default ingress network")
fi
done
# 报告问题
if [ ${#issues[@]} -gt 0 ]; then
log "Network security issues found:"
for issue in "${issues[@]}"; do
log " - $issue"
done
return 1
else
log "No network security issues found"
return 0
fi
}
# 生成安全报告
generate_security_report() {
local report_file="$REPORT_DIR/security-report-$(date +%Y%m%d_%H%M%S).html"
log "Generating comprehensive security report: $report_file"
cat > $report_file << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Docker Swarm Security Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.header { background-color: #f0f0f0; padding: 10px; border-radius: 5px; }
.section { margin: 20px 0; }
.issue { color: red; }
.warning { color: orange; }
.ok { color: green; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<div class="header">
<h1>Docker Swarm Security Report</h1>
<p>Generated: $(date)</p>
<p>Cluster: $(docker info --format '{{.Swarm.NodeID}}')</p>
</div>
EOF
# 添加镜像扫描结果
echo " <div class='section'>" >> $report_file
echo " <h2>Image Vulnerability Scan</h2>" >> $report_file
echo " <table>" >> $report_file
echo " <tr><th>Image</th><th>Critical</th><th>High</th><th>Medium</th><th>Status</th></tr>" >> $report_file
for image in $(docker image ls --format '{{.Repository}}:{{.Tag}}' | grep -v '<none>'); do
if scan_image_vulnerabilities $image > /dev/null 2>&1; then
echo " <tr><td>$image</td><td>0</td><td>0</td><td>-</td><td class='ok'>PASS</td></tr>" >> $report_file
else
echo " <tr><td>$image</td><td>?</td><td>?</td><td>?</td><td class='issue'>FAIL</td></tr>" >> $report_file
fi
done
echo " </table>" >> $report_file
echo " </div>" >> $report_file
# 添加服务配置扫描结果
echo " <div class='section'>" >> $report_file
echo " <h2>Service Configuration Scan</h2>" >> $report_file
echo " <table>" >> $report_file
echo " <tr><th>Service</th><th>Status</th><th>Issues</th></tr>" >> $report_file
for service in $(docker service ls --format '{{.Name}}'); do
if scan_service_config $service > /dev/null 2>&1; then
echo " <tr><td>$service</td><td class='ok'>PASS</td><td>None</td></tr>" >> $report_file
else
echo " <tr><td>$service</td><td class='issue'>FAIL</td><td>See logs</td></tr>" >> $report_file
fi
done
echo " </table>" >> $report_file
echo " </div>" >> $report_file
# 结束 HTML
echo "</body></html>" >> $report_file
log "Security report generated: $report_file"
}
# 主菜单
case "$1" in
"image")
if [ -n "$2" ]; then
scan_image_vulnerabilities $2
else
echo "Usage: $0 image <image-name>"
fi
;;
"container")
if [ -n "$2" ]; then
scan_container_config $2
else
echo "Usage: $0 container <container-id>"
fi
;;
"service")
if [ -n "$2" ]; then
scan_service_config $2
else
echo "Usage: $0 service <service-name>"
fi
;;
"network")
scan_network_config
;;
"all")
log "Starting comprehensive security scan..."
# 扫描所有镜像
for image in $(docker image ls --format '{{.Repository}}:{{.Tag}}' | grep -v '<none>'); do
scan_image_vulnerabilities $image
done
# 扫描所有运行的容器
for container in $(docker ps --format '{{.ID}}'); do
scan_container_config $container
done
# 扫描所有服务
for service in $(docker service ls --format '{{.Name}}'); do
scan_service_config $service
done
# 扫描网络配置
scan_network_config
# 生成报告
generate_security_report
;;
"report")
generate_security_report
;;
*)
echo "Usage: $0 {image|container|service|network|all|report}"
echo " image <name> - Scan image vulnerabilities"
echo " container <id> - Scan container configuration"
echo " service <name> - Scan service configuration"
echo " network - Scan network configuration"
echo " all - Comprehensive security scan"
echo " report - Generate security report"
;;
esac
5.3 合规性检查
CIS Docker Benchmark
# 下载 CIS Docker Benchmark 脚本
wget https://github.com/docker/docker-bench-security/archive/master.zip
unzip master.zip
cd docker-bench-security-master
# 运行 CIS 基准测试
./docker-bench-security.sh
# 生成 JSON 报告
./docker-bench-security.sh -l /tmp/docker-bench.log -j > docker-bench-report.json
# 只检查特定部分
./docker-bench-security.sh -c check_2,check_3
自定义合规性检查
#!/bin/bash
# compliance-checker.sh
COMPLIANCE_REPORT="/tmp/compliance-report-$(date +%Y%m%d_%H%M%S).txt"
# 合规性检查函数
check_compliance() {
echo "Docker Swarm Compliance Check Report" > $COMPLIANCE_REPORT
echo "Generated: $(date)" >> $COMPLIANCE_REPORT
echo "=========================================" >> $COMPLIANCE_REPORT
# 检查 1: TLS 配置
echo "\n1. TLS Configuration:" >> $COMPLIANCE_REPORT
if docker info --format '{{.Swarm.Cluster.TLSInfo.TrustRoot}}' | grep -q "BEGIN CERTIFICATE"; then
echo " ✓ TLS enabled and configured" >> $COMPLIANCE_REPORT
else
echo " ✗ TLS not properly configured" >> $COMPLIANCE_REPORT
fi
# 检查 2: 节点证书
echo "\n2. Node Certificates:" >> $COMPLIANCE_REPORT
for node in $(docker node ls --format '{{.Hostname}}'); do
tls_status=$(docker node inspect $node --format '{{.Description.TLSInfo.TrustRoot}}' | head -1)
if [ -n "$tls_status" ]; then
echo " ✓ Node $node has valid certificate" >> $COMPLIANCE_REPORT
else
echo " ✗ Node $node certificate issue" >> $COMPLIANCE_REPORT
fi
done
# 检查 3: 网络加密
echo "\n3. Network Encryption:" >> $COMPLIANCE_REPORT
for network in $(docker network ls --filter driver=overlay --format '{{.Name}}'); do
encrypted=$(docker network inspect $network --format '{{.Options.encrypted}}')
if [ "$encrypted" = "true" ]; then
echo " ✓ Network $network is encrypted" >> $COMPLIANCE_REPORT
else
echo " ✗ Network $network is not encrypted" >> $COMPLIANCE_REPORT
fi
done
# 检查 4: 密钥管理
echo "\n4. Secrets Management:" >> $COMPLIANCE_REPORT
secret_count=$(docker secret ls --format '{{.Name}}' | wc -l)
if [ $secret_count -gt 0 ]; then
echo " ✓ Docker Secrets in use ($secret_count secrets)" >> $COMPLIANCE_REPORT
# 检查未使用的密钥
unused_secrets=0
for secret in $(docker secret ls --format '{{.Name}}'); do
services=$(docker service ls --filter "secret=$secret" --format '{{.Name}}')
if [ -z "$services" ]; then
unused_secrets=$((unused_secrets + 1))
fi
done
if [ $unused_secrets -gt 0 ]; then
echo " ⚠ $unused_secrets unused secrets found" >> $COMPLIANCE_REPORT
fi
else
echo " ⚠ No Docker Secrets configured" >> $COMPLIANCE_REPORT
fi
# 检查 5: 服务安全配置
echo "\n5. Service Security:" >> $COMPLIANCE_REPORT
for service in $(docker service ls --format '{{.Name}}'); do
# 检查用户配置
user=$(docker service inspect $service --format '{{.Spec.TaskTemplate.ContainerSpec.User}}')
if [ -n "$user" ] && [ "$user" != "<no value>" ]; then
echo " ✓ Service $service runs as non-root user" >> $COMPLIANCE_REPORT
else
echo " ✗ Service $service may run as root" >> $COMPLIANCE_REPORT
fi
# 检查只读根文件系统
readonly=$(docker service inspect $service --format '{{.Spec.TaskTemplate.ContainerSpec.ReadOnly}}')
if [ "$readonly" = "true" ]; then
echo " ✓ Service $service has read-only root filesystem" >> $COMPLIANCE_REPORT
else
echo " ⚠ Service $service has writable root filesystem" >> $COMPLIANCE_REPORT
fi
done
echo "\nCompliance check completed. Report saved to: $COMPLIANCE_REPORT"
}
# 执行合规性检查
check_compliance
6. 实践练习
练习 1:安全集群搭建
# 目标:搭建一个安全加固的 Swarm 集群
# 1. 初始化安全集群
docker swarm init --cert-expiry 24h
# 2. 配置节点安全标签
docker node update --label-add security.zone=production $(docker node ls --format '{{.Hostname}}')
docker node update --label-add security.hardened=true $(docker node ls --format '{{.Hostname}}')
# 3. 创建加密网络
docker network create --driver overlay --opt encrypted secure-net
# 4. 创建安全服务
docker service create --name secure-web \
--network secure-net \
--constraint 'node.labels.security.hardened == true' \
--user 1000:1000 \
--read-only \
--cap-drop ALL \
--cap-add CHOWN \
--cap-add SETGID \
--cap-add SETUID \
--security-opt no-new-privileges:true \
--limit-cpu 0.5 \
--limit-memory 512M \
nginx:alpine
# 5. 验证安全配置
docker service inspect secure-web --format '{{json .Spec.TaskTemplate.ContainerSpec}}' | jq .
练习 2:密钥管理实践
# 目标:实现完整的密钥管理流程
# 1. 创建应用密钥
echo "super-secret-password" | docker secret create app-db-password -
echo "jwt-secret-key-$(date +%s)" | docker secret create app-jwt-secret -
# 2. 创建 TLS 证书
openssl req -new -x509 -days 365 -nodes \
-out app.crt -keyout app.key \
-subj "/C=US/ST=CA/L=SF/O=MyApp/CN=app.example.com"
docker secret create app-tls-cert app.crt
docker secret create app-tls-key app.key
# 3. 部署使用密钥的服务
docker service create --name secure-app \
--secret source=app-db-password,target=/run/secrets/db_password \
--secret source=app-jwt-secret,target=/run/secrets/jwt_secret \
--secret source=app-tls-cert,target=/run/secrets/tls_cert \
--secret source=app-tls-key,target=/run/secrets/tls_key \
--env DB_PASSWORD_FILE=/run/secrets/db_password \
--env JWT_SECRET_FILE=/run/secrets/jwt_secret \
--env TLS_CERT_FILE=/run/secrets/tls_cert \
--env TLS_KEY_FILE=/run/secrets/tls_key \
my-secure-app:latest
# 4. 验证密钥挂载
docker service ps secure-app
docker exec $(docker ps --filter "label=com.docker.swarm.service.name=secure-app" --format '{{.ID}}') \
ls -la /run/secrets/
# 5. 密钥轮换
echo "new-super-secret-password" | docker secret create app-db-password-new -
docker service update \
--secret-rm app-db-password \
--secret-add source=app-db-password-new,target=/run/secrets/db_password \
secure-app
docker secret rm app-db-password
# 清理
rm -f app.crt app.key
练习 3:安全扫描和监控
# 目标:建立安全扫描和监控体系
# 1. 安装安全扫描工具
# 安装 Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# 2. 扫描当前镜像
for image in $(docker image ls --format '{{.Repository}}:{{.Tag}}' | grep -v '<none>'); do
echo "Scanning $image..."
trivy image --severity HIGH,CRITICAL $image
done
# 3. 配置安全监控
cat > security-monitor.sh << 'EOF'
#!/bin/bash
while true; do
# 检查特权容器
privileged_containers=$(docker ps --filter "label=privileged=true" --format '{{.Names}}')
if [ -n "$privileged_containers" ]; then
echo "$(date): WARNING - Privileged containers detected: $privileged_containers"
fi
# 检查根用户容器
for container in $(docker ps --format '{{.ID}}'); do
user=$(docker inspect $container --format '{{.Config.User}}')
if [ -z "$user" ] || [ "$user" = "root" ] || [ "$user" = "0" ]; then
name=$(docker inspect $container --format '{{.Name}}')
echo "$(date): WARNING - Container running as root: $name"
fi
done
sleep 300 # 每5分钟检查一次
done
EOF
chmod +x security-monitor.sh
# 4. 启动监控(后台运行)
./security-monitor.sh > /var/log/security-monitor.log 2>&1 &
# 5. 生成安全报告
./security-scanner.sh all
本章总结
通过本章学习,我们深入了解了 Docker Swarm 的安全管理:
关键要点
安全架构
- TLS 加密通信
- 相互认证机制
- 基于角色的访问控制
- 密钥管理系统
集群安全配置
- 证书管理和轮换
- 节点安全标签
- 安全加固脚本
- 审计日志配置
密钥和证书管理
- Docker Secrets 使用
- 密钥轮换策略
- 外部密钥管理集成
- 访问控制实现
安全扫描和合规性
- 镜像漏洞扫描
- 配置安全检查
- CIS 基准测试
- 合规性报告
最佳实践
定期安全检查
- 自动化安全扫描
- 定期证书轮换
- 持续合规性监控
- 安全事件响应
最小权限原则
- 非特权容器运行
- 只读根文件系统
- 最小能力集合
- 网络隔离策略
深度防护
- 多层安全控制
- 网络分段隔离
- 数据加密保护
- 访问审计跟踪
下一章我们将学习 Docker Swarm 的监控与日志管理,了解如何建立完善的可观测性体系。