SSD Nodes Learn 🎉 VPS החל מ־$5.50/חודש
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-13

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

מעבר ל-sudo-rs ב-Ubuntu 26.04 משנה את אופן העיבוד של תווי 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, והתוכנות שלו נושאות סיומת .ws: sudo.ws ו-visudo.ws.

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

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

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

מדוע כלל ה-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 אינה מרחיבה אותו, לכן הכלל אינו מכסה את systemctl restart app-api ו-sudo מסרבת להריץ את הפקודה. שתי פקודות יחשפו בפניכם את האמת על כל כלל בשרת שלכם: sudo -l -U deploy, בהרצה כ-root, מדפיסה מה החשבון הזה רשאי להריץ בפועל, ו-sudo visudo -c אומרת לכם האם הקובץ תקין מבחינת ניתוח (parsing). הריצו אותן לפני שתתחילו לערוך קבצים באופן אקראי.

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

החלפת ה-wildcard ברשימת פקודות מפורשת

רוב חוקי ה-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 escape) מתוך פקודה מורשית, אינו ממומש. הוא מעולם לא עמד בפני משתמש נחוש. אם כלל מאפשר למישהו להריץ עורך טקסט או מפרש פקודות כ-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 במועד מאוחר יותר משמעותה הגדרת ה-alternative לנתיב הבינארי של sudo-rs מתוך אותה רשימה.

השאירו סשן SSH שני פתוח, מחובר ופעיל, לפני שאתם משנים משהו שמשפיע על sudo. קובץ sudoers שלא מצליח לעבור parsing, או 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.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/, עם אותה תחביר עבור משתמשים, קבוצות, כינויים (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