آموزش SELinux در CentOS 7 — بخش دوم: فایل ها و پردازش ها
در بخش نخست از این سری از مطالب در مورد SELinux با روش فعالسازی و همچنین غیر فعال کردن برخی از تنظیمات سیاست (policy) با استفاده از مقادیر بولی آشنا شدیم. در بخشِ حاضر در مورد چارچوبهای امنیتی فایلها و پردازشها صحبت خواهیم کرد.
برای این که مباحث مطرح شده در بخش قبلی یادآوری شوند، باید اشاره کنیم که چارچوب امنیتی یک فایل، نوع (type) و چارچوب امنیتی پردازش به صورت دامنه (domain) نامیده میشوند.
- بخش اول این مطلب را میتوانید از طریق این لینک مطالعه کنید: آموزش SELinux در CentOS 7 – بخش اول: مفاهیم پایه
نکته: دستورها، بستهها و فایلهایی که در این راهنما میبینید، روی سیستم عامل Centos 7 تست شدهاند؛ اما مفاهیم کلی در مورد هر یک از توزیعهای دیگر لینوکس نیز برقرار هستند.
در این راهنما دستورها را به صورت کاربر root اجرا میکنیم؛ مگر این که جز این اشاره شده باشد. اگر به حساب کاربری root دسترسی ندارید و از حساب دیگری با دسترسیهای sudo استفاده میکنید، باید در ابتدای دستورهای این راهنما کلیدواژه sudo را اضافه کنید.
ایجاد حسابهای کاربران تست
ابتدا چهار حساب کاربری زیر را برای نمایش ظرفیتهای SELinux ایجاد میکنیم:
- regularuser
- switcheduser
- guestuser
- restricteduser
شما اینک باید با حساب کاربری root وارد سیستم شده باشید. دستورهای زیر را برای اضافه کردن حساب regularuser وارد کنید:
useradd -c "Regular User" regularuser
سپس دستور passwd را برای تغییر رمز عبور اجرا کنید:
passwd regularuser
در خروجی دستور فوق از شما رمز عبور جدید پرسیده میشود. زمانی که رمز عبور را وارد کردید، حساب شما آماده ورود خواهد بود:
Changing password for user regularuser. New password: Retype new password: passwd: all authentication tokens updated successfully.
حسابهای دیگر را نیز ایجاد میکنیم:
useradd -c "Switched User" switcheduser passwd switcheduser useradd -c "Guest User" guestuser passwd guestuser useradd -c "Restricted Role User" restricteduser passwd restricteduser
SELinux برای پردازشها و فایلها
هدف از SELinux ایجاد امنیت برای چگونگی دسترسی پردازشها به فایلها در یک محیط لینوکس است. بدون وجود SELinux یک پردازش یا اپلیکیشن برای مثال daemon آپاچی تحت چارچوب کاربری که آن را آغاز میکند اجرا میشود. بنابراین اگر سیستم شما در معرض یک اپلیکیشن خرابکار قرار داشته باشد که با حساب کاربری root اجرا شده باشد، این اپلیکیشن میتواند هر کاری که دلش میخواهد انجام دهد، زیرا کاربر root به همه فایلها دسترسی کامل دارد.
SELinux تلاش میکند تا یک گام به جلو برداشته و این ریسک را از میان ببرد. در SELinux هر پردازش یا اپلیکیشن تنها به دسترسیهایی که برای کارکرد خود نیاز دارد، دست مییابد و نه چیز بیشتر. سیاست SELinux برای اپلیکیشن تعین میکند که به کدام نوع از فایلها باید دسترسی داشته باشد و به کدام پردازشها میتواند انتقال یابد. سیاست یا policy اساساً مجموعهای از قواعدی است که پردازشها و کاربران را به حقوقشان نگاشت میکند.
بحث در مورد این بخش از مقاله را با بررسی معنی چارچوبها و دامنهها در SELinux آغاز میکنیم.
نخستین بخش از امنیت در سیستم لینوکس برای هر نهاد یک برچسب تعیین میکند. برچسب مانند هر خصوصیت دیگر (مانند مالک، گروه، تاریخ ایجاد و غیره) برای یک فایل با پردازش است و چارچوب منابع را نشان میدهد. ممکن است بپرسید بالاخره منظور از این چارچوب چیست؟ به بیان ساده چارچوب به مجموعهای از امنیت گفته میشود که با اطلاعاتی که به SELinux کمک میکنند تا به تصمیمهای کنترلی دسترسی داشته باشند، مرتبط است. هر چیزی در یک سیستم لینوکسی میتواند چارچوب امنیتی داشته باشد: یک حساب کاربری، یک فایل، دایرکتوری، daemon، یا پورت، همگی میتوانند چارچوبهای امنیتی خاص خود را داشته باشند. با این وجود، چارچوب امنیتی به معنی چیزهای مختلف برای انواع متفاوتی از شیءها است.
چارچوب فایل SELinux
ابتدا با بررسی چارچوبهای فایل SELinux آغاز میکنیم. به خروجی دستور ls –l روی دایرکتوری etc/ توجه کنید:
ls -l /etc/*.conf
این دستور خروجی آشنایی را به ما نشان میدهد:
... -rw-r--r--. 1 root root 19 Aug 19 21:42 /etc/locale.conf -rw-r--r--. 1 root root 662 Jul 31 2013 /etc/logrotate.conf -rw-r--r--. 1 root root 5171 Jun 10 07:35 /etc/man_db.conf -rw-r--r--. 1 root root 936 Jun 10 05:59 /etc/mke2fs.conf ...
می بنید که کاملاً ساده است، اینک یک فلگ –z اضافه میکنیم:
... -rw-r--r--. 1 root root 19 Aug 19 21:42 /etc/locale.conf -rw-r--r--. 1 root root 662 Jul 31 2013 /etc/logrotate.conf -rw-r--r--. 1 root root 5171 Jun 10 07:35 /etc/man_db.conf -rw-r--r--. 1 root root 936 Jun 10 05:59 /etc/mke2fs.conf ...
اکنون ستونهای دیگری از اطلاعات داریم که پس از مالکیت کاربر و گروه آمدهاند:
.. -rw-r--r--. root root system_u:object_r:locale_t:s0/etc/locale.conf -rw-r--r--. root root system_u:object_r:etc_t:s0/etc/logrotate.conf -rw-r--r--. root root system_u:object_r:etc_t:s0/etc/man_db.conf -rw-r--r--. root root system_u:object_r:etc_t:s0/etc/mke2fs.conf ...
این ستون، چارچوبهای امنیتی فایلها را نشان میدهد. زمانی که اطلاعات فوق برای یک فایل وجود داشته باشد، میگوییم این فایل با چارچوبهای امنیتی برچسبگذاری شده است. در ادامه نگاهی دقیقتر به یکی از چارچوبهای امنیتی خواهیم داشت:
-rw-r--r--. root root system_u:object_r:etc_t:s0/etc/logrotate.conf
چارچوب امنیتی این بخش است:
system_u:object_r:etc_t:s0
چهار بخش وجود دارند و هر بخش چارچوب امنیتی به وسیله یک دونقطه (:) از هم جدا میشوند. بخش نخست چارچوب کاربر SELinux برای فایل است. کاربر SELinux را در ادامه بیشتر توضیح خواهیم داد؛ اما اکنون میبینیم که مقدار آن system_u است. هر حساب کاربری لینوکس به یک کاربر SELinux نگاشت شده است و در این مورد کاربر root که مسئول فایل است به کاربر SELinux به نام system_u نگاشت شده است. این نگاشت از سوی سیاست SELinux تعیین میشود.
بخش دوم نقش (role) را در SELinux نشان میدهد که به صورت bject_r است. برای این که در مورد مفهوم نقشها در SELinux بیشتر بدانید، میتوانید به بخش قبلی این سلسله نوشتهها مراجعه کنید.
مهمترین بخش در این مورد بخش سوم است که نوع (type) فایل را نشان میدهد و در این جا به صورت etc_t است. این همان بخشی است که تعیین میکند که فایل یا دایرکتوری به کدام نوع تعلق دارد. میتوانیم ببینیم که اغلب فایلها به نوع etc_t در دایرکتوری etc/ تعلق دارند. به طور فرضی میتوان نوع را به صورت شکلی از گروه یا خصوصیتی برای فایلها در نظر گرفت که روشی برای طبقهبندی آنها محسوب میشود.
همچنین میبینیم که برخی از فایلها به انواع دیگری مانند locale.conf تعلق دارند و نوع آنها به صورت locale_t است. حتی وقتی همه فایلهای فهرست شده دارای مالکیت کاربر و گروه یکسانی باشند، نوع آنها میتواند مختلف باشد.
به عنوان مثال دیگر به بررسی چارچوب نوع دایرکتوریهای home کاربر میپردازیم:
ls -Z /home
دایرکتوریهای home نوع چارچوب مختلفی به صورت user_home_dir_t دارند:
drwx------. guestuser guestuser unconfined_u:object_r:user_home_dir_t:s0 guestuser drwx------. root root system_u:object_r:lost_found_t:s0 lost+found drwx------. regularuser regularuser unconfined_u:object_r:user_home_dir_t:s0 regularuser drwx------. restricteduser restricteduser unconfined_u:object_r:user_home_dir_t:s0 restricteduser drwx------. switcheduser switcheduser unconfined_u:object_r:user_home_dir_t:s0 switcheduser drwx------. sysadmin sysadmin unconfined_u:object_r:user_home_dir_t:s0 sysadmin
چهارمین بخش از چارچوب امنیتی s0 است که به امنیت چند سطحی یا MLS مربوط است. در واقع این یک روش دیگر برای الزام سیاست امنیتی SELinux است و در این بخش حساسیت (s0) را نشان میدهد. در ادامه توضیح مختصری در مورد حساسیت و دستهها خواهیم داد. در اغلب تنظیمات پیشفرض SELinux، سه چارچوب امنیتی نخست مهمترین موارد هستند.
چارچوبهای پردازش SELinux
در این بخش به چارچوبهای امنیتی پردازش میپردازیم. ابتدا از سرویس Apache و SFTP آغاز میکنیم. ما این سرویسها را در بخش نخست این سلسله مطالب نصب کردیم.
service httpd start service vsftpd start
دستور ps را با چند فلگ میتوان اجرا کرد تا مشخص شود که پردازشهای Apache و SFTP روی سرور در حال اجرا هستند:
ps -efZ | grep 'httpd\|vsftpd'
در این مورد نیز فلگ z- برای نمایش چارچوبهای SELinux استفاده میشود. خروجی دستور فوق به کاربر نشان میدهد که پردازش در حال اجرا است و همچنین ID آن و ID پردازش والد نیز مشخص میشود.
system_u:system_r:httpd_t:s0 root 7126 1 0 16:50? 00:00:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 apache 7127 7126 0 16:50? 00:00:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 apache 7128 7126 0 16:50? 00:00:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 apache 7129 7126 0 16:50? 00:00:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 apache 7130 7126 0 16:50? 00:00:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 apache 7131 7126 0 16:50? 00:00:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:ftpd_t:s0-s0:c0.c1023 root 7209 1 0 16:54? 00:00:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 root 7252 2636 0 16:57 pts/0 00:00:00 grep --color=auto httpd\|vsftpd
چارچوب امنیتی این چنین است:
system_u:system_r:httpd_t:s0
چارچوب امنیتی چهار بخش دارد: کاربر، نقش، دامنه و حساسیت. کاربر، نقش و حساسیت کارکردی همانند چارچوبهای فایل دارند که در بخش قبل توضیح داده شد؛ اما دامنه مختص پردازشها است.
در مثال فوق میبینیم که چند پردازش درون دامنه httpd_t اجرا میشوند؛ در حالی که یکی از آنها درون دامنه ftpd_t قرار دارد.
اکنون این سؤال پیش میآید که کارکرد دامنه برای پردازشها چیست؟ پاسخ این است که دامنه یک چارچوب به پردازش میدهد که درون این چارچوب اجرا میشود. درواقع چارچوب مانند حبابی پیرامون پردازش قرار میگیرد که آن را احاطه کرده است. چارچوب تعیین میکند که پردازش چه کار میتواند بکند و چه کاری نمیتواند بکند. این احاطه باعث میشود مطمئن شویم که هر دامنه پردازش میتواند تنها به نوع خاصی از فایلها دسترسی یابد و نه بیشتر.
با استفاده از این مدل، حتی اگر یک پردازش از سوی پردازش یا کاربر خرابکاری مورد سوءاستفاده قرار گیرد، بدترین حالتی که اتفاق میافتد این است که فایلهایی که به آن دسترسی دارد آسیب میبینند. برای نمونه دامنه vsftp به فایلهای در چارچوب sendmail یا samba دسترسی ندارد. این محدودیت در سطح کرنل پیادهسازی شده و به صورت یک سیاست SELinux که در حافظه بارگذاری میشود، الزام شده است و از این رو کنترل دسترسی به فرایندی اجباری تبدیل شده است.
رویههای نامگذاری
پیش از آن که به ادامه این مبحث بپردازیم باید به نکاتی در خصوص رویههای مرسوم نامگذاری اشاره کنیم. کاربران SELinux دارای پسوندی به صورت «_u» هستند، پسوند نقشها به صورت «_r» و انواع (برای فایلها) یا دامنهها (برای پردازشها) دارای پسوندی به صورت «_t» هستند.
پردازشها چگونه به منابع دسترسی مییابند؟
تا به این جا دیدیم که فایلها و پردازشها میتوانند چارچوبهای متفاوتی داشته باشند و این که آنها به انواع و دامنههای خودشان محدود شدهاند. بنابراین یک پردازش چگونه اجرا میشود؟ هر پردازشی برای اجرا نیاز دارد که به فایلهای خود دسترسی داشته باشد و برخی اقداماتی مانند باز کردن، خواندن، تغییر یا اجرا روی آنها اجرا کند. همچنین آموختیم که هر پردازش تنها میتواند به نوعهای خاصی از منابع (فایلها، دایرکتوریها، پورتها و غیره) دسترسی داشته باشد.
SELinux این قواعد دسترسی را در یک سیاست جای داده است. قواعد دسترسی از یک ساختار استاندارد allow statement پیروی میکنند.
allow <domain> <type>:<class> { <permissions> };
قبلاً در مورد دامنهها و نوعها صحبت کردیم. Class تعریف میکند که منابع در عمل نماینده چه چیزی هستند: (فایل، دایرکتوری، پیوند نمادین، دستگاه، پورت، کرسر و غیره).
معنی معمول allow statement به شرح زیر است:
- آیا یک پردازش از نوع دامنه خاصی است یا نه.
- و شیءِ منبعی که تلاش میکند به آن دسترسی یابد از کلاس یا نوع خاصی است یا نه.
- سپس اجازه دسترسی داده میشود.
- در غیر این صورت دسترسی انکار میشود.
برای این که شیوه عملی کارکرد آن را ببینید، فرض کنید چارچوبهای امنیتی زیر برای daemon پردازش httpd روی یک سیستم CentOS 7 در حال اجرا هستند:
system_u:system_r:httpd_t:s0 7126? 00:00:00 httpd system_u:system_r:httpd_t:s0 7127? 00:00:00 httpd system_u:system_r:httpd_t:s0 7128? 00:00:00 httpd system_u:system_r:httpd_t:s0 7129? 00:00:00 httpd system_u:system_r:httpd_t:s0 7130? 00:00:00 httpd system_u:system_r:httpd_t:s0 7131? 00:00:00 httpd
دایرکتوری پیشفرض home برای وبسرور به صورت var/www/html/ است. اینک یک فایل درون این دایرکتوری ایجاد و چارچوب آن را بررسی میکنیم:
touch /var/www/html/index.html ls -Z /var/www/html/*
چارچوب فایل برای محتوای وب ما به صورت httpd_sys_content_t خواهد بود:
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
ما میتوانیم از دستور sesearch برای بررسی نوع دسترسی مجاز برای httpd daemon استفاده کنیم:
sesearch --allow --source httpd_t --target httpd_sys_content_t --class file
فلگ های مورد استفاده برای این دستور تقریباً گویا هستند. دامنه مبدأ به صورت httpd_t است، این همان دامنهای است که Apache روی آن اجرا میشود. ما به منابع هدف که فایلها هستند و چارچوبی از نوع httpd_sys_content_t دارند علاقهمند هستیم. خروجی چیزی مانند زیر خواهد بود:
Found 4 semantic av rules: allow httpd_t httpd_sys_content_t: file { ioctl read getattr lock open }; allow httpd_t httpd_content_type: file { ioctl read getattr lock open }; allow httpd_t httpd_content_type: file { ioctl read getattr lock open }; allow httpd_t httpdcontent: file { ioctl read write create getattr setattr lock append unlink link rename execute open };
به خط اول دقت کنید:
allow httpd_t httpd_sys_content_t: file { ioctl read getattr lock open };
این خط اعلام میکند که httpd daemon (وبسرور آپاچی) دسترسیهای کنترل I/O، خواندن، دریافت خصوصیتها، قفل کردن، و باز کردن فایلهای از نوع httpd_sys_content را دارد. در این مورد فایل index.html ما نیز همین نوع را دارد.
اگر بخواهیم یک گام به جلوتر برویم، میتوانیم ابتدا صفحه وب var/www/html/index.html/ را تغییر داده و محتوای زیر را در آن وارد کنیم:
<html> <title> This is a test web page </title> <body> <h1>This is a test web page</h1> </body> </html>
سپس مجوز پوشه /var/www/ و محتوای آن را تغییر داده و در نهایت httpd daemon را ریاستارت میکنیم:
chmod -R 755 /var/www service httpd restart
اینک از درون مرورگر به این فایل دسترسی داریم:
نکته
بسته به این که سرور شما چگونه راهاندازی شده باشد، ممکن است مجبور شوید پورت 80 را در فایروال IPTables باز کنید تا اجازه ورود ترافیک HTTP از محیط خارج از سرور فراهم شود. در این نوشته قصد نداریم به جزییات فعالسازی پورتها در IPTables بپردازیم. شما میتوانید در مقالات و منابع آموزشی دیگر فرادرس در این خصوص بیشتر مطالعه کنید.
تا به این جا همه چیز خوب پیش رفته است. httpd daemon اجازه دسترسی به نوع خاصی از فایل را دارد و میتوانیم هنگام دسترسی از مرورگر آن را ببینیم. در ادامه سعی میکنیم با تغییر دادن چارچوبهای فایل چیزهای اندکی متفاوت را مشاهده کنیم. ما از دستور chcon به این منظور استفاده میکنیم. فلگ –type برای این دستور امکان تعیین نوع جدیدی از فایل برای منبع مورد نظر را فراهم میسازد. در این بخش نوع فایل را به var_t تغییر میدهیم.
chcon --type var_t /var/www/html/index.html
تغییر نوع را تأیید میکنیم:
ls -Z /var/www/html/
-rwxr-xr-x. root root unconfined_u:object_r:var_t:s0 index.html
سپس هنگام دسترسی به صفحه وب یعنی زمانی که httpd daemon تلاش میکند فایل را بخواند، با یک خطای Forbidden مواجه خواهید شد و یا ممکن است با صفحه پیشفرض Testing 123 در CentOS مواجه شوید.
اینجا چه رخ داده است؟ بدیهی است که یکی از دسترسیها انکار شده است؛ اما آن کدام دسترسی است؟ زمانی که از SELinux استفاده میکنیم، وبسرور تنها مجاز به دسترسی به نوع خاصی از فایلها است و var_t در میان این چارچوبها قرار نمیگیرد. از آنجا که ما چارچوب فایل index.html را به var_t تغییر دادهایم، Apache دیگر نمیتواند آن را بخواند و با خطایی مواجه میشویم.
برای این که همه چیز دوباره به حالت عادی بازگردد، باید نوع فایل را با دستور restorecon تغییر دهیم. سوئیچ –v تغییر برچسب چارچوب را نشان میدهد
restorecon -v /var/www/html/index.html
restorecon reset /var/www/html/index.html context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
اینک اگر تلاش کنیم به آن صفحه وب برویم، دوباره میتوانیم متن «This is a test web page» را مشاهده کنیم.
این مفهوم مهمی است که باید درک کنیم: اطمینان یافتن از این که فایلها و دایرکتوریها چارچوب صحیحی دارند، برای مطمئن شدن از عملکرد صحیح SELinux کاملاً حائز اهمیت است. در انتهای این بخش از نوشته با یک مثال عملی این موضوع را بررسی میکنیم، اما قبل از آن باید به چند نکته دیگر اشاره کنیم.
وراثت چارچوب برای فایلها و دایرکتوریها
SELinux چیزی را الزام میکند که ما آن را «وراثت چارچوب» (context inheritance) مینامیم. منظور از وراثت چارچوب آن است که پردازشها و فایلها درون چارچوب والدهایشان ایجاد میشوند؛ مگر این که بر اساس سیاست دیگری تنظیم شوند.
بنابراین اگر پردازشی به نام «proc_a» داشته باشیم که پردازش دیگری به نام proc_b را ایجاد کند، پردازش دوم در همان دامنه پردازش اول اجرا میشود مگر این که در سیاست SELinux چیز دیگری تعیین شده باشد.
به طور مشابه، اگر یک دایرکتوری با نوع «some_context_t» داشته باشیم، هر فایل یا دایرکتوری که زیر آن ایجاد شود، همان چارچوب نوع را خواهد داشت؛ مگر این که سیاست چیز دیگری بگوید:
برای نمایش این موضوع، چارچوبهای دایرکتوری /var/www/ را بررسی میکنیم:
ls -Z /var/www
دایرکتوری html درون مسیر /var/www/ چارچوبی از نوع httpd_sys_content_t دارد. همان طور که قبلاً دیدیم، فایل index.html درون آن چارچوب مشابهی دارد، یعنی از چارچوب والدش استفاده میکند:
drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
این وراثت زمانی که فایلها به مکان دیگری کپی شوند، حفظ نمیشود. در یک عملیات کپی، فایل یا دایرکتوری کپی شده معمولاً چارچوب مکان مقصد خود را میگیرد. در قطعه کد زیر ما فایل index.html با چارچوب نوع httpd_sys_content_t را به دایرکتوری /var/ کپی میکنیم:
cp /var/www/html/index.html /var/
اگر چارچوب فایل کپی شده را بررسی بکنیم، میبینیم که چارچوب دایرکتوری والد کنونی آن به صورت var_t تغییر یافته است:
ls -Z /var/index.html -rwxr-xr-x. root root unconfined_u:object_r:var_t:s0/var/index.html
این تغییر یافتن چارچوب را میتوان با اشاره به بند --preserver=context در دستور cp لغو کرد.
زمانی که فایلها یا دایرکتوریها جابهجا میشوند، چارچوبهای اصلی حفظ میشوند. در دستور زیر ما فایل var/index.html/ را به دایرکتوری /etc/ جابهجا میکنیم:
mv /var/index.html /etc/
زمانی که چارچوب فایل جابهجا شده را بررسی کنیم، میبینیم که چارچوب var_t در دایرکتوری /etc/ حفظ میشود:
ls -Z /etc/index.html -rwxr-xr-x. root root unconfined_u:object_r:var_t:s0/etc/index.html
شاید از خود بپرسید چرا باید در مورد چارچوبهای فایلها نگران باشیم؟ چرا مفهوم کپی و جابجایی مهم هستند؟ تصور کنید میخواهید همه فایلهای HTML وبسرور خود را به دایرکتوری جداگانهای زیر پوشه root انتقال دهید. این کار به منظور تسهیل فرایند پشتیبانگیری و همچنین افزایش امنیت صورت میگیرید، چون نمیخواهید هیچ هکری به راحتی فایلهای وبسایت را حدس بزند. بدین منظور باید کنترل دسترسی دایرکتوری را بهروزرسانی کنید و فایلهای پیکربندی وب را برای اشاره به موقعیت جدید تغییر دهید. همچنین باید سرویس را ریاستارت کنید؛ اما ممکن است همچنان کار نکند. اینک اگر به چارچوبهای دایرکتوری و فایلهای آن نگاه کنید، میتوانید متوجه ریشه مشکل شوید. در ادامه این سناریو را به صورت عملی اجرا میکنیم:
SELimnux در عمل: تست کردن یک خطای چارچوب فایل
ابتدا یک دایرکتوری به نام www در دایرکتوری root ایجاد میکنیم. همچنین پوشهای به نام html زیر www میسازیم.
mkdir -p /www/html
اگر دستور ls –z را اجرا کنیم میبینیم که این دایرکتوریها با چارچوب default_t اجرا شدهاند:
ls -Z /www/
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 html
سپس محتوای دایرکتوری var/www/html/ را به www/html/ کپی میکنیم:
cp /var/www/html/index.html /www/html/
فایل کپی شده دارای چارچوب default_t است. این چارچوب دایرکتوری والد است.
اینک فایل httpd.conf را برای اشاره به دایرکتوری جدید به عنوان پوشه root وبسایت ویرایش میکنیم. همچنین باید حق دسترسی به این دایرکتوری را نیز ایجاد کنیم.
vi /etc/httpd/conf/httpd.conf
کد برای ریشه سند را از حالت کامنت خارج میکنیم و سپس دایرکتیو جدیدی به نام DocumentRoot برای www/html/ اضافه میکنیم:
# DocumentRoot "/var/www/html" DocumentRoot "/www/html"
همچنین بخش حق دسترسی را برای ریشه سند موجود از حالت کامنت خارج کرده و بخش جدیدی اضافه میکنیم:
#<Directory "/var/www"> # AllowOverride None # Allow open access: # Require all granted #</Directory> <Directory "/www"> AllowOverride None # Allow open access: Require all granted </Directory>
ما موقعیت دایرکتوری cgi-bin را چنان که هست رها میکنیم. در این جا نمیخواهیم وارد جزییات پیکربندی Apache بشویم و صرفاً میخواهیم سایتمان به منظور استفاده از SELinux کار کند.
در نهایت httpd daemon را ریاستارت میکنیم:
service httpd restart
زمانی که سرور ریاستارت شود، دسترسی به صفحه وب همان خطای 403 که قبلاً شاهد بودیم را نشان میدهد.
این خطا به این دلیل رخ میدهد که چارچوب فایل index.html در طی عملیات کپی تغییر یافته است. بنابراین باید چارچوب آن را دوباره به چارچوب اصلی یعنی httpd_sys_content_t بازگردانیم؛ اما این کار چگونه امکانپذیر است؟
تغییر و بازیابی چارچوبهای فایل SELinux
در نمونه کد قبلی دو دستور برای تغییر دادن محتوای فایل میبینیم: chcon و restorecon. اجرای chcon یکی معیار موقت محسوب میشود. میتوان از آن برای ایجاد تغییر موقت در چارچوب یک فایل یا دایرکتوری به منظور عیبیابی خطاهای انکار دسترسی استفاده کرد، با این وجود، این روش تنها موقت است و تغییر برچسب یک سیستم فایل یا اجرای دستور restorecon باعث میشود که فایل به چارچوب اولیه خود بازگردد.
ضمناً اجرای chcon نیازمند اطلاع از چارچوب صحیح برای فایل است؛ فلگ –type چارچوبی برای فایل هدف تعیین میکند. restorecon به تعیین این مورد نیاز ندارد. اگر دستور restorecon را اجرا کنید، چارچوب صحیح فایل مجدداً اعمال میشود و تغییرات دائمی خواهند بود.
اما اگر چارچوب صحیح فایل را ندانید، سیستم چگونه میتواند بداند که هنگام اجرای دستور restorecon باید از کدام چارچوب استفاده کند؟
SELinux به طور سنتی چارچوب هر فایل یا دایرکتوری را در سرور میداند. در CentOS 7، چارچوبهای فایل که از قبل در سیستم قرار دارند در فایل etc/selinux/targeted/contexts/files/file_contexts/ نگهداری میشوند. این یک فایل بزرگ است و نوع همه فایلهای مرتبط با همه اپلیکیشنهای مورد پشتیبانی از سوی توزیع لینوکس در آن فهرست شده است. چارچوبهای فایلها و دایرکتوریهای جدید در فایل etc/selinux/targeted/contexts/files/file_contexts.local ثبت شدهاند. بنابراین هنگامی که دستور restorecon را اجرا میکنید، SELinux به دنبال چارچوب صحیحی از یکی از دو فایل میگردد و آن را در مورد فایل مورد نظر اعمال میکند.
قطعه کد زیر چکیده یکی از این فایلها را نشان میدهد:
cat /etc/selinux/targeted/contexts/files/file_contexts
... /usr/(.*/)?lib(/.*)? system_u:object_r:lib_t:s0 /opt/(.*/)?man(/.*)? system_u:object_r:man_t:s0 /dev/(misc/)?agpgart-c system_u:object_r:agp_device_t:s0 /usr/(.*/)?sbin(/.*)? system_u:object_r:bin_t:s0 /opt/(.*/)?sbin(/.*)? system_u:object_r:bin_t:s0 /etc/(open)?afs(/.*)? system_u:object_r:afs_config_t:s0 ...
برای تغییر دائمی چارچوب فایل index.html در مسیر /www/html، باید از یک فرایند دو مرحلهای استفاده کنیم.
ابتدا دستور semanage fcontext را اجرا میکنیم. بدین ترتیب چارچوب جدید در فایل etc/selinux/targeted/contexts/files/file_contexts.local/ نوشته میشود؛ اما خود فایل را برچسبگذاری مجدد نمیکند. این کار را برای هر دو دایرکتوری انجام میدهیم:
semanage fcontext --add --type httpd_sys_content_t "/www(/.*)?" semanage fcontext --add --type httpd_sys_content_t "/www/html(/.*)?"
برای این که مطمئن شویم، میتوانیم پایگاه داده چارچوب فایل را بررسی کنیم. دقت کنید که ما از فایل file_contexts.local استفاده میکنیم:
cat /etc/selinux/targeted/contexts/files/file_contexts.local
میبینید که چارچوبها بهروزرسانی شدهاند:
# This file is auto-generated by libsemanage # Do not edit directly. /www(/.*)? system_u:object_r:httpd_sys_content_t:s0 /www/html(/.*)? system_u:object_r:httpd_sys_content_t:s0
سپس دستور restorecon را اجرا میکنیم. بدین ترتیب فایل یا دایرکتوری را با آن چه در گام قبلی برچسبگذاری شده است، مجدداً برچسبگذاری میکنیم:
restorecon -Rv /www
با این کار چارچوب را در سه سطح ریست میکنیم: سطح فوقانی دایرکتوری /www، دایرکتوری /www/html در زیر آن و فایل index.html در دایرکتوری /www/html:
restorecon reset /www context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0 restorecon reset /www/html context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0 restorecon reset /www/html/index.html context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
اکنون اگر تلاش کنیم به صفحه وب دسترسی داشته باشیم، باید آن را به طور صحیحی مشاهده کنیم.
ابزار مفیدی به نام matchpathcon وجود دارد که میتواند به عیبیابی مسائل مرتبط با چارچوب کمک کند. این دستور به دنبال چارچوب کنونی یک منبع میگردد و آن را با آنچه در پایگاه داده چارچوب SELinux فهرست شده مقایسه میکند. اگر تفاوتی وجود داشته باشد، تغییرات مورد نیاز را پیشنهاد میکند. این وضعیت را در فایل www/html/index.html/ بررسی میکنیم. ما از فلگ –V استفاده میکنیم که چارچوب را بررسی میکند:
matchpathcon -V /www/html/index.html
خروجی matchpathcon باید نشان دهد که چارچوب تأیید میشود:
/www/html/index.html verified.
در مورد فایل با برچسبگذاری نادرست، پیامی که در خروجی ظاهر میشود، نشان میدهد که چارچوب باید چگونه باشد:
/www/html/index.html has context unconfined_u:object_r:default_t:s0، should be system_u:object_r:httpd_sys_content_t:s0
انتقال دامنه
تا به اینجا شیوه دسترسی پردازشها به منابع سیستم فایل را مشاهده کردیم. اینک شیوه دسترسی پردازشها به پردازشهای دیگر را بررسی میکنیم.
انتقال دامنه (Domain transition) به وضعیتی اطلاق میشود که یک پردازش چارچوب خود را از یک دامنه به دامنه دیگر تغییر میدهد. برای درک این وضعیت فرض کنید پردازشی به نام proc_a داریم که درون یک چارچوب به نام contexta_t اجرا میشود. با انتقال دامنه، proc_a میتواند یک اپلیکیشن (برنامه یا اسکریپت) به نام app_x را اجرا کند که پردازش دیگری را ایجاد میکند. این پردازش جدید را میتوان proc_b نامید و میتواند درون چارچوب دامنه contextb_t اجرا شود. بدین ترتیب contextb_t به طرز کاملاً مؤثری از طریق app_x به contextb_t انتقال مییابد. از این رو فایل اجرایی app_x به عنوان یک نقطه ورود برای contextb_t عمل میکند. گردش کار را میتوانید در تصویر زیر مشاهده کنید:
حالت انتقال دامنه در SELinux کاملاً متداول است. فرض کنید پردازش vsftpd روی یک سرور در حال اجرا باشد. اگر این پردازش در حال اجرا نباشد، میتوانیم دستور service vsftpd start را برای آغاز daemon اجرا کنیم.
سپس پردازش systemd را در نظر میگیریم. این پردازش والد همه پردازشها محسوب میشود و در واقع جایگزین پردازش اولیه System V شده است که درون چارچوب init_t اجرا میشود:
ps -eZ | grep init
system_u:system_r:init_t:s0 1? 00:00:02 systemd system_u:system_r:mdadm_t:s0 773? 00:00:00 iprinit
این پردازش در دامنه init_t پردازشی با عمر کوتاه است و یک فایل اجرایی باینری به نام /usr/sbin/vsftpd را فراخوانی میکند که چارچوب نوع آن ftpd_exec_t است. زمانی که فایل اجرایی باینری اجرا میشود، به خود vsftpd daemon تبدیل شده و درون دامنه ftpd_t اجرا میشود.
ما میتوانیم چارچوب دامنه فایلها و پردازشها را بررسی کنیم:
ls -Z /usr/sbin/vsftpd
خروجی دستور فوق چنین است:
-rwxr-xr-x. root root system_u:object_r:ftpd_exec_t:s0 /usr/sbin/vsftpd
برای بررسی پردازش:
ps -eZ | grep vsftpd
که خروجی آن چنین است:
system_u:system_r:ftpd_t:s0-s0:c0.c1023 7708? 00:00:00 vsftpd
از این رو این پردازش در دامنه init_t یک فایل باینری با نوع ftpd_exec_t را اجرا میکند. این فایل نیز یک daemon را در دامنه ftpd_t آغاز میکند.
این انتقال چیزی نیست که کاربر یا اپلیکیشن بتواند کنترل کند. این وضعیت در سیاست SELinux تعیین شده که در هنگام بوت شدن، در حافظه بارگذاری میشود. در یک سرور غیر SELinux کاربر میتواند یک پردازش را با سوئیچ کردن به حساب قدرتمندتر و کسب اجازه انجام این کار، اجرا کند. در SELinux چنین دسترسی به وسیله سیاستهای از پیش تعیین شده کنترل میشود و یک دلیل دیگر برای این نکته است که چرا گفته میشود SELinux، «کنترل دسترسی اجباری» (Mandatory Access Control) را پیادهسازی کرده است.
انتقال دامنه در معرض سه قاعده محدود کننده قرار دارد:
- پردازش والد دامنه مبدأ باید مجوز اجرایی برای قرارگیری اپلیکیشن در هر دو دامنه داشته باشد (این نقطه ورود است).
- چارچوب فایل برای اپلیکیشن باید به عنوان یک نقطه ورود (entrypoint) برای دامنه مقصد شناسایی شود.
- دامنه اولیه باید اجازه انتقال به دامنه مقصد را داشته باشد.
با در نظر گرفتن مثال vsftpd daemon در بخش فوق، میتوانیم دستور sesearch را با سوئیچهای مختلفی اجرا کنیم تا ببینیم آیا این daemon در این سه قاعده میگنجد یا نه.
ابتدا دامنه مبدأ init_t باید مجوز اجزایی روی اپلیکیشن ورودی با چارچوب ftpd_exec_t داشته باشد. بنابراین اگر دستور زیر را اجرا کنید:
sesearch -s init_t -t ftpd_exec_t -c file -p execute –Ad
نتیجه نشان میدهد که پردازشهای درون دامنه init_t میتوانند فایلهای چارچوب ftpd_exec_t را خوانده، خصوصیاتشان را دریافت کنند، یا اجرا و باز نمایند:
Found 1 semantic av rules: allow init_t ftpd_exec_t: file { read getattr execute open };
سپس بررسی میکنیم که آیا فایل باینری نقطه ورودی برای دامنه مقصد ftpd_t است یا نه:
sesearch -s ftpd_t -t ftpd_exec_t -c file -p entrypoint –Ad
و واقعاً نیز چنین است:
Found 1 semantic av rules: allow ftpd_t ftpd_exec_t: file { ioctl read getattr lock execute execute_no_trans entrypoint open };
در نهایت دامنه مبدأ init_t باید مجوز انتقال به دامنه مقصد ftpd_t را داشته باشد:
sesearch -s init_t -t ftpd_t -c process -p transition –Ad
همان طور که در ادامه مشاهده میکنید، دامنه مبدأ آن مجوز را دارد:
Found 1 semantic av rules: allow init_t ftpd_t: process transition;
دامنههای نامحدود
زمانی که مفهوم دامنهها را معرفی میکردیم، آن را با یک حباب فرضی مقایسه کردیم که پیرامون چارچوب را احاطه میکند، یعنی چیزی است که تعیین میکند پردازش چه کار میتواند بکند و چه کاری نمیتواند بکند. این همان چیزی است که پردازش ما را محدود میکند.
SELinux پردازشهایی نیز دارد که در دامنههای نامحدود جای میگیرند. همان طور که میتوان تصور کرد پردازشهای نامحدود میتوانند هر نوع دسترسی در سیستم داشته باشند. حتی در این صورت این دسترسی کامل دلخواه نیست، چون دسترسی کامل نیز در سیاست SELinux تعیین شده است.
نمونهای از یک دامنه پردازش نامحدود، unconfined_t است. این همان دامنهای است که کاربران وارد شده به سیستم پردازشهایشان را به صورت پیشفرض روی آن اجرا میکنند. در مورد کاربران و دسترسیهایشان به دامنههای پردازشها در بخشهای بعدی این سری مقالات بیشتر صحبت خواهیم کرد.
سخن پایانی
در این بخش از سلسله مطالب معرفی SELinux مفاهیم بسیار مهمی را در خصوص این موضوع بررسی کردیم. مدیریت چارچوبهای فایل و پردازش، مهمترین نقطه در خصوص پیادهسازی موفقیتآمیز SELinux محسوب میشوند. همین طور که در بخش بعدی این سری مقالات خواهیم دید این پازل یک تکه دیگر به نام کاربر SELinux نیز دارد.
اگر این مطلب برایتان مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آ؛موزشهای لینوکس (Linux)
- آموزش SELinux در CentOS 7 – بخش اول: مفاهیم پایه
- مجموعه آموزشهای شبکههای کامپیوتری
- آموزش سیستم عامل لینوکس (Linux) – مقدماتی
- آموزش مقدماتی مدیریت سرور لینوکس (Linux CentOS)
- گنجینه آموزش های لینوکس (Linux)
==
متشکر از 2 مطلبی که در این خصوص ارائه کردید بسیار کاربردی بود
منتظر تکه دیگر پازل نیز هستیم
با احترام
تشکر از نویسنده گرامی بابت این مطلب مفید استفاده کردم