SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-13

sudo-rs в Ubuntu: що змінюється в sudoers

Ubuntu 26.04 робить sudo-rs стандартним sudo. Glob-шаблони в аргументах більше не зіставляються: дізнайтеся, як переписати такі правила sudoers.

Що змінює sudo-rs в Ubuntu

Ubuntu 26.04 LTS постачається із sudo-rs як стандартною реалізацією sudo, тому команда sudo на новому сервері запускає реалізацію на Rust замість оригінальної програми на C. Більшість файлів sudoers продовжують працювати без змін. Порушується правило, у якому аргументи команди містять символ узагальнення, оскільки sudo-rs не зіставляє glob-шаблони з текстом аргументів.

Ubuntu 25.10 першою перейшла на sudo-rs, а в Ubuntu 26.04 LTS цей вибір зберігся. Ubuntu 24.04 LTS це не стосується, оскільки в ній за замовчуванням використовується оригінальний sudo, якщо не встановити sudo-rs вручну. Це стає важливим під час оновлення з Ubuntu 24.04 до 26.04 або під час створення нового сервера на новішому випуску. Якщо ви також використовуєте проміжні випуски, у матеріалі як відрізняються LTS і проміжні випуски Ubuntu на сервері пояснюється, на якому сервері така зміна з’явиться першою.

Перевірте, яку саме реалізацію sudo фактично використовує сервер

Не визначайте це за номером релізу. Запитайте саму систему.

sudo --version
update-alternatives --config sudo
dpkg -l 'sudo*'

Довіряйте sudo --version на власному сервері більше, ніж будь-якій таблиці версій в інтернеті, зокрема на цій сторінці. update-alternatives --config sudo — це друга частина відповіді: вона перелічує всіх установлених постачальників /usr/bin/sudo і позначає вибраного. Установлений пакет не обов’язково є вибраним, тому перевіряйте вибір, а не список пакетів.

Під час переходу пакуються обидві реалізації. Реалізація на Rust — це sudo-rs, версія 0.2.13 у 26.04 станом на серпень 2026 року. Оригінальна реалізація, яку підтримує Todd C. Miller, пакується як sudo.ws, а її програми мають суфікс .ws: sudo.ws і visudo.ws.

Чому Ubuntu перейшла на sudo-rs

sudo має біт setuid і запускається від імені root. Будь-який користувач системи може запустити його, і він одразу отримує повні привілеї. Тому помилка роботи з пам’яттю всередині sudo може стати локальною вразливістю для отримання привілеїв root. Саме таким був CVE-2021-3156: переповнення буфера в купі, доступне будь-якому локальному користувачу. Ця вразливість залишалася у випущеному коді приблизно десять років. Rust виявляє такий клас помилок під час компіляції. Саме це є головною причиною переписування.

Друга причина — обсяг функціональності. Саме вона впливає на вашу конфігурацію. Оригінальний sudo накопичував великий набір функцій протягом трьох десятиліть. Кожна функція означає додатковий код, що працює від імені root. sudo-rs навмисно реалізує лише частину цих функцій. Усе, що його автори вважали малопотрібним або потенційно шкідливим, не реалізували. Тому конструкція sudoers, яка роками працювала, може бути просто відсутня. Ваше правило з wildcard — один із таких випадків.

Захист пам’яті усуває один клас помилок. Він не робить програму повністю безпомилковою. Після того як sudo-rs став типовим варіантом, для нього також випускали security fixes. Оновлюйте його, як і будь-яке інше програмне забезпечення.

Які правила sudoers і далі працюють

