プロビジョニングスクリプトを書いています。そのプロビジョニングスクリプトはRootで実行されるのですが、そのスクリプトから、他のユーザとして、別のスクリプトを実行したいというケースがありました。その子スクリプトは、サーバーを起動します。
ところが、そのサーバーの挙動がおかしく、原因は、親スクリプトで設定した環境変数が、子スクリプトに渡っていない様子です。そのサーバーをプロビジョニングしたVMで手動で起動するとすべての環境変数設定が出来て正しく起動しますので、一瞬不思議にみえますが、単純にプロビジョニングスクリプトでの実行時に環境変数がわかっていないのです。
他のユーザとして、シェルを実行する方法
他のユーザとしてシェルの実行はsudo
を使います。現在のユーザが、そのユーザに対して権限がなければ、パスワードを求められますが、例えばRootユーザから、他のユーザになる場合は、パスワードは求められません。
$ sudo -u ushio ./child.sh
ところが、この方法では、親スクリプトで設定した環境変数が渡りません。試してみましょう。
parent.sh
# !/bin/bash
export FOO=BAR
sudo -u ushio ./child.sh
child.sh
# !/bin/bash
# source ~/.bashrc
echo "FOO: "${FOO}
実行結果
sudo su
[sudo] password for ushio:
# ./parent.sh
FOO:
何も表示されません。ちなみに、source ~/.bashrc
の部分を有効にすると、./child.sh: line 3: /root/.bashrc: Permission denied
のエラーになります。これは、別のユーザで実行しても、root としてみなされている雰囲気のようです。実際に、env コマンドをchild.sh
で実行してみると、パスの構成などからみて、ushioユーザの.bashrcは実行されていないようです。これが、envをchild.sh
で実行してみた結果ですが、なんとも中途半端な感じになっていて、パスは、Rootのものだけど、環境変数は特にわたっていません。
LANG=C.UTF-8
SUDO_GID=0
DISPLAY=127.0.0.1:0.0
COLORTERM=truecolor
USERNAME=ushio
SUDO_COMMAND=./child.sh
USER=ushio
PWD=/home/ushio/Codes/DevSecOps/volley/playground/environmentvariables
HOME=/root
SUDO_USER=root
SUDO_UID=0
MAIL=/var/mail/ushio
SHELL=/usr/bin/zsh
TERM=xterm-256color
SHLVL=1
LOGNAME=ushio
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
_=/usr/bin/env
解決策
とても簡単で、-E
オプションを使います。
parent.sh
# !/bin/bash
export FOO=BAR
sudo -u ushio -E ./child.sh
実行結果
# ./parent.sh
FOO: BAR
よりより解決策
今回は、-E
で解決ですが、--preserve-env=
で特定の環境変数も渡せるようですね。
sudo -u ushio --preserve-env=FOO ./child.sh
に変更しても結果は同じでうまくいきました。
-E, --preserve-env
Indicates to the security policy that the user wishes to preserve their existing environment vari‐
ables. The security policy may return an error if the user does not have permission to preserve the
environment.
--preserve-env=list
Indicates to the security policy that the user wishes to add the comma-separated list of environment
variables to those preserved from the user's environment. The security policy may return an error if
the user does not have permission to preserve the environment.
複数のものも試してみましょう。カンマ区切りと書いてあります。
parent.sh
# !/bin/bash
export FOO=BAR
export BUZ=QUUX
sudo -u ushio --preserve-env=FOO,BUZ ./child.sh
実行結果
# ./parent.sh
FOO: BAR
BUZ: QUUX
``
# 追記 $HOME 環境変数にご注意
`-E` を追加したところ、スクリプトが思わぬところで失敗しました。`$HOME` 環境変数が、`-E`なしの時はターゲットのユーザとして動作するので例えば `/home/ushio` になるのですが、`/root`になってしまうようです。先ほどのenv
を`--preserve-env=list` でやってみましょう。ああ!なるほど、だから`--preserve-env=list`オプションがあるのか!意図したもののみ入れ替えるわけですね。
```bash
LANG=C.UTF-8
SUDO_GID=0
DISPLAY=127.0.0.1:0.0
COLORTERM=truecolor
USERNAME=ushio
SUDO_COMMAND=./child.sh
USER=ushio
PWD=/home/ushio/Codes/DevSecOps/volley/playground/environmentvariables
HOME=/root
SUDO_USER=root
FOO=BAR
SUDO_UID=0
MAIL=/var/mail/ushio
SHELL=/usr/bin/zsh
TERM=xterm-256color
SHLVL=1
LOGNAME=ushio
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
_=/usr/bin/env
FOO: BAR