SSD Nodes Learn 🎉 VPS od $5.50/mies.
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-13

sudo-rs w Ubuntu 26.04: zmiany w pliku sudoers

Ubuntu 26.04 wprowadza sudo-rs jako domyślne narzędzie. Dowiedz się, dlaczego reguły z wieloznacznikami przestają działać i jak poprawnie skonfigurować plik sudoers po aktualizacji.

Zmiany wprowadzone przez sudo-rs w Ubuntu

Ubuntu 26.04 LTS dostarcza sudo-rs jako domyślne sudo, więc polecenie sudo na świeżo zainstalowanym serwerze uruchamia reimplementację w języku Rust zamiast oryginalnego programu w języku C. Większość plików sudoers działa bez zmian. Reguła, która przestaje działać, to ta zawierająca wieloznacznik wewnątrz argumentów polecenia, ponieważ sudo-rs nie dopasowuje wzorców glob do tekstu argumentów.

Ubuntu 25.10 wprowadziło tę zmianę jako pierwsze, a Ubuntu 26.04 LTS ją utrzymało. Ubuntu 24.04 LTS nie podlega tej zmianie, ponieważ nadal korzysta z oryginalnego sudo, chyba że sudo-rs zostanie zainstalowane ręcznie. Momentem, w którym ma to znaczenie, jest aktualizacja z Ubuntu 24.04 do 26.04 lub utworzenie nowej instancji na nowszym wydaniu. Jeśli korzystasz również z wydań pośrednich, artykuł jak wydania LTS i pośrednie Ubuntu różnią się na serwerze wyjaśnia, która maszyna pierwsza otrzymuje tego typu zmiany.

Sprawdzenie, która wersja sudo jest faktycznie uruchomiona na serwerze

Nie należy opierać się na numerze wydania systemu. Należy zapytać o to samą maszynę.

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

Na własnej maszynie należy ufać sudo --version bardziej niż jakiejkolwiek tabeli wersji w Internecie, włącznie z tą stroną. update-alternatives --config sudo stanowi drugą część odpowiedzi: wyświetla listę wszystkich zainstalowanych dostawców /usr/bin/sudo i oznacza wybranego z nich. Sam fakt zainstalowania pakietu nie oznacza, że jest on wybrany, dlatego należy sprawdzać wybór, a nie listę pakietów.

Obie implementacje są pakowane w trakcie okresu przejściowego. Wersja napisana w Rust to sudo-rs, w wersji 0.2.13 w wydaniu 26.04 na sierpień 2026 roku. Oryginalna wersja, utrzymywana przez Todda C. Millera, jest pakowana jako sudo.ws, a jej programy posiadają przyrostek .ws: sudo.ws oraz visudo.ws.

Dlaczego Ubuntu przeszło na sudo-rs

sudo posiada uprawnienia setuid root. Każdy użytkownik w systemie może je uruchomić, a proces startuje z pełnymi przywilejami, więc błąd pamięci wewnątrz tego narzędzia stanowi lokalny exploit typu root. CVE-2021-3156 było dokładnie takim przypadkiem: przepełnienie bufora sterty dostępne dla każdego lokalnego użytkownika, które znajdowało się w wydanym kodzie przez około dziesięć lat. Rust eliminuje tę klasę błędów na etapie kompilacji, co stanowi główny argument za przepisaniem tego oprogramowania.

Drugim powodem jest zakres funkcjonalny, który bezpośrednio wpływa na konfigurację. Oryginalne sudo przez trzy dekady zgromadziło ogromny zestaw funkcji, a każda z nich to dodatkowy kod działający z uprawnieniami roota. sudo-rs celowo implementuje tylko podzbiór tych możliwości. Wszystko, co autorzy uznali za niszowe lub potencjalnie szkodliwe, zostało pominięte, więc konstrukcja w pliku sudoers, która działała przez lata, może po prostu nie być obsługiwana. Reguła z użyciem symboli wieloznacznych jest jedną z nich.

Bezpieczeństwo pamięci eliminuje jedną klasę błędów. Nie czyni to programu wolnym od usterek, a sudo-rs od momentu stania się domyślnym rozwiązaniem również otrzymywało własne poprawki bezpieczeństwa. Należy je aktualizować tak samo, jak każde inne oprogramowanie.

Które reguły sudoers nadal działają