Файл залишається тим самим. sudo-rs читає /etc/sudoers і додаткові файли в /etc/sudoers.d/. Підтримуються типові конструкції, які використовує адміністратор сервера:

  • deploy ALL=(ALL:ALL) ALL і форми для груп, наприклад %sudo ALL=(ALL:ALL) ALL
  • теги NOPASSWD: і PASSWD:
  • User_Alias, Runas_Alias, Host_Alias і Cmnd_Alias
  • команда з точним списком аргументів, наприклад /usr/bin/systemctl restart app-api
  • команда з "", яка дозволяє виконувати її лише без аргументів
  • команда, після якої * указано як останній аргумент; це дозволяє будь-які кінцеві аргументи
  • шлях до каталогу, що закінчується на /; це дозволяє виконувати будь-яку команду в цьому каталозі
  • ! для вилучення команди зі списку
  • корисна підмножина Defaults, зокрема secure_path, env_keep, env_check, timestamp_timeout, passwd_tries, editor, umask, targetpw, rootpw і use_pty

Два параметри за замовчуванням працюють інакше, що часто спричиняє помилки. env_reset не можна вимкнути в sudo-rs: він завжди увімкнений. use_pty увімкнений за замовчуванням, тому команда виконується у власному псевдотерміналі.

Чому правило wildcard у sudoers перестало збігатися

Wildcard-символи й далі дозволені в одному місці: в імені файлу команди. Правило `%ops ALL = /sbin/fsck* як і раніше дозволяє sudo fsck і sudo fsck_exfat, оскільки *` є частиною шляху, який порівнюється з файловою системою.

У списку аргументів sudo-rs приймає лише дві спеціальні форми, і жодна з них не є шаблоном. `"" означає відсутність аргументів. Кінцевий * означає будь-які наступні аргументи. Усі інші аргументи порівнюються як літеральний текст. Тому %ops ALL = /sbin/service ntp * працює, оскільки ntp є літеральним текстом, а *` розташований останнім. Однак таке правило не надає жодного з потрібних дозволів:

deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart app-*

`app-* є шаблоном усередині аргументу. sudo-rs не розгортає його, тому правило не поширюється на systemctl restart app-api, і sudo відхиляє команду. Дві команди покажуть фактичну дію будь-якого правила на вашому сервері: sudo -l -U deploy, виконана від імені root, виводить команди, які цей обліковий запис справді може виконувати, а sudo visudo -c` повідомляє, чи файл узагалі має правильний синтаксис. Виконайте їх, перш ніж починати безсистемно редагувати конфігурацію.

Правило з wildcard завжди було вразливістю

У початковій реалізації sudo введені вами аргументи об’єднуються в один рядок і порівнюються з рядком аргументів правила за допомогою glob-шаблону. Glob-шаблон збігається з пробільними символами. Саме це майже всі упускають.

У документації sudo-rs наведено найнаочніший приклад. Правило /bin/rm *.txt також дозволяє sudo rm -rf /home .txt, оскільки один * поглинає -rf /home , а об’єднаний рядок усе одно закінчується на .txt. Формально правило означає «лише текстові файли». Насправді воно означає «будь-які аргументи, якщо рядок закінчується на .txt».

Те саме стосується прикладу із systemctl. Оскільки аргументи порівнюються як один об’єднаний рядок, кінцевий шаблон також збігається з усім, що додано після нього. Тому restart app-* охоплює restart app-api і будь-які додаткові аргументи, які передасть викликач. Шаблон усередині аргументу відкриває доступ до аргументів навколо нього, а саме в аргументах містяться можливості команди. sudo-rs відхиляє таку конструкцію, а не намагається зробити її безпечною, оскільки безпечної загальної форми для неї не існує.

Замініть шаблон явним списком команд

Більшість правил із шаблонами з’являється тому, що хтось не хотів вводити чотири рядки. Введіть ці чотири рядки.

Cmnd_Alias APP_RESTART = /usr/bin/systemctl restart app-api, /usr/bin/systemctl restart app-worker
Cmnd_Alias APP_STATUS = /usr/bin/systemctl status app-api, /usr/bin/systemctl status app-worker
deploy ALL=(root) NOPASSWD: APP_RESTART, APP_STATUS

Укажіть правильний шлях. Правило, у якому зазначено /bin/systemctl, на системі, де двійковий файл розташований за шляхом /usr/bin/systemctl, ніколи не спрацює, а помилка виглядатиме так само, як проблема з правами доступу. Перевірте це за допомогою command -v systemctl і вставте результат його виконання.

