2、Docker守护进程安全:配置daemon.json、TLS认证、限制守护进程权限、审计日志配置

聊到Docker安全,守护进程(dockerd)绝对是第一道防线。我见过太多团队把精力全放在镜像扫描上,结果守护进程裸奔在公网——说白了,门都没锁,墙再高也没用。

这一章,我们聚焦四个核心动作:配置daemon.json、启用TLS认证、限制守护进程权限、审计日志配置。嗯,每一条都是我踩过坑之后才真正重视起来的。

2.1 配置daemon.json:把安全基线写进配置文件

Docker守护进程的默认配置其实挺松的。我个人习惯,拿到一台新机器,第一件事就是检查 /etc/docker/daemon.json 是否存在。如果不存在?说明你正在用默认参数跑,风险不小。

来看一个我常用的安全基线配置:

{
  "icc": false,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "live-restore": true,
  "userland-proxy": false,
  "iptables": true,
  "ip-forward": true,
  "ip-masq": false,
  "bridge": "none",
  "storage-driver": "overlay2",
  "exec-opts": ["native.cgroupdriver=systemd"],
  "selinux-enabled": true,
  "authorization-plugins": []
}

这里有几个关键点,我重点说一下:

  • icc: false —— 禁止容器间通信。除非你明确需要,否则关掉它。我在一个金融项目里遇到过,攻击者通过一个被攻陷的容器横向扩散,就是因为icc没关。
  • userland-proxy: false —— 关闭用户态代理,改用iptables DNAT。性能更好,攻击面更小。
  • live-restore: true —— 守护进程重启时,容器不挂。这个在生产环境太重要了,我曾经因为升级Docker导致所有容器重启,差点被运维同事拉黑。
  • bridge: "none" —— 不创建默认bridge网络。你想想看,默认网络里的容器可以互相通信,这其实是个安全隐患。
⚠️ 注意:修改daemon.json后,记得执行 systemctl daemon-reload && systemctl restart docker。但重启前,务必确认 live-restore 已开启,否则容器会全部停掉。

2.2 TLS认证:别让你的Docker端口裸奔

Docker默认监听在 /var/run/docker.sock,这是Unix socket,相对安全。但如果你需要远程管理,暴露2375端口——嗯,这就是在给黑客送人头。

我建议的做法:启用TLS双向认证。说白了,客户端和服务端都要验证对方的证书。

生成证书的步骤,我整理成了一张表:

步骤 命令 说明
1. 创建CA私钥 openssl genrsa -aes256 -out ca-key.pem 4096 CA密钥,务必保管好
2. 生成CA证书 openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem CA自签名证书
3. 生成服务端密钥 openssl genrsa -out server-key.pem 4096 服务端私钥
4. 生成服务端CSR openssl req -subj "/CN=<你的IP>" -new -key server-key.pem -out server.csr CN填Docker主机IP
5. 签发服务端证书 openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem 得到服务端证书
6. 生成客户端密钥 openssl genrsa -out key.pem 4096 客户端私钥
7. 生成客户端CSR openssl req -subj '/CN=client' -new -key key.pem -out client.csr CN固定为client
8. 签发客户端证书 openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem 得到客户端证书

证书生成后,修改daemon.json,加上TLS配置:

{
  "tls": true,
  "tlsverify": true,
  "tlscacert": "/etc/docker/certs/ca.pem",
  "tlscert": "/etc/docker/certs/server-cert.pem",
  "tlskey": "/etc/docker/certs/server-key.pem",
  "hosts": ["tcp://0.0.0.0:2376", "unix:///var/run/docker.sock"]
}
💡 小提示:客户端连接时,需要指定证书路径:docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H tcp://你的IP:2376 ps。我习惯把这些参数写进 ~/.docker/config.json,省得每次敲一长串。

2.3 限制守护进程权限:最小权限原则

Docker守护进程默认以root运行,权限非常大。你想想看,如果攻击者控制了dockerd,基本上就等于控制了整台宿主机。

我常用的限制手段有三个:

  • 使用非root用户运行dockerd —— 虽然Docker官方不推荐,但你可以通过sudo或systemd的User=指令来降权。不过要注意,降权后有些功能(比如绑定低端口)会受限。
  • 启用用户命名空间(userns-remap) —— 这个我强烈推荐。它把容器内的root映射成宿主机上的普通用户,即使容器被攻破,攻击者拿到的也是普通用户权限。
  • 限制dockerd可访问的资源 —— 通过systemd的 LimitNOFILELimitNPROC 等参数,防止dockerd耗尽系统资源。

配置userns-remap的示例:

{
  "userns-remap": "default"
}

这个配置会让Docker自动创建一个 dockremap 用户和用户组,并把容器内的UID/GID映射到宿主机的高位UID上。我曾经在一个多租户平台上用过这个功能,效果很好——即使某个容器被提权,它也只能在映射后的命名空间里折腾,影响不了宿主机。

⚠️ 注意:启用userns-remap后,宿主机上挂载的卷权限会发生变化。因为容器内的root不再是宿主机上的root了。你需要手动调整卷的所有权,否则容器可能无法写入数据。

2.4 审计日志配置:出了事得有据可查

安全审计这件事,平时觉得烦,出了事才知道有多重要。我记得有一次排查安全事件,就是因为没有审计日志,花了整整两天才定位到问题源头。

Docker的审计日志,我建议从两个层面入手:

  • Docker守护进程自身的日志 —— 通过 --log-driver--log-opts 配置,把日志输出到json-file或syslog。我习惯用json-file,配合日志轮转,防止磁盘写满。
  • 系统层面的auditd审计 —— 监控Docker相关的系统调用和文件访问。

配置auditd监控Docker守护进程:

# /etc/audit/rules.d/docker.rules
-w /usr/bin/docker -p wa -k docker
-w /var/lib/docker -p wa -k docker
-w /etc/docker -p wa -k docker
-w /run/docker.sock -p wa -k docker
-w /usr/lib/systemd/system/docker.service -p wa -k docker

这些规则会监控Docker二进制文件、数据目录、配置文件、socket和systemd服务文件的写操作和属性修改。一旦有人动了这些文件,auditd就会记录下来。

查看审计日志的命令:

ausearch -k docker --start today

嗯,这里要注意,auditd的日志量可能会很大。我建议配合 auditd.conf 中的 max_log_filenum_logs 参数做轮转,避免日志撑爆磁盘。

核心要点回顾:

  • daemon.json是安全基线的起点,别用默认配置
  • TLS双向认证是远程管理的唯一安全方式
  • userns-remap能有效隔离容器和宿主机权限
  • 审计日志是事后追溯的关键,别省这一步

说实话,守护进程安全这部分,我每次给团队培训都会强调:配置再繁琐,也比被攻破后擦屁股强。下一章我们会聊镜像安全,那又是另一个战场了。