Sudo - Arch Linux 中文维基

跳至內容

# Sudo

出自 Arch Linux 中文维基
翻譯狀態：

- 本文（或部分內容）譯自 Sudo，最近一次同步於 2025-01-05，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- 用戶和用戶組
- su
- doas

Sudo 使得系統管理員可以授權特定用戶或用戶組作為 root 或其他用戶執行命令，同時還能夠對命令及其參數提供審核跟蹤。

Sudo 是對於使用 su 以 root 用戶身份執行命令的一個替代。與 su 啟動 root shell 並允許用戶執行之後的所有命令不同，sudo 僅對單個命令臨時授予權限。通過僅在需要時授權，sudo 可以減少因輸錯命令或命令存在問題導致系統損壞的可能性。

sudo 也能以其他用戶身份執行命令，並且會將用戶執行的命令及失敗的權限申請記錄到 journal，以供後續安全審計使用。

## 安裝

安裝 sudo包 軟體包。

## 使用

在正確配置之前，普通用戶無法使用 `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'

## 配置

這篇文章的某些內容需要擴充。

原因：Create an intro discussing `Defaults`, perhaps with a table that lists common settings (在 Talk:Sudo 中討論)

### 默認框架

sudoers(5) § SUDOERS OPTIONS 在 `/etc/sudoers` 文件中列出了所有可以被 `Defaults` 命令使用的選項。

查看 [1] 獲得格式優化後的 `sudoers` 選項列表（解析自 1.8.7 源碼）。

查看 sudoers(5) 獲得更多信息，例如密碼超時設置。

### 查看當前設置

命令 `sudo -ll` 可以顯示當前的 sudo 配置; 命令 `sudo -lU user` 可以查看某個特定用戶的設置。

### 使用 visudo

sudo 的配置文件是 `/etc/sudoers`，必須使用 visudo(8) 編輯該文件。visudo 會鎖定 `sudoers` 文件，將修改保存到臨時文件中，並在將其複製到 `/etc/sudoers` 前檢查語法問題。

警告：

- 必須確保 `sudoers` 沒有語法問題！任何錯誤都會導致 sudo 不可用。必須使用 visudo 編輯該文件防止出錯。
- visudo(8) 警告說，將 visudo 配置為尊重用戶編輯器的環境變量設置可能會是一個安全漏洞，因為它允許擁有 visudo 權限的用戶通過將環境變量設置為其他內容從而以根用戶身份運行任意命令而不被日誌所記錄。

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` 組啟用 sudo 訪問並將管理員加入其中，這是因為默認 Polkit 就認為 wheel 組中的成員是管理員。如果用戶不是 `wheel` 組的成員，使用 Polkit 的軟體可能會要求驗證 root 密碼而非用戶密碼。

禁用詢問用戶 `USER_NAME` 的密碼：

警告：任何以您的用戶名運行的程序都可以無需密碼就執行 sudo。

    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 自動補全支持

這一章節正在考慮移除。

原因: 沒理由不使用 bash-completion包。 (在 Talk:Sudo 討論)

要為 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`.

這篇文章的某些內容需要擴充。

原因：Is it possible to preserve the localized prompt while using bell? The same question for the case when SUDO_PROMPT is used. Is there an alternative, for example by using "-B" option as default? (在 Talk:Sudo 中討論)

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 會話。

如果覺得每開一個終端使用 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 most cases when a user ends up in an emergency shell they are using the initramfs, will not use the following configuration, unless added to the `FILES` in mkinitcpio's configuration.（在 Talk:Sudo 中討論）

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

提示：要在禁用 root 帳號後使用 root 交互終端，請使用 `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 問題

本文或本章節可能需要合併到#配置。

附註： 請提供模板的second參數以more detailed indications。（在 Talk:Sudo 中討論）

遠程執行命令時，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

本文或本章節可能需要合併到#配置。

附註： 請提供模板的second參數以more detailed indications。（在 Talk:Sudo 中討論）

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 設置成什麼都會使用這裡設定的值。

分類：​

- 安全
- 命令
- 使用「模板:Remove」標記的章節

隱藏分類：​

- 使用「模板:準確性」標記的頁面或章節
- 使用「模板:合併」標記的頁面或章節

Sudo
新增話題