Розмістіть правило в окремому drop-in-файлі, а не в /etc/sudoers, щоб оновлення пакета не конфліктувало з вашими змінами:

sudo visudo -f /etc/sudoers.d/90-deploy
sudo visudo -c
sudo -l -U deploy

Назвіть файл без крапки та без кінцевої тильди. Оригінальна версія sudo ігнорує файли в sudoers.d, якщо їхні імена містять крапку, тому 90-deploy.conf є типовою причиною непомітної відсутності ефекту. Дотримуватися цієї конвенції нескладно.

Використовуйте wrapper, власником якого є root, коли список стає довгим

Якщо дозволений набір надто великий для явного перелічення, перенесіть це рішення із sudoers у невелику програму, власником якої є root.

sudo tee /usr/local/sbin/app-restart >/dev/null <<'EOF'
#!/bin/sh
set -eu
case "${1:-}" in
  app-api|app-worker) ;;
  *) echo "app-restart: not allowed: ${1:-}" >&2; exit 1 ;;
esac
exec /usr/bin/systemctl restart "$1"
EOF
sudo chown root:root /usr/local/sbin/app-restart
sudo chmod 0755 /usr/local/sbin/app-restart
ls -l /usr/local/sbin/app-restart

У частині sudoers тоді вказується одна команда:

deploy ALL=(root) NOPASSWD: /usr/local/sbin/app-restart *

Кінцевий * тут допустимий, оскільки дозволи визначає скрипт, а не sudo. Це справедливо лише доти, доки власником скрипту є root і ніхто інший не має права на запис до нього. Якщо deploy може записувати у файл, deploy може замінити його вміст і виконати будь-що від імені root. Це гірше за правило з wildcard, яке ви видалили. Перевірте режим за допомогою ls -l. Якщо виведення незрозуміле, прочитати рядок дозволів drwxr-xr-x можна навчитися за п’ять хвилин. Це саме правило поширюється і на каталог: /usr/local/sbin також не повинен мати права на запис для цього облікового запису, оскільки каталог із правом на запис дає змогу повністю замінити файл.

Надайте завданню власний обліковий запис замість правила sudo

Часто краще спочатку з’ясувати, навіщо команді взагалі потрібні права root. Сервіс, який працює від власного користувача, може керуватися цим користувачем, і рядок у sudoers не потрібен. Для системних unit-файлів systemd уже передає це рішення polkit, тому правило може вказувати один unit-файл і одного оператора:

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units" &&
        action.lookup("unit") == "app-api.service" &&
        subject.user == "deploy") {
        return polkit.Result.YES;
    }
});

Збережіть це як /etc/polkit-1/rules.d/50-app-api.rules, після чого deploy зможе виконувати systemctl restart app-api без sudo. Перевірте правило в тому самому контексті, у якому його буде використано. Правило, що працює у вашому сеансі SSH, потрібно додатково перевірити з cron, перш ніж на нього покладатися. У будь-якому разі обліковий запис, від імені якого виконується робота, має бути призначений лише для цієї роботи. Це той самий принцип, що лежить в основі облікових записів користувачів із мінімальними привілеями на VPS.

Що ще не реалізовано в sudo-rs

sudo -E не реалізовано. Потрібні змінні слід називати за допомогою Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY". Пам’ятайте, що env_reset завжди увімкнено, тому все, що не зберігається, очищається.

Централізоване зберігання sudoers у LDAP вилучено. sudoers.ldap і cvtsudoers не реалізовано, а пакет sudo-ldap вилучено у версії 26.04. Автентифікація LDAP через PAM або SSSD і надалі працює. Поза межами реалізації залишається лише зберігання політик у каталозі.

INTERCEPT, призначений для блокування виходу в оболонку з дозволеної команди, не реалізовано. Водночас він і раніше не був захистом від цілеспрямованого користувача. Якщо правило дозволяє запускати редактор або інтерпретатор від імені root, користувач фактично отримує root-доступ, і жодна опція sudo цього не змінить.

