Prática recomendada para executar o serviço Linux como um usuário diferente

141

Os serviços padrão para iniciar como rootno momento da inicialização na minha caixa RHEL. Se bem me lembro, o mesmo vale para outras distribuições Linux que usam os scripts init /etc/init.d.

Em sua opinião, qual é a melhor maneira de executar os processos como um usuário (estático) de minha escolha?

O único método que eu tinha chegado era usar algo como:

 su my_user -c 'daemon my_cmd &>/dev/null &'

Mas isso parece um pouco desarrumado ...

Existe alguma mágica escondida que fornece um mecanismo fácil para iniciar automaticamente os serviços como outros usuários não-root?

Edição: Eu deveria ter dito que os processos que estou iniciando nesta instância são scripts Python ou programas Java. Prefiro não escrever um wrapper nativo em torno deles, então, infelizmente, não consigo chamar setuid (), como sugere Black .

James Brady
fonte
O Python não fornece acesso à família de chamadas do sistema setuid ()? Isso parece um defeito sério em comparação com o Perl.
Jonathan Leffler
12
Uau, sim, sim: os.setuid (uid). Todo dia é dia de escola!
James Brady

Respostas:

67

No Debian, usamos o start-stop-daemonutilitário, que lida com arquivos pid, alterando o usuário, colocando o daemon em segundo plano e muito mais.

Eu não estou familiarizado com o RedHat, mas o daemonutilitário que você já está usando (definido em /etc/init.d/functions, btw.) É mencionado em todos os lugares como o equivalente a start-stop-daemon, portanto, também pode alterar o uid do seu programa ou a maneira como você faz já é o correto.

Se você olhar em volta da rede, existem vários invólucros prontos que você pode usar. Alguns podem até já estar empacotados no RedHat. Dê uma olhada daemonize, por exemplo.


fonte
O x-ref é interessante. Eu tenho meu próprio programa daemonize, muito semelhante; não executa o pidfile ou o lockfile, define umask. Eu tenho um programa raiz SUID separado para definir grupos UID, GID, EUID, EGID e aux (chamados asroot). Eu uso 'asroot [opts] - env ​​-i [env] daemonize [opts] - comando [opts]' #
Jonathan Leffler
(continuação): o programa env padrão POSIX não aceita '-' entre a configuração do ambiente e o comando executado (irritante, mas sim).
Jonathan Leffler
4
Como a função daemon do /etc/init.d/functions pode ser usada no script inicial? Você pode mostrar um exemplo, por favor.
Meglio
10
No Debian veja /etc/init.d/skeleton. Adicione variáveis ​​UID, GID e em do_start()uso:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham
Percebo que daemon()está definido nas /etc/rc.d/init.d/functionminhas caixas RHEL e CentOS.
quickshiftin
53

Depois de analisar todas as sugestões aqui, descobri algumas coisas que espero que sejam úteis para outras pessoas na minha posição:

  1. hop está certo em me apontar de volta para /etc/init.d/functions: a daemonfunção já permite que você defina um usuário alternativo:

    daemon --user=my_user my_cmd &>/dev/null &
    

    Isso é implementado envolvendo a invocação do processo com runuser- mais sobre isso posteriormente.

  2. Jonathan Leffler está certo: há setuid em Python:

    import os
    os.setuid(501) # UID of my_user is 501
    

    Ainda acho que você não pode configurar de dentro de uma JVM, no entanto.

  3. Nem sunem runuser graciosamente lidar com o caso onde você perguntar para executar um comando como o usuário que já estão. Por exemplo:

    [my_user@my_host]$ id
    uid=500(my_user) gid=500(my_user) groups=500(my_user)
    [my_user@my_host]$ su my_user -c "id"
    Password: # don't want to be prompted!
    uid=500(my_user) gid=500(my_user) groups=500(my_user)
    

Para solucionar esse comportamento de sue runuser, mudei meu script init para algo como:

if [[ "$USER" == "my_user" ]]
then
    daemon my_cmd &>/dev/null &
else
    daemon --user=my_user my_cmd &>/dev/null &
fi

Obrigado a todos por sua ajuda!

James Brady
fonte
5
  • Alguns daemons (por exemplo, apache) fazem isso sozinhos chamando setuid ()
  • Você pode usar o sinalizador setuid-file para executar o processo como um usuário diferente.
  • Obviamente, a solução que você mencionou também funciona.

Se você pretende escrever seu próprio daemon, recomendo chamar setuid (). Dessa forma, seu processo pode

  1. Faça uso de seus privilégios de root (por exemplo, abra arquivos de log, crie arquivos pid).
  2. Solte seus privilégios de root em um determinado ponto durante a inicialização.
Preto
fonte
3

Apenas para adicionar outras coisas a serem observadas:

  • O sudo em um script init.d não é bom, pois precisa de um tty ("sudo: desculpe, você deve ter um tty para executar o sudo")
  • Se você estiver daemonizando um aplicativo java, considere o Java Service Wrapper (que fornece um mecanismo para configurar o ID do usuário)
  • Outra alternativa poderia ser su --session-command = [cmd] [user]
pdeschen
fonte
3

em uma máquina virtual CENTOS (Red Hat) para servidor svn: editada /etc/init.d/svnserver para alterar o pid para algo que o svn possa escrever:

pidfile=${PIDFILE-/home/svn/run/svnserve.pid}

e opção adicionada --user=svn:

daemon --pidfile=${pidfile} --user=svn $exec $args

O pidfile original era /var/run/svnserve.pid. O daemon não foi iniciado porque apenas o root poderia escrever lá.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
dulcana
fonte
3
Isso cria uma vulnerabilidade de escalação de privilégios. O usuário svn agora pode colocar PIDs arbitrários no arquivo /home/svn/run/svnserve.pid, que será eliminado em vez do processo svn sempre que o serviço svn for parado ou reiniciado.
Rbu
2

Algumas coisas a observar:

  • Como você mencionou, su solicitará uma senha se você já for o usuário de destino
  • Da mesma forma, setuid (2) falhará se você já for o usuário de destino (em alguns sistemas operacionais)
  • O setuid (2) não instala privilégios ou controles de recursos definidos em /etc/limits.conf (Linux) ou / etc / user_attr (Solaris)
  • Se você seguir a rota setgid (2) / setuid (2), não se esqueça de chamar initgroups (3) - mais sobre isso aqui

Eu geralmente uso / sbin / su para alternar para o usuário apropriado antes de iniciar daemons.

claymation
fonte
2

Por que não tentar o seguinte no script init:

setuid $USER application_name

Funcionou para mim.

cyberJar
fonte
3
Isso não está disponível em todas as distros. Eu tentei no RHEL 7:setuid: command not found
Cocowalla
0

Eu precisava executar um aplicativo .jar Spring como um serviço e encontrei uma maneira simples de executá-lo como um usuário específico:

Alterei o proprietário e o grupo do meu arquivo jar para o usuário que eu queria executar. Em seguida, vinculou este jarro no init.d e iniciou o serviço.

Assim:

#chown myuser:myuser /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar

#ln -s /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar /etc/init.d/springApp

#service springApp start

#ps aux | grep java
myuser    9970  5.0  9.9 4071348 386132 ?      Sl   09:38   0:21 /bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar
Somaiah Kumbera
fonte