Plik pozostaje ten sam. sudo-rs odczytuje /etc/sudoers oraz pliki w katalogu /etc/sudoers.d/, a standardowe wpisy tworzone przez administratora serwera są obsługiwane:

  • deploy ALL=(ALL:ALL) ALL oraz formy grupowe, takie jak %sudo ALL=(ALL:ALL) ALL
  • znaczniki NOPASSWD: oraz PASSWD:
  • User_Alias, Runas_Alias, Host_Alias oraz Cmnd_Alias
  • polecenie z dokładną listą argumentów, na przykład /usr/bin/systemctl restart app-api
  • polecenie poprzedzone "", co zezwala na wykonanie polecenia wyłącznie bez żadnych argumentów
  • polecenie zakończone * jako ostatnim argumentem, co zezwala na dowolne argumenty końcowe
  • ścieżka do katalogu zakończona /, co zezwala na uruchomienie dowolnego polecenia w tym katalogu
  • ! w celu wykluczenia polecenia z listy
  • użyteczny podzbiór Defaults, w tym secure_path, env_keep, env_check, timestamp_timeout, passwd_tries, editor, umask, targetpw, rootpw oraz use_pty

Dwa ustawienia domyślne działają inaczej i często zaskakują użytkowników. Opcji env_reset nie można wyłączyć w sudo-rs: jest ona zawsze aktywna. Opcja use_pty jest domyślnie włączona, więc polecenie uruchamia się we własnym pseudo-terminalu.

Dlaczego reguła wildcard w sudoers przestała działać

Symbole wieloznaczne (wildcards) są nadal dozwolone w jednym miejscu: w nazwie pliku polecenia. Reguła %ops ALL = /sbin/fsck* nadal zezwala na sudo fsck oraz sudo fsck_exfat, ponieważ * stanowi część ścieżki porównywanej z systemem plików.

Wewnątrz listy argumentów sudo-rs akceptuje tylko dwie specjalne formy i żadna z nich nie jest wzorcem. "" oznacza brak argumentów. Końcowy symbol * oznacza dowolne argumenty końcowe. Każdy inny argument jest porównywany jako tekst dosłowny. Zatem %ops ALL = /sbin/service ntp * jest poprawne, ponieważ ntp jest traktowane dosłownie, a * znajduje się na końcu. Reguła taka jak poniższa nie przyznaje jednak żadnych uprawnień, które zamierzano nadać:

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

app-* jest wzorcem znajdującym się w środku argumentu. sudo-rs nie rozwija go, więc reguła nie obejmuje systemctl restart app-api, a sudo odmawia wykonania polecenia. Dwa polecenia pozwalają zweryfikować stan dowolnej reguły na własnym serwerze: sudo -l -U deploy, uruchomione jako root, wyświetla listę poleceń, które dane konto może faktycznie wykonać, a sudo visudo -c informuje, czy plik jest poprawnie parsowany. Należy je uruchomić przed rozpoczęciem przypadkowej edycji.

Reguła wieloznacznikowa zawsze stanowiła lukę

W oryginalnym sudo wpisywane argumenty są łączone w jeden ciąg znaków i porównywane z ciągiem argumentów reguły za pomocą wzorca glob. Wzorzec glob dopasowuje również spacje. Jest to szczegół, który pomija niemal każdy.

Dokumentacja sudo-rs przedstawia to w najbardziej przejrzysty sposób. Reguła /bin/rm *.txt zezwala również na sudo rm -rf /home .txt, ponieważ pojedyncza spacja * pochłania -rf /home , a połączony ciąg znaków nadal kończy się na .txt. Reguła ta jest interpretowana jako „tylko pliki tekstowe”. W rzeczywistości oznacza ona „dowolne argumenty, pod warunkiem, że wiersz kończy się na .txt”.

To samo dotyczy przykładu z systemctl. Ponieważ argumenty są porównywane jako jeden połączony ciąg, wzorzec końcowy pasuje również do wszystkiego, co zostanie dopisane po nim. W efekcie restart app-* obejmuje restart app-api oraz wszelkie dodatkowe argumenty dodane przez wywołującego. Wzorzec wewnątrz argumentu ujawnia argumenty znajdujące się wokół niego, a to właśnie w argumentach kryje się moc polecenia. sudo-rs odrzuca taką konstrukcję zamiast próbować czynić ją bezpieczną, ponieważ nie istnieje jej bezpieczna, ogólna forma.

Zastąpienie symboli wieloznacznych jawną listą poleceń

