排解 sudoers 檔案問題


本頁面提供使用 sudo 指令列公用程式的訣竅、管理 sudoers 外掛程式,以及避免或修正問題。

問題原因

每次執行 sudo 指令時,系統都會執行下列程序來驗證 sudoers 檔案:

  • 系統會檢查語法是否正確。
  • 系統會分析內容,排除部分邏輯錯誤。
  • 系統會檢查擁有權和權限。

sudoers 檔案驗證失敗的可能原因如下:

語法錯誤

變更 sudoers 檔案時,請務必遵守特定語法規則。如果語法有任何偏差 (包括但不限於缺少或多出字元,或使用不當的半形逗號),檔案就會無效。檔案失效後,就無法使用 sudo 公用程式。

解決方案

解決方法是使用 visudo 公用程式編輯 sudoers 檔案。系統會在儲存檔案前驗證檔案內容,並在發生問題時通知您。visudo 公用程式的用途是安全地編輯檔案。


以下範例顯示正確和不正確的語法範例:

正確語法

user   ALL=(ALL) ALL

語法錯誤

user   ALL=(ALL), ALL

語法錯誤範例

$ sudo useradd username
/etc/sudoers:20:17: syntax error
user   ALL=(ALL), ALL
                ^

邏輯錯誤

這類錯誤可能是由下列其中一項原因造成:

  • 誤解 sudoers 外掛程式的原則。
  • 與正確語法有出入。

不過,驗證程序不會辨識邏輯錯誤,因為這類錯誤不會違反語法規則,因此難以偵測。

解決方案

編輯檔案時,請務必詳閱官方說明文件並遵守相關原則。

此外,Google 也建議您使用 visudo 公用程式編輯 sudoers 檔案,因為這項工具可以偵測某些類型的邏輯錯誤,例如:

  • 未定義或未使用的別名
  • 循環參照
  • 重複項目

如果偵測到任何問題,系統會顯示警告訊息。


以下範例顯示邏輯正確和不正確的樣本:

邏輯正確

barbara   ALL=(ALL:ALL) /usr/bin/ls

邏輯錯誤

barbara   ALL=(4LL:ALL) /usr/bin/ls
               ^
barbara   ALL=(ALL;ALL) /usr/bin/ls
                  ^
bar6ara   ALL=(ALL:ALL) /usr/bin/1s
   ^                             ^

權限錯誤

除了 sudoers 檔案內容造成的錯誤,檔案權限過多或擁有權不正確,也可能導致 sudo 公用程式失敗。

解決方案

您可以在失敗的 sudo 指令輸出中看到這些錯誤的說明。請詳讀錯誤訊息說明,並進行必要的修正。


以下是正確的檔案權限和擁有權範例

$ ls -l /etc/sudoers
-r--r----- 1 root root 700 Jan 1 12:00 /etc/sudoers

$ sudo useradd username

以下範例顯示「所有使用者」權限群組出現多餘權限時顯示的錯誤:

$ ls -l /etc/sudoers
-r--r---w- 1 root root 700 Jan 1 12:00 /etc/sudoers

$ sudo useradd username
sudo: /etc/sudoers is world writable
sudo: no valid sudoers sources found, quitting
sudo: error initializing audit plugin sudoers_audit

下列範例顯示擁有權不正確時出現的錯誤。在這個範例中,ID 不是 0 (或不是 root) 的使用者是檔案擁有者:

$ ls -l /etc/sudoers
-r--r----- 1 user user 700 Jan 1 12:00 /etc/sudoers

$ sudo useradd username
sudo: /etc/sudoers is owned by uid 1000, should be 0
sudo: no valid sudoers sources found, quitting
sudo: error initializing audit plugin sudoers_audit

如要進一步瞭解 sudoers 檔案的設定,請參閱「Sudoers Manual」。

如要瞭解如何管理及使用 visudo 編輯器,請參閱 Visudo 手冊

問題的後果

