Файл /etc/sudoers занимает несколько десятков строк, но его утрата парализует администрирование всего сервера: sudo отказывает с сообщением о недопустимом конфигурационном файле, и даже опытный инженер внезапно оказывается обычным пользователем без права на любой взмах. Хорошая новость в том, что задача решается без переустановки и даже без загрузки с флешки - через single-user mode, встроенный в любой дистрибутив. В этой статье разбираем полный маршрут восстановления: вход в аварийную оболочку через GRUB, пересборка минимального sudoers, проверка синтаксиса и профилактика на будущее, чтобы этот вечер больше не повторялся.

Почему удалённый sudoers парализует администрирование

Механика отказа прямолинейна: sudo читает /etc/sudoers и подключённые файлы из /etc/sudoers.d при каждом вызове, и если главный файл отсутствует или содержит синтаксическую ошибку, утилита останавливается с ошибкой вместо выполнения команды. Файл ломается тремя типовыми путями: случайное удаление при чистке, неудачное редактирование через текстовый редактор вместо visudo и ошибка в правке, сохранённая с опечаткой. Третий путь коварнее первых двух - частично исправленный файл выглядит рабочим, но отказывает при первом же обращении.

Симптомы узнаваемы: на каждый вызов sudo возвращается сообщение sudo unable to load plugin или parse error. Дальше начинается развилка, от которой зависит сценарий восстановления. Если у администратора осталась открытая сессия с правами root или известен пароль root - проблема решается за минуты без перезагрузки. Если же единственным путём к root был sudo, сервер приходится перезагружать в аварийный режим - и делать это правильно.

Живой root-доступ решает всё за минуты

Первая проверка перед любыми сложными манёврами - не остался ли путь к root открытым. Сессия root в соседнем терминале, активный экран tmux под root, известный пароль для su - любой из этих вариантов превращает восстановление в обычную работу за клавиатурой. В этом случае пароль вводится в su, создаётся временный корректный файл, и система снова управляема.

Нюанс для дистрибутивов, где root заблокирован по умолчанию (Ubuntu и родственные): su не сработает, но остаётся шанс на открытое окно с root или на запуск через sudo последней успешной сессии - к сожалению, при сломанном sudoers последний способ обычно уже не работает. Тогда переходим к перезагрузке в single-user mode, и об этом следующий раздел.

Вход в single-user mode через GRUB

Цель аварийной загрузки - получить оболочку с правами root без запроса пароля, пользуясь тем, что загрузчик выполняется до любой аутентификации. Порядок на GRUB: при появлении меню нажать e для редактирования записи; найти строку linux с параметрами ядра; в её конец дописать systemd.unit=rescue.target для систем на systemd (или init=/bin/sh как самый прямой путь); нажать Ctrl-X для загрузки с этими параметрами.

Разница между вариантами существенна. rescue.target поднимает минимальный набор сервисов, монтирует файловые системы и обычно запрашивает пароль root - подходит, если он известен. init=/bin/sh отдаёт оболочку без пароля и без смонтированных корней - жёстче, но надёжнее: параметр systemd.unit требует рабочей systemd-инфраструктуры, а init=/bin/sh обходится без всего.

В оболочке при init=/bin/sh сначала проверяется, как смонтирован корень: команда mount показывает, что корневая файловая система может быть в режиме только для чтения, и перед правками её нужно перемонтировать: mount -o remount,rw / . Только после этого файловые операции начнут сохраняться.

Пять минут работы в аварийной оболочке

С-root-оболочка получена, корень доступен для записи - восстанавливаем. Минимальный рабочий sudoers умещается в одну строку: root ALL=(ALL:ALL) ALL и ниже - строка для группы администраторов, например %sudo ALL=(ALL:ALL) ALL или %wheel ALL=(ALL:ALL) ALL в зависимости от дистрибутива. Файл создаётся любым доступным редактором, а если редактор недоступен - echo перенаправлением: echo "root ALL=(ALL:ALL) ALL" > /etc/sudoers с последующим добавлением второй строки через >>.

Критический шаг после записи - проверка синтаксиса: visudo -c выводит parsed OK либо список ошибок с номерами строк. Без этой проверки перезагружаться нельзя: если в файле осталась ошибка, цикл отказа повторится, и хорошо, если посторонние файлы из /etc/sudoers.d при этом не содержат своих проблем. Заодно проверяется владелец и права: chown root root /etc/sudoers и chmod 440 /etc/sudoers, потому что sudo прихотлив к правам и периодически отказывает на файлах с неправильными полномочиями.

Финал - перезагрузка в нормальный режим и проверка sudo -v из обычной пользовательской сессии. Работает - значит, восстановление завершено; самое время заняться профилактикой, пока свежи воспоминания.

Проверка синтаксиса как мера профилактики

Большинство инцидентов с sudoers предотвращается одной привычкой: любой правкой файла занимается visudo, а не привычный редактор. Visudo открывает файл в редакторе, но перед записью проверяет синтаксис и отказывается сохранять ошибочный вариант, показывая строку с проблемой. Редактирование в обход этой защиты - прямо признанный источник аварий в документации sudo.

Вторая привычка - правки через drop-in файлы: новая строка помещается в /etc/sudoers.d/имя-сценария, а основной файл не трогается вообще. Это уменьшает поверхность риска и облегчает разбор через полгода: имя файла подсказывает, зачем правило добавлено. Перед созданием drop-in проверка через visudo -f /etc/sudoers.d/имя выполняется так же, как для основного файла.

Профилактика случайных удалений на будущее

