sudoでシェルスクリプトを実行した際にPATHが正しく引き継がれない場合の対処

2023-05-07Bash

はじめに

sudo コマンドを使ってシェルスクリプトを実行した際に、実行ユーザの PATH 環境変数の設定が引き継がれずに困ってしまうことがあります。

セキュリティを考慮しての仕組みですが、引き繋がれない原因と対処について解説します。

最近の sudo はデフォルトでは PATH は引き継がれません。
sudo の -E オプションが必要です。この解決方法として Web 上でよく見かけます。
ただし、これだけで解消しない場合もあるため、今回のエントリを書こうと思いました。

検証環境

$ cat /etc/os-release  | head -n 2
NAME="CentOS Linux"
VERSION="7 (Core)"

$ bash -version | head -n 1
GNU bash, version 5.0.18(1)-release (x86_64-apple-darwin19.5.0)

$ sudo --version | head -n 1
Sudo version 1.8.23

問題の事象を確認

まずは今回取り上げる事象がどんなものか具体的にコマンドを実行しながら見ていきたいと思います。
いくつか準備をした後、再現させて見たいと思います。

準備その 1: adm ユーザの設定

事前に作成しておいた adm ユーザ( wheel グループに所属 )を使います。

$ id
uid=3(adm) gid=4(adm) groups=4(adm),10(wheel)

準備その 2: "sudo" の設定

次に、 sudo の設定ファイルである /etc/sudoers は以下のような設定になっています。

# コメント行や空行を除去
$ cat /etc/sudoers | grep -v '^#' | grep -v '^$'
Defaults   !visiblepw
Defaults    always_set_home
Defaults    match_group_by_gid
Defaults    always_query_group_plugin
Defaults    env_reset
Defaults    env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults    env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults    env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults    env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults    env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin
root    ALL=(ALL)       ALL
%wheel  ALL=(ALL)       NOPASSWD: ALL

%wheel グループに対してパスワード不要で sudo が利用できるようになっています。

準備その 3: "PATH" 環境変数を出力するだけのシェルスクリプトを作成

最後に、 PATH 環境変数の設定値を確認するためだけのシェルスクリプトを作成します。

test.sh というファイル名で作成します。

cat <<'EOF' >./test.sh
#!/usr/bin/env bash

echo "${PATH}"
EOF

$ chmod 777 test.sh

"adm" ユーザで test.sh を実行してみる

準備ができたので、 adm ユーザで test.sh ファイルを実行してみます。

  • sudo なし
  • sudo あり

のそれぞれの方法で実行してみます。

# sudo なしで実行!
$ ./test.sh
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin

# sudo ありで実行!
$ sudo ./test.sh
/usr/bin:/bin:/usr/sbin:/sbin

このように sudo なしだと PATH 環境変数の設定が実行ユーザの設定とは異なる値となってしまいます。

sudoなしだと正常に動いていたのに、 sudoありだとコマンドが見つからない!」** といった問題が発生することがあります。

原因

原因は、 /etc/sudoers に設定されている以下の 1 行になります。

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

secure_path が設定されていると、設定されている値で PATH は上書きされてしまいます。

/usr/local/bin ディレクトリなどに得体のしれないファイルが配置されていた場合( ls という名前のスクリプトで rm -rf / するロジックが入っているなど )を考慮したセキュリティ対策なのでしょうが、邪魔な場合もあります。

対処

ここでは対処法を 3 つ紹介します。

対処法 1: secure_path の行をコメントアウト

/etc/sudoerssecure_path の行をコメントアウトしてしまいます。

/etc/sudoers を変更したあとは、もしすでに adm ユーザでログインしていた場合は一度ログアウトしないと反映されません 。

$ sudo ./test.sh
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin

対処法 2: exempt_group を設定 + env_keep を設定

/etc/sudoersexempt_group の行を追記します。

exempt_group に設定されたグループに所属するユーザを一律 secure_path の制限から免除させます。

Defaults    exempt_group = wheel

また、 /etc/sudoersenv_keep の行を追記します。

sudo 実行時に、 env_keep に設定されている環境変数だけが引き継がれます。

PATH を追記することで設定が引き継がれるようになります。

Defaults    env_keep += "PATH"
$ sudo ./test.sh
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin

対処法 3: exempt_group を設定 + sudo -E

対処法 2 に似ていますが、 Defaults env_keep += "PATH" の記述は追記しません。

その代わりに、 adm ユーザでコマンド実行する際に sudo -E のように -E オプションを付与します。

# 環境変数は引き継がれない
$ sudo ./test.sh
/usr/bin:/bin:/usr/sbin:/sbin

# 環境変数は引き継がれる
$ sudo -E ./test.sh
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin

ひとこと

環境によって、 secure_path の設定がされておらず、 sudo -E だけで PATH 引き継ぎの問題が解決したりします。
sudo -E で問題が解決しない場合の参考になれば幸いです。

2023-05-07Bash