Większość reguł z symbolami wieloznacznymi istnieje tylko dlatego, że ktoś nie chciał wpisać czterech linii. Wpisz te cztery linie.

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

Upewnij się, że ścieżka jest poprawna. Reguła wskazująca na /bin/systemctl w systemie, w którym plik binarny znajduje się w /usr/bin/systemctl, nigdy nie zadziała, a błąd będzie wyglądał identycznie jak problem z uprawnieniami. Potwierdź lokalizację za pomocą command -v systemctl i wklej wynik tego polecenia.

Umieść regułę w osobnym pliku konfiguracyjnym zamiast w /etc/sudoers, aby aktualizacja pakietu nie nadpisała Twoich zmian:

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

Nazwij plik bez kropki i bez znaku tyldy na końcu. Oryginalny sudo ignoruje pliki w sudoers.d, których nazwy zawierają kropkę, więc 90-deploy.conf jest klasycznym przykładem cichego braku działania, a trzymanie się konwencji nic nie kosztuje.

Użycie wrappera należącego do root, gdy lista staje się długa

Gdy dozwolony zestaw jest zbyt duży, aby go wypisać, należy przenieść decyzję poza plik sudoers do małego programu, którego właścicielem jest 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

Strona sudoers wskazuje wówczas jedno polecenie:

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

Końcowy * jest tutaj dopuszczalny, ponieważ to skrypt, a nie sudo, decyduje o tym, co jest dozwolone. Zasada ta obowiązuje tylko wtedy, gdy skrypt jest własnością użytkownika root i nikt inny nie ma do niego uprawnień zapisu. Jeśli deploy może zapisywać do pliku, deploy może zastąpić jego zawartość i uruchomić dowolny proces z uprawnieniami root, co jest gorsze niż usunięta reguła z symbolem wieloznacznym. Sprawdź tryb za pomocą ls -l, a jeśli wynik nie jest dla Ciebie oczywisty, zrozumienie ciągu uprawnień drwxr-xr-x zajmuje pięć minut nauki. Ta sama zasada dotyczy katalogu: /usr/local/sbin również nie może być zapisywalny przez to konto, ponieważ zapisywalny katalog oznacza, że plik może zostać całkowicie zastąpiony.

Nadanie zadaniu dedykowanego konta zamiast reguły sudo

Często lepszym pytaniem jest, dlaczego polecenie w ogóle wymaga uprawnień root. Usługa działająca na własnym koncie użytkownika może być zarządzana przez tego użytkownika bez konieczności modyfikowania pliku sudoers. W przypadku jednostek systemd, systemd deleguje tę decyzję do polkit, co pozwala na utworzenie reguły wskazującej konkretną jednostkę oraz operatora:

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;
    }
});

Zapisz to jako /etc/polkit-1/rules.d/50-app-api.rules, a deploy będzie mogło uruchomić systemctl restart app-api bez użycia sudo. Przetestuj rozwiązanie w dokładnie takim kontekście, w jakim będzie używane, ponieważ reguła działająca w sesji SSH powinna zostać zweryfikowana z poziomu cron przed wdrożeniem produkcyjnym. W obu przypadkach konto wykonujące pracę powinno być przeznaczone wyłącznie do tego celu, co stanowi podstawę zasady kont użytkowników z minimalnymi uprawnieniami na VPS.

Czego jeszcze brakuje w sudo-rs

sudo -E nie jest zaimplementowane. Należy zdefiniować wymagane zmienne za pomocą Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY", pamiętając, że env_reset jest zawsze włączone, więc każda niezachowana zmienna zostanie wyczyszczona.

Centralne przechowywanie plików sudoers w LDAP zostało usunięte. sudoers.ldap oraz cvtsudoers nie są zaimplementowane, a pakiet sudo-ldap został usunięty w wersji 26.04. Uwierzytelnianie LDAP poprzez PAM lub SSSD nadal działa. Poza zakresem pozostaje jedynie polityka zarządzana z poziomu katalogu.

INTERCEPT, funkcja mająca ograniczać ucieczki do powłoki z poziomu dozwolonego polecenia, nie jest zaimplementowana. Mechanizm ten i tak nie stanowił zabezpieczenia przed zdeterminowanym użytkownikiem. Jeśli reguła pozwala użytkownikowi na uruchomienie edytora lub interpretera z uprawnieniami root, użytkownik ten uzyskuje dostęp do konta root, a żadna opcja sudo tego nie zmieni.

