توی این درس یاد میگیری کاربر root (مدیر سیستم) کیست و چرا هر کاری میتواند بکند؛ چطور با sudo فقط یک دستور را با دسترسی مدیر اجرا کنی؛ فرق sudo -i و su - چیست؛ چطور با گروه sudo به یک کاربر اجازه بدهی؛ چرا فایل /etc/sudoers را فقط با sudo visudo (ویرایش امن) عوض میکنیم؛ و اصل کمترین دسترسی: هر کس فقط همان چیزی را داشته باشد که لازم دارد. همه را روی کاربرهای واقعی امتحان میکنی. تمرین: به کاربری که میسازی دسترسی sudo میدهی و درستیاش را تست میکنی.
مسئله: کار مدیریتی لازم است، ولی همیشه مدیر بودن خطرناک است
Section titled “مسئله: کار مدیریتی لازم است، ولی همیشه مدیر بودن خطرناک است”نصب برنامه، ویرایش فایلهای /etc، راهاندازی سرویس، ساختن کاربر: همه کار مدیر سیستماند و کاربر عادی اجازهشان را ندارد (درس قبل دیدی: Permission denied). یک راه ساده این است که همیشه با کاربر root کار کنی. ولی root هیچ ترمزی ندارد: یک اشتباه تایپی همهچیز را پاک میکند و هیچکس هم نمیفهمد کار چه کسی بوده.
تشبیه: کلید مادر ساختمان
Section titled “تشبیه: کلید مادر ساختمان”root مثل کلید مادر است که همهی درها را باز میکند. دو راه برای کار با آن هست. راه اول: کلید را همیشه دست همه بدهی (ورود مستقیم با root). راه دوم: یک نگهبان (sudo) داشته باشی که برای هر کار، کلید را موقت بدهد، قبلش بپرسد «تو مجاز هستی؟» و در دفتر بنویسد «علی ساعت ۱۰:۳۰ در انبار را باز کرد». دستور su مثل این است که کلید را برداری و تا وقتی خودت نگذاشتهایاش، همراهت باشد.
کاربر root: همهکاره و خطرناک
Section titled “کاربر root: همهکاره و خطرناک”root کاربری با UID صفر است. هستهی لینوکس برای او قاعدههای دسترسی (درس قبل) را نادیده میگیرد:
| کاربر عادی | root | |
|---|---|---|
| UID | معمولاً از ۱۰۰۰ به بالا | 0 |
| پوشهی خانه | /home/نام |
/root |
| علامت ترمینال (prompt) | $ |
# |
| دسترسی به فایلها | طبق rwx مالک/گروه/بقیه | همه را دور میزند |
| کارهای سیستمی | ندارد | نصب برنامه، ساختن کاربر، بستن هر پروسه، پورت زیر ۱۰۲۴، mount… |
برای همین مهمترین قاعدهی امنیت لینوکس این است: با root کار روزمره نکن؛ فقط برای همان لحظهای که لازم است قدرتش را قرض بگیر. ابزار این قرضگرفتن sudo است.
مثالهای عملی
Section titled “مثالهای عملی”برای آزمایش به چند کاربر نیاز داریم؛ dev1 و dev2 را میسازیم و در پایان درس پاک میکنیم.
مثال ۱: root کیست؟
Section titled “مثال ۱: root کیست؟”echo "من: $(id -un) (UID=$(id -u))"echo "root: $(id -un 0) (UID=0)"echo "--- ردیف root در /etc/passwd:"getent passwd rootecho "--- وضعیت رمز root:"sudo passwd -S root | cut -d' ' -f1,2من: ali (UID=1001)root: root (UID=0)--- ردیف root در /etc/passwd:root:x:0:0:root:/root:/bin/bash--- وضعیت رمز root:root Lسطر /etc/passwd را در درس قبل خواندی: UID و GID برابر 0 و پوشهی خانهی /root. در خروجی passwd -S حرف L یعنی رمز root قفل است: روی Ubuntu نمیشود با رمز به root تبدیل شد؛ فقط با sudo. (این یک تصمیم امنیتی است: رمز rootای که وجود ندارد، نمیشود حدس زد.)
حالا ببین root قاعدههای دسترسی را چطور دور میزند:
mkdir -p ex1 && cd ex1echo "راز" > locked.txt && chmod 000 locked.txtls -l locked.txtcat locked.txtecho "--- با sudo:"sudo cat locked.txtecho "--- فایل رمزهای کاربران (فقط root و گروه shadow):"ls -l /etc/shadowcat /etc/shadowecho "تعداد خطها با sudo: $(sudo cat /etc/shadow | wc -l)"---------- 1 ali ali 7 Oct 3 20:43 locked.txtcat: locked.txt: Permission denied--- با sudo:راز--- فایل رمزهای کاربران (فقط root و گروه shadow):-rw-r----- 1 root shadow 665 Oct 3 20:43 /etc/shadowcat: /etc/shadow: Permission deniedتعداد خطها با sudo: 25فایلی که هیچ دسترسیای ندارد (----------) برای من (مالک) هم خواندنی نیست، ولی با sudo (یعنی root) خوانده میشود. و /etc/shadow که رمزهای (رمزنگاریشدهی) کاربران در آن است را فقط root و گروه shadow میخوانند. (محتوایش را عمداً چاپ نکردهام؛ فقط تعداد خطها را شمردم.)
مثال ۲: sudo، یک دستور با دسترسی root
Section titled “مثال ۲: sudo، یک دستور با دسترسی root”sudo (مخفف superuser do) دستوری که بعد از خودش میآید را با هویت root اجرا میکند و بعد از آن دوباره خودت هستی:
echo "قبل: $(whoami)"sudo whoamisudo idecho "بعد: $(whoami)"echo "--- sudo یادش میماند چه کسی صدایش زده:"sudo env | grep -E '^(USER|HOME|SUDO_USER|SUDO_COMMAND)='قبل: alirootuid=0(root) gid=0(root) groups=0(root)بعد: ali--- sudo یادش میماند چه کسی صدایش زده:USER=rootHOME=/rootSUDO_COMMAND=/usr/bin/envSUDO_USER=aliفقط خود دستور whoami با root اجرا شد؛ همینکه تمام شد، من دوباره ali هستم. متغیرهای محیطی نشان میدهند در آن لحظه USER=root است، ولی SUDO_USER=ali میگوید چه کسی این قدرت را خواسته (برای لاگ و اسکریپتها). با sudo -u کاربر دستور هم میتوانی بهجای کاربر دیگری (نه فقط root) اجرا کنی؛ در درس قبل برای آزمایش دسترسیها از همین استفاده کردیم.
وقتی sudo رمز میخواهد، رمز چه کسی را باید بدهی؟
sudo تأیید میکند که خودِ تو پشت کیبورد هستی (رمز خودت)؛ نیازی نیست رمز root را کسی بداند (و روی Ubuntu اصلاً رمز root وجود ندارد).
مثال ۳: کاربری که اجازهی sudo ندارد
Section titled “مثال ۳: کاربری که اجازهی sudo ندارد”در آزمایشگاه من ali بدون رمز sudo میکند (راحتی خودم برای ساختن درس)، پس رمزخواستن را نمیبینیم. برای دیدن رفتار واقعی، کاربر dev1 را با یک رمز آزمایشی میسازم:
PW=lab-passsudo useradd -m -s /bin/bash dev1echo "dev1:$PW" | sudo chpasswdid dev1uid=1002(dev1) gid=1002(dev1) groups=1002(dev1)برای دیدن صفحهی واقعی ترمینال هنگام ورود کاربر و رمزپرسی، یک ترمینال مجازی (tmux) باز میکنم و تایپها را خودکار میفرستم (مثل درس ویرایشگرها). دو تابع کمکی:
run_in_tmux() { tmux -u kill-server 2>/dev/null; tmux -u new-session -d -s t -x 76 -y "${TH:-24}" "$@"; sleep 1; }screen() { tmux capture-pane -t t -p | sed -e :a -e '/^[[:space:]]*$/{$d;N;ba' -e '}'; }echo "توابع کمکی آماده شد"توابع کمکی آماده شدحالا با su - dev1 (با رمز خودش) به dev1 تبدیل میشوم و sudo را امتحان میکنم. (رمزی که تایپ میشود روی صفحه نمایش داده نمیشود، مثل ترمینال واقعی.)
run_in_tmux "bash --norc"tmux send-keys -t t "su - dev1" Enter; sleep 1tmux send-keys -t t "$PW" Enter; sleep 1tmux send-keys -t t "sudo whoami" Enter; sleep 1tmux send-keys -t t "$PW" Enter; sleep 2screenbash-5.2$ su - dev1Password:dev1@pc:~$ sudo whoami[sudo] password for dev1:dev1 is not in the sudoers file.dev1@pc:~$dev1 رمزش را درست داد، ولی sudo میگوید dev1 is not in the sudoers file: یعنی در فهرست مجازها نیست و دستور اجرا نمیشود. (این تلاش در لاگ هم ثبت میشود؛ مثال ۹.) پس اول باید به او اجازه داد.
مثال ۴: گروه sudo، دادن دسترسی به یک کاربر
Section titled “مثال ۴: گروه sudo، دادن دسترسی به یک کاربر”در Ubuntu و Debian قاعدهای در /etc/sudoers هست که به همهی اعضای گروه sudo اجازه میدهد (مثال ۶). پس برای دادن دسترسی کافی است کاربر را در این گروه بگذاری (در توزیعهای Red Hat مثل Fedora و Rocky همین گروه wheel نام دارد):
echo "--- اعضای فعلی گروه sudo (ubuntu را خودِ تصویر Ubuntu ساخته):"getent group sudosudo usermod -aG sudo dev1echo "--- بعد از usermod -aG sudo dev1:"getent group sudoid dev1echo "--- sudo -l -U: dev1 چه اجازههایی دارد؟"sudo -l -U dev1 | tail -2--- اعضای فعلی گروه sudo (ubuntu را خودِ تصویر Ubuntu ساخته):sudo:x:27:ubuntu--- بعد از usermod -aG sudo dev1:sudo:x:27:ubuntu,dev1uid=1002(dev1) gid=1002(dev1) groups=1002(dev1),27(sudo)--- sudo -l -U: dev1 چه اجازههایی دارد؟User dev1 may run the following commands on pc: (ALL : ALL) ALL-aG یعنی اضافه کن (a = append) به گروه (G)؛ بدون -a گروههای قبلی کاربر پاک میشد (درس کاربرها). خروجی sudo -l -U میگوید dev1 میتواند همهی دستورها را بهعنوان هر کاربر و گروهی اجرا کند: (ALL : ALL) ALL. حالا همان آزمایش را تکرار میکنم، این بار با چند اتفاق دیگر که باید ببینی: حافظهی رمز، sudo -k و sudo !!:
run_in_tmux "bash --norc"tmux send-keys -t t "su - dev1" Enter; sleep 1tmux send-keys -t t "$PW" Enter; sleep 1tmux send-keys -t t "sudo whoami" Enter; sleep 1tmux send-keys -t t "$PW" Enter; sleep 1tmux send-keys -t t "sudo whoami" Enter; sleep 1tmux send-keys -t t "sudo -k" Enter "sudo whoami" Enter; sleep 1tmux send-keys -t t "$PW" Enter; sleep 1tmux send-keys -t t "wc -l /etc/shadow" Enter; sleep 1tmux send-keys -t t 'sudo !!' Enter; sleep 1screenbash-5.2$ su - dev1Password:To run a command as administrator (user "root"), use "sudo <command>".See "man sudo_root" for details.
dev1@pc:~$ sudo whoami[sudo] password for dev1:rootdev1@pc:~$ sudo whoamirootdev1@pc:~$ sudo -kdev1@pc:~$ sudo whoami[sudo] password for dev1:rootdev1@pc:~$ wc -l /etc/shadowwc: /etc/shadow: Permission denieddev1@pc:~$ sudo !!sudo wc -l /etc/shadow26 /etc/shadowdev1@pc:~$مرحله به مرحله:
- اولین بار
[sudo] password for dev1:رمز خودش را خواست و نتیجهrootشد. (پیام اول، «To run a command as administrator…»، راهنمای Ubuntu برای کاربرهایی است که عضو گروهsudoهستند و هنوز sudo نکردهاند.) - بار دوم رمز نخواست: sudo رمزِ درست را برای هر ترمینال چند دقیقه (پیشفرض ۱۵) یادش نگه میدارد.
- با
sudo -kآن حافظه پاک شد و بار بعد دوباره رمز خواست. wc -l /etc/shadowبدون sudoPermission deniedداد؛sudo !!یعنی «همان دستور قبلی را دوباره، این بار با sudo». (!!را خود bash جایگزین میکند و دستور کامل را چاپ میکند.) یک ترفند پرکاربرد وقتی بعد از زدن دستور یادت میافتد sudo لازم بود.
مثال ۵: sudo -i، sudo -s و su -
Section titled “مثال ۵: sudo -i، sudo -s و su -”گاهی میخواهی چند دستور پشتسرهم با root بزنی. سه راه هست؛ فرقشان را با یک دستور که کاربر، پوشهی خانه و پوشهی فعلی را چاپ میکند ببین:
cd /tmpecho "--- sudo دستور (همان پوشهی فعلی):"sudo sh -c 'echo "کاربر=$(id -un) HOME=$HOME PWD=$PWD"'echo "--- sudo -i (ورود کامل مثل login؛ میرود به HOME):"sudo -i sh -c 'echo "کاربر=$(id -un) HOME=$HOME PWD=$PWD"'echo "--- sudo -s (shell با root، در همان پوشه):"sudo -s sh -c 'echo "کاربر=$(id -un) HOME=$HOME PWD=$PWD"'--- sudo دستور (همان پوشهی فعلی):کاربر=root HOME=/root PWD=/tmp--- sudo -i (ورود کامل مثل login؛ میرود به HOME):کاربر=root HOME=/root PWD=/root--- sudo -s (shell با root، در همان پوشه):کاربر=root HOME=/root PWD=/tmpsudo -i (interactive login) یک شل ورود کامل برای root میسازد: به /root میروی و فایلهای شروع root اجرا میشود. sudo -s فقط یک shell با هویت root در همان پوشهی فعلی میدهد. این هم صفحهی واقعی sudo -i؛ ببین علامت ترمینال از $ به # عوض شد:
run_in_tmux "bash --norc"tmux send-keys -t t "sudo -i" Enter; sleep 1tmux send-keys -t t "whoami; pwd" Enter; sleep 1tmux send-keys -t t "exit" Enter; sleep 1screenbash-5.2$ sudo -iroot@pc:~# whoami; pwdroot/rootroot@pc:~# exitlogoutbash-5.2$su (switch user) هم به کاربر دیگری تبدیل میشود، ولی رمز کاربر مقصد را میخواهد. برای root یعنی رمز root، که روی Ubuntu قفل است:
run_in_tmux "bash --norc"tmux send-keys -t t "su -" Enter; sleep 1tmux send-keys -t t "hope-this-works" Enter; sleep 6screenbash-5.2$ su -Password:su: Authentication failurebash-5.2$(رمز اشتباه است و حتی رمز درستی هم وجود ندارد: su: Authentication failure.) پس روی Ubuntu همان sudo -i جای su - را میگیرد. su - برای وقتی است که رمز کاربر مقصد را داری. فرق خطتیره را وقتی میبینی که به یک کاربر عادی تبدیل شوی (اینجا چون با sudo اجرا میکنم رمز نمیخواهد):
cd /tmpecho "--- su dev1 (بدون خطتیره: پوشهی فعلی میماند):"sudo su dev1 -c 'echo "کاربر=$(id -un) HOME=$HOME PWD=$PWD"'echo "--- su - dev1 (ورود کامل: به HOME او میروی):"sudo su - dev1 -c 'echo "کاربر=$(id -un) HOME=$HOME PWD=$PWD"'--- su dev1 (بدون خطتیره: پوشهی فعلی میماند):کاربر=dev1 HOME=/home/dev1 PWD=/tmp--- su - dev1 (ورود کامل: به HOME او میروی):کاربر=dev1 HOME=/home/dev1 PWD=/home/dev1sudo در برابر su
Section titled “sudo در برابر su”sudo دستور |
sudo -i |
sudo -s |
su - |
su |
|
|---|---|---|---|---|---|
| رمز چه کسی؟ | خودت | خودت | خودت | کاربر مقصد (مثلاً root) | کاربر مقصد |
| چه میشود؟ | فقط همان یک دستور با root | شل ورود کامل root (در /root) |
شل root در همان پوشه | شل ورود کامل کاربر مقصد | شل با محیط فعلی تو |
| ثبت در لاگ | هر دستور جدا، با نام تو | فقط شروع جلسه | فقط شروع جلسه | فقط ورود | فقط ورود |
| روی Ubuntu (root قفل) | کار میکند | کار میکند | کار میکند | نه (رمز root نیست) | نه |
نتیجه: برای کار معمول sudo دستور را بزن (کمترین قدرت، بهترین ثبت). فقط وقتی دهها دستور مدیریتی پشتسرهم داری از sudo -i استفاده کن و بعد حتماً exit.
مثال ۶: /etc/sudoers را بخوان
Section titled “مثال ۶: /etc/sudoers را بخوان”قاعدههای sudo در /etc/sudoers و فایلهای پوشهی /etc/sudoers.d/ هستند. فقط root میخواندشان:
sudo ls -l /etc/sudoersecho "--- قاعدههای فعال (بدون توضیح و خط خالی):"sudo grep -v '^#' /etc/sudoers | grep -v '^$'echo "--- پوشهی sudoers.d:"sudo ls -l /etc/sudoers.d/-r--r----- 1 root root 1800 Jan 29 2024 /etc/sudoers--- قاعدههای فعال (بدون توضیح و خط خالی):Defaults env_resetDefaults mail_badpassDefaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"Defaults use_ptyroot ALL=(ALL:ALL) ALL%admin ALL=(ALL) ALL%sudo ALL=(ALL:ALL) ALL@includedir /etc/sudoers.d--- پوشهی sudoers.d:total 8-r--r----- 1 root root 1068 Jan 29 2024 README-r--r----- 1 root root 27 Oct 3 09:36 aliهر قاعده این شکل را دارد: چه کسی، روی کدام میزبان = (بهعنوان چه کاربری) چه دستورهایی:
| قطعه | معنی | نمونه |
|---|---|---|
%sudo |
چه کسی: علامت % یعنی یک گروه؛ بدون آن، نام کاربر |
%sudo، root، dev2 |
ALL (اول) |
روی کدام میزبان (در سرورهای تکی همیشه ALL) |
ALL |
(ALL:ALL) |
بهعنوان کدام کاربر:گروه میتواند اجرا کند | (root)، (ALL) |
NOPASSWD: |
برچسب اختیاری: بدون پرسیدن رمز | NOPASSWD: |
ALL (آخر) |
کدام دستورها؛ مسیر کامل یا ALL |
/usr/bin/du -sh /var/log |
پس %sudo ALL=(ALL:ALL) ALL یعنی «اعضای گروه sudo، روی هر میزبان، بهعنوان هر کاربر و گروه، هر دستور را میتوانند اجرا کنند.» خط آخر (@includedir) هر فایل داخل sudoers.d را هم میخواند. فایل ali را آزمایشگاه برای راحتی من ساخته (NOPASSWD:ALL)؛ روی سرور واقعی چنین قاعدهای برای یک آدم نمیگذاری.
مثال ۷: ویرایش امن با visudo
Section titled “مثال ۷: ویرایش امن با visudo”اگر /etc/sudoers را مثل یک فایل عادی ویرایش کنی و یک غلط تایپی بگذاری، دستور همان خط کار نمیکند و (مثال «اشتباهات رایج») هر بار هم sudo خطا چاپ میکند. برای همین قاعدهها را فقط با sudo visudo عوض میکنیم. این دستور:
- روی یک نسخهی موقت کار میکند، نه خود فایل؛
- بعد از بستن ویرایشگر، نحو (syntax) را بررسی میکند و فقط اگر درست بود جایگزین میکند؛
- در عین حال قفل میگذارد تا دو نفر همزمان ویرایش نکنند.
ویرایشگر پیشفرضش با EDITOR عوض میشود. بهتر است قاعدهها را بهجای دستزدن به فایل اصلی، در یک فایل جدا در /etc/sudoers.d/ بنویسی (-f همان فایل را به visudo میدهد). برای dev2 یک قاعدهی محدود مینویسم: فقط اجازهی یک دستور. اینجا هم با tmux nano را باز میکنم و خطی را که تو تایپ میکردی میفرستم:
sudo useradd -m -s /bin/bash dev2TH=12 # ارتفاع ترمینال مجازی (برای nano کوتاهتر کافی است)run_in_tmux "bash --norc"tmux send-keys -t t "sudo EDITOR=nano visudo -f /etc/sudoers.d/dev2" Enter; sleep 2tmux send-keys -t t -l "dev2 ALL=(root) NOPASSWD: /usr/bin/du -sh /var/log"; sleep 1screen GNU nano 7.2 /etc/sudoers.d/dev2.tmp *dev2 ALL=(root) NOPASSWD: /usr/bin/du -sh /var/log
^G Help ^O Write Out ^W Where Is ^K Cut ^T Execute^X Exit ^R Read File ^\ Replace ^U Paste ^J Justifyبه نام فایل بالای nano دقت کن: dev2.tmp، همان نسخهی موقت. حالا ذخیره میکنم (Ctrl+X، بعد Y و Enter) و ببین visudo چه میگوید:
tmux send-keys -t t C-x; sleep 1tmux send-keys -t t y; sleep 1tmux send-keys -t t Enter; sleep 2screenbash-5.2$ sudo EDITOR=nano visudo -f /etc/sudoers.d/dev2bash-5.2$ساکت بود، یعنی نحو درست بود و فایل جایگزین شد. بررسی کامل با visudo -c (فایل جدید را 0640 میسازد ولی visudo -c برای فایلهای sudoers.d حالت 0440 میخواهد):
sudo ls -l /etc/sudoers.d/dev2sudo visudo -cecho "--- اصلاح دسترسی و بررسی دوباره:"sudo chmod 440 /etc/sudoers.d/dev2sudo visudo -c-rw-r----- 1 root root 51 Oct 3 20:44 /etc/sudoers.d/dev2/etc/sudoers: parsed OK/etc/sudoers.d/README: parsed OK/etc/sudoers.d/ali: parsed OK/etc/sudoers.d/dev2: bad permissions, should be mode 0440--- اصلاح دسترسی و بررسی دوباره:/etc/sudoers: parsed OK/etc/sudoers.d/README: parsed OK/etc/sudoers.d/ali: parsed OK/etc/sudoers.d/dev2: parsed OKحالا عمداً یک غلط میگذارم: بعد از NOPASSWD دو نقطه (:) را فراموش میکنم. با Alt+/ میروم آخر فایل:
tmux send-keys -t t "clear" Entertmux send-keys -t t "sudo EDITOR=nano visudo -f /etc/sudoers.d/dev2" Enter; sleep 2tmux send-keys -t t M-/; sleep 1tmux send-keys -t t -l "dev2 ALL=(ALL) NOPASSWD ALL"; sleep 1tmux send-keys -t t C-x; sleep 1tmux send-keys -t t y; sleep 1tmux send-keys -t t Enter; sleep 2tmux send-keys -t t "?" Enter; sleep 1screenbash-5.2$ sudo EDITOR=nano visudo -f /etc/sudoers.d/dev2/etc/sudoers.d/dev2:2:25: syntax errordev2 ALL=(ALL) NOPASSWD ALL ^~~What now? ?Options are: (e)dit sudoers file again e(x)it without saving changes to sudoers file (Q)uit and save changes to sudoers file (DANGER!)
What now?visudo شمارهی خط و ستون خطا را نشان داد (:2:25) و پرسید «What now؟». سه گزینه دارد: دوباره ویرایش کن (e)، بدون ذخیره خارج شو (x)، یا با خطر ذخیره کن (Q؛ هرگز). x را میزنم و میبینم فایل دستنخورده مانده:
tmux send-keys -t t "x" Enter; sleep 1tmux send-keys -t t "clear" Entertmux send-keys -t t "sudo cat /etc/sudoers.d/dev2" Enter; sleep 1screentmux -u kill-serverbash-5.2$ sudo cat /etc/sudoers.d/dev2dev2 ALL=(root) NOPASSWD: /usr/bin/du -sh /var/logbash-5.2$فقط قاعدهی درست مانده. برای بررسی یک فایل قبل از نصب (مثلاً در اسکریپت) از visudo -cf استفاده کن:
printf 'dev2 ALL=(ALL) NOPASSWD ALL\n' > /tmp/bad.sudoerssudo visudo -cf /tmp/bad.sudoers; echo "کد خروجی: $?"printf 'dev2 ALL=(root) NOPASSWD: /usr/bin/id\n' > /tmp/good.sudoerssudo visudo -cf /tmp/good.sudoers; echo "کد خروجی: $?"rm /tmp/bad.sudoers /tmp/good.sudoers/tmp/bad.sudoers:1:25: syntax errordev2 ALL=(ALL) NOPASSWD ALL ^~~کد خروجی: 1/tmp/good.sudoers: parsed OKکد خروجی: 0مثال ۸: اصل کمترین دسترسی، فقط یک دستور
Section titled “مثال ۸: اصل کمترین دسترسی، فقط یک دستور”اصل کمترین دسترسی (principle of least privilege) یعنی هر کاربر و هر برنامه فقط همان اندازه که برای کارش لازم است دسترسی داشته باشد، نه بیشتر. dev2 که الان فقط قاعدهی du را دارد را آزمایش میکنم (-n یعنی اگر رمز لازم شد نپرس و خطا بده):
sudo -l -U dev2 | tail -2echo "--- dev2 دستور مجاز را اجرا میکند:"sudo -u dev2 sudo -n du -sh /var/logecho "--- دستور دیگر (غیرمجاز):"sudo -u dev2 sudo -n cat /etc/shadowUser dev2 may run the following commands on pc: (root) NOPASSWD: /usr/bin/du -sh /var/log--- dev2 دستور مجاز را اجرا میکند:620K /var/log--- دستور دیگر (غیرمجاز):sudo: a password is requireddev2 اندازهی پوشهی لاگها را میتواند ببیند (که بدون root ممکن نیست)، ولی هر چیز دیگر sudo: a password is required میگیرد: چون قاعدهی دیگری ندارد، و رمز هم که ندارد. این همان چیزی است که برای حسابهای اتوماسیون (دیپلوی، مانیتورینگ) میخواهی: «فقط همین یک کار».
قاعدههای سرانگشتی:
- کار روزمره را با کاربر عادی انجام بده و فقط دستور لازم را با
sudoبزن. sudo دستوررا بهsudo -iترجیح بده تا هر دستور با نام خودت ثبت شود.- برای آدمها و سرویسها فقط دستور مشخص با مسیر کامل مجاز کن (در
sudoers.d)، نهALL. NOPASSWD: ALLرا فقط برای ماشینهای آزمایشی بگذار، نه سرور واقعی و نه آدمها.- هرگز ویرایشگر (
vim،nano)، pager (less) یا shell را با sudo مجاز نکن؛ از داخلشان میشود shell گرفت و آن کاربر root کامل است. - از
*در قاعدهها دوری کن (در «اشتباهات رایج» میبینی چرا).
مثال ۹: sudo همهچیز را ثبت میکند
Section titled “مثال ۹: sudo همهچیز را ثبت میکند”بزرگترین فایدهی sudo نسبت به ورود مستقیم با root ردپا است. این بار روی سرور systemdدار آزمایشگاه (که سرویس لاگ دارد) کار میکنم: ali دو دستور با sudo میزند، و کاربر eve که مجاز نیست رمز اشتباه میدهد؛ بعد لاگ را میخوانم. (روی Ubuntu و Debian لاگ sudo در /var/log/auth.log و در journal است؛ روی Red Hat در /var/log/secure.)
useradd -m -s /bin/bash eve 2>/dev/nullecho "eve:pw1234" | chpasswdsu - ali -c 'sudo whoami; sudo ls /root > /dev/null'su - eve -c 'echo wrongpass | sudo -S whoami' > /dev/null 2>&1sleep 1echo "--- /var/log/auth.log (آخرین سه دستور):"grep 'COMMAND=' /var/log/auth.log | tail -3 | sed -E 's/^[^ ]+ //'echo "--- journal:"journalctl -t sudo --no-pager -o cat | grep 'COMMAND=' | tail -3userdel -r eve 2>/dev/nullroot--- /var/log/auth.log (آخرین سه دستور):server sudo: ali : PWD=/home/ali ; USER=root ; COMMAND=/usr/bin/whoamiserver sudo: ali : PWD=/home/ali ; USER=root ; COMMAND=/usr/bin/ls /rootserver sudo: eve : user NOT in sudoers ; PWD=/home/eve ; USER=root ; COMMAND=/usr/bin/whoami--- journal: ali : PWD=/home/ali ; USER=root ; COMMAND=/usr/bin/whoami ali : PWD=/home/ali ; USER=root ; COMMAND=/usr/bin/ls /root eve : user NOT in sudoers ; PWD=/home/eve ; USER=root ; COMMAND=/usr/bin/whoamiهر خط میگوید چه کسی (ali)، از کدام پوشه (PWD)، با چه هویتی (USER=root) و چه دستوری (COMMAND=) را اجرا کرده، و تلاش eve هم با عبارت user NOT in sudoers ثبت شده است. اگر هر دو با root وارد میشدند، هیچکدام از اینها معلوم نبود.
پشت پرده: sudo چطور قدرت میگیرد؟
Section titled “پشت پرده: sudo چطور قدرت میگیرد؟”خود sudo یک برنامهی معمولی روی دیسک است، ولی با یک حالت ویژه: حرف s بهجای x در دسترسی مالک (setuid). یعنی هر کس اجرایش کند، برنامه با هویت مالکش (root) اجرا میشود. (درس بعدی «دسترسیهای ویژه» دقیقاً دربارهی همین است.)
ls -l /usr/bin/sudo /usr/bin/suecho "--- حافظهی رمز: برای هر کاربر یک فایل زمانسنج (نامش UID کاربر است):"sudo ls -l /run/sudo/ts/-rwsr-xr-x 1 root root 67744 Aug 19 16:47 /usr/bin/su-rwsr-xr-x 1 root root 335120 Sep 21 18:37 /usr/bin/sudo--- حافظهی رمز: برای هر کاربر یک فایل زمانسنج (نامش UID کاربر است):total 12-rw------- 1 root dev1 448 Oct 3 20:43 1002-rw------- 1 root dev2 336 Oct 3 20:44 1003-rw------- 1 root 1004 224 Oct 3 20:43 1004مراحل اجرای یک sudo دستور:
- هسته چون
sudoمالکش root و بیت setuid دارد، آن را با دسترسی root اجرا میکند. - sudo قاعدههای
/etc/sudoersوsudoers.dرا میخواند و بررسی میکند تو مجاز هستی یا نه؛ آخرین قاعدهی منطبق تعیینکننده است. - اگر لازم باشد، رمز تو را از طریق PAM (سیستم احراز هویت لینوکس) میپرسد، مگر در
/run/sudo/ts/گواهی تازهای باشد. - محیط را پاکسازی میکند (
env_reset) وPATHرا به یک مقدار امن ثابت (secure_path) برمیگرداند. (این همان چیزی است که یکی از «اشتباهات رایج» را میسازد.) - دستور را با هویت مقصد اجرا و رویداد را در syslog ثبت میکند.
جدولهای مرجع
Section titled “جدولهای مرجع”| دستور | کار |
|---|---|
sudo دستور |
اجرای یک دستور با root |
sudo -u کاربر دستور |
اجرا با هویت یک کاربر دیگر |
sudo -i |
شل ورود کامل root (و exit در پایان) |
sudo -s |
شل root در همان پوشه |
sudo -l / sudo -l -U کاربر |
فهرست اجازههای خودت / کاربر دیگر |
sudo -k |
فراموشکردن رمز کششده |
sudo -n دستور |
اگر رمز لازم شد نپرس و خطا بده (برای اسکریپت) |
sudo -S |
خواندن رمز از stdin (فقط آزمایش) |
sudo !! |
دستور قبلی را دوباره با sudo بزن |
su - کاربر |
ورود کامل با رمز آن کاربر |
sudo visudo |
ویرایش امن sudoers |
sudo visudo -f /etc/sudoers.d/نام |
ویرایش امن یک فایل جدا |
visudo -c / visudo -cf فایل |
بررسی نحو همهی فایلها / یک فایل |
usermod -aG sudo کاربر |
دادن دسترسی کامل (Debian/Ubuntu) |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) sudo echo ... > فایل
Section titled “۱) sudo echo ... > فایل”sudo echo "setting=1" > /etc/lxtest.confecho "--- راهحل: tee با sudo اجرا شود:"echo "setting=1" | sudo tee /etc/lxtest.confsudo rm /etc/lxtest.confbash: /etc/lxtest.conf: Permission denied--- راهحل: tee با sudo اجرا شود:setting=1sudo فقط echo را با root اجرا کرد؛ ریدایرکت (>) را خود shell تو انجام میدهد و تو اجازهی نوشتن در /etc را نداری. راهحل: tee را با sudo اجرا کن (... | sudo tee فایل؛ برای اضافهکردن tee -a).
۲) فایل با نقطه در نام، داخل sudoers.d
Section titled “۲) فایل با نقطه در نام، داخل sudoers.d”echo 'dev2 ALL=(root) NOPASSWD: /usr/bin/id' | sudo tee /etc/sudoers.d/dev2-extra.conf > /dev/nullsudo chmod 440 /etc/sudoers.d/dev2-extra.confsudo visudo -cecho "--- قاعدههای dev2:"sudo -l -U dev2 | tail -2echo "--- بعد از حذف پسوند .conf از نام فایل:"sudo mv /etc/sudoers.d/dev2-extra.conf /etc/sudoers.d/dev2-extrasudo -l -U dev2 | tail -3sudo rm /etc/sudoers.d/dev2-extra/etc/sudoers: parsed OK/etc/sudoers.d/README: parsed OK/etc/sudoers.d/ali: parsed OK/etc/sudoers.d/dev2: parsed OK--- قاعدههای dev2:User dev2 may run the following commands on pc: (root) NOPASSWD: /usr/bin/du -sh /var/log--- بعد از حذف پسوند .conf از نام فایل:User dev2 may run the following commands on pc: (root) NOPASSWD: /usr/bin/du -sh /var/log (root) NOPASSWD: /usr/bin/idsudo فایلهایی که در نامشان . دارند یا با ~ تمام میشوند را بیصدا نادیده میگیرد (حتی visudo -c اسمی از آن نمیآورد). قاعدهی id تا وقتی اسم فایل .conf داشت اعمال نشد. راهحل: نام فایلهای sudoers.d را بدون نقطه بنویس (dev2-extra).
۳) sudo: command not found برای برنامهی خودت
Section titled “۳) sudo: command not found برای برنامهی خودت”mkdir -p ~/binprintf '#!/bin/sh\necho "mytool اجرا شد"\n' > ~/bin/mytoolchmod +x ~/bin/mytoolexport PATH="$HOME/bin:$PATH"which mytoolmytoolsudo mytoolecho "--- راهحل: مسیر کامل یا ردکردن PATH:"sudo "$(which mytool)"sudo env "PATH=$PATH" mytoolrm -rf ~/bin/home/ali/bin/mytoolmytool اجرا شدsudo: mytool: command not found--- راهحل: مسیر کامل یا ردکردن PATH:mytool اجرا شدmytool اجرا شدشل تو برنامه را در PATH خودت (شامل ~/bin) پیدا میکند، ولی sudo برای امنیت PATH را به secure_path ثابت برمیگرداند (مثال ۶). راهحل: مسیر کامل را بده، یا برنامه را در یک پوشهی سیستمی مثل /usr/local/bin بگذار.
۴) قاعدهی sudoers با *
Section titled “۴) قاعدهی sudoers با *”echo 'dev2 ALL=(root) NOPASSWD: /usr/bin/cat /var/log/*' | sudo tee /etc/sudoers.d/dev2-wild > /dev/nullsudo chmod 440 /etc/sudoers.d/dev2-wildecho "--- مجاز: خواندن لاگها (قصد قاعده همین بود):"sudo -u dev2 sudo -n cat /var/log/dpkg.log | head -1echo "--- نفوذ: نام کاربران از /etc/shadow (فقط ستون اول):"sudo -u dev2 sudo -n cat /var/log/../../etc/shadow | cut -d: -f1 | head -3echo "--- مستقیم:"sudo -u dev2 sudo -n cat /etc/shadowsudo rm /etc/sudoers.d/dev2-wild--- مجاز: خواندن لاگها (قصد قاعده همین بود):2026-09-11 02:06:06 startup archives install--- نفوذ: نام کاربران از /etc/shadow (فقط ستون اول):rootdaemonbin--- مستقیم:sudo: a password is required* در قاعدهی sudoers هر چیزی را شامل / و .. میشود؛ پس /var/log/../../etc/shadow هم با آن میخواند و dev2 در عمل همهی فایلهای سیستم را میخواند. راهحل: مسیر دقیق بده (/usr/bin/cat /var/log/syslog) یا بهتر، کاربر را عضو گروه adm کن که لاگها را بخواند، بدون sudo.
۵) ویرایش مستقیم /etc/sudoers و غلط تایپی
Section titled “۵) ویرایش مستقیم /etc/sudoers و غلط تایپی”این بار در سرور systemdدار آزمایشگاه (یک ماشین دورریختنی) عمداً بدون visudo یک خط خراب به فایل اصلی اضافه میکنم: برای eve قاعدهای بنویسم و دو نقطهی NOPASSWD: را فراموش کنم:
cp /etc/sudoers /tmp/sudoers.bakuseradd -m -s /bin/bash eve 2>/dev/nullecho "eve ALL=(ALL) NOPASSWD ALL" >> /etc/sudoersecho "--- یک کاربر دیگر (ali) که فقط sudo میزند:"su - ali -c 'sudo -n true'; echo "کد خروجی ali: $?"echo "--- eve که قاعدهاش خراب است:"su - eve -c 'sudo -n true'; echo "کد خروجی eve: $?"cp /tmp/sudoers.bak /etc/sudoers && chmod 440 /etc/sudoersuserdel -r eve 2>/dev/null; rm /tmp/sudoers.bak--- یک کاربر دیگر (ali) که فقط sudo میزند:/etc/sudoers:58:24: syntax erroreve ALL=(ALL) NOPASSWD ALL ^~~کد خروجی ali: 0--- eve که قاعدهاش خراب است:/etc/sudoers:58:24: syntax erroreve ALL=(ALL) NOPASSWD ALL ^~~sudo: a password is requiredکد خروجی eve: 1هر اجرای sudo، برای همه، خطای نحو را چاپ میکند، و قاعدهای که غلط داشت اجرا نمیشود: eve هیچ دسترسیای ندارد (و اگر آن خط، دسترسی خودِ تو بود، همینجا sudo را از دست میدادی؛ روی Ubuntu که root رمز ندارد یعنی نیاز به حالت بازیابی سیستم). راهحل: همیشه با sudo visudo و ترجیحاً فایل جدا در sudoers.d کار کن؛ مثال ۷.
با id و sudo id نشان بده «من» چه کسی هستم و با sudo چه کسی میشوم، UID root چند است، و با sudo -l فهرست اجازههایت را بگیر.
دیدن جواب
echo "من: $(id -un) | با sudo: $(sudo id -un) | UID با sudo: $(sudo id -u)"sudo -l | tail -2من: ali | با sudo: root | UID با sudo: 0User ali may run the following commands on pc: (ALL) NOPASSWD: ALLتمرین اصلی: به کاربری که میسازی دسترسی sudo بده و تست کن. کاربر dev3 را با رمز بساز، ثابت کن قبل از افزودن به گروه sudo نمیتواند، بعد او را اضافه کن و ثابت کن حالا میتواند. (برای رمزدادن در اسکریپت: echo رمز | sudo -S؛ فقط برای آزمایش.)
دیدن جواب
PW=lab-passsudo useradd -m -s /bin/bash dev3echo "dev3:$PW" | sudo chpasswdecho "گروهها قبل: $(id -nG dev3)"sudo su - dev3 -c "echo $PW | sudo -S -p '' whoami" 2>&1sudo usermod -aG sudo dev3echo "گروهها بعد: $(id -nG dev3)"sudo -l -U dev3 | tail -2sudo su - dev3 -c "echo $PW | sudo -S -p '' whoami" 2>&1sudo userdel -r dev3 2>/dev/nullگروهها قبل: dev3dev3 is not in the sudoers file.گروهها بعد: dev3 sudoUser dev3 may run the following commands on pc: (ALL : ALL) ALLrootقبل از usermod -aG sudo خطای is not in the sudoers file و بعد از آن root. (-p '' یعنی پیام رمزپرسی چاپ نشود.)
یک حساب deploy بساز که فقط بتواند touch /var/tmp/deploy.flag را با root اجرا کند، نه هیچ دستور دیگری. قاعده را قبل از نصب با visudo -cf بررسی کن، با install -m 440 در sudoers.d بگذار، و هم مجاز و هم غیرمجاز را تست کن.
دیدن جواب
sudo useradd -m -s /bin/bash deployecho 'deploy ALL=(root) NOPASSWD: /usr/bin/touch /var/tmp/deploy.flag' > /tmp/deploy.sudoerssudo visudo -cf /tmp/deploy.sudoerssudo install -m 440 -o root -g root /tmp/deploy.sudoers /etc/sudoers.d/deploysudo -l -U deploy | tail -2echo "--- مجاز:"sudo -u deploy sudo -n /usr/bin/touch /var/tmp/deploy.flag && ls -l /var/tmp/deploy.flagecho "--- غیرمجاز (فایل دیگر):"sudo -u deploy sudo -n /usr/bin/touch /var/tmp/other.flagsudo rm -f /var/tmp/deploy.flag /etc/sudoers.d/deploy /tmp/deploy.sudoerssudo userdel -r deploy 2>/dev/null/tmp/deploy.sudoers: parsed OKUser deploy may run the following commands on pc: (root) NOPASSWD: /usr/bin/touch /var/tmp/deploy.flag--- مجاز:-rw-r--r-- 1 root root 0 Oct 3 20:44 /var/tmp/deploy.flag--- غیرمجاز (فایل دیگر):sudo: a password is requiredفایل ساختهشده مالکش root است (دستور با هویت root اجرا شد) و دستور دیگر برای deploy مجاز نیست.
آزمونک
Section titled “آزمونک”UID کاربر root چند است؟
root همیشه UID صفر دارد و هسته برای UID صفر قاعدههای دسترسی را دور میزند.
وقتی sudo رمز میخواهد، رمز چه کسی را باید داد؟
sudo تأیید میکند که خودِ تو پشت کیبورد هستی؛ رمز root لازم نیست (و روی Ubuntu وجود ندارد).
روی Ubuntu برای دادن دسترسی sudo به کاربر dev1 کدام دستور درست است؟
-aG اضافه میکند؛ بدون -a گروههای قبلی کاربر پاک میشوند.
چرا ویرایش /etc/sudoers را با visudo انجام میدهیم؟
غلط تایپی در sudoers قاعدهی خراب را از کار میاندازد و ممکن است دسترسی مدیریتی را از بین ببرد.
کدام قاعده به اصل کمترین دسترسی نزدیکتر است؟
فقط یک دستور مشخص با مسیر کامل؛ ویرایشگر و * و ALL همه راه گرفتن دسترسی کاملاند.
چرا sudo echo x > /etc/file خطا میدهد؟
فقط echo با root اجرا میشود؛ باز کردن فایل مقصد قبل از آن و با هویت تو انجام میشود.
جمعبندی
Section titled “جمعبندی”- root (UID صفر) قاعدههای دسترسی را دور میزند؛ کار روزمره با او خطرناک و بیردپاست.
sudo دستورفقط همان یک دستور را با root اجرا میکند، رمز خودت را میخواهد (چند دقیقه یادش میماند؛sudo -kفراموشش میکند) و هر دستور را با نام تو ثبت میکند.sudo -iشل ورود کامل root است؛su -رمز کاربر مقصد را میخواهد و روی Ubuntu برای root کار نمیکند (رمز قفل است).- دسترسی sudo با عضویت در گروه
sudo(usermod -aG sudo کاربر) یا قاعدهی جدا در/etc/sudoers.d/داده میشود؛sudo -l -U کاربراجازهها را نشان میدهد. - قاعدهها را فقط با
sudo visudo(ترجیحاً-f /etc/sudoers.d/نام، بدون نقطه در نام، دسترسی0440) و باvisudo -cبررسی کن. - اصل کمترین دسترسی: دستور مشخص با مسیر کامل، نه
ALL، نه*، نه ویرایشگر؛NOPASSWDفقط جاهای ایزوله.
| دستور | کاری که میکند |
|---|---|
sudo دستور | یک دستور با root (رمز خودت) |
sudo -u کاربر دستور | اجرا با هویت کاربر دیگر |
sudo -i | شل ورود کامل root (در پایان exit) |
sudo -s | شل root در همان پوشه |
sudo !! | دستور قبلی را دوباره با sudo |
sudo -l / sudo -l -U کاربر | فهرست اجازهها |
sudo -k | پاککردن رمز کششده |
su - کاربر | ورود کامل با رمز آن کاربر |
sudo usermod -aG sudo کاربر | دادن دسترسی sudo (Debian/Ubuntu) |
sudo visudo | ویرایش امن /etc/sudoers |
sudo visudo -f /etc/sudoers.d/نام | ویرایش امن یک فایل جدا |
sudo visudo -c / visudo -cf فایل | بررسی نحو |
grep COMMAND= /var/log/auth.log | ردگیری دستورهای sudo (Debian/Ubuntu) |