web-dev-qa-db-ja.com

bashスクリプトでSudoを使用する際のベストプラクティス

少数のコマンドをrootとして実行する必要があり、コマンドの大部分はSudoの前に通常のユーザーとして実行する必要がある、長時間にわたる実行中のbashスクリプトがあります。ファイル所有権などを台無しにするためです。

いくつかの方法を思いつきましたが、それぞれに問題があります

方法1:ファイル内でのSudoの使用

#!/bin/bash
Sudo echo "I must be run by root"
touch needsToBeOwnedByUser1
echo "needs to be run by user"
sleep 1000
Sudo echo "I, again, must be run by root"

コードの記述方法からすると、これは見栄えがよくなります。 Sudoは、rootで実際に実行する必要があるいくつかのステートメントの前に記述されますが、各Sudo呼び出し間の時間が長すぎる場合は、Sudoが再度パスワードを要求します。また、Sudoの最初の実行が失敗した場合、たとえばパスワードが無効なため、スクリプトの残りの部分は引き続き実行されます。

方法2:Sudoを使用してファイルを呼び出し、必要に応じて元のユーザーに戻す

#!/bin/bash
echo "I must be run by root"
su username -c 'touch needsToBeOwnedByUser1'
su username -c 'echo "needs to be run by user"'
su username -c 'sleep 1000'
echo "I, again, must be run by root"

ほぼすべての行の前にsu username -cを追加する必要があるため、これも面倒です。 Sudoの後に元のユーザー名を見つけることも可能ですが、面倒です。

もっと良い方法はありますか?

編集:私が話していることを示すために、ここでは小さな無意味なスクリプトのみを投稿しました。実際のスクリプトには、Sudoを必要とする行(サービスの開始と停止)、Sudoが存在するかどうかに関係ない行、およびSudoなしで実行する必要のある行が多数あります。

8
Dakkaron

方法2に関しては、関数を使用する方が簡単です。例えば:

#!/bin/bash

func(){
    echo "Username: $USER"
    echo "    EUID: $EUID"
}

export -f func

func
su "$Sudo_USER" -c 'func'

$Sudo_USERは、sudoerのユーザー名です。代わりに$(logname)を使用することもできます。

私のマシンで実行する:

$ Sudo bash test.sh
[Sudo] password for wja: 
Username: root
    EUID: 0
Username: wja
    EUID: 1000
5
wjandrea

man sudoersを読むと、次のことがわかります。

 PASSWD and NOPASSWD

   By default, Sudo requires that a user authenticate him or herself
   before running a command.  This behavior can be modified via the
   NOPASSWD tag.  Like a Runas_Spec, the NOPASSWD tag sets a default for
   the commands that follow it in the Cmnd_Spec_List.  Conversely, the
   PASSWD tag can be used to reverse things.  For example:

   ray     rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm

   would allow the user ray to run /bin/kill, /bin/ls, and /usr/bin/lprm
   as root on the machine rushmore without authenticating himself. 

したがって、ホストでregularを許可し、machine1command1およびcommand2をルートとして実行できます。withoutパスワード認証:

reguser machine1 root = NOPASSWD: /usr/local/command1, /usr/local/command2  

ただし、詳細についてはman -k Sudoをそれぞれお読みください。

2
waltinator