su と sudo の環境変数に関連するオプションを完全に理解するためのまとめ
Written by @ryysud Oct 19, 2018 19:08 · 2618 words · 6 minutes read
TL;DR
環境変数周りで困ったら、基本的には login shell で実行するオプションを使っておくのが間違いなさそう。
- su -
- sudo -i
su コマンドの環境変数に関連するオプション
- -m, -p, –preserve-environment は切り替え先のユーザーの ~/.bashrc を読まないオプション
- - (hyphen), -l, –login は login shell で実行するオプション
sudo コマンドの環境変数に関連するオプション
- -E, –preserve-env はコマンドを実行する際に切り替え元のユーザーの環境変数を保持しておくオプション
- -i, –login は login shell で実行するオプション
検証環境
- OS は CentOS 7.5(ローカルで Docker Container として起動)
- 検証ユーザーとして anonymous ユーザーを用意(sudoers にも追加)
- su のバージョンは 2.23.2
- sudo のバージョンは 1.8.19p2
[root@dev /]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
[root@dev /]# uname -a
Linux dev 4.9.93-linuxkit-aufs #1 SMP Wed Jun 6 16:55:56 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[root@dev /]# su --version
su from util-linux 2.23.2
[root@dev /]# sudo --version
Sudo version 1.8.19p2
基本方針
su –help と sudo –help で表示された options を眺めて、それっぽいものを洗い出す方針で進めていきます。
bash での login shell が読むファイルの順番をおさらい
ここから下で、login shell で実行するオプションが出てくるので軽くおさらいしておくと、login shell で実行するオプションが指定された際には ① から読まれ、オプションが指定されずに interactive shell で実行する際には ③ から読まれる形となります。
〜 login shell で実行するオプションが “指定された” ときはここから 〜
① /etc/profile
② ~/.bash_profile(なかったら ~/.bash_login、~/.profile の順で読まれる)
〜 login shell で実行するオプションが “指定されてない” ときはここから 〜
③ ~/.bashrc
④ /etc/bashrc
⑤ bash 実行
bash での login shell が読むファイルも用意しておく
以下のファイルに確認用の環境変数を仕込んでおく。
- /root/.bash_profile( export READ_ROOT_BASH_PROFILE=true を末尾に追加 )
- /root/.bashrc( export READ_ROOT_BASHRC=true を末尾に追加 )
- /home/anonymous/.bash_profile( export READ_ANONYMOUS_BASH_PROFILE=true を末尾に追加 )
- /home/anonymous/.bashrc( export READ_ANONYMOUS_BASHRC=true を末尾に追加 )
su コマンドの環境変数に関連するオプション
オプションなし
初めに1つもオプションをつけない状態の挙動を確認しておきます。オプションなしで root ユーザーから anonymous ユーザーに切り替えてみると、切り替え先のユーザーである anonymous ユーザーの ~/.bashrc が読まれて、環境変数が追加されていることがわかります。
# root ユーザー時点での状態
[root@dev /]# env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
# anonymous ユーザーに切り替え
[root@dev /]# su anonymous
# anonymous ユーザーに切り替え後の状態
[anonymous@dev /]$ env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
READ_ANONYMOUS_BASHRC=true # <--- 追加された環境変数
-m, -p, –preserve-environment
説明
切り替え先のユーザーの ~/.bashrc を読まないオプション。このオプションを指定することで、切り替え先のユーザーの ~/.bashrc を読まずに、切り替え元のユーザーの ~/.bashrc を再度読ませることができます。
[root@dev /]# su --help | grep '\-m'
-m, -p, --preserve-environment do not reset environment variables
実際に挙動をみていく
-m オプションありで root ユーザーから anonymous ユーザーに切り替えてみると、anonymous ユーザーの ~/.bashrc が読まれずに、root ユーザーの ~/.bashrc が読まれ、結果的に切り替え先のユーザーの環境変数は追加されていないことがわかります。しかも、切り替え先のユーザーで切り替え元のユーザーの ~/.bashrc を読みにいくので、大体は Permission denied になりそうですし、このオプションがあって嬉しいユースケースが浮かびません…。まあ、覚えておいて損はなさそうな感じですね〜!
# root ユーザー時点での状態
[root@dev /]# env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
# anonymous ユーザーに切り替え(同一の挙動なので -m だけ試す)
[root@dev /]# su -m anonymous
bash: /root/.bashrc: Permission denied
# anonymous ユーザーに切り替え後の状態
bash-4.2$ env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
- (hyphen), -l, –login
説明
login shell で実行するオプション。
[root@dev /]# su --help | grep '\--login'
-, -l, --login make the shell a login shell
実際に挙動をみていく
- (hyphen) オプションありで root ユーザーから anonymous ユーザーに切り替えてみると、login shell での実行となり、anonymous ユーザーの ~/.bash_profile と ~/.bashrc が読まれて、結果的に切り替え元のユーザーが保持していた環境変数は破棄されて、切り替え先のユーザーの環境変数のみになることがわかります。切り替え先のユーザーの初期設定が適用されるので、クリーンな状態でユーザー切り替えをやりたいときには、このオプション一択となります!(自分もよっぽどのことがない限りは基本的にこれを使ってます)
# root ユーザー時点での状態
[root@dev /]# env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
# anonymous ユーザーに切り替え(同一の挙動なので - だけ試す)
[root@dev /]# su - anonymous
Last login: Fri Oct 19 11:23:58 UTC 2018 on pts/2
# anonymous ユーザーに切り替え後の状態
[anonymous@dev ~]$ env | grep -i read
READ_ANONYMOUS_BASHRC=true # <--- 切り替え先のユーザーの環境変数のみになる
READ_ANONYMOUS_BASH_PROFILE=true # <--- 切り替え先のユーザーの環境変数のみになる
sudo コマンドの環境変数に関連するオプション
オプションなし
初めに1つもオプションをつけない状態の挙動を確認しておきます。オプションなしで root ユーザーから anonymous ユーザーに切り替えてコマンドを実行してみると、切り替え元のユーザーの環境変数は渡らないことがわかります。
# root ユーザー時点での状態
[root@dev /]# env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
# anonymous ユーザーに切り替えてコマンドを実行
[root@dev /]# sudo -u anonymous env | grep -i read
-E, –preserve-env
説明
コマンドを実行する際に、切り替え元のユーザーの環境変数を保持しておくオプション。
[root@dev /]# sudo --help | grep '\-E'
-E, --preserve-env preserve user environment when running command
実際に挙動をみていく
-E オプションありで root ユーザーから anonymous ユーザーに切り替えてコマンドを実行してみると、コマンド実行時に切り替え元のユーザーの環境変数が渡っていることがわかります。
# root ユーザー時点での状態
[root@dev /]# env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
# anonymous ユーザーに切り替えてコマンドを実行
[root@dev /]# sudo -E -u anonymous env | grep -i read
READ_ROOT_BASH_PROFILE=true # <--- 切り替え元のユーザーの環境変数が渡っている
READ_ROOT_BASHRC=true # <--- 切り替え元のユーザーの環境変数が渡っている
-i, –login
説明
[root@dev /]# sudo --help | grep '\--login'
-i, --login run login shell as the target user; a command may also be
実際に挙動をみていく
-i オプションありで root ユーザーから anonymous ユーザーに切り替えてコマンドを実行してみると、login shell での実行となり、su - と同じ挙動となります。クリーンな状態でやりたいときは、このオプションが良さそうですね!(いつも sudo -E しか使ってなかったので今後はこれを使っていく所存)
なお、-E と -i の両方を指定した際には、-i の login shell 実行に -E が負ける形となります。参考までに。
# root ユーザー時点での状態
[root@dev /]# env | grep -i read
READ_ROOT_BASH_PROFILE=true
READ_ROOT_BASHRC=true
# anonymous ユーザーに切り替えてコマンドを実行
[root@dev /]# sudo -i -u anonymous env | grep -i read
READ_ANONYMOUS_BASHRC=true
READ_ANONYMOUS_BASH_PROFILE=true
まとめ
冒頭の TL;DR がまとめ的な役割なので、そちらを参照ください。基本的には su - と sudo -i でやっていくのが1番良さそうということがわかったので、今後はググることはなさそうです。