以与长期运行的Python进程不同的用户身份运行子进程 [英] Run child processes as different user from a long running Python process
问题描述
我有一个长期运行的守护进程Python进程,该进程使用子进程在发生某些事件时生成新的子进程.长时间运行的过程由具有超级用户特权的用户启动.我需要它产生的子进程以其他用户身份(例如"nobody")运行,同时保留父进程的超级用户特权.
I've got a long running, daemonized Python process that uses subprocess to spawn new child processes when certain events occur. The long running process is started by a user with super user privileges. I need the child processes it spawns to run as a different user (e.g., "nobody") while retaining the super user privileges for the parent process.
我当前正在使用
su -m nobody -c <program to execute as a child>
但这似乎很重,而且不会很干净地死掉.
but this seems heavyweight and doesn't die very cleanly.
有没有一种方法可以通过编程而不是使用su来完成?我正在查看os.set * uid方法,但是Python std lib中的文档在该区域相当稀疏.
Is there a way to accomplish this programmatically instead of using su? I'm looking at the os.set*uid methods, but the doc in the Python std lib is quite sparse in that area.
推荐答案
由于您提到了守护程序,因此我可以得出结论,您正在运行在类似Unix的操作系统上.这很重要,因为如何执行此操作取决于所用的操作系统.此答案仅适用于 Unix ,包括Linux和Mac OS X.
Since you mentioned a daemon, I can conclude that you are running on a Unix-like operating system. This matters, because how to do this depends on the kind operating system. This answer applies only to Unix, including Linux, and Mac OS X.
- 定义一个函数,该函数将设置正在运行的进程的gid和uid.
- 将此函数作为preexec_fn参数传递给subprocess.Popen
subprocess.Popen将使用fork/exec模型来使用您的preexec_fn.这等效于按此顺序调用os.fork(),preexec_fn()(在子进程中)和os.exec()(在子进程中).由于os.setuid,os.setgid和preexec_fn仅在Unix上受支持,因此该解决方案无法移植到其他类型的操作系统上.
subprocess.Popen will use the fork/exec model to use your preexec_fn. That is equivalent to calling os.fork(), preexec_fn() (in the child process), and os.exec() (in the child process) in that order. Since os.setuid, os.setgid, and preexec_fn are all only supported on Unix, this solution is not portable to other kinds of operating systems.
以下代码是演示如何执行此操作的脚本(Python 2.4 +):
The following code is a script (Python 2.4+) that demonstrates how to do this:
import os
import pwd
import subprocess
import sys
def main(my_args=None):
if my_args is None: my_args = sys.argv[1:]
user_name, cwd = my_args[:2]
args = my_args[2:]
pw_record = pwd.getpwnam(user_name)
user_name = pw_record.pw_name
user_home_dir = pw_record.pw_dir
user_uid = pw_record.pw_uid
user_gid = pw_record.pw_gid
env = os.environ.copy()
env[ 'HOME' ] = user_home_dir
env[ 'LOGNAME' ] = user_name
env[ 'PWD' ] = cwd
env[ 'USER' ] = user_name
report_ids('starting ' + str(args))
process = subprocess.Popen(
args, preexec_fn=demote(user_uid, user_gid), cwd=cwd, env=env
)
result = process.wait()
report_ids('finished ' + str(args))
print 'result', result
def demote(user_uid, user_gid):
def result():
report_ids('starting demotion')
os.setgid(user_gid)
os.setuid(user_uid)
report_ids('finished demotion')
return result
def report_ids(msg):
print 'uid, gid = %d, %d; %s' % (os.getuid(), os.getgid(), msg)
if __name__ == '__main__':
main()
您可以像这样调用此脚本:
You can invoke this script like this:
以root身份启动...
Start as root...
(hale)/tmp/demo$ sudo bash --norc
(root)/tmp/demo$ ls -l
total 8
drwxr-xr-x 2 hale wheel 68 May 17 16:26 inner
-rw-r--r-- 1 hale staff 1836 May 17 15:25 test-child.py
成为非root用户的子进程...
Become non-root in a child process...
(root)/tmp/demo$ python test-child.py hale inner /bin/bash --norc
uid, gid = 0, 0; starting ['/bin/bash', '--norc']
uid, gid = 0, 0; starting demotion
uid, gid = 501, 20; finished demotion
(hale)/tmp/demo/inner$ pwd
/tmp/demo/inner
(hale)/tmp/demo/inner$ whoami
hale
子进程退出时,我们回到父进程的根目录...
When the child process exits, we go back to root in parent ...
(hale)/tmp/demo/inner$ exit
exit
uid, gid = 0, 0; finished ['/bin/bash', '--norc']
result 0
(root)/tmp/demo$ pwd
/tmp/demo
(root)/tmp/demo$ whoami
root
请注意,让父进程等待子进程退出只是出于演示目的.我这样做是为了使父母和孩子可以共享一个终端.守护程序没有终端,几乎不需要等待子进程退出.
Note that having the parent process wait around for the child process to exit is for demonstration purposes only. I did this so that the parent and child could share a terminal. A daemon would have no terminal and would seldom wait around for a child process to exit.
这篇关于以与长期运行的Python进程不同的用户身份运行子进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!