第4章 私钥存储安全:文件系统权限

文件系统权限是这个链条上最基础的防线。说实话,我见过不少线上事故,起因就是一个 chmod 777 的私钥文件。你想想看,如果私钥本体都没保护好,后面做再多的轮换、审计也是白搭。

这一章,我把项目中踩过的坑、总结出来的最佳实践,一次性梳理清楚。

4.1 最小权限原则

核心就一句话:谁需要,给谁;不需要,一律拒绝。私钥文件不是共享文档,不该让 nginx 用户、运维脚本、甚至 cron 任务都能直接读取。

建议清单:
  • 私钥文件所有者:仅限启动 TLS 服务的系统用户(例如 www-data、nginx、haproxy)
  • 组:不设置任何共享组,或仅限专门的密钥管理组
  • 其他用户:无任何权限

我在审计一个金融项目时发现,他们的私钥文件属于 root:root,权限却是 644。这意味着所有系统用户都能读。嗯,这种配置基本等于把钥匙挂在门上。

4.2 文件权限位:0400 还是 0600?

常见的争议是:私钥到底该给读权限,还是读写权限?我个人习惯只给读权限(0400),因为私钥本身不需要写操作。如果需要替换密钥,直接删除旧文件再创建新文件即可。

场景推荐权限说明
Nginx / Apache / HAProxy0400只读,防止被意外覆写
手动轮换脚本(需覆盖密钥)0600仅在脚本执行期间临时设置,事后改回 0400
多进程共享(极少见)0440(组可读)必须严格管控组范围,我一般不建议
千万不要给执行权限。私钥不是可执行程序,加 x 位除了增加攻击面之外毫无用处。我审查过一个 CI 镜像,里面私钥权限是 0700……运维同学把私钥当脚本部署了。

4.3 目录权限:被忽视的前线

很多人只盯着文件本身,却忘了目录权限。举个例子:私钥文件权限 0400,但父目录权限是 777。攻击者能不能读文件?不能。但能不能删除文件?可以!一旦私钥被删除,你的 TLS 服务会立即崩溃。

我建议父目录权限严格限制在 0700(所有者)或 0750(专用组)。曾经有次线上事故,就是因为一个临时脚本把 /etc/ssl/private 目录的权限 reset 成了 777,导致了后续的私钥丢失。

检查路径链:从根目录到私钥文件,每一个中间目录的权限都要过一遍。特别留意 /、/etc、/etc/ssl 这三级,确保它们没有不合理的开放权限。

4.4 ACL 与特殊场景

传统的 POSIX 权限有时不够用。比如你需要让一个审计脚本只读,又不想改文件所属组。这时候 ACL(访问控制列表)就可能派上用场。

# 给 audit_user 只读权限
setfacl -m u:audit_user:r /etc/ssl/private/server.key
# 检查 ACL
getfacl /etc/ssl/private/server.key

但请注意,ACL 在跨平台迁移(例如从 ext4 到 xfs 或 NFS)时可能会丢失。我个人只在临时需求时用 ACL,真正的长期配置还是靠标准的用户和组权限。

另外,如果你用容器或 Kubernetes 挂载 Secret,文件系统权限通常以挂载方式控制。不过底层宿主机上,哪怕你设置了 0400,容器内 UID 映射也会造成权限错乱。我建议在这种情况下使用 临时密钥注入 方式,而非持久化文件挂载。

4.5 审计检查清单

每次做私钥审计,我都会逐项检查以下内容。你可以把它做成脚本的一部分,或者手动核对。

  1. 文件权限:确认 ≤ 0400 或 0600,无 x 位
  2. 文件所有者:是否为运行 TLS 服务的系统用户
  3. 文件所在目录:权限 ≤ 0700,无组/其他写权限
  4. 父目录链:每层目录无 group/other write
  5. 符号链接:如果私钥是软链,检查目标文件权限
  6. 备份目录:备份副本和原始文件权限保持一致
  7. ACL:确认为预期配置,无意外 entry
快速巡检命令:
find /etc/ssl/private -type f -perm /0777 -o -perm /0111
find /etc/ssl/private -type d -perm /0022

以上就是文件系统权限这层防线的核心内容。记住:权限不是配完就一劳永逸的,每次私钥轮换、服务器迁移、人员变更后,都应该重新跑一遍审计清单。

私钥存储安全 · 文件系统权限核心体系 私钥文件 文件权限位 父目录权限 ACL 扩展权限 所有者 & 组 审计检查清单 权限不合格 → 私钥泄露 / 服务中断 每轮轮换后重新检查,不留死角