Перейти к содержимому

Sudoers: NOPASSWD без дыр

Почему NOPASSWD + ALL — это не решение, а дыра

%admin ALL=(ALL) NOPASSWD: ALL — самая частая ошибка в sudoers. Пользователь получает неограниченный root-доступ без пароля. Любой скрипт, любая утилита, любая уязвимость в окружении пользователя становится прямым путём к полному контролю машины. NOPASSWD без ограничений по командам — это не удобство, это бэкдор в явном виде.

Правильный подход: разрешить конкретные команды через Cmnd_Alias и повесить NOPASSWD только на них. Тогда пользователь может перезапустить сервис, но не сможет читать /etc/shadow или запустить su.


visudo: единственный безопасный способ правки sudoers

Редактирование /etc/sudoers напрямую через vi или nano — путь к тому, что заблокируешь себя и всю команду. visudo блокирует файл, проверяет синтаксис перед сохранением и отклоняет некорректные записи.

# Правильный путь:
sudo visudo

# Если используется редактор по умолчанию неудобен:
sudo EDITOR=nano visudo

# Для отдельных файлов в /etc/sudoers.d/:
sudo visudo -f /etc/sudoers.d/deployer
Предупреждение

Синтаксическая ошибка в sudoers = потеря sudo-возможностей у всех. visudo предотвращает это, но только если пользоваться им.


Cmnd_Alias: группируем команды вместо разрешения всего

Cmnd_Alias позволяет создать именованную группу команд. Далее ссылаешься на имя алиаса — читаемо и легко менять.

Cmnd_Alias RESTART_WEB = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
Cmnd_Alias RESTART_DB = /usr/bin/systemctl restart postgresql
Cmnd_Alias PACKAGE_MGMT = /usr/bin/apt, /usr/bin/yum, /usr/bin/dnf
Cmnd_Alias LOG_VIEW = /usr/bin/tail, /usr/bin/journalctl

Синтаксис алиаса: имя в верхнем регистре, через запятую абсолютные пути к бинарникам. Путь обязателен — systemctl без /usr/bin/ не сработает.


Пример: ограниченный NOPASSWD для конкретных задач

Реальный сценарий: деплой-юзеру нужно перезапускать nginx и смотреть логи, но ничего больше.

Cmnd_Alias RESTART_WEB = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
Cmnd_Alias LOG_VIEW = /usr/bin/journalctl, /usr/bin/tail

deployer ALL=(ALL) NOPASSWD: RESTART_WEB, LOG_VIEW

Теперь deployer может:

sudo systemctl restart nginx    # без пароля
sudo journalctl -u nginx        # без пароля
sudo apt update                 # отказано
sudo su                         # отказано

Если нужно разрешить конкретному пользователю (не группе) один бинарник:

monitor ALL=(ALL) NOPASSWD: /usr/bin/tail /var/log/syslog
Подсказка

Для нескольких пользователей одной задачи — используй группу. %deployers ALL=(ALL) NOPASSWD: RESTART_WEB удобнее, чем дублировать строки.


Чего избегать: типичные ошибки в sudoers

ОшибкаПочему плохоКак правильно
ALL ALL=(ALL) NOPASSWD: ALLПолный root без пароляПеречислить конкретные команды через Cmnd_Alias
user ALL=NOPASSWD: /bin/bashОткрывает shell от rootНикогда не давать интерпретаторы или su
user ALL=(ALL) ALL, NOPASSWD: ALLNOPASSWD распространяется на всё из-за порядкаNOPASSWD: ставить перед списком команд, не после
Редактирование /etc/sudoers через echo или cpНет валидации синтаксисаТолько visudo или visudo -f
Отсутствие #includedir /etc/sudoers.dРучной файл перезатирается при обновленииПроверить наличие include, класть кастомные правила в /etc/sudoers.d/

Ещё одна частая ловушка — пробелы в Cmnd_Alias. Запятая и пробел после неё обязательны:

# Правильно:
Cmnd_Alias WEB = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx

# Неправильно (пробел заменяет запятую, парсинг ломается):
Cmnd_Alias WEB = /usr/bin/systemctl restart nginx /usr/bin/systemctl reload nginx

Проверить работу правила можно без sudo-прав:

sudo -l -U deployer

Вывод покажет, какие команды разрешены и с какими флагами. Если список пуст — правила не применились, и проблема в синтаксисе или пути.