Learning Platform
Глоссарий Troubleshooting
Урок 07.04 · 25 мин
Начальный
sudosudoersvisudoNOPASSWDsudo-rsPrivilege escalation

Что такое sudo

sudo буквально расшифровывается как “super user do” — «сделай как суперпользователь». Это утилита, которая позволяет обычному юзеру выполнить отдельную команду от имени root (или любого другого user), не открывая полноценный root-shell.

Идея простая: раньше админ заходил через su - (substitute user), вводил root-пароль и сидел в root-shell весь сеанс. Это опасно: одна опечатка rm -rf . где-нибудь в корне — катастрофа. Плюс root-пароль приходилось хранить и периодически менять.

sudo решил это: каждая команда — отдельный privilege-grant, с аудит-логом и гранулярной политикой. Можно разрешить sudo systemctl restart airflow, но запретить sudo bash. Команды логируются. Пароль для sudo — пароль самого юзера, а не root.

$ whoami
levo

$ id -u
1000

$ sudo whoami      # запросит пароль ОДИН раз, потом cache 15 минут
[sudo] password for levo:
root

$ sudo id -u
0

Как sudo работает технически

sudo и root: модель привилегий Unix Linux capabilities: права без полного root

/usr/bin/sudo — это SUID-binary:

$ ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 277736 Feb 10 12:34 /usr/bin/sudo

Видишь s вместо x для owner? Это SUID-bit (детально — урок 05). Когда обычный user запускает sudo, kernel при execve():

  1. Видит SUID-bit
  2. Устанавливает effective UID = owner-UID файла (то есть root=0)
  3. Запускает sudo с euid=0, оставляя ruid=1000 (твой настоящий UID)

Sudo, уже работающий с euid=0, может:

  1. Прочитать /etc/sudoers (доступен только root)
  2. Проверить: имеет ли user levo право выполнять эту команду?
  3. Если да — спросить пароль (опционально), выполнить setuid(0) (теперь и real UID = 0) и execve() запрошенной команды
  4. Команда выполняется уже от полноценного root
Поток выполнения sudo

Каждый шаг — это явное действие kernel или sudo.

1. levo: sudo systemctl restart xruid=1000, euid=1000
2. execve(/usr/bin/sudo)kernel видит SUID -> euid=0Это hardcoded механизм kernel. SUID-bit + owner=root = euid становится 0.
3. sudo читает /etc/sudoersruid=1000, euid=0С euid=0 sudo может open() файл с правами 0440 root:root.
4. Проверка политикиlevo ALL=(ALL) ALL -> разрешено
5. Запрос пароляgetpass() + PAM authenticatePAM (Pluggable Authentication Modules) — стандартный auth-фреймворк Linux. /etc/pam.d/sudo описывает шаги: проверить пароль, проверить 2FA, etc.
6. setuid(0)ruid=0, euid=0Теперь полный root — и real, и effective.
7. execve(systemctl)systemctl запущен от root

/etc/sudoers: политика

Файл /etc/sudoers — это конфиг правил «кто что может». Минимальный пример:

# Members of group sudo may gain root privileges
%sudo   ALL=(ALL:ALL) ALL

# User airflow can restart airflow services without password
airflow ALL=(root) NOPASSWD: /bin/systemctl restart airflow-*

Синтаксис: WHO HOST=(AS_USER:AS_GROUP) [TAGS:] WHAT.

  • WHO: user1, %groupname (любой member), +netgroup
  • HOST: на каком хосте действует. ALL = везде. Используется для одного /etc/sudoers, который раздаётся на много серверов.
  • AS_USER: от чьего имени можно выполнять. ALL = от любого. По умолчанию это root.
  • AS_GROUP: от какой group выполнять.
  • TAGS: NOPASSWD: (не спрашивать пароль), SETENV: (разрешить передавать переменные окружения)
  • WHAT: список команд через запятую. ALL = что угодно. Можно с аргументами: /bin/systemctl restart nginx.

Никогда не редактируй напрямую — используй visudo

# [X] ОЧЕНЬ ПЛОХО:
$ sudo vim /etc/sudoers
# Если ты ошибся в синтаксисе, файл повредится и НИКТО не сможет sudo.
# Получишь "syntax error" при попытке использовать sudo.
# Восстановление потребует boot в single-user mode.

# [x] ПРАВИЛЬНО:
$ sudo visudo
# Открывает /etc/sudoers в твоём $EDITOR, при сохранении ВАЛИДИРУЕТ синтаксис.
# Если ошибка — предложит исправить, не сохранит broken-версию.

visudo — это безопасный wrapper: parsing-check перед сохранением, locking файла (нельзя редактировать вдвоём), сохранение в temp-файл с атомарной заменой.

/etc/sudoers.d/ — рекомендованный путь

Вместо правки главного /etc/sudoers правильнее класть файлы в /etc/sudoers.d/. Имя — без точек и расширений:

