最近、色々とsudoで設定を変えたりすることが多かったので調べてみたら、結構色々な設定やsudoコマンドのオプションとかがあるようだったので、調べた内容から基本的な設定や便利そうな使い方についてまとめてみることにした。 なお、/etc/sudoersではなくLDAPでもポリシー設定はできるようなのだが、あまり使うパターンも少ないだろうから今回は割愛する。 SELinuxのポリシー設定についても設定はできるようなのだが、今回は割愛する。 なお、検証にはCentOS 7の以下のバージョンを用いている。

[root@BS-PUB-CENT7-01 test]# sudo -V | head -1
Sudo バージョン 1.8.6p7

/etc/sudoersの設定について

sudoコマンドのポリシー設定は、/etc/sudoers(includeさせるなら、/etc/sudoers.d/配下のファイルに記述を分ける事もできる)で設定する。 sudo自体は特にサービスとして動いているものではないので、ファイルを変更したら設定は即時反映される。

編集自体はvimなどのエディタで普通にいじることができるのだが、保存時に構文チェックを行ってくれるvisudoコマンドで編集するのが良いだろう。

基本的な書き方

基本的な書き方は単純で、以下のようにデフォルトで適用させるオプション値とユーザごとで適用させるポリシーを書いてやればよい(Aliasとかも設定できるのだが後述)。

Defaults オプション # sudoで適用させるオプション
Defaults !オプション # sudoで適用させるオプション(頭に!を付けると明示的に無効化できる)
Defaults:ユーザ名 !オプション # ユーザごとにオプションの有効化・無効化を指定する
...

ユーザ名 対象ホスト=(コマンドを実行させるユーザ・グループ) TAG(実行可能・不可能なコマンドやNOPASSWDなど) # ユーザごとの設定値
ユーザ名 対象ホスト=(コマンドを実行させるユーザ・グループ) TAG,TAG # TAGは複数設定できる
ユーザ名 対象ホスト=(コマンドを実行させるユーザ・グループ1) TAG,(コマンドを実行させるユーザ・グループ2) TAG # このような区切りもできる

%グループ名 対象ホスト=(コマンドを実行させるユーザ・グループ) TAG # sudoコマンドを実行するグループごとでの設定
...
includedir DIRPATH # 設定を外に出してある、インクルードするディレクトリ(基本は/etc/sudoers.d)

エイリアスについて

/etc/sudoersでは、ユーザやグループ、実行可能なコマンドなどについてエイリアスを定義して、それを設定に利用する事ができる。 設定できるエイリアスは「User_Alias」「Runas_Alias」「Host_Alias」「Cmnd_Alias」の4種類(Host_Aliasは使うこと無いような気もするけど)。 以下のように設定することができる。

User_Alias   エイリアス名 = ユーザ1,ユーザ2,ユーザ3
Runas_Alias  エイリアス名 = ユーザ名:グループ名
Cmnd_Alias   エイリアス名 = コマンドPATH1,コマンドPATH2

これを利用することで、以下のように/etc/sudoersを記述することができる。 複数のユーザやグループがいて、それぞれに設定がある場合にはエイリアスを使うことで簡潔に記述することができる。 (まぁ、以下の例だと同一サブグループで同一のグループに所属させて%グループ名で指定してやる方法でもいけるが…)

User_Alias   TESTUSER = test1,test2,test3

TESTUSER     ALL=(ALL) NOPASSWD: ALL

Defaultsで設定できるオプション

