root権限への昇格時のsudo su と sudo su - の違いについて

はじめに

業務で、sudo surootユーザへ権限昇格した際に、あるコマンドにおいて文字化けしてしまうということが起きていた。
sudo su -でのrootユーザへ権限昇格だと正常にコマンドが実行できた。
このあたり理解が浅いのでまとめておく。

環境

Windows 11 Professional
WSL2 Ubuntu 24.04 LTS

sudo su について

コマンドの動作

現在のシェル環境をそのまま引き継ぎ、新しいユーザー(通常は root)としてシェルを起動する。

環境変数の挙動

元のユーザーの環境変数を引き継ぐ。
例として、$HOME$PATH は元のユーザーの設定が維持される。このため、デフォルトの root ユーザーの設定は適用されない。
※正確には、/etc/sudoersenv_keepが有効であれば環境変数が設定される。

用途

環境を引き継いだまま一時的に権限を上げてコマンドを実行したい場合に便利である。しかし、意図しない環境変数が root の操作に影響を与えるリスクがある。

sudo su - について

コマンドの動作

新しいユーザー(通常は root)としてログインし、そのユーザーのデフォルト環境を完全にロードする。

環境変数の挙動

元のユーザーの環境変数はクリアされ、新しいユーザー(root)のデフォルト環境が読み込まれる。 例として、$HOME/root に変更され、root ユーザー専用のパスや設定が適用される。
この際、/etc/profile/root/.bashrc などの設定ファイルが読み込まれる。

用途

完全に root 環境で作業したい場合に推奨される。
root 専用の設定や環境が必要なタスク(システム管理、パッケージのインストールなど)を行う際に有効である。

違いについての例

sudo su

user@machine:~$ echo $HOME
/home/user
user@machine:~$ sudo su
root@machine:/home/user# echo $HOME
/home/user

$HOME が元のユーザーのままとなる。

sudo su -

user@machine:~$ echo $HOME
/home/user
user@machine:~$ sudo su -
root@machine:~# echo $HOME
/root

$HOME/root に切り替わる。

実際にやってみる

WSL2の環境でやってみる。

kbushiユーザーがカレントユーザなので、これを sudo suでの昇格とsudo su -での昇格で確認してみる。

kbushiユーザの $HOMEと$PATH

echo $HOME                                                                                
/home/kbushi

echo $PATH                                                                               
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/mnt/c/Program Files/Microsoft SDKs/Azure/CLI2/wbin:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Windows/System32/OpenSSH/:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/Git/cmd:/mnt/c/Program Files/Microsoft SQL Server/150/Tools/Binn/:/mnt/c/Program Files/Microsoft SQL Server/Client SDK/ODBC/170/Tools/Binn/:/mnt/c/Program Files (x86)/Nodist/bin:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA app/NvDLISR:/Docker/host/bin:/mnt/c/Users/pspkk/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/pspkk/AppData/Local/Programs/Microsoft VS Code/bin:/mnt/c/Users/pspkk/.dotnet/tools:/home/kbushi/.dotnet:/home/kbushi/.dotnet/tools

sudo suで実行

sudo su

root@kbushi:/home/kbushi# echo $HOME
/root

root@kbushi:/home/kbushi# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

sudo su -で実行

sudo su -

root@kbushi:~# echo $HOME
/root

root@kbushi:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

やってみたが、変わっていないようだった。
sudo suだと環境変数が切り替わるようだが、なぜ?

/etc/sudoersのenv_keep, secure_pathについて

/etc/sudoersには、環境変数の保持 (env_keep)が存在している。
sudo の設定ファイル(/etc/sudoers)で、env_keep オプションによってどの環境変数を保持するかが制御されている。
そのため、この中でこの設定がされているかどうかを確認するのが良い。
※デフォルトでは、$PATH などが引き継がれることが一般的である。
また、secure_pathが設定されていると、sudo 実行時に $PATH をこの値に強制的に設定するため、ここも確認をする。

下記を見てみると、secure_pathが設定されており、これが$PATHに上書きするようなので、引き継ぎされないようだ。

/etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

# This fixes CVE-2005-4890 and possibly breaks some versions of kdesu
# (#1011624, https://bugs.kde.org/show_bug.cgi?id=452532)
Defaults        use_pty

# This preserves proxy settings from user environments of root
# equivalent users (group sudo)
#Defaults:%sudo env_keep += "http_proxy https_proxy ftp_proxy all_proxy no_proxy"

