SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-09-08

מעבר ל-sudo-rs ב-Ubuntu: מה משתנה בקובץ sudoers

Ubuntu 26.04 הופכת את sudo-rs לברירת המחדל. המדריך מסביר מדוע חוקי wildcard ב-sudoers מפסיקים לעבוד וכיצד לעדכן את ההגדרות שלכם כדי למנוע תקלות הרשאה במערכת.

מה sudo-rs משנה ב-Ubuntu

גרסת Ubuntu 26.04 LTS מפיצה את sudo-rs כברירת המחדל של sudo, לכן הפקודה sudo בשרת חדש מריצה את המימוש מחדש ב-Rust במקום את תוכנית ה-C המקורית. רוב קובצי ה-sudoers ממשיכים לעבוד בדיוק כפי שעבדו. הכלל שאינו עובד הוא זה המכיל תו כללי (wildcard) בתוך הארגומנטים של פקודה, מכיוון ש-sudo-rs אינו מבצע התאמת תבניות (glob patterns) מול טקסט הארגומנטים.

גרסת Ubuntu 25.10 ביצעה את המעבר ראשונה ו-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 כך שניתן להתקין את שתיהן בו-זמנית: /usr/bin/sudo.ws ו־/usr/bin/visudo.ws, לצד cvtsudoers.ws ו־sudoreplay.ws. אומת מול הארכיון של 26.04 בספטמבר 2026: dpkg -L sudo מפרט את הבינאריים בעלי הסיומת, ו־sudo-rs מספק את /usr/bin/sudo-rs לצידם.

מדוע Ubuntu עברה לשימוש ב-sudo-rs

התוכנה sudo מוגדרת כ-setuid root. כל משתמש במערכת יכול להפעיל אותה, והיא מתחילה עם הרשאות מלאות; לכן, באג זיכרון בתוכה מהווה פרצת אבטחה המאפשרת השגת הרשאות root מקומיות. ה-CVE-2021-3156 היה בדיוק מסוג זה: גלישת חוצץ (heap buffer overflow) שכל משתמש מקומי יכול היה לנצל, והוא היה קיים בקוד המופץ במשך כעשור. Rust מונעת סוג זה של באגים בזמן ההידור, וזהו הטיעון המרכזי לכתיבה מחדש של הכלי.

הסיבה השנייה היא היקף התוכנה, וזהו ההיבט שמשפיע על קובץ ה-config שלכם. ה-sudo המקורי צבר סט תכונות רחב במשך שלושה עשורים, וכל תכונה מוסיפה עוד קוד שרץ עם הרשאות root. ה-sudo-rs מיישם במכוון תת-קבוצה של תכונות אלו. כל מה שהכותבים שלו הגדירו כנישתי או כמזיק בפועל הושמט, ולכן הגדרת sudoers שעבדה במשך שנים עלולה פשוט לא להיות נתמכת. כלל ה-wildcard שלכם הוא אחד מאותם מקרים.

בטיחות זיכרון מסירה סוג אחד של באגים. היא לא הופכת תוכנה לחסינה מבאגים, ו-sudo-rs כבר קיבל תיקוני אבטחה משלו מאז שהפך לברירת המחדל. יש לעדכן אותו (patch) כמו כל תוכנה אחרת.

אילו חוקי sudoers עדיין עובדים

הקובץ הוא אותו קובץ. sudo-rs קורא את /etc/sudoers ואת קובצי ה-drop-in ב-/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 הפסיק להתאים

שימוש ב-wildcards עדיין מותר במקום אחד: בשם הקובץ של הפקודה. כלל מסוג %ops ALL = /sbin/fsck* עדיין מאפשר את sudo fsck ואת sudo fsck_exfat, מכיוון ש-* הוא חלק מהנתיב שמושווה מול מערכת הקבצים.

בתוך רשימת הארגומנטים, sudo-rs מקבל רק שתי צורות מיוחדות, ואף אחת מהן אינה תבנית (pattern). המשמעות של "" היא ללא ארגומנטים. * בסוף הפקודה משמעו כל ארגומנט נוסף. כל ארגומנט אחר מושווה כטקסט ליטרלי. לכן, %ops ALL = /sbin/service ntp * תקין, מכיוון ש-ntp הוא ליטרלי ו-* מופיע בסוף. לעומת זאת, כלל כזה אינו מעניק את ההרשאות שביקשת:

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

