запуск python-daemon в качестве непривилегированного пользователя и сохранение членства в группах

Я пишу демон на python, используя пакет python-daemon. демон запускается во время загрузки (init.d) и нуждается в доступе к различным устройствам. демон должен работать во встроенной системе (beaglebone), работающей под управлением Ubuntu.

теперь моя проблема в том, что я хочу запустить демон как непривилегированный пользователь (например, mydaemon), а не root.

чтобы разрешить демону доступ к устройствам, я добавил этого пользователя в необходимые группы. в коде Python я использую daemon.DaemonContext(uid=uidofmydamon).

процесс, запущенный root, прекрасно демонизируется и принадлежит правильному пользователю, но я получаю ошибки отказ в доступе при попытке доступа к устройствам. Я написал небольшое тестовое приложение, и кажется, что процесс не наследует членство в группах пользователя.

#!/usr/bin/python
import logging, daemon, os

if __name__ == '__main__':
  lh=logging.StreamHandler()
  logger = logging.getLogger()
  logger.setLevel(logging.INFO)
  logger.addHandler(lh)

  uid=1001 ## UID of the daemon user
  with daemon.DaemonContext(uid=uid,
                            files_preserve=[lh.stream],
                            stderr=lh.stream):
    logger.warn("UID : %s" % str(os.getuid()))
    logger.warn("groups: %s" % str(os.getgroups()))

когда я запускаю приведенный выше код как пользователь с uid=1001, я получаю что-то вроде

$ ./testdaemon.py
UID: 1001
groups: [29,107,1001]

тогда как когда я запускаю приведенный выше код от имени пользователя root (или su), я получаю:

$ sudo ./testdaemon.py
UID: 1001
groups: [0]

Как я могу создать демон-процесс, запущенный пользователем root, но с другим эффективным uid и неповрежденным членством в группах?


person umläute    schedule 01.07.2013    source источник
comment
Для какого дистрибутива Linux это?   -  person rkyser    schedule 01.07.2013
comment
ubuntu и debian (соответственно я обновил вопрос)   -  person umläute    schedule 02.07.2013
comment
Есть ли причина, по которой вы не можете изменить своего пользователя-демона перед запуском демона python? Возможно, что-то вроде (этот ответ)[stackoverflow.com/a/8941040/651848] подойдет для ваших нужд?   -  person rkyser    schedule 02.07.2013
comment
@rkyser да, я делаю это сейчас (см. мой собственный ответ), но это усложняет некоторые вещи с правами доступа к файлам (PID-файлы обычно создаются в местах, где может писать только root)   -  person umläute    schedule 02.07.2013


Ответы (2)


мое текущее решение включает отказ от привилегий root перед запуском фактического демона с использованием аргумента chuid для start-stop-daemon:

 start-stop-daemon \
      --start \
      --chuid daemonuser \
      --name testdaemon \
      --pidfile /var/run/testdaemon/test.pid \
      --startas /tmp/testdaemon.py \
     -- \
      --pidfile /var/run/testdaemon/test.pid \
      --logfile=/var/log/testdaemon/testdaemon.log

недостатком этого решения является то, что мне нужно создать все каталоги, в которые демон должен писать (особенно /var/run/testdaemon и /var/log/testdaemon), до запуска фактического демона (с соответствующими правами доступа к файлам).

я бы предпочел написать эту логику на python, а не на bash.

на данный момент это работает, но я думаю, что это должно быть решено более элегантным способом.

person umläute    schedule 02.07.2013

Это может быть исправлено путем исправления обезьяной модуля демона, код выглядит следующим образом:

import os, grp, pwd

class DaemonError(Exception):
    pass

class DaemonOSEnvironmentError(DaemonError, OSError):
    pass

def change_process_owner(uid, gid):
    try:
        # This line adds all the groups the user is member of
        # to keep the expected permissions
        os.setgroups(
            [g.gr_gid for g in grp.getgrall()
                if pwd.getpwuid(uid).pw_name in g.gr_mem
            ]
        )
        os.setgid(gid)
        os.setuid(uid)
    except Exception, exc:
        error = DaemonOSEnvironmentError(u"Unable to change process 
                    owner (%(exc)s)" % vars())
        raise error

А затем патч обезьяны:

import daemon
daemon.daemon.change_process_owner = change_process_owner
person Ricardo Manriquez    schedule 06.07.2018