sudoersで、Defaultsで設定できるオプションは結構多く、その中には使ってる最中に引っかかるものもあったりする。 manを見るとかなり種類があるので、便利そうなの、変なの、よく使いそうなもの、ディストリビューションによってはよくデフォルトで設定されているものを抜粋する(詳細はmanを参照)。

  • always_set_home … 環境変数$HOMEを変身対象ユーザ(指定がない場合はデフォルトでroot)のホームディレクトリに設定する。デフォルトでは無効。
  • authenticate … 有効にしておくと、sudoコマンド実行ユーザはパスワード認証などでの認証が求められる(ユーザごとの設定でNOPASSWDなどで上書き変更可能)。デフォルトで有効。
  • insults … 有効にしておくと、パスワードの入力間違い時に英文で悪態を付いてくる。使うにはコンパイル時にオプションを有効にしておく必要がある(RHEL系ではコンパイル時に無効になってる様子)。デフォルトでは無効。
  • log_output … sudoコマンドによるスクリーンへの出力結果を全て特定のファイルに取得する(入力結果をログに出すlog_inputもあるが、あまり利用しないと思うので省略)。つまり、sudoを経由したコマンドでscriptコマンドのような使い方ができる。デフォルトでは無効。詳細は後述。
  • logfile = ログファイルPATH … デフォルトではsudoのログはsyslog経由で出力されるが、指定されたPATHに出力されるようになる。デフォルトでは無効。
  • iolog_dir = ディレクトリPATH … log_output、log_inputで取得されるログの出力先ディレクトリのPATHが指定できる。出力先にはstrftimeの変数(%Y%m%dでYYYYMMDDとか)の他、以下の変数が使用可能。
    • %{seq}
    • %{user}
    • %{group}
    • %{runas_user}
    • %{runas_group}
    • %{hostname}
    • %{command}
  • iolog_file = ログファイルPATH … log_output、log_inputで取得されるログの出力先ファイルのPATHが指定できる。iolog_dirと同じように、出力先には変数が使用可能。詳細は後述。
  • syslog = ログレベル … sudoの動作ログについて、syslog経由で指定したログレベルで出力する。デフォルトではauthprivになっている。
  • syslog_badpri = ログレベル … sudo実行ユーザが不正なパスワード入力時にsyslogに記録するログレベル。デフォルトではalertになっている。
  • syslog_goodpri = ログレベル … sudo実行ユーザが正しいパスワード入力時にsyslogに記録するログレベル。デフォルトではnoticeになっている。
  • mail_always … sudoコマンドが実行されるたびにmailtoオプションで指定したアドレスにメールを送信する
  • mailfrom = メールアドレス … メール送信時に送信元となるメールアドレス。記述時は@をダブルクォーテーションで囲むこと。
  • mailto = メールアドレス … メール送信先のメールアドレス。記述時は@をダブルクォーテーションで囲むこと
  • noexec … sudoを経由して実行されるコマンドが、EXECタグで無効にされない限りNOEXECでの動作(sudoで実行したプログラムから他のプログラムを起動させない)になる。デフォルトでは無効。
  • requiretty … sudoの実行に擬似端末(tty)を要求する。つまり、このオプションが有効になっている場合、sudoの実行できるのはログインセッション(sshで擬似端末を要求した場合含む)だけで、cronなどからの実行を許可させない。デフォルトでは無効(RHEL系のディストリビューションでは設定ファイルで有効にされている場合がある)。
  • root_sudo … rootもsudoが実行できるようになる。これが無効化されていると、rootユーザでsudoeditなどが利用できなくなる。デフォルトで有効。
  • rootpw … sudo実行時に、ユーザのパスワードではなくrootのパスワードを求められるようになる。デフォルトでは無効。
  • targetpw … sudo実行時に、ユーザのパスワードではなく-uで指定されたユーザのパスワード(デフォルトはroot)を求められるようになる。デフォルトでは無効。
  • visiblepw … 有効にすると、sudo実行時にパスワードがスクリーンに表示されてしまう場合でもプロンプトを表示していパスワード入力を受け付けるようになる(デフォルトではエラーが表示される)。デフォルトでは無効。
  • verifypw = パターン … sudoコマンドを-vオプション付きで実行した際、ユーザがパスワードを要求されるのはどういう場合かを指定する。指定できるパターンは以下。
    • all … パスワードの入力を回避するには、sudoersの使用中ホストに対するユーザの全エントリーにNOPASSWDタグが設定されている必要がある。
    • always … -vオプション付きでsudoを実行した場合、必ずパスワードの入力を求められるようになる。
    • any … パスワードの入力を回避するには、sudoersの使用中ホストに対するユーザのエントリーに最低一つはNOPASSWDタグが設定されている必要がある。
    • never …  -vオプション付きでsudoを実行した場合、パスワードの入力を求められなくなる。
  • listpw = パターン … sudoコマンドを-lオプション付きで実行した際、ユーザがパスワードを要求されるのはどういう場合かを指定する。指定できるパターンは↑のverifypwと同じ。
  • passwd_tries = Num … パスワードの試行回数を設定できる。デフォルトは3回。
  • badpass_message = "メッセージ(文字列)" … 間違えたパスワード入力時のメッセージを、指定したメッセージに変更する。
  • passprompt = "プロンプトメッセージ(文字列)" … sudoコマンドから実行時のパスワード入力プロンプトを、指定したプロンプトに変更する。
  • shell_noargs … このオプションが有効の場合、-sが指定されたとみなしrootユーザでシェルが実行される。デフォルトでは無効。
  • use_pty … このオプションが有効の場合、sudoは入出力ロギングが無効の場合でも疑似ttyでコマンドを実行するようになる。
  • lecture = パターン … このオプションが有効の場合、sudo実行時に警告(というか訓戒。管理者としての心構えなど)を表示するようになる。指定できるパターンは以下。なお、パターンを指定しない場合、onceが指定される。
    • always … 常時警告を表示させる
    • never … 常時警告を表示させない
    • once … ユーザが初めてsudoを実行した際に表示させる
  • lecture_file = ファイルPATH … lectureオプション有効時に表示させる警告の内容を、指定したファイルPATHの内容に書き換える。

