应以最小能力原则为服务授予权限,如Web服务仅需CAP_NET_BIND_SERVICE,避免滥用CAP_SYS_ADMIN;可通过setcap或systemd的CapabilityBoundingSet精确管控,并配合NoNewPrivileges、ProtectSystem等机制实现纵深防御。

不是“剥离 root 特权”,而是让服务彻底不用 root 身份启动,只拿它真正需要的那几个内核级能力——比如绑定 80 端口,只要 CAP_NET_BIND_SERVICE,其他一概不给。
先搞清服务到底要什么能力
别一上来就加 CAP_SYS_ADMIN。多数服务连它的一半功能都用不上,反而埋下提权隐患。关键看它实际触发了哪些被拒绝的系统调用:
- Web 服务监听 80/443 → 只需 CAP_NET_BIND_SERVICE
- ping、tcpdump 发原始包 → 需要 CAP_NET_RAW,一般不需要 CAP_NET_ADMIN
- 日志服务写 /dev/log → 需要 CAP_SYSLOG
- 修改文件属主(如 logrotate)→ 只需 CAP_CHOWN,而非完整 root
- 挂载临时文件系统?先评估能否用 tmpfs 或 bind mount 替代,CAP_SYS_ADMIN 应极度谨慎
用 setcap 给二进制“钉”上最小能力
这是最轻量、最直接的方式,适用于已编译完成的服务程序:
- 给 nginx 添加绑定低端口能力:sudo setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx
- 验证是否生效:getcap /usr/sbin/nginx 应输出对应能力标记
- 确保该文件没有 setuid/setgid 位(ls -l 中不能出现 s),否则 capability 会被内核忽略
- 注意:setcap 对 shell 脚本、符号链接无效;脚本类服务建议用 systemd 封装或编译为专用二进制
在 systemd 服务中做能力边界管控
即使服务以 User=root 启动,也能通过 unit 文件强制收缩其真实权限范围:
- 用 CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_MODULE CAP_SYS_PTRACE 排除高危能力
- 再显式放行必需项:CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SYSLOG
- 搭配 AmbientCapabilities=CAP_NET_BIND_SERVICE 确保子进程继承
- 必须启用 NoNewPrivileges=true,防止 execve 调用绕过限制
- 加上 ProtectSystem=full 和 ProtectHome=true,堵住能力之外的路径越权可能
配合命名空间与账号策略,切断 root 的实际使用链
capability 解决的是“能不能做”,但还得管住“谁来做”和“在哪做”:
- 禁用交互式 root 登录:sudo passwd -l root,改用 sudo 白名单管控敏感命令
- 容器或沙箱场景中,用 user namespace 创建“伪 root”:unshare --user --net --mount --fork /bin/bash,内部 UID 0 映射到宿主机非特权 UID(如 100000)
- 配合 RestrictSUIDSGID=true 和 ReadOnlyPaths=/etc /usr,从文件系统层加固


















