Best Practice, um den Linux-Dienst als einen anderen Benutzer auszuführen

141

Die Dienste werden standardmäßig zum Startzeitpunkt rootauf meiner RHEL-Box gestartet. Wenn ich mich richtig erinnere, gilt das Gleiche für andere Linux-Distributionen, die die Init-Skripte in verwenden /etc/init.d.

Was ist Ihrer Meinung nach der beste Weg, um die Prozesse stattdessen als (statischer) Benutzer meiner Wahl ausführen zu lassen?

Die einzige Methode, zu der ich gekommen war, war, etwas zu verwenden wie:

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

Aber das scheint ein bisschen unordentlich ...

Ist etwas Magie versteckt, die einen einfachen Mechanismus zum automatischen Starten von Diensten als andere Benutzer ohne Rootberechtigung bietet?

EDIT: Ich hätte sagen sollen, dass die Prozesse, die ich in dieser Instanz starte, entweder Python-Skripte oder Java-Programme sind. Ich möchte lieber keinen nativen Wrapper um sie schreiben, daher kann ich setuid () leider nicht aufrufen, wie Black vorschlägt.

James Brady
quelle
Bietet Python keinen Zugriff auf die setuid () -Familie von Systemaufrufen? Das scheint im Vergleich zu Perl ein schwerwiegender Mangel zu sein.
Jonathan Leffler
12
Wow, ja, das tut es: os.setuid (uid). Jeder Tag ist ein Schultag!
James Brady

Antworten:

67

Unter Debian verwenden wir das start-stop-daemonDienstprogramm, das PID-Dateien verarbeitet, den Benutzer ändert, den Daemon in den Hintergrund stellt und vieles mehr.

Ich bin mit RedHat nicht vertraut, aber das daemonDienstprogramm, das Sie bereits verwenden (das /etc/init.d/functionsübrigens in definiert ist), wird überall als Äquivalent zu erwähnt start-stop-daemon, sodass entweder die UID Ihres Programms oder die Art und Weise, wie Sie dies tun, geändert werden kann es ist schon das richtige.

Wenn Sie sich im Internet umschauen, gibt es mehrere vorgefertigte Wrapper, die Sie verwenden können. Einige sind möglicherweise bereits in RedHat verpackt. Schauen Sie sich daemonizezum Beispiel an.


quelle
Der x-ref ist interessant. Ich habe mein eigenes Daemonize-Programm, sehr ähnlich; macht nicht die PID-Datei oder Sperrdatei, setzt umask. Ich habe ein separates SUID-Root-Programm zum Festlegen von UID-, GID-, EUID-, EGID- und Aux-Gruppen (asroot genannt). Ich benutze 'asroot [opts] - env ​​-i [env] daemonize [opts] - command [opts]'
Jonathan Leffler
(Fortsetzung): Das POSIX-Standard-env-Programm akzeptiert kein '-' zwischen der Umgebungseinstellung und dem ausgeführten Befehl (lästig, aber so).
Jonathan Leffler
4
Wie kann die Daemon-Funktion von /etc/init.d/functions im Upstart-Skript verwendet werden? Können Sie bitte ein Beispiel zeigen?
Meglio
10
Auf Debian siehe /etc/init.d/skeleton. Fügen Sie UID, GID-Variablen hinzu und do_start()verwenden Sie:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham
Ich stelle fest, dass dies sowohl in meinen RHEL- als auch in meinen CentOS-Boxen daemon()definiert ist /etc/rc.d/init.d/function.
Quickshiftin
53

Nachdem ich mir alle Vorschläge hier angesehen habe, habe ich einige Dinge entdeckt, von denen ich hoffe, dass sie für andere in meiner Position nützlich sind:

  1. hop weist mich zu Recht auf Folgendes zurück /etc/init.d/functions: Mit der daemonFunktion können Sie bereits einen alternativen Benutzer festlegen:

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

    Dies wird implementiert, indem der Prozessaufruf mit runuser- dazu später mehr verpackt wird .

  2. Jonathan Leffler hat recht: In Python gibt es Setuid:

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

    Ich glaube jedoch immer noch nicht, dass Sie innerhalb einer JVM eine Einstellung vornehmen können.

  3. Behandeln Sie den Fall, in dem Sie als Benutzer, den Sie bereits sind, aufgefordert werden, einen Befehl auszuführen, weder ordnungsgemäß sunoch runuserordnungsgemäß. Z.B:

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

