You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本以sudo启动后如何切换普通用户执行再切回root权限

答案

完全可以实现,且不会触发sudo超时问题,也不需要修改系统sudo配置。

实现原理

  • 通过sudo启动的root进程会自动继承SUDO_UID、SUDO_GID两个环境变量,存储了发起sudo的普通用户的UID和GID。
  • root权限的进程可以自由修改有效用户ID(euid)、有效用户组ID(egid):临时降权时切换为普通用户的UID/GID,需要高权限时再切回0即可。整个过程进程本身的root权限不会丢失,完全不需要重新验证sudo密码,自然不会触发超时问题。

修改后的完整脚本

#!/usr/bin/env python

import os
import sys
import pwd


def update():
    if os.geteuid() != 0:
        print("The --config function must run as root.")
        raise SystemExit(0)

    print("About to upgrade your OS")
    os.system("apt-get -y update; apt-get -y dist-upgrade")


def build():
    if os.geteuid() == 0:
        print("This function should not be run as root.")
        raise SystemExit(0)

    if not os.path.isdir("source"):
        os.system("git clone https://path.to/source/source.git")
    else:
        os.system("(chdir source; git pull)")
    os.chdir("source")
    os.system("make")


def install():
    "Install software & start service once everything has been tested."
    if os.geteuid() != 0:
        print("The --install function must run as root.")
        raise SystemExit(0)

    os.chdir("source")
    os.system("make install")
    os.system("systemctl daemon-reload")
    os.system("systemctl enable software.service")
    
if __name__ == "__main__":
    # 校验运行身份
    if os.geteuid() != 0:
        print("请使用sudo启动本脚本")
        raise SystemExit(1)
    
    # 获取发起sudo的普通用户信息
    sudo_uid = int(os.environ.get("SUDO_UID", -1))
    sudo_gid = int(os.environ.get("SUDO_GID", -1))
    if sudo_uid < 0 or sudo_gid < 0:
        print("未检测到普通用户信息,请不要在root shell下直接执行本脚本,需通过sudo调用")
        raise SystemExit(1)
    sudo_user = pwd.getpwuid(sudo_uid)
    ordinary_home = sudo_user.pw_dir
    root_home = os.environ.get("HOME", "/root")

    # 1. root权限执行update
    print("===== 运行update环节 =====")
    update()

    # 2. 降权为普通用户执行build
    print("\n===== 运行build环节 =====")
    # 切换顺序必须先改GID再改UID
    os.setegid(sudo_gid)
    os.seteuid(sudo_uid)
    os.environ["HOME"] = ordinary_home
    build()

    # 3. 恢复root权限执行install
    print("\n===== 运行install环节 =====")
    # 切换顺序必须先改UID再改GID
    os.seteuid(0)
    os.setegid(0)
    os.environ["HOME"] = root_home
    install()

    print("\n所有环节执行成功")

注意事项

  • 权限切换顺序不能乱:降权时先改GID再改UID,升权时先改UID再改GID,否则会因为权限不足修改失败。
  • 脚本自动同步了HOME环境变量,避免build环节生成的文件归属root,导致后续操作权限异常。
  • 执行时仅需要运行一次命令即可:sudo ./script.py,不需要传任何参数。

内容的提问来源于stack exchange,提问作者shouldbeq931

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 23:48:04