第4章 私钥存储安全:文件系统权限
文件系统权限是这个链条上最基础的防线。说实话,我见过不少线上事故,起因就是一个 chmod 777 的私钥文件。你想想看,如果私钥本体都没保护好,后面做再多的轮换、审计也是白搭。
这一章,我把项目中踩过的坑、总结出来的最佳实践,一次性梳理清楚。
4.1 最小权限原则
核心就一句话:谁需要,给谁;不需要,一律拒绝。私钥文件不是共享文档,不该让 nginx 用户、运维脚本、甚至 cron 任务都能直接读取。
- 私钥文件所有者:仅限启动 TLS 服务的系统用户(例如
www-data、nginx、haproxy) - 组:不设置任何共享组,或仅限专门的密钥管理组
- 其他用户:无任何权限
我在审计一个金融项目时发现,他们的私钥文件属于 root:root,权限却是 644。这意味着所有系统用户都能读。嗯,这种配置基本等于把钥匙挂在门上。
4.2 文件权限位:0400 还是 0600?
常见的争议是:私钥到底该给读权限,还是读写权限?我个人习惯只给读权限(0400),因为私钥本身不需要写操作。如果需要替换密钥,直接删除旧文件再创建新文件即可。
| 场景 | 推荐权限 | 说明 |
|---|---|---|
| Nginx / Apache / HAProxy | 0400 | 只读,防止被意外覆写 |
| 手动轮换脚本(需覆盖密钥) | 0600 | 仅在脚本执行期间临时设置,事后改回 0400 |
| 多进程共享(极少见) | 0440(组可读) | 必须严格管控组范围,我一般不建议 |
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 审计检查清单
每次做私钥审计,我都会逐项检查以下内容。你可以把它做成脚本的一部分,或者手动核对。
- 文件权限:确认 ≤ 0400 或 0600,无 x 位
- 文件所有者:是否为运行 TLS 服务的系统用户
- 文件所在目录:权限 ≤ 0700,无组/其他写权限
- 父目录链:每层目录无 group/other write
- 符号链接:如果私钥是软链,检查目标文件权限
- 备份目录:备份副本和原始文件权限保持一致
- ACL:确认为预期配置,无意外 entry
find /etc/ssl/private -type f -perm /0777 -o -perm /0111
find /etc/ssl/private -type d -perm /0022
以上就是文件系统权限这层防线的核心内容。记住:权限不是配完就一劳永逸的,每次私钥轮换、服务器迁移、人员变更后,都应该重新跑一遍审计清单。