Sudo 使得系統管理員可以授權特定用戶或用戶組作為 root 或其他用戶執行命令,同時還能夠對命令及其參數提供審核跟蹤。
Sudo 是對於使用 su 以 root 用戶身份執行命令的一個替代。與 su 啟動 root shell 並允許用戶執行之後的所有命令不同,sudo 僅對單個命令臨時授予權限。通過僅在需要時授權,sudo 可以減少因輸錯命令或命令存在問題導致系統損壞的可能性。
sudo 也能以其他用戶身份執行命令,並且會將用戶執行的命令及失敗的權限申請記錄到 journal,以供後續安全審計使用。
安裝
使用
在正確配置之前,普通用戶無法使用 sudo
。參見#配置。
要使用 sudo,只需在命令和其參數前加上 sudo
和空格:
$ sudo cmd
例如,要使用 pacman:
$ sudo pacman -Syu
參見 sudo(8)。
Login shell
並不是所有命令都可以在前面加上 sudo 就能以其它用戶身份執行。特別是在使用重定向和命令替換時,必須通過 sudo -iu user
(目標用戶是 root 時可以省略 -u user
)使用 login shell。
以下為例,其可以在完整的 shell 環境中執行,但無法直接附加 sudo 執行:
$ sudo wpa_supplicant -B -i interface -c <(wpa_passphrase MYSSID passphrase)
Successfully initialized wpa_supplicant Failed to open config file '/dev/fd/63', error: No such file or directory Failed to read or parse configuration '/dev/fd/63'
配置
Defaults skeleton
sudoers(5) § SUDOERS OPTIONS lists all the options that can be used with the Defaults
command in the /etc/sudoers
file.
See [1] for a list of options (parsed from the version 1.8.7 source code) in a format optimized for sudoers
.
See sudoers(5) for more information, such as configuring the password timeout.
查看當前設置
命令 sudo -ll
可以顯示當前的 sudo 配置; 命令 sudo -lU user
可以查看某個特定用戶的設置。
使用 visudo
sudo 的配置文件是 /etc/sudoers
,必須使用 visudo(8) 編輯該文件。visudo 會鎖定 sudoers
文件,將修改保存到臨時文件中,並在將其複製到 /etc/sudoers
前檢查語法問題。
- 必須確保
sudoers
沒有語法問題!任何錯誤都會導致 sudo 不可用。必須使用 visudo 編輯該文件防止出錯。 - visudo(8) warns that configuring visudo to honor the user environment variables for their editor of choice may be a security hole, since it allows the user with visudo privileges to run arbitrary commands as root without logging simply by setting that variable to something else.
visudo 調用的默認編輯器是 vi。sudo包 包在編譯時啟用了 --with-env-editor
,會採用 環境變量 SUDO_EDITOR
,VISUAL
和 EDITOR
的設置。如果設置了VISUAL
,就不會使用 EDITOR
。
要在當前 shell 會話中使用 nano 作為 visudo 編輯器,可以設置 EDITOR=nano
環境變量;如果要臨時使用其他編輯器,在調用 visudo 前設置環境變量即可。
# EDITOR=nano visudo
你還可以編輯 /etc/sudoers
的副本,然後使用 visudo -c /copy/of/sudoers
進行檢查。該操作可以避免 visudo 鎖定文件。
要永久設置編輯器,請參考定義本地環境變量。要僅修改 visudo 的系統級編輯器設置,可以在 /etc/sudoers
中添加以下內容(假設你要使用 nano 作為默認編輯器):
# Set default EDITOR to restricted version of nano, and do not allow visudo to use EDITOR/VISUAL. Defaults editor=/usr/bin/rnano, !env_editor
設置示例
要允許指定用戶在命令前添加 sudo
時獲得完全 root 權限,在配置文件中加入該行:
用户名 ALL=(ALL:ALL) ALL
要限定主機名為 HOST_NAME
的設備上的指定用戶可以執行任意命令:
用户名 HOST_NAME=(ALL:ALL) ALL
要允許 wheel 用戶組成員使用sudo:
%wheel ALL=(ALL:ALL) ALL
wheel
group and add the user to it, since by default Polkit treats the members of the wheel
group as administrators. If the user is not a member of wheel
, software using Polkit may ask to authenticate using the root password instead of the user password.禁用詢問用戶 USER_NAME
的密碼:
Defaults:USER_NAME !authenticate
僅允許主機 HOST_NAME
上的用戶 USER_NAME
執行特定命令:
USER_NAME HOST_NAME=/usr/bin/halt,/usr/bin/poweroff,/usr/bin/reboot,/usr/bin/pacman -Syu
%wheel
用戶組內,就需要將該行放於對應組配置之後。僅允許主機 HOST_NAME
上的用戶 USER_NAME
執行特定命令,但不用輸入密碼:
USER_NAME HOST_NAME= NOPASSWD: /usr/bin/halt,/usr/bin/poweroff,/usr/bin/reboot,/usr/bin/pacman -Syu
更詳細的 sudoers
範例請參考 /usr/share/doc/sudo/examples/sudoers
。此外,更多信息參見 sudoers(5)。
sudoers 文件默認權限
sudoers
文件的屬主和屬組 ID 必須都是 0,文件權限位是 0440(-r--r-----)。如果你不小心改變了默認權限,應當立即恢復它們,否則 sudo 將會出錯:
# chown -c root:root /etc/sudoers # chmod -c 0440 /etc/sudoers
使用技巧
禁用密碼輸入超時
比較常見的煩人問題是有個後台終端上長時間運行的進程,該進程以正常權限運行,只有在需要時才提升權限。這時就會出現 sudo 密碼輸入提示,該提示很容易會被忽略並導致超時,此時進程就會死亡,已完成的工作也會丟失,或者最多只是被緩存。常見的建議是啟用無密碼 sudo 或延長 sudo 記住密碼的超時時間。這兩種方法都會帶來負面的安全影響。這裡的解決方案應是將輸入提示超時禁用,且不會造成任何合理的安全影響:
Defaults passwd_timeout=0
bash 自動補全支持
要為 sudo 命令提供完整的 bash 自動補全功能,請安裝 bash-completion包 軟體包。如果由於某些原因無法安裝該包,則可在 .bashrc 中添加以下內容,以獲得部分 sudo 命令的自動補全功能:
complete -cf sudo
Passing aliases
The following is only relevant if the bash completion is not available (either full or reduced as described above): Aliases in Zsh and Bash are normally only expanded for the first word in a command. This means that your aliases will not normally get expanded when running the sudo
command. One way to make the next word expand is to make an alias for sudo ending with a space. Add the following to your shell's configuration file:
alias sudo='sudo '
zshmisc(1) § ALIASING describes how this works:
- If the replacement text ends with a space, the next word in the shell input is always eligible for purposes of alias expansions.
As well as bash(1) § ALIASES:
- If the last character of the alias value is a blank, then the next command word following the alias is also checked for alias expansion.
Add terminal bell to the password prompt
To draw attention to a sudo prompt in a background terminal, users can simply make it echo a bell character:
Defaults passprompt="^G[sudo] password for %p: "
Note the ^G
is a literal bell character. E.g. in vim, insert using the sequence Ctrl+v
Ctrl+g
. If Ctrl+v
is mapped, e.g. for pasting, one can usually use Ctrl+q
instead. In nano, Alt+v
Ctrl+g
.
Another option is to set the SUDO_PROMPT
environment variable. For example, add the following to your shell configuration file:
export SUDO_PROMPT=$'\a[sudo] password for %p: '
禁用單終端 sudo
如果覺得每開一個終端使用 sudo 都要輸密碼很煩,可以將 timestamp_type
設為 global
:
Defaults timestamp_type=global
減少要求輸入密碼的次數
如果覺得每 5 分鐘(默認值)都要重新輸密碼很煩,可以將 timestamp_timeout
改成更長的值(單位為分鐘):
Defaults timestamp_timeout=10
如果在較長的腳本中使用 sudo 命令,且不想在超時後等待用戶輸入,則可以通過循環運行 sudo -v
來刷新超時(而 sudo -K
則會立即取消超時)。
環境變量
如果你使用了大量環境變量,或者你通過 export http_proxy="..."
配置了代理設置,除非執行 sudo 時使用了 -E
/--preserve-env
選項,否則這些變量不會被傳遞到根用戶下。
$ sudo -E pacman -Syu
推薦方法是將要傳遞的環境變量添加到 env_keep
中:
/etc/sudoers
Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"
使用 root 密碼
通過將 targetpw
(目標用戶,默認為 root)或 rootpw
添加到 /etc/sudoers
的 Defaults 一行中,可以讓 sudo 詢問 root 帳戶的密碼,而不是用戶密碼:
Defaults targetpw
為避免向用戶暴露 root 帳戶密碼,可以將該設置限定到特定組:
Defaults:%wheel targetpw %wheel ALL=(ALL) ALL
禁止 root 登錄
用戶也許希望禁止使用 root 登錄。沒有了 root 用戶,黑客就必須要知道 sudoer 的用戶名和密碼,具體實例請參考 OpenSSH#拒絕。
- 注意,禁用 root 登陸後有可能會把你自己鎖在系統外。默認情況下沒有安裝 sudo,其默認配置也不允許無密碼使用 root 權限和使用用戶密碼獲取 root 權限。在禁用 root 之前,務必確保已正確配置至少一個用戶的權限!
- 如果你在 sudoers 中配置了默認使用 rootpw,就不要執行下列任一命令禁用 root 登陸:
- 如果你已經被鎖在系統外了,請參考重置 root 密碼。
使用 passwd
命令鎖住 root 用戶:
# passwd -l root
使用以下命令解鎖 root 用戶:
$ sudo passwd -u root
或者,編輯 /etc/shadow
文件,將 root 的加密口令列替換為 !*
:
root:!*:12345::::::
要再次允許 root 登陸,重新設置其密碼即可:
$ sudo passwd root
In case of system emergency, the recovery prompt is going to ask your for a root password, making it impossible to log into recovery shell. To automatically unlock the root account in case of emergency add SYSTEMD_SULOGIN_FORCE=1
environment variable to rescue.service
using a drop-in file:
/etc/systemd/system/rescue.service.d/SYSTEMD_SULOGIN_FORCE.conf
[Service] Environment=SYSTEMD_SULOGIN_FORCE=1
sudo -i
。kdesu
KDE 下可能會使用 kdesu 以 root 權限執行圖形程序。默認情況下,即使 root 帳戶被禁用,kdesu 仍可能會嘗試使用 su 切換 root。可以配置 kdesu 以使用sudo,創建或編輯 ~/.config/kdesurc
,加入:
[super-user-command] super-user-command=sudo
或者使用下面命令:
$ kwriteconfig6 --file kdesurc --group super-user-command --key super-user-command sudo
示例:通過 sudo 強化安全
假設你創建了 3 個用戶:admin,devel 和 archie。用戶「admin」用於 journalctl,systemctl,mount,kill 和 iptable;「devel」用於安裝軟體包和編輯配置文件;「archie」是用戶登錄使用的帳戶。為了允許「archie」進行重啟,關機和使用 netctl,需要進行以下步驟:
編輯 /etc/pam.d/su
和 /etc/pam.d/su-l
。Require user be in the wheel group, but do not put anyone in it.
#%PAM-1.0 auth sufficient pam_rootok.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient pam_wheel.so trust use_uid # Uncomment the following line to require a user to be in the "wheel" group. auth required pam_wheel.so use_uid auth required pam_unix.so account required pam_unix.so session required pam_unix.so
僅允許 'ssh' 用戶組下的用戶通過 SSH 登錄,只有「archie」在該組內:
# groupadd -r ssh # gpasswd -a archie ssh # echo 'AllowGroups ssh' >> /etc/ssh/sshd_config
重啟 sshd.service
。
將用戶添加到其它組中:
# for g in power network ;do ;gpasswd -a archie $g ;done # for g in network power storage ;do ;gpasswd -a admin $g ;done
設置配置文件的權限,以使 devel 能夠進行編輯:
# chown -R devel:root /etc/{http,openvpn,cups,zsh,vim,screenrc}
Cmnd_Alias POWER = /usr/bin/shutdown -h now, /usr/bin/halt, /usr/bin/poweroff, /usr/bin/reboot Cmnd_Alias STORAGE = /usr/bin/mount -o nosuid\,nodev\,noexec, /usr/bin/umount Cmnd_Alias SYSTEMD = /usr/bin/journalctl, /usr/bin/systemctl Cmnd_Alias KILL = /usr/bin/kill, /usr/bin/killall Cmnd_Alias PKGMAN = /usr/bin/pacman Cmnd_Alias NETWORK = /usr/bin/netctl Cmnd_Alias FIREWALL = /usr/bin/iptables, /usr/bin/ip6tables Cmnd_Alias SHELL = /usr/bin/zsh, /usr/bin/bash %power ALL = (root) NOPASSWD: POWER %network ALL = (root) NETWORK %storage ALL = (root) STORAGE root ALL = (ALL) ALL admin ALL = (root) SYSTEMD, KILL, FIREWALL devel ALL = (root) PKGMAN archie ALL = (devel) SHELL, (admin) SHELL
完成配置後,就基本不需要以 root 身份登錄了。
「archie」可以連接到家裡的 Wi-Fi:
$ sudo netctl start home $ sudo poweroff
「archie」無法以其他用戶身份使用 netctl:
$ sudo -u admin -- netctl start home
如果「archie」需要使用 journalctl 或殺死其它進程,可以切換到對應用戶:
$ sudo -i -u devel $ sudo -i -u admin
但「archie」無法切換到根用戶:
$ sudo -i -u root
如果「archie」想以 admin 身份啟動 gnu-screen 會話,可以參考以下操作:
$ sudo -i -u admin [admin]$ chown admin:tty `echo $TTY` [admin]$ screen
讓 sudo 使用 /etc/sudoers.d 中的文件
sudo 可以解析 /etc/sudoers.d/
目錄中的文件,這樣就不需要編輯 /etc/sudoers
,可以單獨將配置寫入到新文件中,然後放入到該目錄。該方式的優點包括:
- 不需要編輯
sudoers.pacnew
文件; - 如果新配置有問題,可以刪除這個文件而不用編輯
/etc/sudoers
(但注意下方警告)。
該目錄下的文件格式與 /etc/sudoers
一致。如需直接編輯這些文件,可以使用 visudo -f /etc/sudoers.d/somefile
,具體請參考 sudoers(5) § Including other files from within sudoers。
/etc/sudoers.d/
目錄中的文件是按字母順序加載的,.
或 ~
開頭的文件會被跳過。為避免排序問題,文件名應以兩位數字開頭,例如:01_foo
。
/etc/sudoers.d/
中的文件和 /etc/sudoers
一樣,格式錯誤將導致 sudo
無法正常運行。因此,強烈建議同樣使用 visudo
。編輯文件
sudo
提供了 sudoedit
命令(與 sudo -e
等效),能以當前用戶身份及配置運行編輯器時修改僅 root 有權編輯的文件。
要編輯文件,需將 SUDO_EDITOR
設為編輯器名稱,並將文件名傳遞給 sudoedit
,例如:
$ SUDO_EDITOR=vim sudoedit /etc/file
設置編輯器的方式請參考#使用 visudo 和 sudo(8) § e,但需要注意潛在的安全問題。
如果一次性向 sudo
傳入多個文件名,則會在編輯器中同時打開所有文件:
$ SUDO_EDITOR=vimdiff sudoedit /etc/file /etc/file.pacnew
啟用嘲諷
通過 visudo
在 sudoers
文件中添加下行可以啟用嘲諷彩蛋:
/etc/sudoers
Defaults insults
在用戶輸錯密碼時,會將 Sorry, try again.
替換成各種嘲諷。
啟用密碼輸入反饋
默認情況下,輸入密碼是不會有視覺反饋的,目的是增強安全性。如果你想啟用視覺反饋,可以添加下行進行啟用:
/etc/sudoers
Defaults pwfeedback
彩色密碼提示
在 shell 初始化文件中設置 SUDO_PROMPT
環境變量和 tput(1) 可以自定義彩色和/或粗體密碼提示。
以將 Password:
顯示為紅色粗體為例:
export SUDO_PROMPT="$(tput setaf 1 bold)Password:$(tput sgr0) "
也可以使用不同顏色來顯示默認消息:
export SUDO_PROMPT="$(tput setab 1 setaf 7 bold)[sudo]$(tput sgr0) $(tput setaf 6)password for$(tput sgr0) $(tput setaf 5)%p$(tput sgr0): "
詳細信息請參考在終端輸出彩色和 Bash/Prompt customization。
使用 U2F
將 U2F 與 sudo 搭配使用,可以通過物理觸碰進行批准,還能基本消除公眾場合下被肩窺的風險。
具體信息請參考通用第二因素#無密碼 sudo。
寫入到受保護文件
在使用 sudo 時,無法使用 >
/>>
寫入到受保護文件,這時候可以使用 tee:
$ input stream | sudo tee --option protected_file_1 protected_file_2...
Vim 環境內
A similar concept is useful when you forgot to start Vim with sudo when editing a file owned by an other user. In this case you can do the following inside Vim to save the file:
:w !sudo tee %
You can add this to your ~/.vimrc
to make this trick easy-to-use with :w!!
mapping in command mode:
~/.vimrc
" Allow saving of files as sudo when I forgot to start vim using sudo cmap w!! w !sudo tee > /dev/null %
The > /dev/null
part explicitly throws away the standard output since we do not need to pass anything to another piped command.
More detailed explanation of how and why this works can be found in How does the vim 「write with sudo」 trick work? article on StackOverflow.
疑難解答
SSH TTY 問題
遠程執行命令時,SSH 默認不會分配 tty。沒有分配 tty,sudo 就無法在獲取密碼時關閉回顯。使用 SSH 的 -t
選項可以強制分配 tty。
Defaults
的 requiretty
選項可以僅允許有 tty 的用戶才能使用 sudo:
# Disable "ssh hostname sudo <cmd>", because it will show the password in clear text. You have to run "ssh -t hostname sudo <cmd>". # #Defaults requiretty
權限 Umask
Sudo 會統一用戶的 umask 值和它自己的 umask(默認是 0022)。這會防止 sudo 創建的文件權限比該用戶 umask 允許的更廣。在沒有使用自定義 umask 時,該配置比較合理,但可能導致 sudo 創建的文件權限與 root 下直接創建的權限不同。如果這導致了問題,sudo 提供了一個方法來修復 umask,即使想要的 umask 比用戶指定的 umask 權限還要多。添加下面內容(使用 visudo
)會覆蓋 sudo 的默認行為:
Defaults umask = 0022 Defaults umask_override
這會將 sudo 的 umask 設置為 root 的默認 umask(0022),覆蓋掉默認行為,無論用戶的 umask 設置成什麼都會使用這裡設定的值。