一个 Web 服务能正常启动、页面也能访问,只能证明已测试的路径可用,不能证明它需要当前拥有的全部设备和内核权限。本文只审计单个由 systemd 管理的服务,不把限制项当作通用主机基线。开始前先确定观察范围:除首页访问,还要覆盖登录、上传、定时任务、日志写入和备份;后台进程则换成它实际承担的核心任务。
先只读盘点:服务以什么身份运行、实际碰到了什么
在测试环境选一个与生产配置一致的单元。以下用 web-app.service 代称,执行时替换为真实名称。先不要改配置:
systemctl cat web-app.service
systemctl show web-app.service
-p User -p Group -p ExecStart -p WorkingDirectory
-p PrivateDevices -p ProtectKernelTunables
-p ProtectKernelModules -p RestrictAddressFamilies
systemctl status web-app.service
journalctl -u web-app.service -b --no-pager
systemctl cat 用于核对主单元和已有的覆盖文件;show 用于查看相关属性的当前值。逐项记下可验证的需求:程序读取哪些配置和证书,向哪些目录写入上传文件、缓存与日志,是否访问 /dev 下的设备,是否修改内核参数或加载模块,以及实际使用哪些本地和网络通信方式。配置、程序文档和日志都只是线索;“没在日志里看到访问”不足以证明某项权限不需要,还要覆盖低频的备份、轮转和故障恢复路径。
判断权限是否过宽时,问题应是“这项能力由谁、在什么业务路径上使用”。例如,普通应用进程没有修改内核参数的职责,可以成为限制候选;但不能仅凭它目前运行正常,就推断设备访问和地址族都可以关闭。
逐项评估候选限制,而不是整组套用
| 限制项 | 核对重点 | 可能受影响的路径 |
|---|---|---|
PrivateDevices=yes |
服务是否必须直接访问宿主机设备节点;私有 /dev 是否满足其需求 |
数据库使用特定设备、观测代理采集设备信息等 |
ProtectKernelTunables=yes |
服务是否需要修改内核可调参数;不要把“读取 /proc”一概当成修改需求 |
启动脚本或辅助进程调整 /proc/sys、/sys 设置 |
ProtectKernelModules=yes |
服务是否负责加载、卸载内核模块 | 容器运行时及依赖动态加载模块的管理进程 |
RestrictAddressFamilies= |
列出实际使用的套接字地址族,包括本地通信和网络通信 | HTTP 出入站、Unix 套接字、需要其他地址族的观测或管理功能 |
数据库、容器运行时和观测代理尤其需要按职责单独判断。RestrictAddressFamilies= 也不能代替网络访问控制:它限制的是进程创建指定地址族套接字的能力,不能据此推断服务只能连接某个目标地址;已由套接字激活等方式传入的套接字也要另行核对。需要对照选项行为时,可查阅 Red Hat 的 systemd 服务安全说明,并以目标机器上的 systemd 版本和实测结果为准。
在测试环境一次只改一项
先保存 systemctl cat web-app.service 的输出,并备份将要改动的覆盖文件。确认测试机没有同名文件后,新建专用于本次审计的 /etc/systemd/system/web-app.service.d/90-audit-sandbox.conf。例如,仅在已核对设备需求后先试一项:
[Service]
PrivateDevices=yes
在测试机执行:
sudo systemctl daemon-reload
systemctl cat web-app.service
sudo systemctl restart web-app.service
systemctl status web-app.service
journalctl -u web-app.service -b --no-pager
daemon-reload 让管理器重新读取配置;需要重启服务,限制才会作用于新进程。预期是覆盖文件出现在 systemctl cat 输出中,服务重启后保持运行,且没有新的设备访问或权限错误。重启可能中断请求,应在约定的观察窗口内进行;不要在同一次测试里再叠加另外三项,否则失败时难以定位原因。
接着从业务入口验证,而非只看 active:访问与登录是否成功,上传文件能否落盘并读取,队列或计划任务是否完成,日志是否持续写入,备份能否生成且可读取。对纯后台服务,应触发一项真实任务并检查结果。每通过一项,再决定是否测试下一项限制,并记录变更前后配置、测试时间和结果。
兼容性失败时先恢复,再定位
若重启失败或核心路径异常,先停止继续叠加限制,记录 journalctl -u web-app.service -b 中的报错和失败操作。移除本次新建的 90-audit-sandbox.conf(若修改的是原有文件,则恢复备份),然后在测试机执行 sudo systemctl daemon-reload 和 sudo systemctl restart web-app.service,重测刚才失败的路径。恢复成功只能说明变更与故障有关;还需核对是否另有权限、路径或依赖变化。
复盘时把每一项写成“所需资源—验证路径—限制结果—保留或放弃理由”。只有测试环境覆盖了关键业务和低频任务、回退步骤也走通后,才考虑在生产观察窗口按同样顺序逐项推进。

山东省烟台市 1F
一次只改一项这个做法太重要了
山东省烟台市 B1
@ 卡通贴纸控 测试环境先跑一轮确实稳
重庆市 2F
我们之前就是一次性加了好几个限制,出问题根本查不出来
甘肃省 3F
RestrictAddressFamilies这个坑踩过,Unix套接字忘了加
甘肃省 B1
@ 小鹿鹿鹿 Unix套接字这个太容易漏了
广东省深圳市 4F
备份和日志轮转这种低频路径确实容易被忽略
广东省深圳市 5F
想问下PrivateDevices开了之后数据库还正常吗
甘肃省 6F
先只读盘点再动手,这个顺序很关键
重庆市 B1
@ 暗夜蝶 盘点这一步省了后面全是坑
重庆市 7F
光看服务active真说明不了什么,业务路径都得过一遍
重庆市 B1
@ 悄悄话小精灵 登录上传这些入口都得测,光刷首页没意义
广东省深圳市 8F
回退步骤也要提前走通,不然生产上出事就麻烦了
上海市浦东新区 B1
@ 银杏叶舞 备份脚本的路径别忘了加进验证清单
甘肃省 9F
观测代理那块限制起来是真的费劲
山东省烟台市 B1
@ 驼铃客 观测代理地址族确实多,限制完得跑一轮采集
山东省烟台市 10F
覆盖文件单独放一个目录方便回滚,学到了
山东省烟台市 11F
ProtectKernelTunables开了之后有服务报错过吗
重庆市 12F
低频路径不测,上线就是开盲盒
甘肃省 13F
systemd版本不同行为也有差异,得实测
上海市松江区 14F
想请教下容器运行时这类限制一般怎么定
山东省烟台市 15F
日志轮转那块我准备单独列个清单
重庆市 16F
覆盖文件命名带编号确实好回滚
山东省烟台市 17F
观测代理要用的地址族比想象中多