# This allows running arbitrary commands, but so does ALL, and it means
# different sudoers have their choice of editor respected.
#Defaults:%sudo env_keep += "EDITOR"

# Completely harmless preservation of a user preference.
#Defaults:%sudo env_keep += "GREP_COLOR"

# While you shouldn't normally run git as root, you need to with etckeeper
#Defaults:%sudo env_keep += "GIT_AUTHOR_* GIT_COMMITTER_*"

# Per-user preferences; root won't have sensible values for them.
#Defaults:%sudo env_keep += "EMAIL DEBEMAIL DEBFULLNAME"

# "sudo scp" or "sudo rsync" should be able to use your SSH agent.
#Defaults:%sudo env_keep += "SSH_AGENT_PID SSH_AUTH_SOCK"

# Ditto for GPG agent
#Defaults:%sudo env_keep += "GPG_AGENT_INFO"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "@include" directives:

@includedir /etc/sudoers.d

Defaults env_reset

sudo コマンド実行時に、環境変数をリセットする。
一部の変数($PATH など)はリセットされるか、secure_path によって上書きされる。

Defaults secure_path="..."

sudo 実行時に $PATH をこの値に強制的に設定する。
これにより、通常のユーザーが持つ $PATH の内容は無視される。
sudo を使った場合、secure_path に定義された値が $PATH として使用されるため、sudo susudo su - を実行しても $PATH はこの値が反映される。

環境変数を引き継ぎしつつ切り替えをする

確認するために、環境変数を引き継ぎできるようにしてみる。

/etc/sudoersの設定を変更する

sudo EDITOR=vim visudo
/etc/sudoers
Defaults        env_reset
Defaults        mail_badpass
# Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

として保存する。

下記を実行する。
sudo suだと、どうやら$PATHの環境変数が引継ぎされないようだった。
今回はsudo -iで実行して試した結果となる。

sudo -i

root@kbushi:~# echo $HOME
/root

root@kbushi:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/mnt/c/Program Files/Microsoft SDKs/Azure/CLI2/wbin:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Windows/System32/OpenSSH/:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/Git/cmd:/mnt/c/Program Files/Microsoft SQL Server/150/Tools/Binn/:/mnt/c/Program Files/Microsoft SQL Server/Client SDK/ODBC/170/Tools/Binn/:/mnt/c/Program Files (x86)/Nodist/bin:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA app/NvDLISR:/Docker/host/bin:/mnt/c/Users/pspkk/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/pspkk/AppData/Local/Programs/Microsoft VS Code/bin:/mnt/c/Users/pspkk/.dotnet/tools:/home/kbushi/.dotnet:/home/kbushi/.dotnet/tools:/snap/bin

環境変数を引き継ぎしつつ切り替えをする2

気になったので、$PATH以外の環境変数で実験した。

一般ユーザで環境変数をexportする。

export ICHI=1
env | grep ICHI

## 結果
ICHI=1

/etc/sudoersを修正する。

/etc/sudoers
Defaults        env_reset
Defaults        env_keep += "ICHI"
Defaults        mail_badpass
# Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

sudo su, sudo su -, sudo -iを試す。

sudo suでの実行

sudo su

root@kbushi:/home/kbushi# env | grep ICHI
ICHI=1

root@kbushi:/home/kbushi#

sudo su -での実行

sudo su -

root@kbushi:~# env | grep ICHI

root@kbushi:~#

sudo -i での実行

sudo -i

root@kbushi:~# env | grep ICHI
ICHI=1

root@kbushi:~#

結果として、sudo suだと環境変数が引き継がれるようだった。
sudo suでのPATHの環境変数が引き継がれないところについては、secure_path以外にも設定している箇所があるのかもしれない…。

おまけ

suについて

suで 特定のユーザに切り替えることもできる。

su 

これだと、rootユーザへの切り替え。
この場合は、rootユーザのパスワードが必要になることに注意。

susu -も今回記載したsudo susudo su -と同じなのでここでは記載しない。

例えば、rootユーザ以外の切り替えであれば、

# - なし
su user

# - あり
su user -

というように切り替えができる。
-のあり/なしでカレントユーザの環境変数が引き継がれるかどうかが決まるのでこの点に注意すること。

参考

おわりに

sudo suを何も考えずに気軽に使ってしまっていたので、このあたりちゃんと覚えておきたい。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。