# /etc/sudoers.d/airflow
airflow ALL=(root) NOPASSWD: /usr/bin/docker
airflow ALL=(root) NOPASSWD: /bin/systemctl restart airflow-*

Файлы из /etc/sudoers.d/ подцепляются @includedir /etc/sudoers.d в главном /etc/sudoers. Это удобно для:

  • Управления через Ansible/Puppet (один файл — один сервис)
  • Безопасных обновлений (изменения изолированы)
  • Чистого uninstall (рудалили файл — правило исчезло)

Редактирование тоже через visudo: sudo visudo -f /etc/sudoers.d/airflow.

NOPASSWD: автоматизация без пароля

В CI/CD и для service-аккаунтов часто нужно выполнять sudo без интерактива:

deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart api
deploy ALL=(root) NOPASSWD: /usr/bin/docker pull *

Теперь user deploy может в скрипте написать sudo systemctl restart api без [sudo] password: prompt. Это безопасно если:

  • Команды максимально специфичны (restart api, не ALL)
  • User deploy — service-аккаунт, не интерактивный человек
  • Пароль/ключ deploy хранится в secret-менеджере
# В Ansible playbook:
- name: Restart API after deploy
  become: false   # не нужно sudo для всего playbook
  shell: sudo systemctl restart api

sudo -u: выполнить от другого пользователя

$ sudo -u postgres psql -c "SELECT version()"
# Запустить psql от user postgres (полезно для local-trust в pg_hba.conf)

$ sudo -u airflow ls -la /var/log/airflow/
# Прочитать логи airflow с правами airflow (которые airflow и должны быть)

$ sudo -u www-data tail -f /var/log/nginx/error.log
# Хотя обычно nginx логи доступны через group adm

Без -u дефолт = root (или то, что задано в sudoers (AS_USER)). С -u USER — от его имени.

DE-сценарий: ты залогинен как levo, но Airflow CLI должен запускаться от service-аккаунта airflow, иначе он создаст файлы с твоим UID и потом сам не сможет их прочитать:

$ sudo -u airflow airflow dags list
$ sudo -u airflow airflow connections add my_conn ...

sudo !! и sudo -s

$ ls /etc/shadow
ls: cannot open '/etc/shadow': Permission denied

$ sudo !!     # повторить последнюю команду с sudo
sudo ls /etc/shadow
ls /etc/shadow

!! — bash-расширение для «последняя команда». sudo !! — самый частый идиом после первого permission denied.

$ sudo -s
# root-shell, $HOME остаётся /home/levo
# полезно когда надо несколько команд подряд от root

$ sudo -i
# полноценный root-login: $HOME=/root, root-environment
# как если бы залогинился сразу как root

sudo-rs: Rust-замена в Ubuntu 26.04

С Ubuntu 25.10 (Plucky Puffin) и в Ubuntu 26.04 LTS sudo-rs становится дефолтной реализацией. Это полная переписка sudo на Rust, разработанная в рамках инициативы prossimo от ISRG (которые сделали Let’s Encrypt). Цели:

  • Memory safety: исторический sudo на C имел регулярные CVE с buffer overflow (например, Baron Samedit / CVE-2021-3156, exploit за 13 лет был незамечен).
  • Меньше attack surface: sudo-rs пока поддерживает только core-функциональность, без экзотических плагинов и legacy-опций.
  • Audit-friendly: меньше кодовой базы, проще верифицировать.

Для пользователя совместимость почти полная: sudo command, sudoers-синтаксис, visudo работают так же. Различия:

  • Не поддерживаются устаревшие опции (SSSD интеграция, runaspw, etc.)
  • Лучше error messages
  • Меньше rate-limit issues в multi-process scenarios
$ sudo --version    # на Ubuntu 26.04
Sudo-rs 0.2.8
sudo-rs is an open source Sudo implementation in Rust.

Старый Sudo (/usr/bin/sudo.legacy) остаётся доступен на случай несовместимостей, но дефолт — Rust-версия. Если ты пишешь sudoers-правила и не используешь экзотику — никаких изменений не нужно.

Логи sudo

Все sudo-операции пишутся в /var/log/auth.log (Debian/Ubuntu) или /var/log/secure (RHEL/Fedora):

$ sudo grep sudo /var/log/auth.log | tail -3
May 13 12:34:01 host sudo: levo : TTY=pts/0 ; PWD=/home/levo ; USER=root ; COMMAND=/bin/systemctl restart nginx
May 13 12:35:02 host sudo: airflow : TTY=unknown ; PWD=/opt/airflow ; USER=root ; COMMAND=/usr/bin/docker pull img:v1
May 13 12:36:03 host sudo: levo : 3 incorrect password attempts ; TTY=pts/0 ; PWD=/home/levo ; USER=root ; COMMAND=/bin/cat /etc/shadow

