Короткий ответ
(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плюс ещёrootALL в drop-in — дубль.
| Находка | Риск | Не путать с |
|---|---|---|
%sudo ALL=(ALL:ALL) ALL | стандарт Ubuntu, нужен пароль | NOPASSWD |
admin ALL=NOPASSWD: ALL | полный root без пароля | узкий NOPASSWD на systemctl |
группа docker | root через сокет | docker.sock |
sudoedit на /etc/shadow | почти root | правка nginx conf |
Возможные причины
- Быстрый bootstrap:
echo 'admin ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/admin. - Ansible
become_userи желание non-interactive на всё. - Панель/скрипт провайдера.
%sudoплюс персональная строка ALL.sudoersскопирован с « fort» без#includedir.- Владелец сервиса добавлен в 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.
- Найдите drop-in с NOPASSWD ALL.
- Удалите или замените через 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: FULLsudo -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.