La mejor práctica para ejecutar el servicio Linux como un usuario diferente

141

Servicios predeterminados para comenzar rooten el momento del arranque en mi cuadro RHEL. Si recuerdo correctamente, lo mismo es cierto para otras distribuciones de Linux que usan los scripts de inicio en /etc/init.d.

¿Cuál crees que es la mejor manera de ejecutar los procesos como un usuario (estático) de mi elección?

El único método al que había llegado era usar algo como:

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

Pero esto parece un poco desordenado ...

¿Hay algo de magia escondida que proporcione un mecanismo fácil para iniciar automáticamente los servicios como otros usuarios no root?

EDITAR: Debería haber dicho que los procesos que estoy comenzando en esta instancia son scripts Python o programas Java. Prefiero no escribir un contenedor nativo alrededor de ellos, así que desafortunadamente no puedo llamar a setuid () como sugiere Black .

James Brady
fuente
¿Python no proporciona acceso a la familia setuid () de llamadas al sistema? Eso parece un defecto grave en comparación con Perl.
Jonathan Leffler
12
Wow, sí lo hace: os.setuid (uid). ¡Cada día es un día escolar!
James Brady

Respuestas:

67

En Debian utilizamos la start-stop-daemonutilidad, que maneja archivos pid, cambia el usuario, pone el demonio en segundo plano y mucho más.

No estoy familiarizado con RedHat, pero la daemonutilidad que ya está usando (que se define en /etc/init.d/functions, por cierto) se menciona en todas partes como el equivalente a start-stop-daemon, por lo que también puede cambiar el uid de su programa o la forma en que lo hace Ya es el correcto.

Si mira alrededor de la red, hay varios envoltorios listos para usar que puede usar. Algunos incluso pueden estar ya empaquetados en RedHat. Echa un vistazo daemonize, por ejemplo.


fuente
La x-ref es interesante. Tengo mi propio programa daemonize, muy similar; no hace el archivo pid o lockfile, establece umask. Tengo un programa raíz SUID separado para configurar UID, GID, EUID, EGID y grupos auxiliares (llamados asroot). Uso 'asroot [opts] - env ​​-i [env] daemonize [opts] - command [opts]'
Jonathan Leffler
(continuación): el programa env estándar POSIX no acepta '-' entre la configuración del entorno y el comando ejecutado (molesto, pero así).
Jonathan Leffler
44
¿Cómo se puede utilizar la función daemon de /etc/init.d/functions en el script de inicio? ¿Puedes mostrar un ejemplo, por favor?
Meglio
10
En Debian ver /etc/init.d/skeleton. Agregue UID, variables GID y en do_start()uso:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham
Noto que daemon()está definido en las /etc/rc.d/init.d/functiondos cajas de RHEL y CentOS.
quickshiftin
53

Después de ver todas las sugerencias aquí, descubrí algunas cosas que espero sean útiles para otros en mi posición:

  1. hop tiene razón al señalarme /etc/init.d/functions: la daemonfunción ya le permite configurar un usuario alternativo:

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

    Esto se implementa envolviendo la invocación del proceso con runusermás información sobre esto más adelante.

  2. Jonathan Leffler tiene razón: hay setuid en Python:

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

    Sin embargo, todavía no creo que pueda establecerse desde dentro de una JVM.

  3. Ni sutampoco runuser maneja con gracia el caso en el que solicita ejecutar un comando como el usuario que ya es. P.ej:

    [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 ese comportamiento de suy runuser, he cambiado mi script de inicio a algo como:

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

¡Gracias a todos por su ayuda!

James Brady
fuente
5
  • Algunos demonios (por ejemplo, apache) lo hacen solos llamando a setuid ()
  • Puede usar el indicador setuid-file para ejecutar el proceso como un usuario diferente.
  • Por supuesto, la solución que mencionó también funciona.

Si tiene la intención de escribir su propio demonio, le recomiendo llamar a setuid (). De esta manera, su proceso puede

  1. Utilice sus privilegios de root (por ejemplo, abrir archivos de registro, crear archivos pid).
  2. Descarte sus privilegios de root en un momento determinado durante el inicio.
Negro
fuente
3

Solo para agregar algunas otras cosas a tener en cuenta:

  • Sudo en un script init.d no es bueno ya que necesita un tty ("sudo: lo siento, debes tener un tty para ejecutar sudo")
  • Si está demonizando una aplicación Java, es posible que desee considerar Java Service Wrapper (que proporciona un mecanismo para configurar la identificación del usuario)
  • Otra alternativa podría ser su --session-command = [cmd] [usuario]
Pdeschen
fuente
3

en una máquina virtual CENTOS (Red Hat) para el servidor svn: editado /etc/init.d/svnserver para cambiar el pid a algo que svn pueda escribir:

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

y opción agregada --user=svn:

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

El original pidfile fue /var/run/svnserve.pid. El demonio no comenzó porque solo la raíz podía escribir allí.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
dulcana
fuente
3
Esto crea una vulnerabilidad de escalada de privilegios. El usuario svn ahora puede poner PID arbitrarios en el archivo /home/svn/run/svnserve.pid que se eliminará en lugar del proceso svn siempre que el servicio svn se detenga o reinicie.
rbu
2

Algunas cosas a tener en cuenta:

  • Como mencionó, su le pedirá una contraseña si ya es el usuario objetivo
  • Del mismo modo, setuid (2) fallará si ya es el usuario objetivo (en algunos sistemas operativos)
  • setuid (2) no instala privilegios o controles de recursos definidos en /etc/limits.conf (Linux) o / etc / user_attr (Solaris)
  • Si va por la ruta setgid (2) / setuid (2), no olvide llamar a initgroups (3); más sobre esto aquí

Generalmente uso / sbin / su para cambiar al usuario apropiado antes de iniciar los demonios.

plastilina
fuente
2

¿Por qué no prueba lo siguiente en el guión de inicio?

setuid $USER application_name

Funcionó para mi.

cyberJar
fuente
3
Esto no está disponible en todas las distribuciones. setuid: command not found
Probé
0

Necesitaba ejecutar una aplicación Spring .jar como servicio, y encontré una manera simple de ejecutar esto como un usuario específico:

Cambié el propietario y el grupo de mi archivo jar al usuario que quería ejecutar. Luego vinculó este jar en init.d e inició el servicio.

Entonces:

#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
fuente