引言
在 Linux 系统管理中,权限控制是安全体系的核心。当你需要以特定用户身份运行程序、临时切换用户组,或是精细控制进程权限时,setpriv 和 newgrp 分别代表了“精细化权限控制”和“会话级组切换”两条不同的技术路线。本文将深入介绍这两个命令的使用方法、工作原理和典型应用场景。
一、setpriv:精细控制进程权限
1.1 命令概述
setpriv 是 util-linux 包中的一个工具,允许用户在运行程序时设置或查询各种 Linux 权限参数。与传统的 su 或 sudo 不同,setpriv 既不使用 PAM(可插拔认证模块),也不会提示输入密码,它是一个简单的、非 set-user-ID 的 execve 包装器。
核心特点:
- 不依赖 PAM,无密码交互
- 可以精确控制 UID、GID、能力集等权限参数
- 支持 Linux 安全模块(LSM)如 SELinux、AppArmor
- 支持
no_new_privs等内核安全特性
1.2 进程凭证管理
flowchart TB
subgraph ProcessCredentials[进程凭证体系]
UID[UID 凭证]
GID[GID 凭证]
Caps[能力集 Capabilities]
Other[其他安全属性]
end
subgraph UIDDetails[UID 类型]
RUID[Real UID<br/>真实用户ID]
EUID[Effective UID<br/>有效用户ID]
SUID[Saved UID<br/>保存的用户ID]
end
subgraph GIDDetails[GID 类型]
RGID[Real GID<br/>真实组ID]
EGID[Effective GID<br/>有效组ID]
SGID[Saved GID<br/>保存的组ID]
SuppGID[Supplementary GIDs<br/>附加组列表]
end
subgraph CapDetails[能力集类型]
Perm[Permitted<br/>允许的能力]
Inherit[Inheritable<br/>可继承的能力]
Effective[Effective<br/>有效的能力]
Ambient[Ambient<br/>环境能力]
Bounding[Bounding Set<br/>边界集]
end
UID --> UIDDetails
GID --> GIDDetails
Caps --> CapDetails
setpriv 可以精确设置上述所有凭证类型。这种细粒度控制是实现最小权限原则的关键工具。
1.3 用户 ID 与组 ID 设置
设置用户 ID
使用 --ruid、--euid 或 --reuid 选项可以分别设置真实用户 ID、有效用户 ID 或同时设置两者:
# 切换到用户 alice(同时设置真实和有效 UID)
setpriv --reuid=alice id
# 仅设置有效 UID
setpriv --euid=bob whoami
设置组 ID
类似地,使用 --rgid、--egid 或 --regid 设置组 ID:
# 切换主要组到 developers
setpriv --regid=developers --init-groups id
# 设置附加组
setpriv --groups=staff,admin --regid=developers id
安全注意事项: 当你设置任何主要组 ID 时,必须同时指定 --clear-groups、--groups、--keep-groups 或 --init-groups 之一来明确附加组的处理方式。
同时管理 UID/GID :
# 以指定用户运行程序(类似 su,但无PAM)
setpriv --reuid=1000 --regid=1000 --init-groups /bin/bash
# 同时设置真实和有效UID/GID
setpriv --reuid=www-data --regid=www-data --clear-groups /usr/sbin/nginx
# 指定辅助组
setpriv --reuid=1000 --regid=1000 --groups=audio,video,plugdev /bin/bash
1.4 能力集管理
Linux 能力(Capabilities)将 root 用户的特权细分为独立单元,允许进程仅获得所需的特定权限。
# 查看所有可用能力
setpriv --list-caps
# 移除所有继承能力(降权运行)
setpriv --inh-caps=-all --reuid=nobody --regid=nogroup /bin/bash
# 添加特定能力
setpriv --ambient-caps=+cap_net_bind_service /usr/bin/myserver
# 从边界集中移除能力
setpriv --bounding-set=-cap_sys_admin,-cap_sys_ptrace /bin/bash
# 保留特定能力
setpriv --inh-caps=+net_raw,+cap_dac_override ./tcpdump
能力集操作语法:
+cap_name:添加能力-cap_name:移除能力+all/-all:添加/移除所有能力
重要限制: 向边界集(bounding set)添加能力是不可能的——这是内核层面的硬性限制。如果你从边界集中移除了某个能力,务必同时从可继承集中移除它,否则会导致配置混乱。
1.5 高级安全特性
no_new_privs 位
设置 --no-new-privs 后,进程及其子进程将无法通过 execve 获得新权限。这意味着 setuid/setgid 位和文件能力将被禁用:
setpriv --no-new-privs --reuid=nobody ./untrusted-program
这个特性对于运行不可信代码至关重要,自 Linux 3.5 起支持。
Landlock 沙盒
Landlock 是 Linux 内核的安全模块,允许非特权进程创建安全沙盒:
# 阻止所有文件系统访问
setpriv --landlock-access fs ./sandboxed-app
# 阻止文件删除和目录创建
setpriv --landlock-access fs:remove-file,make-dir ./restricted-app
# 允许读取 /boot 目录下的文件
setpriv --landlock-access fs --landlock-rule path-beneath:read-file:/boot ./reader
seccomp 过滤
通过 --seccomp-filter 可以加载 BPF 过滤器来限制系统调用。
1.6 setpriv 最佳实践
flowchart LR
subgraph BestPractices[最佳实践场景]
S1[服务降权<br/>删除root权限启动守护进程]
S2[沙盒执行<br/>隔离不可信代码]
S3[能力修剪<br/>仅保留必要权限]
S4[环境重置<br/>清除污染环境变量]
end
subgraph Example[命令示例]
E1["setpriv --reuid=www-data --regid=www-data<br/>--init-groups --inh-caps=-all nginx"]
E2["setpriv --no-new-privs --reuid=nobody<br/>--reset-env ./untrusted"]
E3["setpriv --inh-caps=+net_admin<br/>./privileged-app"]
E4["setpriv --reuid=1000 --reset-env bash"]
end
S1 --> E1
S2 --> E2
S3 --> E3
S4 --> E4
典型场景示例:
- 服务进程权限降级:
setpriv --reuid=www-data --regid=www-data --init-groups --inh-caps=-all nginx
- 安全沙盒执行:
setpriv --no-new-privs --reuid=nobody --regid=nogroup --clear-groups ./untrusted
- 环境重置:
setpriv --reset-env --reuid=1000 bash
二、newgrp:临时切换用户组
2.1 命令概述
newgrp 命令允许用户在登录会话中临时切换当前组 ID。它在不退出当前会话的情况下,更改用户的真实组 ID(RGID),并尝试将该组添加到用户的附加组集合中。
核心机制:
- 启动一个新的 shell 实例,使用新的组身份
- 退出新 shell 后恢复原始组设置
- 支持组密码验证(如果用户不是组成员)
2.2 工作流程
flowchart TD
Start[用户执行 newgrp group] --> Check{用户是<br/>组成员?}
Check -->|是| Change[切换到目标组]
Check -->|否| PassCheck{组有密码?}
PassCheck -->|有密码| Prompt[提示输入组密码]
PassCheck -->|无密码| Deny[拒绝访问]
Prompt --> PassVerify{密码正确?}
PassVerify -->|正确| Change
PassVerify -->|错误| Deny
Change --> NewShell[启动新 shell<br/>RGID = 目标组]
NewShell --> Exit[用户执行 exit]
Exit --> Restore[恢复原始组身份]
Deny --> End1[保持原组]
2.3 基本用法
# 切换到 developers 组
newgrp developers
# 切换回用户默认组(无参数)
newgrp
# 使用 "-" 选项重新初始化环境(类似重新登录)
newgrp - developers
# 在指定组下执行单个命令(util-linux 版本支持)
newgrp developers -c "touch /tmp/shared-file"
2.4 密码验证机制
newgrp 的密码验证遵循以下规则:
- 如果用户已经是组成员,直接切换,无需密码
- 如果用户不是组成员且组有密码,提示输入密码
- 如果用户不是组成员且组没有密码,拒绝访问
- 密码从
/etc/gshadow或/etc/group读取
2.5 相关命令对比
| 命令 | 作用范围 | 权限要求 | 使用场景 |
|---|---|---|---|
newgrp |
当前 shell | 组成员或有组密码 | 临时以其他组身份创建文件 |
sg |
单个命令 | 同 newgrp | 以指定组执行单个命令 |
sudo -g |
单个命令 | sudo 权限 | 需要 root 授权的组切换 |
setpriv --regid |
指定程序 | root 或相应能力 | 服务/进程权限控制 |
三、实际应用场景
3.1 服务进程沙盒化
#!/bin/bash
# 以最小权限运行 Web 服务
setpriv --reuid=httpd \
--regid=httpd \
--init-groups \
--inh-caps=-all \
--no-new-privs \
--reset-env \
/usr/sbin/httpd -DFOREGROUND
3.2 协作目录管理
# 场景:开发团队共享目录
# 用户 alice 需要创建属于 project 组的文件
alice@host:~$ newgrp project
alice@host:~$ touch shared-file.txt
alice@host:~$ ls -l shared-file.txt
-rw-r--r-- 1 alice project 0 Dec 15 10:30 shared-file.txt
alice@host:~$ exit
3.3 能力集限制实践
# 仅允许进程使用原始套接字(ping 命令)
setpriv --inh-caps=+cap_net_raw \
--reuid=nobody \
--regid=nogroup \
--clear-groups \
/bin/ping -c 1 8.8.8.8
四、注意事项与最佳实践
setpriv 安全警告
- 能力集一致性: 从边界集移除能力时,必须同时从可继承集中移除,否则会导致不可预测的行为
- LSM 交互: 设置
no_new_privs可能会影响 SELinux/AppArmor 策略的执行 - root 权限处理: 从 root 切换普通用户时,通常需要同时丢弃所有能力:
setpriv --reuid=1000 --regid=1000 --inh-caps=-all
newgrp 使用建议
- 组密码管理: 避免使用组密码,优先将用户添加到所需组
- 使用
-选项谨慎: 该选项会重置环境变量和当前目录,可能造成意外 - 单命令执行: 如需只执行单个命令,优先使用
sg命令
总结
setpriv 和 newgrp 是 Linux 权限管理的两个不同层次的工具:
-
setpriv 提供精细的进程权限控制,是服务降权、沙盒实现和安全加固的首选工具。它支持 UID/GID 切换、能力集管理、Landlock 沙盒、seccomp 过滤等现代 Linux 安全特性。
-
newgrp 专注于组身份切换,是团队协作和临时文件权限管理的便捷工具。它简单直观,适合交互式使用场景。
理解并善用这两个工具,能够帮助系统管理员更好地贯彻“最小权限原则”,构建更加安全的 Linux 系统环境。
原文 https://blog.csdn.net/2301_79518550/article/details/161903494