对 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 手册

如需了解如何管理和使用 visudo 编辑器,请参阅 Visudo 手册

问题的后果

sudoers 文件中的问题会造成负面影响,并可能影响整个系统的功能。

  • sudo 命令不再有效。

    这是 sudoers 文件中存在问题时的最常见后果。这样的后果是无法使用用户的提升权限,从而阻止用户在服务器上的活动。

    但是,更具破坏性且不可预测的后果是依赖于 sudo 命令的应用执行失败。在某些情况下,这可能会导致应用完全失败,进而导致意外行为、崩溃或数据丢失。另一个示例是,应用在操作系统启动序列期间调用 sudo 命令并失败时。它可能会导致操作系统故障或者导致启动序列卡住。

  • 可能导致对系统的未经授权访问。

    另一个风险在于,sudoers 文件中的问题可能会导致对系统的未经授权访问。当 sudoers 文件中的规则向某些用户或群组授予过多权限时,便可能会因逻辑错误而发生该问题。

    另外,也可能会因为系统所有者暂时停用或削弱系统防御机制来登录并解决问题而发生该问题。

出现问题时的恢复方法

如果由于 sudoers 文件问题而失去提升的用户权限或无法使用 sudo 命令,请使用超级用户账号进行恢复。

在类 Unix 操作系统中,超级用户是一个 ID 等于 0 的特殊用户账号,通常称为 root。超级用户拥有对系统资源的完全访问权限,并且可以不受限制地执行任何管理任务。虽然通常认为以超级用户的身份与操作系统进行交互是不安全的,但这可能是执行某些任务(例如恢复 sudoers 文件)的唯一选项。

以超级用户身份直接登录会使操作系统面临风险。为了避免这种风险,Google 建议使用启动脚本功能,因为此脚本会以超级用户的身份执行。

详细了解 Compute Engine 启动脚本

如需使用启动脚本恢复 sudoers 文件,请执行以下操作:

  1. 创建当前启动脚本(如果已在使用)的备份副本。备份方法取决于启动脚本的配置方式。

    startup-script

    如果脚本内容直接在元数据值中设置,您可以将脚本内容复制到 Cloud Storage 存储桶、本地文件或任何其他临时私有存储空间。

    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 文件,其中仅包含一条规则,该规则允许有权访问虚拟机的获授权 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. 停止虚拟机(如果正在运行)。重启虚拟机以触发启动脚本的执行。

  4. 连接到虚拟机,并修改损坏的 sudoers 文件以将其恢复。

    sudo visudo /etc/sudoers.backup.TIMESTAMP
  5. 保存更改,并将当前的 /etc/sudoers 文件替换为您刚刚修改的文件。

    sudo mv /etc/sudoers.backup.TIMESTAMP /etc/sudoers
  6. 确保使用 sudo 命令和提升权限的原始问题已修复。

  7. 移除临时启动脚本,并恢复原始脚本(如果使用过)。

后续步骤