Dropping Privileges in Python
When writing a small Python web application using the lightweight CherryPy framework, I needed the server to run on port 80. Of course running a server as root
is enough to scare even the hardest sysadmin, so I obviously wanted it to drop privs immediately upon startup, once it had opened the default http port. I wrote the function below to drop privs and switch to a new user and group (usually nobody/nogroup
). It is self-contained, should work with anything - there is nothing specific to any system. If you find it useful of have any suggestions to improve it, please leave a comment.
To use this within Cherrypy, set the port to 80 in the cherrypy config file, then add the following before your server start:
Archived Comments
AUTHOR: Dan C DATE: 12/30/2005 11:54:37 PM Thanks Hey thanks, this function was exactly what I was looking for! (made me realise I should’ve been able to code it myself too :-). I’m running Cherrypy on an embedded system (crazy, I know!) so I want to minimise memory overheads, therefore no Apache or lighttpd with FCGI or anything – I’m just serving everything from the Python HTTP server. I really wanted it to drop privileges so it’s not running as root …
The only problem is, Cherrypy calls the onStartServerList functions before it starts the HTTP server i.e. before it binds to the socket. I can’t figure out how to get around it without editing the code for the HTTP server … any ideas?
AUTHOR: gavinb DATE: 01/31/2006 12:21:04 PM Socket binding CherryPy Hi Dan,
Glad it helped! I’ve been using this code successfully for a while to run a private server on port 80. I went to the CherryPy code to check on the order as you mentioned, and verified that (in at least version 2.0) it calls the onServerStartList functions after it binds to the socket. I checked both the regular server class and the PooledThreadServer class.
It’s possible that in v2.1 (I haven’t upgraded yet) they have changed the order of initialisation and binding. And things are different again now that 2.2 is using WSGI. I suggest you send your question to the cherrypy mailing list.
Best - G
AUTHOR: Dwayne Litzenberger DATE: 11/02/2007 12:36:27 PM What about os.setgroups()? You missed something: os.setgroups([]). Look:
import os os.setgid(1000) os.setuid(1000) os.getgroups() [0] os.system(“id”) uid=1000(dwon) gid=1000(dwon) groups=0(root)
COMMENT: AUTHOR: Anonymous DATE: 08/06/2008 02:59:35 AM A slight change to make this prettier: To get the current userid name:
pwd.getpwuid(os.getuid()).pw_name
is better than
pwd.getpwuid(os.getuid())[0]
Marius.