open atlas
↑ К треку
Linux: операционная система LIN · 05 · 03

sudo и привилегии

sudo — это движок политик: правила sudoers решают, кто может запустить какую команду от чьего имени. visudo — единственный безопасный редактор. NOPASSWD — осознанный компромисс. su меняет всю идентичность; sudo повышает привилегии для одной команды.

LIN Middle ◷ 20 min
Уровень
ОсновыJuniorMiddleSenior

Разработчик просит доступ sudo «просто чтобы перезапустить nginx». Ты даёшь. Через три месяца обнаруживаешь, что он запускал sudo bash для получения root-оболочки и вносил недокументированные изменения. Или ты получаешь в наследство сервер, где каждый разработчик в sudoers с ALL=(ALL:ALL) NOPASSWD:ALL — фактически root без аутентификации. Или аудитор обнаруживает, что CI-пайплайн запускается от root, потому что кто-то добавил sudo к каждой команде деплоя. Управление привилегиями в Linux — это не вопрос, использовать ли sudo, а вопрос точности использования, минимизирующей радиус поражения при утечке учётных данных или человеческой ошибке.

Цель

После этого урока ты сможешь писать правила sudoers с корректным синтаксисом, объяснить, почему sudoers нужно редактировать только через visudo, сформулировать разницу между su и sudo, спроектировать минимально привилегированный доступ для типовой задачи и объяснить компромисс безопасности NOPASSWD.

1

sudo — движок политик, а не просто кнопка «запустить как root». Перед выполнением sudo читает политику sudoers, сопоставляет вызывающего пользователя + хост + целевого пользователя + команду и разрешает или запрещает. Каждый вызов логируется в syslog/journald.

# Базовое использование: запустить одну команду от root
sudo systemctl restart nginx

# Запустить от имени конкретного пользователя (не root)
sudo -u postgres psql -c 'SELECT version();'

# Запустить от имени конкретного пользователя И группы
sudo -u www-data -g www-data /opt/app/run.sh

# Получить root-оболочку (избегай в проде — лучше логировать сессию)
sudo -i   # login shell: загружает /root/.profile, /root/.bashrc
sudo -s   # non-login shell: наследует большую часть окружения вызывающего

# Посмотреть, что тебе разрешено делать
sudo -l
# Matching Defaults entries for alice on server1:
#     env_reset, mail_badpass, secure_path=...
# User alice may run the following commands on server1:
#     (root) /usr/bin/systemctl restart nginx
#     (root) NOPASSWD: /usr/bin/journalctl -u nginx *

# Каждый вызов sudo логируется
journalctl -t sudo --since '10 minutes ago'
# Jun 21 14:32:01 server1 sudo[8821]: alice : TTY=pts/0 ; PWD=/home/alice ;
#   USER=root ; COMMAND=/usr/bin/systemctl restart nginx

Журнал аудита — одна из главных причин использовать sudo вместо su. su логирует только аутентификацию; sudo логирует точную команду. В ретроспективе инцидента логи sudo говорят тебе точно, что делал пользователь.

2

Синтаксис sudoers следует строгому шаблону — и ошибки в нём могут лишить тебя доступа к root. Базовая форма: кто где=(от_кого) что.

# НИКОГДА не редактируй /etc/sudoers напрямую — всегда используй visudo
# visudo блокирует файл, проверяет синтаксис перед сохранением и предотвращает двух редакторов
sudo visudo

# Формат правила:
# user  host=(run_as_user:run_as_group)  command

# Примеры:
alice   ALL=(ALL:ALL)   ALL
# alice может запускать любую команду от любого пользователя/группы на любом хосте — слишком широко

alice   ALL=(root)   /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
# alice может только перезапускать или перезагружать nginx

%ops    ALL=(root)   /usr/sbin/useradd, /usr/sbin/userdel
# ГРУППА ops может управлять пользователями

# NOPASSWD: без запроса пароля для этих команд
deploy  ALL=(root)   NOPASSWD: /usr/bin/systemctl restart myapp
# пользователь deploy (например, CI-runner) может перезапускать myapp без пароля

# Псевдонимы для ясности в больших sudoers-файлах
Cmnd_Alias NGINX_CMDS = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
alice  ALL=(root)  NGINX_CMDS

# Drop-in файлы: предпочтительнее редактирования основного файла
# /etc/sudoers.d/alice-nginx:
alice  ALL=(root)  /usr/bin/systemctl restart nginx
# Включается автоматически, если /etc/sudoers содержит '#includedir /etc/sudoers.d'

Каждое правило в sudoers является аддитивным. Нет «запрета» в традиционном смысле (есть отрицание !, но у него есть ловушки безопасности — избегай его). Если пользователь соответствует любому правилу, он может выполнить эту команду.

