/etc/login.defs 中的 UMASK 027 仅影响 useradd 创建新用户的初始值,无法覆盖 su、sudo、cron 等会话;必须通过 PAM(如 /etc/pam.d/common-session)配置 session optional pam_umask.so umask=027 实现全局强制生效,并配合 /etc/profile 末尾加固及多路径验证。

为什么改 /etc/login.defs 不够用
只改 /etc/login.defs 中的 UMASK 027,只能影响 useradd 创建的新用户首次登录时的初始值;但 su -、sudo -i、cron 启动的 shell、systemd --user 服务等场景下,这个设置完全不生效。普通用户仍可通过 umask 002 或修改 ~/.bashrc 覆盖掉它——这不是“配置没生效”,而是机制上就没覆盖全。
必须通过 PAM 强制全局生效
PAM 是唯一能拦截所有会话类型(包括 su、sudo、login、cron)并统一注入 umask 的机制。关键不是“加一行”,而是选对模块和位置:
- 编辑
/etc/pam.d/common-session(Debian/Ubuntu)或/etc/pam.d/system-auth(RHEL/CentOS),在末尾添加:session optional pam_umask.so umask=027
- 不要用
required:PAM 链中任意required模块失败会导致整个会话中断,而pam_umask.so在某些旧内核或容器环境可能加载失败 - 必须用
optional+ 显式umask=027:避免依赖/etc/login.defs,绕过用户可篡改的配置源 - 验证是否加载成功:
grep -r pam_umask /etc/pam.d/,确认只有一处生效,且没被其他pam_umask行覆盖
如何阻止用户在 shell 配置里覆盖 umask
用户写 umask 002 到 ~/.bashrc 或 /etc/profile.d/ 下的脚本,会直接覆盖 PAM 设置——因为 shell 初始化顺序是:PAM → 读取 profile → 读取 rc 文件 → 执行用户命令。要阻断这个链路:
- 禁止用户修改自己的 shell 初始化文件:把
~/.bashrc、~/.profile设为只读(chown root:root+chmod 644),但代价是无法定制 prompt 等,不推荐 - 更可靠的做法是在系统级配置中「后置强制」:在
/etc/profile末尾加一行umask 027,并确保它不被/etc/profile.d/*.sh中的脚本覆盖(检查这些脚本里有没有umask) - 终极手段:用 SELinux 或 AppArmor 限制用户进程执行
umask系统调用(极少见,运维成本高,仅限高敏环境)
验证时别只看当前终端
运行 umask 命令看到 0027,不代表策略已落地。必须测试真实路径:
- 新开一个非登录 shell:
bash -c 'umask'→ 应输出0027 - 切换用户:
su -l nobody -c 'umask'→ 注意用-l模拟完整登录 - sudo 测试:
sudo -u nobody sh -c 'umask' - crontab 测试:写一条
* * * * * umask > /tmp/cron-umask.log 2>&1,等一分钟看结果 - 如果任一路径返回非
0027,说明 PAM 配置未覆盖该会话类型,得回查对应 PAM 配置文件名(如 RHEL 的 cron 用的是/etc/pam.d/crond)
真正难的不是设一个值,而是让这个值在所有上下文里都不可绕过——PAM 是必经之路,而验证必须覆盖 su、sudo、cron 这三类最常被忽略的逃逸路径。











