python 子进程 popen 以不同用户身份执行

Chr*_*ris 3 python subprocess python-3.x

python 3.6我正在尝试以不同的用户身份执行命令,popensubprocess它仍然会以调用脚本的用户身份执行(我计划将其称为 root)。我正在使用线程,因此当两个线程并行执行时,不要侵犯用户权限,这一点很重要。

proc = subprocess.Popen(['echo $USER; touch myFile.txt'],
                          shell=True,
                          env={'FOO':'bar', 'USER':'www-data'},
                          stdout=subprocess.PIPE)

Run Code Online (Sandbox Code Playgroud)

上面的例子仍然会用myFile.txt我的user_id 1000

我尝试了不同的方法:

  1. 尝试按照与长时间运行的Python进程不同的用户身份运行子进程中所述,通过复制os.environment并更改用户等
    (注意这是针对python 2)

  2. 按照https://docs.python.org/3.6/library/subprocess.html#popen-constructor中的描述尝试使用start_new_session=True

我的最后一个选择是在命令前加上前缀sudo -u username command,但我认为这不是优雅的方式。

lem*_*ead 5

标准方法 [仅限 POSIX] 是用于preexec_fn设置 gid 和 uid,如本答案中更详细所述

像这样的事情应该可以解决问题 - 为了完整起见,我还修改了您的初始代码片段以包含您可能想要设置的其他环境变量,但preexec_fn对于您正在运行的简单命令来说,只需设置就足够了:

import os, pwd, subprocess

def demote(user_uid, user_gid):
    def result():
        os.setgid(user_gid)
        os.setuid(user_uid)
    return result

def exec_cmd(username):
    # get user info from username
    pw_record = pwd.getpwnam(username)
    homedir = pw_record.pw_dir
    user_uid = pw_record.pw_uid
    user_gid = pw_record.pw_gid
    env = os.environ.copy()
    env.update({'HOME': homedir, 'LOGNAME': username, 'PWD': os.getcwd(), 'FOO': 'bar', 'USER': username})

    # execute the command
    proc = subprocess.Popen(['echo $USER; touch myFile.txt'],
                              shell=True,
                              env=env,
                              preexec_fn=demote(user_uid, user_gid),
                              stdout=subprocess.PIPE)
    proc.wait()


exec_cmd('www-data')
Run Code Online (Sandbox Code Playgroud)

请注意,您还需要确保降级用户可以访问当前工作目录(例如用于写入),因为没有显式覆盖它