Это золотая жила для аудита: кто что запускал, успешно или нет. Логи stream-ятся в journald тоже (journalctl _COMM=sudo).

Для DE: если твой Airflow worker внезапно начал делать sudo-операции, которые не должен, в auth.log это видно. Это первый артефакт компрометации, на который смотрят SRE.

DE-сценарии: где встретишься с sudo

Когда DE использует sudo

Список регулярных задач, где без sudo не обойтись.

apt installsudo apt install postgresql-clientapt пишет в /var/lib/dpkg и /etc/apt — это root-only.
systemctl restartsudo systemctl restart airflow-schedulersystemd-юниты находятся в /etc/systemd/system, restart требует root.
Запуск под service-юзеромsudo -u airflow airflow tasks test ...Чтобы файлы получили правильный owner и логи попали куда нужно.
Чтение логовsudo tail -f /var/log/postgresql/*.logЛоги часто 0640 root:adm. Можно либо sudo, либо добавиться в group adm.
Правка конфиговsudo vim /etc/airflow/airflow.cfgКонфиги сервисов обычно root-owned.
Открыть privileged portsudo ./api (port 80, 443)Порты < 1024 требуют CAP_NET_BIND_SERVICE — обычно через sudo. Альтернатива — setcap.
Запуск Docker-контейнера не от root: USER и userns

Безопасность

Несколько правил которые сэкономят тебе нервы:

  1. Никогда не sudo curl URL | bash для скриптов с непроверенного источника. Прочитай скрипт сначала.
  2. NOPASSWD только для специфичных команд, не для ALL. Полный NOPASSWD: ALL равен «у user есть root без аутентификации» — атакующий через любой бэкдор получает root.
  3. sudo log — это compliance. Не отключай его (!log_input/!log_output) без согласия SRE.
  4. Не запускай длинные процессы через sudo — таймаут sudo-токена 15 минут, потом надо переаутентифицироваться. Для daemons используй systemd unit с User=.

Попробуй сам

  1. Проверь, какие команды можешь выполнять через sudo:
    sudo -l
  2. Открой sudoers через visudo (не сохраняй изменения!):
    sudo visudo
    # выйди через :q без сохранения
  3. Запусти id от другого юзера:
    sudo -u nobody id
  4. Посмотри последние sudo-операции:
    sudo tail -20 /var/log/auth.log | grep sudo
  5. Проверь свою версию sudo:
    sudo --version | head -1

macOS-различия

  • На macOS sudo — оригинальная C-версия от sudo project (не sudo-rs).
  • Конфиг там же: /etc/sudoers, /etc/sudoers.d/. visudo работает идентично.
  • На macOS правило по умолчанию: %admin ALL=(ALL) ALL — все админы могут sudo.
  • Логи: log show --predicate 'process == "sudo"'.
Проверка знанийKnowledge check
В /etc/sudoers.d/etl написано: 'etl ALL=(root) NOPASSWD: /usr/bin/python3 /opt/jobs/*.py'. Может ли user etl выполнить 'sudo /usr/bin/python3 /opt/jobs/load_data.py'? А 'sudo /usr/bin/python3 /opt/jobs/../etc/shadow'?
ОтветAnswer
Первая команда — да, выполнится. Вторая — это серьёзная уязвимость sudoers-конфига, и она тоже выполнится. Глоб /opt/jobs/*.py матчит '/opt/jobs/../etc/shadow' ТОЛЬКО если '../etc/shadow' заканчивается на .py — здесь не заканчивается, поэтому не пройдёт. НО: атакующий может создать /opt/jobs/evil.py с содержимым 'import os; os.system("cat /etc/shadow > /tmp/leaked")' и запустить через sudo — он root внутри python. Правило 'разрешить /usr/bin/python3 ANY_SCRIPT' эквивалентно даче root-доступа, потому что python может выполнить произвольный код. Это классическая ошибка sudoers: разрешать interpreter (python, bash, perl, awk) с произвольным аргументом. Правильно: явные пути к каждому скрипту, или sudoedit для редактирования конкретных файлов, или wrapper-скрипт с фиксированной логикой.

Главное

  • sudo — SUID-binary, который через PAM-аутентификацию и /etc/sudoers даёт granular privilege escalation.
  • Никогда не редактируй /etc/sudoers напрямую — только через visudo, иначе можешь сломать sudo полностью.
  • Современная практика — /etc/sudoers.d/имяСервиса, один файл на сервис, валидация через visudo -f.
  • NOPASSWD только для специфичных команд, never для ALL.
  • sudo -u USER — выполнить от другого пользователя.
  • Ubuntu 26.04 переходит на sudo-rs (Rust). Совместимость почти полная, безопаснее.
  • Логи в /var/log/auth.log (Debian/Ubuntu) — это аудит-история.
  • Разрешать interpreter в sudoers — это эквивалент NOPASSWD: ALL.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Какой пароль запрашивает sudo при первом запуске после долгого простоя?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5