Najlepsze praktyki dotyczące uruchamiania usługi Linux jako inny użytkownik

141

Usługi domyślnie uruchamiają się rootw czasie rozruchu na moim urządzeniu RHEL. Jeśli dobrze pamiętam, to samo dotyczy innych dystrybucji Linuksa, które używają skryptów inicjujących w /etc/init.d.

Jak myślisz, jaki jest najlepszy sposób, aby zamiast tego uruchomić procesy jako (statyczny) użytkownik według mojego wyboru?

Jedyną metodą, do której doszedłem, było użycie czegoś takiego:

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

Ale to wydaje się trochę nieporządne ...

Czy ukryto jakąś magię, która zapewnia łatwy mechanizm automatycznego uruchamiania usług jako użytkownicy inni niż root?

EDYCJA: Powinienem był powiedzieć, że procesy, które uruchamiam w tym przypadku, to skrypty w Pythonie lub programy Java. Wolałbym nie pisać wokół nich natywnego opakowania, więc niestety nie mogę wywołać setuid (), jak sugeruje Black .

James Brady
źródło
Czy Python nie zapewnia dostępu do rodziny wywołań systemowych setuid ()? Wydaje się, że to poważna wada w porównaniu z Perlem.
Jonathan Leffler
12
Wow, tak to działa: os.setuid (uid). Każdy dzień jest dniem szkolnym!
James Brady

Odpowiedzi:

67

W Debianie używamy start-stop-daemon narzędzia, które obsługuje pliki pid, zmienia użytkownika, umieszcza demona w tle i wiele więcej.

Nie jestem zaznajomiony z RedHatem, ale daemonnarzędzie, którego już używasz (które jest zdefiniowane w /etc/init.d/functions, przy okazji) jest wymieniane wszędzie jako odpowiednik start-stop-daemon, więc albo może zmienić uid twojego programu, albo sposób, w jaki to robisz to już jest poprawne.

Jeśli rozejrzysz się po sieci, jest kilka gotowych opakowań, których możesz użyć. Niektóre mogą być już zapakowane w RedHacie. Spójrz na daemonizeprzykład.


źródło
X-ref jest interesujący. Mam swój własny program demonizujący, bardzo podobny; nie wykonuje pliku pid ani pliku blokującego, ustawia umask. Mam oddzielny program główny SUID do ustawiania grup UID, GID, EUID, EGID i aux (nazywany asroot). Używam „asroot [opts] - env ​​-i [env] daemonize [opts] - command [opts]”
Jonathan Leffler
(ciąg dalszy): standardowy program env zgodny z POSIX nie akceptuje '-' między ustawieniem środowiska a wykonanym poleceniem (irytujące, ale tak).
Jonathan Leffler,
4
Jak można używać funkcji demona z /etc/init.d/functions w skrypcie startowym? Czy możesz pokazać przykład?
Meglio,
10
Na Debianie zobacz /etc/init.d/skeleton. Dodaj zmienne UID, GID i w do_start()użyciu:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham
Zauważyłem, że daemon()jest zdefiniowany w /etc/rc.d/init.d/functionobu moich polach RHEL i CentOS.
quickshiftin
53

Po przejrzeniu wszystkich sugestii tutaj odkryłem kilka rzeczy, które mam nadzieję będą przydatne dla innych na moim stanowisku:

  1. hop ma rację, wskazując mnie z powrotem /etc/init.d/functions: daemonfunkcja pozwala już ustawić alternatywnego użytkownika:

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

    Jest to realizowane przez zawijanie wywołania procesu runuser- więcej na ten temat później.

  2. Jonathan Leffler ma rację: w Pythonie jest setuid:

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

    Nadal jednak nie sądzę, aby można było ustawiać z poziomu JVM.

  3. Ani z wdziękiem sunie runuserobsługuj przypadku, w którym prosisz o uruchomienie polecenia jako użytkownik, którym już jesteś. Na przykład:

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

Aby obejść to zachowanie sui runuser, zmieniłem mój skrypt startowy na coś takiego:

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

Dziękuję wszystkim za pomoc!

James Brady
źródło
5
  • Niektóre demony (np. Apache) robią to samodzielnie, wywołując setuid ()
  • Możesz użyć flagi setuid-file aby uruchomić proces jako inny użytkownik.
  • Oczywiście rozwiązanie, o którym wspomniałeś, również działa.

Jeśli zamierzasz napisać własnego demona, to polecam wywołanie setuid (). W ten sposób twój proces może

  1. Skorzystaj z jego uprawnień roota (np. Otwieranie plików dziennika, tworzenie plików PID).
  2. Porzuć swoje uprawnienia roota w pewnym momencie podczas uruchamiania.
czarny
źródło
3

Dodam tylko kilka rzeczy, na które trzeba uważać:

  • Sudo w skrypcie init.d nie jest dobre, ponieważ wymaga tty ("sudo: przepraszam, musisz mieć tty, aby uruchomić sudo")
  • Jeśli demonizujesz aplikację java, możesz rozważyć Java Service Wrapper (który zapewnia mechanizm ustawiania identyfikatora użytkownika)
  • Inną alternatywą może być su --session-command = [cmd] [użytkownik]
pdeschen
źródło
3

na maszynie wirtualnej CENTOS (Red Hat) dla serwera svn: edytowane, /etc/init.d/svnserver aby zmienić pid na coś, co może zapisać svn:

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

i dodana opcja --user=svn:

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

Oryginalny plik pid to /var/run/svnserve.pid. Demon nie został uruchomiony, ponieważ tylko root mógł tam pisać.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
dulcana
źródło
3
Stwarza to lukę umożliwiającą eskalację uprawnień. Użytkownik svn może teraz umieścić dowolne PIDy w pliku /home/svn/run/svnserve.pid, które zostaną zabite zamiast procesu svn za każdym razem, gdy usługa svn jest zatrzymywana lub restartowana.
rbu,
2

Kilka rzeczy, na które należy uważać:

  • Jak wspomniałeś, su poprosi o podanie hasła, jeśli jesteś już użytkownikiem docelowym
  • Podobnie, setuid (2) nie powiedzie się, jeśli jesteś już użytkownikiem docelowym (w niektórych systemach operacyjnych)
  • setuid (2) nie instaluje uprawnień ani kontroli zasobów zdefiniowanych w /etc/limits.conf (Linux) lub / etc / user_attr (Solaris)
  • Jeśli wybierzesz trasę setgid (2) / setuid (2), nie zapomnij zadzwonić do initgroups (3) - więcej na ten temat tutaj

Generalnie używam / sbin / su, aby przełączyć się na odpowiedniego użytkownika przed uruchomieniem demonów.

Claymation
źródło
2

Spróbuj wykonać następujące czynności w skrypcie startowym:

setuid $USER application_name

U mnie zadziałało.

cyberJar
źródło
3
Nie jest to dostępne we wszystkich dystrybucjach. Próbowałem na RHEL 7:setuid: command not found
Cocowalla
0

Musiałem uruchomić aplikację Spring .jar jako usługę i znalazłem prosty sposób, aby uruchomić to jako określony użytkownik:

Zmieniłem właściciela i grupę mojego pliku jar na użytkownika, jako którego chciałem uruchomić. Następnie dowiązałem symbolicznie ten jar w init.d i uruchomiłem usługę.

Więc:

#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
źródło