3

visudo обязателен — никогда не редактируй sudoers обычным текстовым редактором. Синтаксическая ошибка в /etc/sudoers полностью отключает sudo. Если у тебя также нет root-доступа по SSH, ты заблокирован.

# Что делает visudo, чего не делают обычные редакторы:
# 1. Захватывает эксклюзивную блокировку на /etc/sudoers
# 2. Пишет во временный файл, запускает 'visudo -c' (проверка синтаксиса) перед сохранением
# 3. Отказывается сохранять при неверном синтаксисе
# 4. Автоматически устанавливает корректные права (0440)

# Проверить синтаксис sudoers-файла без его открытия:
sudo visudo -c -f /etc/sudoers.d/alice-nginx
# /etc/sudoers.d/alice-nginx: parsed OK

# Что происходит при плохой строке в /etc/sudoers:
# sudo /usr/bin/systemctl restart nginx
# >>> /etc/sudoers: syntax error near line 42 <<<
# sudo: parse error in /etc/sudoers near line 42
# sudo: no valid sudoers sources found, quitting
# sudo: unable to initialize policy plugin

# Восстановление при блокировке (требует физического/консольного доступа или root SSH):
# Загрузиться в single-user mode (systemd: добавить 'single' к cmdline ядра в GRUB)
# mount -o remount,rw /   (если read-only)
# visudo   (исправить ошибку)

Подход с drop-in файлами (/etc/sudoers.d/) частично существует по этой причине: ошибки в drop-in файле заставляют sudo вывести предупреждение, но правила из основного файла всё равно применяются. Это также правильный паттерн для систем управления конфигурацией — Ansible, Chef и Puppet пишут отдельные файлы в /etc/sudoers.d/, а не изменяют основной файл.

4

su и sudo решают разные задачи. Понимание разницы определяет, как проектировать политики доступа.

# su: substitute user — открывает оболочку от имени другого пользователя
# Требует пароль ЦЕЛЕВОГО пользователя (или root)
su - alice         # login shell как alice (- означает: загрузить окружение alice)
su alice           # non-login shell как alice (наследует окружение вызывающего)
su -               # login shell как root (требует пароль root)

# sudo: запустить команду с повышенными привилегиями
# Требует ТВОЙ СОБСТВЕННЫЙ пароль (вызывающего), не root
sudo systemctl restart nginx
sudo -u alice /opt/run.sh

# Ключевые различия:
# su: ты становишься пользователем для интерактивной сессии; логируется только событие su
# sudo: одна команда, затем возврат к собственной идентичности; логируется точная команда

# Почему sudo победил su в многоадминистраторных средах:
# - Не нужно делиться паролем root (критично в командной работе)
# - Гранулярность на уровне команд (можно перезапустить nginx, нельзя удалять файлы)
# - Полный журнал аудита на команду
# - Можно отозвать для конкретного пользователя без смены пароля root

# su всё ещё имеет законные применения:
# - Переключение на сервисную учётку для отладки в её собственном окружении
#   (sudo -u postgres psql работает, но не загружает .bashrc postgres)
# - Начальная настройка системы, где sudo ещё не установлен
su - postgres      # загружает окружение postgres, полезно для отладки pg_dump

Эмпирическое правило: sudo для разовых административных команд; su -u для длительных интерактивных сессий как сервисная учётка, где нужно полное окружение.

5

Принцип минимальных привилегий означает предоставлять ровно столько доступа, сколько нужно — и обдумывать пути обхода. Типичные ошибки, превращающие «ограниченный» sudo в полный root:

# ПЛОХО: текстовые редакторы, запущенные через sudo, открывают оболочку через :!bash
sudo vi /etc/nginx/nginx.conf    # :!bash в vi даёт root-оболочку
sudo nano /etc/hosts             # ^R command даёт оболочку

# ПЛОХО: разрешение любого пути означает, что пользователь контролирует, что запускается
alice  ALL=(root)  /usr/bin/python3     # python3 -c 'import os; os.system("bash")'
alice  ALL=(root)  /home/alice/scripts/ # пользователь контролирует каталог скриптов

# ПЛОХО: wildcard без привязки аргумента
alice  ALL=(root)  /usr/bin/systemctl * nginx
# покрывает: sudo systemctl start nginx — задумано
# также покрывает: sudo systemctl daemon-reexec && sudo systemctl bash
# (wildcard в sudoers совпадает в том числе с пробелами — классический обход)

# ХОРОШО: конкретные команды с конкретными аргументами
alice  ALL=(root)  /usr/bin/systemctl restart nginx, \
                   /usr/bin/systemctl reload nginx, \
                   /usr/bin/systemctl status nginx

