Короткий ответ

(ALL) NOPASSWD: ALL — это root без пароля и без следа в вашей голове, только в auth.log. Цель: пользователь admin в группе sudo с паролем (или с узким NOPASSWD на конкретные бинарники), плюс Cmnd_Alias для деплоя. Править только через visudo / visudo -f /etc/sudoers.d/…. Не удаляйте себе sudo до проверки sudo -l на второй сессии. Не лечите широкие права отключением AppArmor или firewall.

Хост host.example (10.0.20.10).

Симптомы и как отличить

  • sudo -n true код 0 у человека, которому нужен только restart nginx;
  • в /etc/sudoers.d/ файлы от панелей (90-cloud-init-users, zz-vendor);
  • Defaults !authenticate глобально;
  • членство в sudo плюс ещё root ALL в drop-in — дубль.
НаходкаРискНе путать с
%sudo ALL=(ALL:ALL) ALLстандарт Ubuntu, нужен парольNOPASSWD
admin ALL=NOPASSWD: ALLполный root без пароляузкий NOPASSWD на systemctl
группа dockerroot через сокетdocker.sock
sudoedit на /etc/shadowпочти rootправка nginx conf

Возможные причины

  1. Быстрый bootstrap: echo 'admin ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/admin.
  2. Ansible become_user и желание non-interactive на всё.
  3. Панель/скрипт провайдера.
  4. %sudo плюс персональная строка ALL.
  5. sudoers скопирован с « fort» без #includedir.
  6. Владелец сервиса добавлен в sudo «на час», час длится два года.

Диагностика

sudo visudo -c
sudo grep -REn '^[^#]*ALL' /etc/sudoers /etc/sudoers.d/
getent group sudo admin
sudo -l -U admin

Только то, что видно sudo -l -U admin, реально действует (с учётом Match Host/Runas).

ls -la /etc/sudoers /etc/sudoers.d/
# visudo игнорирует файлы с точкой и ~ в имени в sudoers.d — но не полагайтесь на это как на защиту
sudo awk 'NF && $1 !~ /^#/' /etc/sudoers /etc/sudoers.d/* 2>/dev/null

Журнал:

sudo journalctl _COMM=sudo --since '14 days ago' --no-pager | tail -n 50
sudo grep sudo /var/log/auth.log 2>/dev/null | tail

Ищите COMMAND= — если там bash, su, chmod, visudo, dd — это уже shell, не «перезапуск сервиса».

Побочные root-эквиваленты: passwd без ограничений, tee /etc/shadow, apt-get, systemctl, chown, pkexec, членство в lxd/libvirt/docker.

Решение

Сценарий A. Убрать NOPASSWD:ALL, оставить стандартную группу sudo

Ubuntu по умолчанию:

%sudo   ALL=(ALL:ALL) ALL

Это ALL с паролем UNIX пользователя. Для человека-админа это нормальный baseline.

  1. Найдите drop-in с NOPASSWD ALL.
  2. Удалите или замените через visudo:
sudo visudo -f /etc/sudoers.d/90-admin

Целевое для человека admin (член sudo): файл vendor NOPASSWD удалить. Проверка:

sudo -l -U admin
sudo -n -U admin true; echo no_pass_exit:$?

sudo -n должен падать, интерактивный sudo true — спрашивать пароль.

Не ставьте Defaults:admin !authenticate.

Сценарий B. Нужен NOPASSWD, но не ALL

Типичный deploy:

sudo visudo -f /etc/sudoers.d/20-deploy

Пример содержимого (пути уточните type systemctl nginx, не копируйте лишнее):

Cmnd_Alias NGINX_RESTART = /usr/bin/systemctl reload nginx, /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx
deploy ALL=(root) NOPASSWD: NGINX_RESTART

Запрещены shell-метасимволы по умолчанию; не добавляйте ALL «чтобы sed в конфиг». Для правок конфигов — sudoedit на конкретный файл:

deploy ALL=(root) NOPASSWD: sudoedit /etc/nginx/sites-available/host.example

Не давайте sudoedit /etc/ рекурсивно.

Проверка:

sudo -u deploy sudo -n /usr/bin/systemctl reload nginx
sudo -u deploy sudo -n /bin/bash; echo should_fail:$?

Сценарий C. Ansible / CI

Отдельный пользователь deploy, ключ только с CI CIDR, NOPASSWD на список команд. Не используйте admin с ALL. Старый ключ: отзыв.

Defaults logfile и log_output усиливают след. Для расследований включите auditd на sudoers и execve для sudo.

Сценарий D. Скрытый ALL через алиасы

Cmnd_Alias FULL = ALL
admin ALL=NOPASSWD: FULL

sudo -l покажет ALL. Grep по ALL обязателен. То же для !ALL с последующим исключением, которое вы не поняли.

После сужения сверьте, что сервис не крутится зря от root: сервис от root.

Как проверить, что проблема устранена

sudo visudo -c
sudo -l -U admin
sudo grep -RIn 'NOPASSWD:.*ALL' /etc/sudoers /etc/sudoers.d/ || true

Ожидание: нет NOPASSWD: ALL (и нет NOPASSWD:ALL). Для admin — команды либо через %sudo с паролем, либо явный список. Функциональный тест дежурства: restart согласованного сервиса тем способом, который остался в политике. Вход SSH не сломан.

Попробуйте то, что должно быть запрещено (в заявке, не на проде вслепую): sudo bash, sudo su -, sudo visudo от deploy — отказ.

Если не помогло

  • После правки sudo: parse error: не логиньтесь заново; чините с ещё живой root-сессии / консоли pkexec visudo или visudo.
  • Файл в sudoers.d не подхватился: имя с точкой (admin.bak) ignore. Используйте 20-deploy без точки в суффиксе как у .conf привычки.
  • Права на файл не 0440 — visudo ругается. Не 0777.
  • includedir выключен в основном файле.
  • Пользователь в sudo и в admin (Debian admin group) — на Ubuntu обычно sudo. Проверьте groups admin.
  • pam_sudo / LDAP sudoers (sss): локальный файл не полная картина. sudo -l всё равно прав.

Профилактика

  • Запрет в политике: NOPASSWD ALL в любом sudoers.d.
  • CI-линтер на NOPASSWD: ALL.
  • Квартальный аудит пользователей.
  • Не выдавайте docker+sudo одному «прикладному» пользователю.
  • timestamp_timeout не ставьте -1 (бесконечный ticket).

FAQ

Чем %sudo ALL хуже NOPASSWD ALL?

Пароль и TTY. Украденный unlocked session всё ещё опасен, но бот с ключом без пароля UNIX не получит root сразу, если ключ только SSH и нет NOPASSWD. Это не полная защита — см. ключи и firewall.

Можно ли NOPASSWD на apt-get?

apt-get = установка любого пакета = root. Считайте ALL. Для патчей — unattended-upgrades под root, не sudo разработчика: security patches.

sudo -n в мониторинге

Отдельный пользователь с одной командой systemctl is-active …, не admin ALL.

visudo -c ок, sudo -l пустой

Пользователь не тот, Host_Alias не совпал, или LDAP. Смотрите sudo -ll -U admin.

Defaults !secure_path

Риск PATH hijack. Оставьте secure_path. Связано с небезопасным cron.