app-* הוא תבנית באמצע ארגומנט. sudo-rs אינו מבצע הרחבה (expand) לתבנית זו, לכן הכלל אינו מכסה את systemctl restart app-api ו-sudo מסרב להריץ את הפקודה. שתי פקודות יציגו בפניך את המידע המדויק לגבי כל כלל בשרת שלך: sudo -l -U deploy, בהרצה כ-root, מדפיסה מה החשבון רשאי להריץ בפועל, ו-sudo visudo -c בודקת אם הקובץ תקין מבחינת תחביר (parse). הרץ אותן לפני שתתחיל לבצע עריכות אקראיות.

כלל ה-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 מסרב להשתמש במבנה הזה במקום לנסות להפוך אותו לבטוח, כיוון שאין לו צורה כללית בטוחה.

החלפת תווים כלליים (wildcards) ברשימת פקודות מפורשת

רוב חוקי ה-wildcard קיימים רק כי מישהו לא רצה להקליד ארבע שורות. הקלידו את ארבע השורות.

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

תנו לקובץ שם ללא נקודה וללא תו tilde בסופו. ה-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. עבור יחידות systemd, המערכת כבר מאצילה את ההחלטה הזו ל-polkit, כך שכלל יכול להגדיר יחידה אחת ומפעיל אחד:

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 עדיין עובד. החלק שאינו נתמך הוא ניהול המדיניות מתוך ספרייה (directory).

INTERCEPT, שניסה למנוע בריחה ל-shell מתוך פקודה מורשית, אינו ממומש. ממילא הוא מעולם לא עמד בפני משתמש נחוש. אם כלל מסוים מאפשר למשתמש להריץ עורך טקסט או מפרש פקודות כ-root, יש לו הרשאות root, ושום אפשרות ב-sudo לא תשנה זאת.

תיעוד סשנים אינו ממומש, לכן אין יומן קלט/פלט ואין sudoreplay. הרישום מתבצע ל-syslog בלבד, ואין אפשרות logfile להפנות אותו למקום אחר; הודעות sudo יגיעו ליעד שאליו המערכת שלכם כבר שולחת את ה-syslog.

האם כדאי לחזור ל-sudo.ws?

ניתן לעשות זאת, ובמהלך מחזור הגרסה 26.04 הגרסה המקורית נשארת זמינה בחבילות בדיוק מהסיבה הזו.

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

העתיקו את הנתיבים המדויקים מתוך הפלט של --config במקום מדף זה, שכן זו הרשימה שהמערכת שלכם תקבל. חזרה ל-sudo-rs במועד מאוחר יותר משמעותה הגדרת ה-alternative לנתיב הבינארי של sudo-rs מתוך אותה רשימה.

השאירו סשן SSH שני פתוח, מחובר ופעיל, לפני שאתם משנים משהו שמשפיע על sudo. קובץ sudoers שלא מצליח להתפרש, או alternative שמצביע על קובץ בינארי שאינו מותקן, עלולים להותיר אתכם ללא יכולת להפוך ל-root בשרת מרוחק. הרגל זה הוא חלק מכל פעולה אחרת שאתם מבצעים ב-עשר הדקות הראשונות ב-VPS חדש.

התייחסו לחזרה לאחור כאל פתרון זמני ולא כאל תיקון קבוע. זה קונה לכם שבוע כדי לשכתב את הכללים כראוי, והשכתוב כדאי בזכות עצמו, כיוון שכל כלל עם wildcard שמחקתם העניק הרשאות רחבות יותר ממה שהכותב המקורי הבין.

FAQ

מדוע כלל ה-wildcard שלי ב-sudoers הפסיק לעבוד ב-Ubuntu 26.04?

מכיוון ש-Ubuntu 26.04 LTS בוחרת ב-sudo-rs כברירת המחדל עבור sudo, ו-sudo-rs אינו תואם תבניות wildcard בתוך ארגומנטים של פקודה. הוא מאפשר wildcard בשם הקובץ של הפקודה, "" לציון ללא ארגומנטים, ו-* בודד כארגומנט האחרון. כלל כמו /usr/bin/systemctl restart app-* מציב תבנית באמצע ארגומנט, לכן הוא אינו מעניק הרשאות והפקודה נדחית. הריצו sudo -l -U deploy כ-root כדי לראות אילו הרשאות יש לחשבון בפועל, ולאחר מכן החליפו את הכלל בפקודות מדויקות או בסקריפט עטיפה (wrapper) בבעלות root.

כיצד אוכל לחזור ל-sudo המקורי ב-Ubuntu 26.04?

הגרסה המקורית מגיעה בחבילה sudo, שהבינאריים שלה נושאים את הסיומת .ws. התקינו אותה באמצעות sudo apt install sudo, ולאחר מכן כוונו אליה את ה-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/, עם אותה תחביר עבור משתמשים, קבוצות, כינויים (aliases), הגדרות 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