# ХОРОШО: sudoedit для редактирования файлов — копирует во временный файл,
# редактирует от имени процесса вызывающего, затем копирует обратно — побег через оболочку невозможен
alice  ALL=(root)  sudoedit /etc/nginx/nginx.conf

# ХОРОШО: минимально привилегированный паттерн перезапуска сервиса для CI
deploy ALL=(root)  NOPASSWD: /usr/bin/systemctl restart myapp.service
# NOPASSWD приемлем здесь: deploy — сервисная учётка, не человек;
# у неё нет интерактивного входа; команда специфична; ротация секретов
# происходит на уровне API-ключа, а не пароля sudo

Компромисс NOPASSWD: он убирает фактор аутентификации, поэтому единственная защита гранта — секретность учётных данных для становления пользователем deploy. Приемлемо для выделенной сервисной учётки CI с узко ограниченной командой; никогда не приемлемо для учётки разработчика-человека.

Разбор примера

Написание минимально привилегированного sudo-гранта для деплой-пайплайна.

Требование: CI/CD-пайплайн, запущенный от пользователя deploy, должен перезапускать юнит myapp.service и ротировать лог-файл. Без запроса пароля (автоматический режим). Без возможности делать что-либо ещё от root.

# Шаг 1: определить точные нужные команды
# - systemctl restart myapp.service
# - mv /var/log/myapp/app.log /var/log/myapp/app.log.1

# Шаг 2: проверить риски побега через оболочку
# systemctl: нет риска побега для подкоманды restart
# mv: ограниченный путь — но нужно привязать к конкретным путям

# Шаг 3: написать drop-in файл через visudo
sudo visudo -f /etc/sudoers.d/deploy-myapp

# Содержимое:
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp.service
deploy ALL=(root) NOPASSWD: /bin/mv /var/log/myapp/app.log /var/log/myapp/app.log.[0-9]*

# Шаг 4: проверить синтаксис
sudo visudo -c -f /etc/sudoers.d/deploy-myapp
# /etc/sudoers.d/deploy-myapp: parsed OK

# Шаг 5: тест от имени deploy
sudo -u deploy sudo -l
# User deploy may run the following commands on server1:
#     (root) NOPASSWD: /usr/bin/systemctl restart myapp.service
#     (root) NOPASSWD: /bin/mv /var/log/myapp/app.log /var/log/myapp/app.log.[0-9]*

sudo -u deploy sudo systemctl restart myapp.service
# (успех — пароль не запрашивается)

sudo -u deploy sudo systemctl restart nginx
# Sorry, user deploy is not allowed to execute '/usr/bin/systemctl restart nginx'

Wildcard [0-9]* в правиле mv допускает ротацию логов с числовыми суффиксами, но не позволяет пользователю deploy переместить лог в произвольный путь вроде /etc/cron.d/evil.

Частая ошибка

Никогда не давай sudo-доступ к командам, запускающим текстовый редактор, пейджер или оболочку напрямую. Классический обход: sudo less /var/log/syslog → набрать !bash → root-оболочка. То же относится к vim, man, awk, python3, perl, find -exec и многим другим командам, способным порождать подпроцессы. Безопасная альтернатива для редактирования файлов — sudoedit (или sudo -e), редактирующий копию от имени собственного процесса вызывающего, без возможности побега через оболочку. Если пользователю «нужен sudo» для задачи, которая на самом деле требует чтения файла, рассмотри возможность дать ему право чтения на этот файл напрямую.

Проверь себя
Викторина

Разработчику нужно редактировать /etc/nginx/nginx.conf от root. Какой sudo-грант наиболее безопасен?

Итог

sudo — движок политик: читает правила sudoers, сопоставляет пользователя + хост + цель + команду, логирует результат и опционально аутентифицирует. Формат правила: кто где=(от_кого) команда. visudo — единственный безопасный редактор: проверяет синтаксис перед сохранением. /etc/sudoers.d/ — правильное место для drop-in правил (удобно для систем управления конфигурацией). NOPASSWD убирает фактор аутентификации — приемлемо для выделенных сервисных учёток с узкими командами, никогда для разработчиков-людей. su меняет всю идентичность (нужен пароль цели); sudo повышает для одной команды (нужен свой пароль) и логирует точную команду. Минимальные привилегии: давать конкретные команды с конкретными аргументами; избегать редакторов, оболочек и команд с неограниченными wildcard-аргументами; использовать sudoedit для грантов редактирования файлов.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 3 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources1
expand
  1. 01

Trademarks belong to their respective owners. Editorial reference only.