ユーザ・グループごとのポリシー設定(TAG)

ユーザ・グループごとのポリシー設定(このユーザ・グループはsudoを使えるとか、どのコマンドを使用できるかなど)は、TAGで設定することができる。

ユーザ名 対象ホスト=(コマンドを実行させるユーザ・グループ) TAG(実行可能・不可能なコマンドやNOPASSWDなど)

設定可能なTAGは以下。

  • EXEC/NOEXEC … sudo経由で実行したプログラムから、さらにプログラムを呼び出せるか否か(対象のプログラムがNOEXECに対応している必要がある)。
  • FOLLOW/NOFOLLOW … sudo経由で実行したプログラムで、シンボリックリンクをたどるかどうか。
  • LOG_INPUT/NOLOG_INPUT … ユーザのインプットをログに記録するかどうか。
  • LOG_OUTPUT/NOLOG_OUTPUT … スクリーンへのアウトプットをログに記録するかどうか。
  • MAIL/NOMAIL … ユーザがsudo経由でコマンド実行時にメールを送信するか否か。
  • PASSWD/NOPASSWD … ユーザがsudo実行時にパスワード入力を要求するか否か。
  • SETENV/NOSETENV … ユーザがsudo実行時に環境変数を継承するか否か。

よく使いそうな設定・使用例

sudoの設定で、個人的によく使いそうな設定について記述してみる。

ユーザに特定のコマンドのみ実行を許可する

結構よく使う設定。単純に、以下のように対象のプログラムのPATHを指定してやれば良い。

ユーザー  ALL=(ALL) コマンドPATH

ユーザに特定のコマンドのみ実行を許可しない

基本的にはどのコマンドも使ってよいが、ある特定のコマンドのみを許可したくない場合、以下のように続けて!で対象のコマンドPATHを指定する。

ユーザー  ALL=(ALL) ALL,!コマンドPATH

以下、実際にlsコマンドのみを実行不可にした場合。

[test1@BS-PUB-CENT7-01 ~]$ sudo cat /etc/sudoers | grep ^test1
test1   ALL=(ALL)       ALL,!/usr/bin/ls
[test1@BS-PUB-CENT7-01 ~]$ sudo pwd
/home/test1
[test1@BS-PUB-CENT7-01 ~]$ sudo ls -la
ユーザー test1 は'/bin/ls -la' を root として BS-PUB-CENT7-01.blacknon.local 上で実行することは許可されていません。すみません。

