Linuxサービスを別のユーザーとして実行するためのベストプラクティス


141

サービスはデフォルトrootで、RHELボックスの起動時に起動します。私が正しく思い出した場合、同じことがのinitスクリプトを使用する他のLinuxディストリビューションにも当てはまります/etc/init.d

代わりに、プロセスを私の選択した(静的)ユーザーとして実行する最良の方法は何だと思いますか?

私が到達した唯一の方法は、次のようなものを使用することでした:

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

しかし、これは少し乱雑に見えます...

他の非rootユーザーとしてサービスを自動的に開始する簡単なメカニズムを提供する、ちょっとした魔法が隠れていますか?

編集:私がこのインスタンスで開始しているプロセスは、PythonスクリプトまたはJavaプログラムのいずれかであると言っておくべきでした。それらの周りにネイティブラッパーを記述したくないので、残念ながら、Blackが示唆するように、setuid()を呼び出すことができません。


Pythonはsetuid()ファミリーのシステムコールへのアクセスを提供しませんか?これは、Perlと比較すると深刻な欠陥のようです。
ジョナサンレフラー

12
うわー、そうです:os.setuid(uid)。毎日が学校の日です!
James Brady

回答:


67

Debian start-stop-daemonでは、pidファイルを処理し、ユーザーを変更し、デーモンをバックグラウンドにするなどのユーティリティを使用します。

私はRedHatに精通していませんが、daemon既に使用しているユーティリティ(これは/etc/init.d/functions、btw。で定義されています)はどこでもと同等のものとして言及されているstart-stop-daemonため、プログラムのuidを変更したり、それはすでに正しいものです。

ネットを見回すと、使用できる既製のラッパーがいくつかあります。RedHatに既にパッケージされているものさえあるかもしれません。daemonizeたとえばを見てください。


外部参照は興味深いものです。私は自分のデーモン化プログラムを持っています。非常に似ています。pidfileやlockfileを実行せず、umaskを設定します。UID、GID、EUID、EGID、およびauxグループ(asrootと呼ばれる)を設定するための別のSUIDルートプログラムがあります。私は「asroot [opts]-env -i [env] daemonize [opts]-command [opts]」を使用しています
Jonathan Leffler

(続き):POSIX標準envプログラムは、環境設定と実行されたコマンドの間の「-」を受け入れません(厄介ですがそうです)。
Jonathan Leffler

4
/etc/init.d/functionsのデーモン関数をupstartスクリプトでどのように使用できますか?例を示してください。
Meglio

10
Debianについては、を参照してください/etc/init.d/skeleton。UID、GID変数を追加してdo_start()使用中:start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $UID:$GID -- $DAEMON_ARGS
Jonathan Ben-Avraham

私のRHELとCentOSの両方のボックスでdaemon()定義され/etc/rc.d/init.d/functionていることに気づきました。
クイックシフトイン2014

53

ここですべての提案を検討した後、私は自分の立場にある他の人に役立つことを願っています。

  1. ホップは私に戻って指し示すのに正しいです/etc/init.d/functions:この daemon関数はすでに代替ユーザーを設定することを許可しています:

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

    これは、プロセス呼び出しをラップすることで実装されますrunuser-これについては後で詳しく説明します。

  2. Jonathan Leffler正解です。Pythonにはsetuidがあります。

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

    ただし、JVM内からsetuidできるとはまだ思いません。

  3. すでにそうであるユーザーとしてコマンドを実行するように依頼する場合suも、runuser適切に処理しません。例えば:

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

suおよびの動作を回避するためにrunuser、initスクリプトを次のように変更しました。

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

あなたの助けをありがとう!


5
  • 一部のデーモン(Apacheなど)は、setuid()を呼び出して自分でこれを行います
  • setuid-fileフラグを使用して、別のユーザーとしてプロセスを実行できます。
  • もちろん、あなたが言及したソリューションも同様に機能します。

独自のデーモンを作成する場合は、setuid()を呼び出すことをお勧めします。このようにして、プロセスは

  1. ルート権限を利用します(ログファイルを開いたり、pidファイルを作成したりします)。
  2. 起動中の特定の時点でルート権限を削除します。

3

注意すべき他のことを追加するだけです:

  • init.dスクリプトのsudoは、ttyが必要なため無効です( "sudo:申し訳ありませんが、sudoを実行するにはttyが必要です")
  • Javaアプリケーションをデーモン化する場合は、Java Service Wrapper(ユーザーIDを設定するためのメカニズムを提供する)を検討することをお勧めします。
  • 別の方法としては、su --session-command = [cmd] [user]があります。

3

CENTOS(Red Hat)仮想マシン(svnサーバー用):/etc/init.d/svnserver pidをsvnが書き込み可能なものに変更するために編集:

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

追加されたオプション--user=svn

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

元のpidfileはでした/var/run/svnserve.pid。デーモンは起動せず、ルートのみがそこに書き込むことができました。

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

3
これにより、権限昇格の脆弱性が生まれます。svnユーザーは任意のPIDを/home/svn/run/svnserve.pidファイルに置くことができるようになり、svnサービスが停止または再起動されるたびに、svnプロセスの代わりに強制終了されます。
rbu 14

2

注意すべきいくつかのこと:

  • すでに述べたように、すでにターゲットユーザーである場合、suはパスワードの入力を求めます
  • 同様に、(一部のOSでは)すでにターゲットユーザーである場合、setuid(2)は失敗します。
  • setuid(2)は、/ etc / limits.conf(Linux)または/ etc / user_attr(Solaris)で定義された特権またはリソース制御をインストールしません
  • setgid(2)/ setuid(2)ルートを使用する場合は、initgroups(3)を呼び出すことを忘れないでください-詳細は こちら

デーモンを起動する前に、通常/ sbin / suを使用して適切なユーザーに切り替えます。


2

initスクリプトで次のことを試してみませんか。

setuid $USER application_name

それは私のために働いた。


3
これはすべてのディストリビューションで利用できるわけではありません。私はRHEL 7で試してみました:setuid: command not found
Cocowalla 14

0

Spring .jarアプリケーションをサービスとして実行する必要があり、これを特定のユーザーとして実行する簡単な方法を見つけました。

jarファイルの所有者とグループを、実行したいユーザーに変更しました。次に、このjarをinit.dにシンボリックリンクして、サービスを開始しました。

そう:

#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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.