sudoers 檔案中的問題會造成負面影響,並可能影響整個系統的功能。

  • sudo」指令已失效。

    這是 sudoers 檔案發生問題時最明顯的後果。 這會導致使用者無法使用提升的權限,進而阻礙他們在伺服器上的活動。

    不過,如果依賴 sudo 指令的應用程式發生故障,後果可能更具破壞性且難以預測。在某些情況下,這可能會導致應用程式完全失敗,進而產生非預期的行為、異常終止或資料遺失。另一個例子是 OS 開機順序期間,應用程式呼叫 sudo 指令失敗。這可能會導致作業系統故障,或啟動順序停滯。

  • 系統可能遭到未經授權的存取。

    另一個風險是,sudoers 檔案中的問題可能會導致系統遭到未經授權的存取。如果 sudoers 檔案中的規則賦予某些使用者或群組過多的權限,就可能發生邏輯錯誤。

    系統擁有者也可能為了登入並修正問題,暫時停用或削弱系統防禦機制,導致這種情況發生。

發生問題時的復原方式

如果失去提升的使用者權限,或因 sudoers 檔案發生問題而無法使用 sudo 指令,請使用超級使用者帳戶進行復原。

在類 Unix 作業系統中,超級使用者是 ID 等於 0 的特殊使用者帳戶,通常稱為 root。超級使用者可完整存取系統資源,且不受限制地執行任何管理工作。雖然代表超級使用者與 OS 互動通常被視為不安全,但對於某些工作 (例如復原 sudoers 檔案) 而言,這可能是唯一選項。

直接以超級使用者身分登入會使作業系統暴露於風險中。為避免這項風險,Google 建議您使用啟動指令碼功能,因為這類指令碼會以超級使用者的身分執行。

進一步瞭解 Compute Engine 開機指令碼

如要使用啟動指令碼復原 sudoers 檔案,請按照下列步驟操作:

  1. 如果目前已在使用開機指令碼,請建立備份副本。 備份方法取決於開機指令碼的設定方式。

    startup-script

    如果指令碼內容是直接在中繼資料值中設定,您可以將指令碼內容複製到 Cloud Storage bucket、本機檔案或任何其他臨時私人儲存空間。

    startup-script-url

    如果指令碼內容已儲存在遠端儲存空間,且使用其網址,則只要暫時移除 startup-script-url 中繼資料鍵,即可停用目前的開機指令碼。

  2. 更新啟動指令碼: 使用下列指令序列:

    mv /etc/sudoers /etc/sudoers.backup.$(date +"%s") && echo "%google-sudoers ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers && chown 0:0 /etc/sudoers && chmod 0440 /etc/sudoers
    

    進一步瞭解指令的用途

    mv /etc/sudoers /etc/sudoers.backup.$(date +"%s")

    這個指令會建立 /etc/sudoers 檔案的副本,並重新命名,然後刪除原始檔案。新檔案的名稱結尾會加上時間戳記,確保名稱不重複 (例如 sudoers.backup.1672527600)。

    echo "%google-sudoers ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers

    這個指令會建立先前刪除的檔案 /etc/sudoers,並使用單一規則,允許有權存取 VM 的授權使用者代表任何系統使用者執行任何指令。 Google Cloud 這個規則預設一律存在於額外檔案 /etc/sudoers.d/google_sudoers 中。

    chown 0:0 /etc/sudoers

    這項指令會將 /etc/sudoers 檔案的擁有者設為 ID 為 0 的使用者,並將擁有者群組設為 ID 為 0 的群組。

    chmod 0440 /etc/sudoers

    這項指令會將 /etc/sudoers 檔案的權限設為唯讀,只有檔案擁有者和擁有者群組可以讀取檔案。

  3. 停止 VM (如果正在執行)。重新啟動 VM,觸發執行開機指令碼。

  4. 連線至 VM,然後編輯損毀的 sudoers 檔案以復原。

    sudo visudo /etc/sudoers.backup.TIMESTAMP
  5. 儲存變更,並以剛編輯的檔案取代目前的 /etc/sudoers 檔案。

    sudo mv /etc/sudoers.backup.TIMESTAMP /etc/sudoers
  6. 請確認使用 sudo 指令和提升權限時的原始問題已修正。

  7. 移除暫時性開機指令碼,並還原原始指令碼 (如有)。

後續步驟