特定のソフトウェアを使っていると内部的に sudo
を実行しており、毎回パスワードの入力を要求されて面倒!ということがあると思います。例えばVagrantのsynced_folder機能をnfsで使っていると vagrant up
の度にパスワードを入力しなければなりませんが、正直面倒ですね。
というわけでパスワード入力を省略したいです。でもなんでもかんでもパスワード無しで sudo
できてしまうのは怖いので、特定のコマンドだけパスワード無しでも sudo
できるようにする方法の解説です。
免責
ご自身の責任の元に信頼できる相手だけに sudo
権限を渡すようにしてください。
sudo
しているコマンドを把握する
まずはパスワード入力を求められた際に、ソフトウェアの内部で実行しているコマンドが何なのか知らなければいけません。
それを知るにはシステムログを見るのが手っ取り早いです。環境によりけりですが、Macはデフォルトで /var/log/system.log に書きだすようです。ご自身の環境についてはsyslogとかrsyslogの設定ファイルを読んでください。
で、 sudo
が実行されると全てのログが出てくるので tail
しときます。
tail -f /var/log/system.log | grep sudo
この状態でそのパスワード入力を要求してくるソフトウェアを実行し、実際にパスワードを入力したりすると、ここにもりもりとログが出てきます。例えば vagrant up
するとこんなログが得られます。(分かりやすいように若干加工しています)
% tail -f /var/log/system.log | grep sudo | cut -d';' -f 4
COMMAND=/usr/bin/sed -E -e /^# VAGRANT-BEGIN:( 501)? ad65f9aa-b0f6-4c6a-820b-f8e51d79ab3e/,/^# VAGRANT-END:( 501)? ad65f9aa-b0f6-4c6a-820b-f8e51d79ab3e/ d -ibak /etc/exports
COMMAND=/bin/zsh -c echo '# VAGRANT-BEGIN: 501 ad65f9aa-b0f6-4c6a-820b-f8e51d79ab3e' >> /etc/exports
COMMAND=/bin/zsh -c echo '"/Users/yuku/src/qiita" 192.168.33.11 -alldirs -mapall=501:20' >> /etc/exports
COMMAND=/bin/zsh -c echo '# VAGRANT-END: 501 ad65f9aa-b0f6-4c6a-820b-f8e51d79ab3e' >> /etc/exports
COMMAND=/sbin/nfsd restart
というわけでこれらのコマンドを sudo
できれば vagrant up
時のパスワード入力をスキップできることになります。
特定コマンドをパスワードなしで sudo
できるようにする
先ほどのコマンドをパスワード無しでroot権限で実行できるようにする設定は例えばこんな感じで書けます。
yuku mba=(root) NOPASSWD: /bin/zsh -c echo '*' >> /etc/exports
yuku mba=(root) NOPASSWD: /sbin/nfsd restart
yuku mba=(root) NOPASSWD: /usr/bin/sed -E -e /*/\,/*/ d -ibak /etc/exports
詳しくはsudoers(5)を読んでもらうとして、軽く意味だけ説明すると「yukuユーザはmbaマシンでrootとしてパスワード無しでこれらのコマンドを実行できる」という意味になります。コマンドの中に含まれる *
はワイルドカードです。3行目でやっているようにコマンド中に ,
が出てくる場合はバックスラッシュでエスケープする必要があります。
ところでmbaというのは僕のMACのマシン名なのでローカルマシンでのみ実行できることになります(localhostとか127.0.0.1と入力してもローカルマシンという意味にはならないので注意)。ちなみにマシンの名前は hostname
で確認できます。
% hostname
mba
どのマシンでも、どのユーザとしても実行できるようにするにはALLを指定します。手軽な反面権限が強いのでご利用は計画的に。
yuku ALL=(ALL) NOPASSWD: /sbin/nfsd restart
Cmnd_Aliasを使って共通化
ただこれだとこれらの3つの設定が互いに関係しあったものだということが分かりませんし、権限を変えようと思うと3箇所も変えないといけなくて面倒なので、こういう時はCmnd_Aliasという機能を使います。
Cmnd_Alias VAGRANT_EXPORTS_ADD = /bin/zsh -c echo '*' >> /etc/exports
Cmnd_Alias VAGRANT_NFSD = /sbin/nfsd restart
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -E -e /*/\,/*/ d -ibak /etc/exports
yuku mba=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE
/etc/sudoersを編集する場合は必ず visudo
を使う
ところで/etc/sudoersを直接編集しては 絶対にいけません
/etc/sudoersは変更したら、ファイルが正しかろうが文法に間違いがあろうが、即座にその効果が適用されます。つまり、ファイルを壊したらあなたは sudo
できなくなります。 sudo
できないということは/etc/sudoersを編集することもできないので、何かしらの方法で直接rootになるか、ストレージを外部マシンにマウントしてそっちで編集するとかしないと復旧できなくなります。
visudo
は/etc/sudoersを編集する専用のコマンドで、編集完了時に保存する前に構文をチェックして問題がある場合はロールバックしたりしてくれます。名前を見るとViじゃないとダメな雰囲気がありますが、EDITOR
環境変数を指定しているとそのエディタが使われます。
スクリプトから編集する場合は visudo -c -f
手動で編集する場合は visudo
を使うとして、スクリプトなどから自動的に編集する場合は visudo -c -f
を使うといいと思います。-c
はcheck-onlyオプションで変更を適用せずに構文のチェックだけを行い、 -f
は外部ファイルをチェックするオプションです。
例えば既存のものに新しい設定を追記するスクリプトはこんな感じで書いておくと安心感があります。
# 一時ファイルを作成
tmp=`mktemp -t vagrant_sudors`
# /etc/sudoersの内容を取ってくる
cat /etc/sudoers > $tmp
# 追記したい内容
cat >> $tmp <<EOF
Cmnd_Alias VAGRANT_EXPORTS_ADD = $SHELL -c echo '*' >> /etc/exports
Cmnd_Alias VAGRANT_NFSD = /sbin/nfsd restart
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -E -e /*/\\,/*/ d -ibak /etc/exports
%staff `hostname`=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE
EOF
# 構文をチェック
visudo -c -f $tmp
if [ $? -eq 0 ]; then
echo 'Vagrant用のコマンドをsudoersに追加'
cat $tmp > /etc/sudoers
else
echo '構文エラー。中止'
fi
rm -f $tmp
合わせて読みたい
-
sudoers(5)
-
visudo(8)
-
https://gist.github.com/GUI/2864683
元ネタになったシェルスクリプト。対応しているVagrantのバージョンが古いので注意。