# Sudoers: NOPASSWD без дыр

Индекс LLMS: [llms.txt](/llms.txt)

---

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

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

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

---

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

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

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

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

# Для отдельных файлов в /etc/sudoers.d/:
sudo visudo -f /etc/sudoers.d/deployer
```

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

---

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

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

```sudoers
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 и смотреть логи, но ничего больше.

```sudoers
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` может:

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

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

```sudoers
monitor ALL=(ALL) NOPASSWD: /usr/bin/tail /var/log/syslog
```

> [!TIP]
> Для нескольких пользователей одной задачи — используй группу. `%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: ALL` | `NOPASSWD` распространяется на всё из-за порядка | `NOPASSWD:` ставить перед списком команд, не после |
| Редактирование `/etc/sudoers` через `echo` или `cp` | Нет валидации синтаксиса | Только `visudo` или `visudo -f` |
| Отсутствие `#includedir /etc/sudoers.d` | Ручной файл перезатирается при обновлении | Проверить наличие include, класть кастомные правила в `/etc/sudoers.d/` |

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

```sudoers
# Правильно:
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-прав:

```bash
sudo -l -U deployer
```

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