Rejestrowanie sesji nie jest zaimplementowane, dlatego nie ma logów I/O ani sudoreplay. Logowanie odbywa się wyłącznie do syslog, a brak opcji logfile uniemożliwia przekierowanie logów w inne miejsce. Komunikaty sudo trafiają zatem tam, gdzie system domyślnie przesyła dane syslog.

Czy należy wrócić do sudo.ws?

Jest to możliwe, a w cyklu 26.04 oryginał pozostaje dostępny w pakietach właśnie z tego powodu.

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

Należy kopiować dokładne ścieżki z danych wyjściowych --config, a nie z tej strony, ponieważ jest to lista akceptowana przez dany system. Powrót do sudo-rs w późniejszym terminie oznacza ustawienie alternatywy na ścieżkę do pliku binarnego sudo-rs z tej samej listy.

Przed wykonaniem jakichkolwiek operacji wpływających na sudo należy pozostawić otwartą, zalogowaną i bezczynną drugą sesję SSH. Błąd parsowania pliku sudoers lub wskazanie alternatywy na niezainstalowany plik binarny może uniemożliwić uzyskanie uprawnień root na zdalnej maszynie. Ten nawyk powinien towarzyszyć wszystkim działaniom opisanym w pierwsze dziesięć minut na nowym VPS.

Powrót do poprzedniego rozwiązania należy traktować jako ostateczny termin, a nie jako naprawę. Daje to tydzień na poprawne przepisanie reguł, co jest działaniem korzystnym samym w sobie, ponieważ każda usunięta reguła z użyciem symboli wieloznacznych przyznawała więcej uprawnień, niż zakładał jej autor.

FAQ

Dlaczego moja reguła z wieloznacznikiem w sudoers przestała działać w Ubuntu 26.04?

Ponieważ Ubuntu 26.04 LTS domyślnie używa sudo-rs, a sudo-rs nie obsługuje wzorców z wieloznacznikami wewnątrz argumentów polecenia. Obsługuje wieloznacznik w nazwie pliku polecenia, "" oznaczające brak argumentów oraz pojedyncze * jako ostatni argument. Reguła taka jak /usr/bin/systemctl restart app-* umieszcza wzorzec w środku argumentu, więc nie nadaje uprawnień, a polecenie jest odrzucane. Uruchom sudo -l -U deploy jako root, aby sprawdzić rzeczywiste uprawnienia konta, a następnie zastąp regułę dokładnymi poleceniami lub skryptem opakowującym należącym do roota.

Jak wrócić do oryginalnego sudo w Ubuntu 26.04?

Oryginalne sudo jest dostępne w pakiecie sudo.ws. Zainstaluj go za pomocą sudo apt install sudo.ws, a następnie wskaż go za pomocą sudo update-alternatives --set sudo /usr/bin/sudo.ws. Uruchom najpierw update-alternatives --config sudo, aby odczytać dokładne ścieżki oferowane przez system i utrzymuj otwartą drugą sesję SSH podczas wprowadzania zmian. Nie przywraca to sudo-ldap, które zostało usunięte z wersji 26.04 niezależnie od wybranej implementacji.

Czy sudo-rs odczytuje ten sam plik /etc/sudoers?

Tak. sudo-rs odczytuje /etc/sudoers oraz pliki w katalogu /etc/sudoers.d/, używając tej samej składni dla użytkowników, grup, aliasów, specyfikacji run-as oraz znacznika NOPASSWD. Implementuje podzbiór języka sudoers, więc różnice objawiają się brakiem obsługi niektórych konstrukcji, a nie ich odmiennym działaniem. Edytuj plik za pomocą sudo visudo, a następnie zweryfikuj go za pomocą sudo visudo -c przed zamknięciem sesji.

Co zastępuje sudo -E w sudo-rs?

sudo -E nie jest zaimplementowane i było już odradzane w oryginalnym sudo, ponieważ przekazywanie procesowi roota środowiska kontrolowanego przez wywołującego jest znanym sposobem na zmianę zachowania tego procesu. Zamiast tego należy wymienić zmienne, które są faktycznie potrzebne w pliku sudoers, używając linii takiej jak Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY". env_reset jest zawsze włączone w sudo-rs i nie można go wyłączyć, więc każda zmienna, która nie została zachowana, jest usuwana.

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