Best practice per eseguire il servizio Linux come utente diverso


141

Per impostazione predefinita, i servizi si avviano rootall'avvio nella mia casella RHEL. Se ricordo bene, lo stesso vale per altre distro Linux che usano gli script init in /etc/init.d.

Quale pensi sia il modo migliore per far funzionare invece i processi come utente (statico) di mia scelta?

L'unico metodo con cui ero arrivato era usare qualcosa del tipo:

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

Ma questo sembra un po 'disordinato ...

C'è un po 'di magia nascosta che fornisce un meccanismo semplice per avviare automaticamente i servizi come altri utenti non root?

EDIT: avrei dovuto dire che i processi che sto avviando in questa istanza sono script Python o programmi Java. Preferirei non scrivere un wrapper nativo attorno a loro, quindi sfortunatamente non riesco a chiamare setuid () come suggerisce Black .


Python non fornisce accesso alla famiglia di chiamate di sistema setuid ()? Sembra un grave difetto rispetto a Perl.
Jonathan Leffler,

12
Wow, sì, lo fa: os.setuid (uid). Ogni giorno è un giorno di scuola!
James Brady,

Risposte:


67

Su Debian usiamo l' start-stop-daemonutility, che gestisce i file pid, cambia l'utente, mette il demone in background e molto altro.

Non ho familiarità con RedHat, ma l' daemonutilità che stai già utilizzando (che è definita in /etc/init.d/functions, tra l'altro) è menzionata ovunque come equivalente a start-stop-daemon, quindi o può anche cambiare l'UID del tuo programma, o il modo in cui lo fai è già quello corretto.

Se ti guardi intorno, ci sono diversi involucri pronti che puoi usare. Alcuni potrebbero anche essere già impacchettati in RedHat. Dai un'occhiata daemonize, per esempio.


L'x-ref è interessante. Ho il mio programma daemonize, molto simile; non esegue il pidfile o il lockfile, imposta umask. Ho un programma root SUID separato per l'impostazione di UID, GID, EUID, EGID e gruppi aux (chiamati asroot). Io uso 'asroot [opts] - env ​​-i [env] daemonize [opts] - command [opts]'
Jonathan Leffler

(continua): il programma env standard POSIX non accetta '-' tra l'impostazione dell'ambiente e il comando eseguito (fastidioso, ma così).
Jonathan Leffler,

4
Come si può usare la funzione demone da /etc/init.d/functions nello script upstart? Puoi mostrare un esempio, per favore.
Meglio,

10
Su Debian vedere /etc/init.d/skeleton. Aggiungi UID, variabili GID e in do_start()uso:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham il

Ho notato che daemon()è definito in /etc/rc.d/init.d/functionentrambe le mie scatole RHEL e CentOS.
cambio rapido il

53

Dopo aver esaminato tutti i suggerimenti qui, ho scoperto alcune cose che spero possano essere utili agli altri nella mia posizione:

  1. hop ha ragione a riportarmi a /etc/init.d/functions: la daemonfunzione ti consente già di impostare un utente alternativo:

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

    Questo viene implementato avvolgendo l'invocazione del processo con runuser- ne parleremo più avanti.

  2. Jonathan Leffler ha ragione: c'è setuid in Python:

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

    Tuttavia, non penso ancora che tu possa essere impostato all'interno di una JVM.

  3. surunuser gestire correttamente il caso in cui si chiede di eseguire un comando come utente che già sono. Per esempio:

    [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)
    

Per ovviare a quel comportamento di sue runuser, ho cambiato il mio script init in qualcosa del tipo:

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

Grazie a tutti per il vostro aiuto!


5
  • Alcuni demoni (ad esempio apache) lo fanno da soli chiamando setuid ()
  • È possibile utilizzare il flag setuid-file per eseguire il processo come un altro utente.
  • Naturalmente, anche la soluzione che hai citato funziona.

Se hai intenzione di scrivere il tuo demone, allora ti consiglio di chiamare setuid (). In questo modo, il tuo processo può

  1. Usa i suoi privilegi di root (es. Apri file di log, crea file pid).
  2. Rilascia i privilegi di root a un certo punto durante l'avvio.

3

Solo per aggiungere alcune altre cose a cui fare attenzione:

  • Sudo in uno script init.d non va bene poiché ha bisogno di un tty ("sudo: scusa, devi avere un tty per eseguire sudo")
  • Se stai eseguendo la demonizzazione di un'applicazione Java, potresti prendere in considerazione Java Service Wrapper (che fornisce un meccanismo per l'impostazione dell'ID utente)
  • Un'altra alternativa potrebbe essere su --session-command = [cmd] [utente]

3

su una macchina virtuale CENTOS (Red Hat) per server svn: modificato /etc/init.d/svnserver per cambiare il pid in qualcosa che svn può scrivere:

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

e aggiunta opzione --user=svn:

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

Il pidfile originale era /var/run/svnserve.pid. Il demone non è stato avviato perché solo root poteva scrivere lì.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart

3
Ciò crea una vulnerabilità di escalation di privilegi. L'utente svn può ora inserire PID arbitrari nel file /home/svn/run/svnserve.pid che verrà ucciso al posto del processo svn ogni volta che il servizio svn viene arrestato o riavviato.
rbu,

2

Alcune cose a cui fare attenzione:

  • Come hai già detto, su ti chiederà una password se sei già l'utente di destinazione
  • Allo stesso modo, setuid (2) fallirà se sei già l'utente di destinazione (su alcuni SO)
  • setuid (2) non installa i privilegi o i controlli delle risorse definiti in /etc/limits.conf (Linux) o / etc / user_attr (Solaris)
  • Se segui il percorso setgid (2) / setuid (2), non dimenticare di chiamare initgroups (3) - di più su questo qui

In genere uso / sbin / su per passare all'utente appropriato prima di avviare i demoni.


2

Perché non provare quanto segue nello script init:

setuid $USER application_name

Ha funzionato per me.


3
Questo non è disponibile su tutte le distro. Ho provato su RHEL 7:setuid: command not found
Cocowalla il

0

Avevo bisogno di eseguire un'applicazione .jar di Spring come servizio e ho trovato un modo semplice per eseguirlo come utente specifico:

Ho cambiato il proprietario e il gruppo del mio file jar con l'utente che volevo eseguire come. Quindi ha ricollegato questo vaso in init.d e avviato il servizio.

Così:

#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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.