Praktik terbaik untuk menjalankan layanan Linux sebagai pengguna yang berbeda

141

Layanan standar untuk memulai rootpada saat boot pada kotak RHEL saya. Jika saya ingat dengan benar, hal yang sama berlaku untuk distro Linux lain yang menggunakan skrip init di /etc/init.d.

Menurut Anda apa cara terbaik untuk menjalankan proses sebagai pengguna (statis) yang saya pilih?

Satu-satunya metode yang saya gunakan adalah menggunakan sesuatu seperti:

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

Tapi ini sepertinya agak berantakan ...

Apakah ada sedikit keajaiban yang tersimpan yang menyediakan mekanisme mudah untuk secara otomatis memulai layanan seperti pengguna non-root lainnya?

EDIT: Saya seharusnya mengatakan bahwa proses yang saya mulai dalam contoh ini adalah skrip Python atau program Java. Saya lebih suka tidak menulis pembungkus asli di sekitar mereka, jadi sayangnya saya tidak dapat memanggil setuid () seperti yang disarankan Black .

James Brady
sumber
Apakah Python tidak menyediakan akses ke keluarga setuid () dari panggilan sistem? Itu tampak seperti cacat serius dibandingkan dengan Perl.
Jonathan Leffler
12
Wow, ya itu: os.setuid (uid). Setiap hari adalah hari sekolah!
James Brady

Jawaban:

67

Pada Debian kita menggunakan start-stop-daemonutilitas, yang menangani file pid, mengubah pengguna, menempatkan daemon ke latar belakang dan banyak lagi.

Saya tidak terbiasa dengan RedHat, tetapi daemonutilitas yang sudah Anda gunakan (yang didefinisikan dalam /etc/init.d/functions, btw.) Disebutkan di mana-mana sebagai setara dengan start-stop-daemon, jadi itu juga dapat mengubah uid program Anda, atau cara Anda melakukannya itu sudah benar.

Jika Anda melihat-lihat jaring, ada beberapa bungkus siap pakai yang dapat Anda gunakan. Beberapa bahkan mungkin sudah dikemas dalam RedHat. Lihat daemonize, misalnya.


sumber
X-ref menarik. Saya memiliki program daemonize saya sendiri, sangat mirip; tidak melakukan pidfile atau lockfile, tidak mengatur umask. Saya memiliki program root SUID terpisah untuk mengatur grup UID, GID, EUID, EGID, dan aux (disebut asroot). Saya menggunakan 'asroot [opts] - env ​​-i [env] daemonize [opts] - command [opts]'
Jonathan Leffler
(lanjutan): program env standar POSIX tidak menerima '-' antara pengaturan lingkungan dan perintah yang dijalankan (irksome, but so).
Jonathan Leffler
4
Bagaimana fungsi daemon dari /etc/init.d/functions digunakan dalam skrip pemula? Tolong tunjukkan contoh.
Meglio
10
Pada Debian, lihat /etc/init.d/skeleton. Tambahkan UID, variabel GID dan sedang do_start()digunakan:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham
Saya perhatikan daemon()didefinisikan /etc/rc.d/init.d/functionpada kedua kotak RHEL & CentOS milik saya.
quickshiftin
53

Setelah melihat semua saran di sini, saya telah menemukan beberapa hal yang saya harap akan bermanfaat bagi orang lain di posisi saya:

  1. hop benar untuk mengarahkan saya kembali ke /etc/init.d/functions: daemonfungsi sudah memungkinkan Anda untuk menetapkan pengguna alternatif:

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

    Ini diimplementasikan dengan membungkus doa proses dengan runuser- lebih lanjut tentang ini nanti.

  2. Jonathan Leffler benar: ada setuid dengan Python:

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

    Saya masih tidak berpikir Anda bisa setuid dari dalam JVM, namun.

  3. Baik sumaupun runuser anggun menangani kasus di mana Anda meminta untuk menjalankan perintah sebagai pengguna yang sudah ada. Misalnya:

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

Untuk mengatasi perilaku itu sudan runuser, saya telah mengubah skrip init saya menjadi sesuatu seperti:

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

Terima kasih atas bantuan Anda!

James Brady
sumber
5
  • Beberapa daemon (mis. Apache) melakukan ini sendiri dengan memanggil setuid ()
  • Anda bisa menggunakan flag file-setuid untuk menjalankan proses sebagai pengguna yang berbeda.
  • Tentu saja, solusi yang Anda sebutkan juga berfungsi.

Jika Anda bermaksud untuk menulis daemon Anda sendiri, maka saya sarankan memanggil setuid (). Dengan cara ini, proses Anda bisa

  1. Manfaatkan hak akses root-nya (mis. File log terbuka, buat file pid).
  2. Jatuhkan hak akses root pada titik tertentu selama startup.
Hitam
sumber
3

Hanya untuk menambahkan beberapa hal lain yang harus diperhatikan:

  • Sudo dalam skrip init.d tidak baik karena memerlukan tty ("sudo: maaf, Anda harus memiliki tty untuk menjalankan sudo")
  • Jika Anda melakukan daemonisasi aplikasi java, Anda mungkin ingin mempertimbangkan Java Service Wrapper (yang menyediakan mekanisme untuk mengatur id pengguna)
  • Alternatif lain bisa su --session-command = [cmd] [pengguna]
pdeschen
sumber
3

pada mesin virtual CENTOS (Red Hat) untuk svn server: diedit /etc/init.d/svnserver untuk mengubah pid ke sesuatu yang dapat ditulis svn:

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

dan opsi tambahan --user=svn:

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

Pidfile asli adalah /var/run/svnserve.pid. Daemon tidak mulai karena hanya root yang bisa menulis di sana.

 These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
Dulcana
sumber
3
Ini menciptakan kerentanan eskalasi hak istimewa. Pengguna svn sekarang dapat meletakkan PID sewenang-wenang dalam file /home/svn/run/svnserve.pid yang akan dibunuh alih-alih proses svn setiap kali layanan svn dihentikan atau dimulai kembali.
rbu
2

Beberapa hal yang harus diperhatikan:

  • Seperti yang Anda sebutkan, su akan meminta kata sandi jika Anda sudah menjadi pengguna target
  • Demikian pula, setuid (2) akan gagal jika Anda sudah menjadi pengguna target (pada beberapa OS)
  • setuid (2) tidak menginstal hak istimewa atau kontrol sumber daya yang ditentukan dalam /etc/limits.conf (Linux) atau / etc / user_attr (Solaris)
  • Jika Anda memilih rute setgid (2) / setuid (2), jangan lupa untuk memanggil initgroups (3) - lebih lanjut tentang ini di sini

Saya biasanya menggunakan / sbin / su untuk beralih ke pengguna yang sesuai sebelum memulai daemon.

claymation
sumber
2

Mengapa tidak mencoba yang berikut ini di skrip init:

setuid $USER application_name

Ini berhasil untuk saya.

cyberJar
sumber
3
Ini tidak tersedia di semua distro. Saya mencoba di RHEL 7:setuid: command not found
Cocowalla
0

Saya perlu menjalankan aplikasi .jar Spring sebagai layanan, dan menemukan cara sederhana untuk menjalankan ini sebagai pengguna tertentu:

Saya mengubah pemilik dan grup file jar saya ke pengguna yang ingin saya jalankan. Kemudian sambungkan toples ini di init.d dan mulai layanan.

Begitu:

#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
Somaya Kumbera
sumber