特定のコマンドのみパスワード入力ありで実行できるようにしたい

基本的にはどのコマンドもNOPASSWDでパスワード入力を省略させたいが、特定のコマンド(エイリアスでの設定含む)のみパスワード認証をさせたい場合、以下のように記述する。 もちろん、この逆で特定のコマンドのみパスワード入力なしも可能だ。

ユーザ  ALL=(ALL) NOPASSWD: ALL,PASSWD: コマンドPATH

以下、実際にsuコマンドのみをパスワード要求するように設定した場合。

[test@BS-PUB-CENT7-01 ~]$ sudo cat /etc/sudoers | grep -E "^test\s"
test    ALL=(ALL)       NOPASSWD: ALL,PASSWD: /usr/bin/su
[test@BS-PUB-CENT7-01 ~]$ sudo pwd
/home/test
[test@BS-PUB-CENT7-01 ~]$ sudo su

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for test:
[root@BS-PUB-CENT7-01 test]#

sudo経由での操作(出力内容・ターミナルログなど)をログに記録・再生する

sudo経由での操作をscriptコマンドのように自動的にログに記録するには、以下のようにする。

Defaults    log_output
Defaults    iolog_dir = ログ出力先ディレクトリ # デフォルトの/var/log/sudo-io以外にする場合

設定後は、バイナリファイルでターミナルでの操作タイミングや出力データを保存する。 保存された操作ログは、sudoreplayで再生することができる。イメージ的には、scriptreplayでのターミナル操作の再生に近い。

sudoreplay [-d iolog_dir(デフォルトだと/var/log/sudo-io)] ログ番号

例えば、「/var/log/sudo_io/00/00/02」のログを再生する場合は、以下のようにコマンドを実行する。

sudoreplay 000002

sudoreplayで再生できるログは、以下のコマンドで確認できる。

sudoreplay -l
[root@BS-PUB-CENT7-01 test]# sudoreplay -l
 6月 17 19:39:27 2017 : root : TTY=/dev/pts/4 ; CWD=/root ; USER=root ; TSID=000001 ; COMMAND=/bin/su - test
 6月 17 19:39:42 2017 : test : TTY=/dev/pts/5 ; CWD=/home/test ; USER=root ; TSID=000002 ; COMMAND=/usr/bin/su -
 6月 17 19:39:49 2017 : test : TTY=/dev/pts/5 ; CWD=/home/test ; USER=root ; TSID=000003 ; COMMAND=/bin/bash
 6月 17 20:01:00 2017 : test : TTY=/dev/pts/4 ; CWD=/home/test ; USER=root ; TSID=000004 ; COMMAND=/bin/ls -la
 6月 17 20:01:04 2017 : test : TTY=/dev/pts/4 ; CWD=/home/test ; USER=root ; TSID=000005 ; COMMAND=/bin/pwd
 6月 17 20:45:53 2017 : root : TTY=/dev/pts/4 ; CWD=/root ; USER=root ; TSID=000006 ; COMMAND=/bin/vi ./test.txt
...

残念ながらscriptコマンドのようにawkと組み合わせて行頭にタイムスタンプの付与は難しそうだが、sudoを経由しての処理のみをログに残しておくと考えると悪くはなさそうだ(suでrootユーザに切り替えられた後のbashの操作もログに残しておけるので)。

cronやssh経由でもsudoを使えるようにする

cronやssh経由(それでも-ttオプションつければいけるのだが…)でsudoを使う場合、「requiretty」オプションが付いていると擬似端末を要求されるため、sudoを使用できない事がある(CentOSなど、RHEL系だとOSインストール時に有効化されていたりする)。 そんなときは、対象の処理をコメントアウトして無効化するか、もしくは以下のように対象のユーザのみで「requiretty」を無効化してやるようにしたらよい。

Defaults:ユーザ名 !requiretty

sudoコマンドについて

/etc/sudoersの設定を終えて、実際にsudoコマンドを実行する際、色々な使い方がある。

コマンドを実行するユーザ・グループを指定する