Опыт аврии полезно конвертировать в систему. Etckeeper ставит каталог /etc под контроль версий - каждая правка фиксируется коммитом, и восстановление любой версии файла занимает секунды. Резервное копирование /etc в бэкап сервера - вторая страховка, и хорошо, когда она делает это по расписанию, а не по желанию. Третий уровень - дисциплина работы: rm в каталогах конфигурации заменяется mv во временный каталог, потому что отложенное удаление стоит дешевле случайно выполненного.

После восстановления стоит потратить десять минут на все три меры - это единственная гарантия, что следующий вечер пройдёт без аварийной загрузки.

Итоговая памятка дежурного инженера

Свод всех действий в короткий порядок: проверить оставшиеся пути к root (su, открытая сессия); при их отсутствии перезагрузиться с параметром init=/bin/sh в GRUB; перемонтировать корень на запись; воссоздать минимальный sudoers с двумя строками; проверить через visudo -c; выставить права 440 и владельца root; перезагрузиться в нормальный режим и проверить sudo -v; поставить etckeeper и завести привычку visudo. От первого звонка до полного восстановления проходит около пятнадцати минут, и из них половина - ожидание загрузок.
Типичные ошибки восстановления и как их избежать

Первая классика - правки не сохраняются, потому что корень остался смонтирован в режиме только для чтения: echo и редактор отрабатывают без ошибок, но после перезагрузки файл оказывается прежним. Лечение и профилактика - команда mount перед началом работ и явное remount,rw. Вторая классика - перезагрузка без visudo -c: если в спешке осталась опечатка в строке ALL, цикл отказа повторяется, и второй раз входить в аварийную оболочку уже унизительно. Третья - неправильные права: sudo строго относится к владельцу и маске, и файл с правами 777 или владельцем не-root будет молча игнорироваться, возвращая систему к исходной проблеме.

Четвёртая ошибка - забытый flush перед перезагрузкой при init=/bin/sh: в этой минимальной среде не работает привычный shutdown, и корректное завершение - команда sync, а уже потом reboot -f. Пятая - редактирование через vi с автодополнением TAB в оболочке, где нет полной инициализации терминала: периодически вводимые символы выглядят странно, и это лечится экспортом переменной TERM=linux перед началом работы. Все пять ошибок известны каждому, кто проходил этот путь, и все пять предотвращаются одним и тем же способом - чек-листом из предыдущего раздела.

Когда single-user mode не срабатывает

У аварийной загрузки через GRUB есть свои ограничения, о которых стоит знать заранее. Если на загрузчике установлен пароль и он неизвестен, редактирование записи недоступно, и путь к восстановлению лежит через спасательную флешку - грузимся с неё и чиним систему из chroot. Если корень зашифрован LUKS, аварийная оболочка запросит пароль шифрования, что закономерно, но добавляет шаг; сама механика восстановления после этого не меняется.

На серверах с IPMI или серийной консолью весь сценарий выполняется удалённо, если в настройки GRUB заранее добавлен вывод на консоль - именно для таких случаев в серьёзных инфраструктурах параметры console= прописаны в загрузчике по умолчанию. Ещё одно ограничение - системы с paranoid-настройками, где даже rescue.target запрашивает пароль root: если он не известен, init=/bin/sh остаётся последним универсальным способом, потому что эта оболочка не проходит через аутентификацию вообще.

Drop-in файлы sudoers.d и организация правил

Восстановленный минимальный sudoers - это скелет, и после аварии стоит сразу навести порядок по-человечески: правила раскладываются по файлам в /etc/sudoers.d, где каждый файл назван по сценарию - 90-backup, 91-monitoring, 92-deploy. Читаются файлы по алфавиту, основной файл подключает каталог директивой @includedir, и на практике это означает, что конкретное правило ищется в предсказуемом месте, а не в одной большой простыне.

Из тонкостей: имена файлов не должны содержать точек, иначе они игнорируются; права на каждый drop-in - 440 и владелец root; проверка отдельного файла - visudo -f путь. Структура окупается при любой аварии: восстановить один понятный файл проще, чем разбирать тысячу строк легаси, а при делегировании прав разным командам границы доступа читаются прямо из списка файлов.

Автоматическая проверка конфигурации в пайплайнах

Команды, которые управляют серверами через Ansible или Puppet, добавляют финальный рубеж - проверку синтаксиса в пайплайне: роль с файлом sudoers сопровождается шагом запуска visudo -cf на артефакте до выкатки. Ошибка ловится в CI за секунды, а не на проде в полночь. Для Ansible подходит модуль lineinfile с validate, который проверяет синтаксис перед записью прямо на целевом хосте - это дешевле любого разбора и делает повторение описанной в этой статье аварии практически невозможным.

Дисциплина из четырёх элементов - visudo, drop-in файлы, etckeeper и проверка в CI - складывается в систему, где утрата или поломка sudoers перестаёт быть событием вообще: откат к прошлой версии занимает одну команду и не требует даже перезагрузки.
Короткая история из практики для полноты картины

Характерный кейс из жизни: инженер чистил тестовый сервер и удалил каталог /etc/sudoers.d целиком, а вместе с ним случайно задел основной файл, который лежал в соседней вкладке терминала. Ночь была короткой, сессий root не осталось, но под рукой оказалась памятка из этой статьи. GRUB, init=/bin/sh, remount, пересоздание файла из четырёх строк, visudo -c, sync, перезагрузка - и через восемь минут сервер снова отвечал на sudo. На разбор потом ушло больше времени, чем на починку, и это лучшая иллюстрация того, почему процедуру стоит знать заранее, а не изобретать в полночь.
Пусть же эта история останется для вас теорией, но процедуру держите под рукой - в runbook, в заметках, в голове. Однажды вечер сложится неудачно, и именно эти пять минут холодной методики отличат дежурство с перерывом на сон от дежурства с перерывом на восстановление всего сервера.
Всем спокойных дежурств и пусть пароль root всегда будет под рукой, когда он действительно нужен.