در این نوشتار در دو قسمت به بررسی فضانامها در لینوکس و جزئیات ایزوله کردن پردازه پرداختهایم. آشنایی با این جزئیات کمک میکند که درک درستتری از کانتینری کردن یک پردازه توسط تکنولوژیهایی مثل داکر داشته باشیم. در قسمت اول این نوشتار فضانامهای uts، pid، mount و network را مورد بررسی قرار دادیم. در این قسمت به بررسی فضانامهای user، ipc، cgroup و time میپردازیم.
فضانام کاربر (user)
این فضانام به پردازهها اجازه میدهد که User ID و Group ID جدا از میزبان داشته باشند. مهمترین مزیتی که این سطح از ایزوله کردن فراهم میکند این است که در داخل کانتینر میتوان کاربر یک root داشت که خارج از کانتینر یک کاربر غیر root باشد. یکی از چالشهای امنیتی کانتینرها دور زدن مکانیزمهای امنیتی (مثلا container escape) و دسترسی به میزبان است. از منظر امنیت این یک ویژگی کلیدی است که اجازه میدهد پردازهی داخل کانتینر که وابسته به کاربر root است اجرا شود ولی حتی اگر به نحوی پردازه بتواند از محیط ایزوله خارج شود سطح دسترسی آن در میزبان کمتر از کاربر root میباشد.
برای آزمایش این ویژگی دستورات زیر را اجرا میکنیم.
|
|
همانطور که میبینیم در فضانام user که ساختیم کاربر دارای شناسهی nobody است و همینطور هیچ capability نیز به آن تخصیص نیافته است.
برای ادامهی کار به pid پردازهی bash در این فضانام نیاز داریم. در اینجا باید یک نگاشت بین شناسهی کاربر در داخل فضانام و داخل میزبان ایجاد کنیم. این نگاشت باید در فایل proc/
|
|
توضیح:
|
|
با توجه به توضیحات موجود در راهنمای user_namespaces در این فایل باید سه مقدار معین شود. مقدار اول مشخص کنندهی شناسهی کاربر در فضانام ایجاد شده میباشد. مقدار دوم مشخص کنندهی شناسهی کاربر در میزبان میباشد و سومین مقدار تعداد شناسهها برای نگاشت را مشخص میکند. به طور خلاصه:
UID-inside-namespace UID-outside-namespace length
برای مثال اگر بخواهیم کاربر milad را به کاربر root در داخل فضانام بایند کنیم باید به ترتیب مقادیر 1000 (شناسهی کاربر milad در میزبان)، 0 (شناسهی کاربر root در فضانام) و 1 (فقط یک نگاشت میخواهیم انجام بدیم).
|
|
مشابه همین نگاشت برای شناسهی گروه (gid) نیز انجام میشود.
|
|
سپس مجددا در ترمینال ایجاد شده در فضانام دستور id را اجرا میکنیم.
|
|
با توجه به خروجی بالا مشاهده میشود که کاربر در داخل فضانام root است و به capabilityها دسترسی دارد و در خارج از فضانام همان کاربر milad با شناسه کاربری 1000 میباشد.
فضانام ارتباط بین پردازهای(IPC)
در سیستمعامل لینوکس دو پردازه میتوانند از طریق حافظهی مشترک یا صف پیام مشترک ([mq_open]https://man7.org/linux/man-pages/man3/mq_open.3.html)) با یکدیگر پیام تبادل کنند. برای اینکار این دو پردازه باید عضو یک فضانام IPC یکسان باشند. از طرفی به طور پیشفرض ما انتظار داریم که پردازههای موجود در کانتینرهای مختلف نتوانند به حافظهی مشترک یکدیگر دسترسی داشته باشند برای همین برای آنها فضانامهای IPC مجزا ایجاد میکنیم.
برای نمونه میبینیم که به صورت پیشفرض کانتینرها در داکر دارای فضانام ipc اختصاصی هستند:
|
|
برای آزمایش فضانام ipc ابتدا یک حافظهی مشترک ایجاد میکنیم سپس با دستور ipcs فهرست ipcهای موجود را بررسی میکنیم:
|
|
سپس با استفاده از unshare یک فضانام ipc ایجاد میکنیم و با دستور ipcs فهرست ipcها را بررسی میکنیم.
|
|
همانطور که مشاهده میکنیم پردازهی موجود در داخل فضانام جدید به فهرست ipcهای موجود در میزبان دسترسی ندارد.
فضانام cgroup
در سیستمعامل منابعی مانند پردازنده (CPU)، حافظهی اصلی (RAM)، پهنایباند شبکه و … به صورت مشترک بین پردازهها استفاده میشود. در این شرایط یک پردازه میتواند به صورت ناعادلانه بخش زیادی از این منابع را تصرف نماید. برای محدود کردن میزان مصرف این منابع توسط پردازهها در سیستمعامل لینوکس قابلیتی به نام control groups یا به اختصار cgroups وجود دارد. با بهرهبرداری از cgroups مدیر سیستم میتواند به صورت دقیق و بهینه بر روی تخصیص و محدود کردن (Resource limiting)، اولویتبندی (Prioritization)، مدیریت (Control) و حسابرسی (Accounting) منابع (زیر سیستمها) کنترل داشته باشد.
تنظیمات cgroupها در قالب یک فایل سیستم مجازی و به صورت سلسله مراتبی نگهداری میشود. این ساختار مشابه اطلاع پردازهها در مسیر proc/ میباشد. در این ساختار سلسله مراتبی میتوان cgroupهای متعددی تعریف کرد که هر کدام از آنها میتواند اطلاعاتی را از پدرش به ارث ببرد. همینطور هر کدام از cgroupها میتواند برای محدود کردن یک یا چند منابع (RAM, CPU, …) تعریف شده باشند.
در لینوکس ۱۲ نوع کنترلر (زیرسیستم) برای cgroup وجود دارد که جزئیات دقیق آنها را میتوانید در اینجا مطالعه کنید. با استفاده از دستور زیر میتوانید فهرست آنها را مشاهده کنید:
|
|
وقتی شما از یک تکنولوژی کانتینری استفاده میکنید به صورت خودکار عملیات لازم و مرتبط با تنظیمات شما اجرا خواهد شد. برای مثال در داکر با استفاده از دستور زیر یک کانتینر ایجاد کنید:
|
|
سپس با استفاده از شناسهی (ID) کانتینر ایجاد شده در داخل مسیر مربوط به cgroupها در داخل سیستم میزبان شناسهی پردازههای مربوط به این cgroup را مشاهده میکنیم. مقدار pid درج شده در این فایل مربوط به پردازهی sleep اجرا شده در داخل کانتینر است.
|
|
با بررسی پردازهها از طریق سیستم میزبان صحت این موضوع را بررسی میکنیم.
|
|
فضانام cgroup برای جلوگیری از دسترسی پردازهها به تنظیمات cgroup یکدیگر میباشد. هر پردازه در فضانام cgroup مسیر ریشهی مختص به خود را خواهد داشت. این جداسازی هم از منظر امنیت جهت جلوگیری از نشت اطلاعات میزبان و هم از منظر صحت عملکرد به دلیل وجود قابلیت ارثبری و عدم تصادم نامها مهم است.
برای بررسی قابلیت فضانام cgroup، یک فضانام از این نوع ایجاد میکنیم سپس محتویات فایل /proc/self/cgroup را در داخل فضانام و داخل ماشین میزبان بررسی میکنیم.
در داخل میزبان:
|
|
در داخل فضانام:
|
|
همانطور که مشاهده میکنیم محتویات این دو فایل متفاوت است.
فضانام time
یکی دیگر از فضانامها در لینوکس که اخیرا در کرنل نسخهی ۵.۶ اضافه شده است فضانام زمان یا time است. با استفاده از این فضانام پردازهها میتوانند مقادیر دلخواهی برای CLOCK_MONOTONIC و CLOCK_BOOTTIME داشته باشد. بنابراین زمان جاری و مقدار uptime میزبان میتواند با پردازهی داخل این فضانام متفاوت باشد. داکر و تکنولوژیهای مشابه آن فعلا از این ویژگی در زمان ایجاد کانتینر استفاده نمیکنند.
برای مثال با استفاده از دستور زیر میتوانید یک کانتینر ایجاد کنید و مقدار uptime را در داخل کانیتنر و میزبان مقایسه کنید.
در داخل کانتینر:
|
|
در داخل میزبان:
|
|
این تفاوت ساعت در داخل کانتینر و میزبان به علت تفاوت timezone میباشد.
جمعبندی
بعد از آشنایی با فضانامها در لینوکس و cgroups حالا درک درستتری از کانتینرها یا کانتینری کردن یک پردازه داریم. الان میدانیم که در داخل یک کانتینر یک پردازه در حال اجرا است که توسط فضانامها ایزوله شده و آستانهی مصرف منابع آنها توسط قابلیت cgroups محدود شده است. تصویر زیر به خوبی نحوهی عملکرد این ویژگیها را نمایش میدهد.
البته باید توجه داشت که همهی این پردازههای کانتینری شده بر روی یک کرنل مشترک اجرا میشوند و مفهوم ایزوله شدن نبست به اجرا در یک ماشین مجازی (virtual machine) به معنای واقعی اینجا رعایت نمیشود که میتواند از منظر امنیت مخاطراتی داشته باشد. برای مثال یک آسیبپذیری یا تنظیمات غیر امن میتواند منجر به خارج شدن از داخل کانتینر شود و در نتیجه دسترسی به تمامی کانتینرها فراهم شود. در نوشتارهای آتی به بررسی این نوع حملات میپردازیم.