sudoでは、実行するコマンドについて -u でユーザ、 -g でグループを指定して実行することができる。

sudo -u ユーザ コマンド
[test@BS-PUB-CENT7-01 ~]$ sudo -u test1 id
uid=1004(test1) gid=1004(test1) groups=1004(test1),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

sudoで実行可能なコマンドのリストを確認する

-l オプションを付与することで、そのユーザで実行可能なプログラムや適用されるsudoers設定について確認することができる。

sudo -l
sudo -l -U ユーザ
[test@BS-PUB-CENT7-01 ~]$ sudo -l
このホスト上でユーザー test に一致したデフォルト項目:
    !visiblepw, lecture=always, always_set_home, log_output, iolog_dir=/var/log/sudo_log,
    env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL
    PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION
    LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER
    LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
    insults, secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

ユーザー test は次のコマンドをこのホスト上で実行できます:
    (ALL) NOPASSWD: ALL, (ALL) PASSWD: /usr/bin/su
[test@BS-PUB-CENT7-01 ~]$ sudo -l -U test1
このホスト上でユーザー test1 に一致したデフォルト項目:
    !visiblepw, lecture=always, always_set_home, log_output, iolog_dir=/var/log/sudo_log,
    env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL
    PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION
    LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER
    LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
    insults, secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

ユーザー test1 は次のコマンドをこのホスト上で実行できます:
    (ALL) ALL, (ALL) !/usr/bin/ls

プログラムをバックグラウンド実行させる

sudoで実行するプログラムをバックグラウンドで実行させたい場合、-bオプションを付与すると良いだろう。

sudo -b コマンド

出力結果はターミナルに表示される。vmstatなどを定期実行させてその結果をリダイレクトでファイルに書き出すときなどに有効だ。

パスワード入力を標準入力(パイプとか)から行わせる

パスワードをプロンプト表示させず、パイプなどから受け付けて処理させる場合、-Sオプションを付与する。

echo password | sudo -S コマンド
[test2@BS-PUB-CENT7-01 ~]$ echo P@ssw0rd | sudo -S id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

ssh越しにrequirettyを有効にした状態でsudoコマンドを実行するなんかには、以下のようにコマンドを実行すると良いだろう。

ssh user@hostname 'echo password | sudo -S cmd 2>/dev/null'

パスワードを聞かれるようにする

パスワードを特定のプログラム(x11のaskpassなど)から聞かれる用にする場合、-Aオプションを付与する。 これを利用することで、例えば擬似端末が必要な環境でx11forwardingを経由してのssh越しのsudo実行といった事が可能になる。

SUDO_ASKPASS=プログラムPATH sudo -A コマンド

パスワードプロンプトを任意の文字列にする

パスワードプロンプトに任意の文字列を使用する場合、-pオプションで指定することができる。

sudo -p "prompt" コマンド
[test2@BS-PUB-CENT7-01 ~]$ sudo -p "test password prompt:" ls -la

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

test password prompt:
合計 16
drwx------. 2 test2 test2  79  6月 18 03:02 .
drwxr-xr-x. 6 root  root   52  6月 18 03:02 ..
-rw-------. 1 test2 test2   5  6月 18 03:02 .bash_history
-rw-r--r--. 1 test2 test2  18 12月  7  2016 .bash_logout
-rw-r--r--. 1 test2 test2 193 12月  7  2016 .bash_profile
-rw-r--r--. 1 test2 test2 231 12月  7  2016 .bashrc

認証をリセットする

次回以降sudoを利用する際、再度パスワードを求められるよう認証状況をリセットする場合、-kオプションを付与する。

sudo -k # 認証情報をクリアする
sudo -k コマンド # 認証情報をクリアしてコマンドを実行する(次回以降はデフォルトの動作)

シェルにログインする

単純にログインシェルを切り替える場合、suコマンドを使わずとも、以下のように-iもしくは-sオプションを利用することでシェルを起動できる。

sudo -i # 対象ユーザのログインシェル
sudo -s # 環境変数$SHELLもしくは対象ユーザのログインシェル

参考