Запис сеансів не реалізовано, тому немає журналу введення-виведення та sudoreplay. Журнали записуються лише до syslog. Опції logfile для перенаправлення журналів в інше місце немає, тому повідомлення sudo надходять туди, куди ваша система вже спрямовує syslog.

Чи варто повернутися до sudo.ws?

Так, це можна зробити. Протягом циклу 26.04 оригінальний пакет залишається доступним саме з цієї причини.

sudo apt install sudo.ws
update-alternatives --config sudo
sudo update-alternatives --set sudo /usr/bin/sudo.ws

Копіюйте точні шляхи з виводу --config, а не з цієї сторінки, оскільки саме цей список прийме ваша система. Щоб пізніше повернутися до sudo-rs, потрібно встановити альтернативу на шлях до бінарного файлу sudo-rs із цього самого списку.

Перш ніж змінювати будь-що, що впливає на sudo, відкрийте другий сеанс SSH, увійдіть у систему та залиште його бездіяльним. Файл sudoers із синтаксичною помилкою або альтернатива, що вказує на неінстальований бінарний файл, може позбавити вас можливості отримати root на віддаленій машині. Дотримуйтеся цього правила разом з іншими діями, які ви виконуєте протягом перших десяти хвилин на новому VPS.

Розглядайте повернення як тимчасовий захід із визначеним кінцевим терміном, а не як виправлення. Це дає вам тиждень, щоб належним чином переписати правила. Саме переписування також варте зусиль, оскільки кожне видалене правило з підстановочними символами надавало більше дозволів, ніж передбачав його автор.

FAQ

Чому моє правило sudoers із шаблоном wildcard перестало працювати в Ubuntu 26.04?

Тому що Ubuntu 26.04 LTS використовує sudo-rs як стандартний sudo, а sudo-rs не зіставляє шаблони wildcard всередині аргументів команди. Wildcard дозволено у назві файлу команди, "" означає відсутність аргументів, а одиночний * може бути лише останнім аргументом. Правило на кшталт /usr/bin/systemctl restart app-* містить шаблон посередині аргументу, тому воно нічого не дозволяє, і команду відхилено. Виконайте sudo -l -U deploy від імені root, щоб перевірити фактичні дозволи облікового запису, а потім замініть правило точними командами або скриптом-обгорткою, власником якого є root.

Як повернутися до оригінального sudo в Ubuntu 26.04?

Оригінальний sudo постачається в пакеті sudo.ws. Установіть його за допомогою sudo apt install sudo.ws, а потім виберіть його для alternative командою sudo update-alternatives --set sudo /usr/bin/sudo.ws. Спочатку виконайте update-alternatives --config sudo, щоб переглянути точні шляхи, доступні у вашій системі, і залиште відкритим другий SSH-сеанс під час зміни. Це не повертає sudo-ldap, оскільки його вилучено з 26.04 незалежно від вибраної реалізації.

Чи читає sudo-rs той самий файл /etc/sudoers?

Так. sudo-rs читає /etc/sudoers і файли drop-in у /etc/sudoers.d/, використовуючи той самий синтаксис для користувачів, груп, псевдонімів, специфікацій run-as і тега NOPASSWD. Він реалізує підмножину мови sudoers, тому відмінності проявляються у відсутніх конструкціях, а не в конструкціях, які працюють інакше. Відредагуйте файл за допомогою sudo visudo, а потім перевірте його командою sudo visudo -c, перш ніж завершити сеанс.

Що замінює sudo -E у sudo-rs?

sudo -E не реалізовано. У початковому sudo його також уже не рекомендували, оскільки передавання root-процесу середовища, яким керує користувач, є відомим способом змінити поведінку цього процесу. У sudoers явно вкажіть потрібні змінні, використовуючи рядок на кшталт Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY". env_reset у sudo-rs завжди увімкнено і його не можна вимкнути, тому всі змінні, які ви не залишили, очищуються.

#sudo#sudo-rs#ubuntu#sudoers#permissions