Um dieses Verhalten von suund zu umgehen runuser, habe ich mein Init-Skript in Folgendes geändert:

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

Vielen Dank für Ihre Hilfe!

James Brady
quelle
5
  • Einige Dämonen (z. B. Apache) tun dies selbst, indem sie setuid () aufrufen.
  • Sie können das Flag setuid-file verwenden , um den Prozess als anderer Benutzer auszuführen.
  • Natürlich funktioniert auch die von Ihnen erwähnte Lösung.

Wenn Sie beabsichtigen, einen eigenen Daemon zu schreiben, empfehle ich, setuid () aufzurufen. Auf diese Weise kann Ihr Prozess

  1. Nutzen Sie die Root-Rechte (z. B. Protokolldateien öffnen, PID-Dateien erstellen).
  2. Löschen Sie die Root-Berechtigungen zu einem bestimmten Zeitpunkt während des Startvorgangs.
Schwarz
quelle
3

Nur um einige andere Dinge hinzuzufügen, auf die Sie achten sollten:

  • Sudo in einem init.d-Skript ist nicht gut, da es ein tty benötigt ("sudo: Entschuldigung, Sie müssen ein tty haben, um sudo ausführen zu können")
  • Wenn Sie eine Java-Anwendung dämonisieren, sollten Sie Java Service Wrapper in Betracht ziehen (der einen Mechanismus zum Festlegen der Benutzer-ID bietet).
  • Eine andere Alternative könnte su --session-command = [cmd] [user] sein.
pdeschen
quelle
3

auf einer virtuellen CENTOS (Red Hat) -Maschine für SVN-Server: Bearbeitet /etc/init.d/svnserver , um die PID in etwas zu ändern, das SVN schreiben kann:

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

und hinzugefügte Option --user=svn:

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

Das ursprüngliche Pidfile war /var/run/svnserve.pid. Der Daemon wurde nicht gestartet, da nur root dort schreiben konnte.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
Dulcana
quelle
3
Dies führt zu einer Sicherheitsanfälligkeit bezüglich der Eskalation von Berechtigungen. Der svn-Benutzer kann nun beliebige PIDs in die Datei /home/svn/run/svnserve.pid einfügen, die bei jedem Stopp oder Neustart des svn-Dienstes anstelle des svn-Prozesses beendet werden.
Rbu
2

Einige Dinge, auf die Sie achten sollten:

  • Wie Sie bereits erwähnt haben, fordert su Sie zur Eingabe eines Kennworts auf, wenn Sie bereits der Zielbenutzer sind
  • Ebenso schlägt setuid (2) fehl, wenn Sie bereits der Zielbenutzer sind (auf einigen Betriebssystemen).
  • setuid (2) installiert keine Berechtigungen oder Ressourcensteuerelemente, die in /etc/limits.conf (Linux) oder / etc / user_attr (Solaris) definiert sind.
  • Wenn Sie die Route setgid (2) / setuid (2) wählen, vergessen Sie nicht, initgroups (3) aufzurufen - mehr dazu hier

Im Allgemeinen verwende ich / sbin / su, um vor dem Starten von Daemons zum entsprechenden Benutzer zu wechseln.

Claymation
quelle
2

Probieren Sie im Init-Skript Folgendes aus:

setuid $USER application_name

Es hat bei mir funktioniert.

cyberJar
quelle
3
Dies ist nicht in allen Distributionen verfügbar. Ich habe RHEL 7 setuid: command not found
anprobiert
0

Ich musste eine Spring .jar-Anwendung als Dienst ausführen und fand eine einfache Möglichkeit, dies als bestimmter Benutzer auszuführen:

Ich habe den Eigentümer und die Gruppe meiner JAR-Datei in den Benutzer geändert, als den ich ausführen wollte. Dann verknüpfte dieses Glas in init.d und startete den Dienst.

So:

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