feat(node-setup): #23 向导降权 (sudo finalize-helper) + finalize 加固 - #181
Merged
Merged
Conversation
…finalize hardening 向导降权(opt-in,向后兼容): - finalize-helper.sh: finalize 里唯一需 root 的动作(关 provisioning gate + 重启 kms-api/dvt + disable 向导)单列成特权 helper,经 sudoers NOPASSWD 白名单被非 root 向导调用。 - aastar-node-setup.sudoers: 只白名单这一个绝对路径,收窄降权后向导的 root 面。 - setup-server.py finalize(): 优先 `sudo -n helper`(捕获 stderr 成 warnings),失败回落 直接 systemctl → root 部署行为不变,非 root 是 opt-in。 - .service: 文档化非 root 启用(User=/Group= +⚠️ NoNewPrivileges=no 否则 sudo 被挡); 修既有隐患:ProtectSystem=strict 下 finalize 删 prov.conf 被沙箱拦→gate 关不掉, 把该 drop-in 目录加进 ReadWritePaths(`-`前缀可选)。 顺手:删文件头过时注释「生产前需加认证」(误导 reviewer;认证 #156 已在位),step4 不再标 stub。 非 root 路径需真板首启验证后再切(systemd 沙箱/sudo 交互本地测不了);root 默认路径不变。 py_compile / bash -n 通过。 Claude-Session: https://claude.ai/code/session_015cWRdv3oPjoQ21PEjwo9m5
Security Audit ReportDate: Fri Jul 17 10:39:02 UTC 2026 Cargo Audit Results |
clestons
approved these changes
Jul 17, 2026
clestons
left a comment
Contributor
There was a problem hiding this comment.
APPROVE — 向导降权设计扎实、向后兼容零回归。一条 sudoers 硬化建议。
核过(正确)
- sudoers 严格:
aastar-setup ALL=(root) NOPASSWD: /opt/aastar/node-setup/finalize-helper.sh—— 绝对路径、无参数、无通配、单命令。 - helper 安全:不读
$@(无参数注入面)、固定动作(rm -f prov.conf+ 3 条systemctl)、幂等(|| true)、set -u。攻破向导最多拿到「跑这条固定收尾脚本」。 - 回落向后兼容:
sudo -n helper非 0/异常即回落原直接systemctl+rm,root 部署逐字不变。subprocess.run(["sudo","-n",helper])数组参数无 shell 注入。 ReadWritePaths修得准:加-/etc/systemd/system/kms-api.service.d。关键点抓对了 ——ProtectSystem=strict靠 mount namespace 把 /etc 设只读,即便 sudo 到 root,helper 仍是 unit 的子进程、共享该只读命名空间,不列进 RW 就删不掉 gate。-前缀容忍目录不存在。✓- 顺手删了文件头「生产前需加认证」过时注释(正是它误导了我 #179 的判断)+ step4 去掉
[Phase 1 stub]。
🟠 硬化建议:把「父目录也不可写」写进安装步骤
sudoers 白名单一个脚本路径,安全性完全系于该脚本及其所在目录 aastar-setup 均不可改。README step2 已要求 finalize-helper.sh 装成 0755 root:root(文件本身堵住了 ✓),但没写死父目录 /opt/aastar/node-setup/ 的属主/权限。若该目录可被 aastar-setup 写(如运维图省事 chown -R aastar-setup /opt/aastar),攻击者能 rm 掉再重建同名脚本 —— 目录写权限允许 unlink+create,绕过文件 0755。这正是 sudoers-脚本-白名单的经典逃逸向量。建议 step2 明确:/opt/aastar/node-setup/ 也须 root:root 且 group/world 不可写(chmod 755),并可加一句「helper 及其目录任一可被向导用户写 = 提权」。
非 root 路径你已诚实标注需真板首启验证。机制 + 向后兼容回落到位,可合。
…sudoers escape) review Low(#181):helper root:root 还不够。父目录链(/opt /opt/aastar /opt/aastar/node-setup) 必须 root 拥有、aastar-setup 不可写,否则目录可写=删脚本重建恶意同名文件借 NOPASSWD 白名单 提权(sudoers 脚本白名单经典逃逸)。README 降权启用 + sudoers 注释均补上。 Claude-Session: https://claude.ai/code/session_015cWRdv3oPjoQ21PEjwo9m5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
承接 #23(向导拆非 root)。向后兼容 + opt-in:root 默认部署行为不变,非 root 是可选启用、需真板验证。
改动
finalize-helper.sh(新):finalize 里唯一需 root 的动作(关 provisioning gate + 重启 kms-api/dvt + disable 向导)单列成特权 helper。aastar-node-setup.sudoers(新):只 NOPASSWD 白名单这一个绝对路径 → 降权后向导即便被攻破,拿到的也只是"跑这条固定收尾脚本",不是整机 root。setup-server.pyfinalize():优先sudo -n helper(捕获 stderr 成 warnings),失败回落直接 systemctl → root 部署行为完全不变。.service:文档化非 root 启用(User=/Group=+NoNewPrivileges=no否则 sudo 被挡)。ProtectSystem=strict下 finalize 删/etc/systemd/.../prov.conf会被沙箱拦 → provisioning gate 关不掉。把该 drop-in 目录加进ReadWritePaths(-前缀可选)。[Phase 1 stub]。为什么安全合入
未做非 root provisioning 时,
sudo -n helper失败即回落原直接 systemctl 逻辑,与之前逐字一致。非 root 路径 opt-in,systemd 沙箱/sudo 交互本地测不了 → 真板首启验证后再切。测试
python3 -m py_compile setup-server.py✅ ·bash -n finalize-helper.sh✅ · AST 解析 ✅诚实说明
非 root 实跑(User= + sudo helper + NoNewPrivileges=no + 目录 ownership)未在真板验证——需首启实测。本 PR 提供机制 + 文档 + 向后兼容回落,root 路径零回归。
https://claude.ai/code/session_015cWRdv3oPjoQ21PEjwo9m5