<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های میلاد بهاری</title>
        <link>https://virgool.io/feed/@milad_bahari</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-17 03:31:13</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/684767/avatar/ALv894.png?height=120&amp;width=120</url>
            <title>میلاد بهاری</title>
            <link>https://virgool.io/@milad_bahari</link>
        </image>

                    <item>
                <title>پویش امنیتی برنامه‌های کانتینری شده در چرخه‌ی CI/CD</title>
                <link>https://virgool.io/hamravesh/%D9%BE%D9%88%DB%8C%D8%B4-%D8%A7%D9%85%D9%86%DB%8C%D8%AA%DB%8C-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%DA%A9%D8%A7%D9%86%D8%AA%DB%8C%D9%86%D8%B1%DB%8C-%D8%B4%D8%AF%D9%87-%D8%AF%D8%B1-%DA%86%D8%B1%D8%AE%D9%87-%DB%8C-cicd-vm0ig1ft733v</link>
                <description>مقدمهدر روزهای گذشته آسیب‌پذیری‌ Log4Shell (CVE-2021-44228, CVE-2021-45046) در صدر اخبار حوزه‌ی امنیت فناوری اطلاعات بوده است. بسیاری از شرکت‌ها برای شناسایی و رفع این آسیب‌پذیری دچار چالش شده بودند. برای شناسایی این آسیب‌پذیری ابزار‌ها و یک‌خطی‌های (one-liners) مختلفی در دسترس بوده است. ما در هم‌روش برای شناسایی و کمک به مشتریانی که آسیب‌پذیر بوده‌اند از ابزار Trivy استفاده کردیم. در کلاستر‌های هم‌روش به صورت مداوم در بازه‌های زمانی معین کانتینر‌های در حال اجرا توسط Trivy پویش می‌شوند. در این مورد خاص به علت اهمیت این موضوع نتایج آسیب‌پذیری در اختیار مشتریان قرار گرفت. مزایای استفاده از Trivy به جای راه‌کارهای سنتی در بستر کوبرنتیز ما را ترغیب کرد که در یک نوشتار به معرفی Trivy و نحوه‌ی استفاده از آن در چرخه‌ی CI/CD در گیت‌لب بپردازیم.اهمیت اسکن کردن ایمیج‌ها در DevSecOpsیکی از گام‌های ساده در عین حال بسیار اثرگذار در بحث امن‌سازی سیستم‌ها، پویش (scan) آسیب‌پذیری‌های شناخته شده (known vulnerabilities) می‌باشد. بسیاری از اپ‌های کانتینری شده ممکن است بر پایه‌ی یک ایمیج قدیمی ایجاد شده باشند یا همچنین ممکن است در توسعه‌ی آنها از کتابخانه‌هایی استفاده شده باشد که دارای آسیب‌پذیری شناخته شده باشد. در یک برنامه‌ی کانتینری شده یک آسیب‌پذیری در سطح سیستم‌عامل می‌تواند امنیت کل برنامه را زیر سوال ببرد. همچنین یکی از مواردی که اغلب توسط برنامه‌نویس‌ها نادیده گرفته می‌شود پویش آسیب‌پذیری کتابخانه‌های ثالث است که در توسعه‌ی برنامه مورد استفاده قرار می‌گیرد. به همین دلیل لازم است قبل از برپاسازی یک برنامه در محیط عملیاتی از جنبه‌ی امنیت و همچنین انطباق با سیاست‌های خاص (مثلا برنامه‌های حوزه‌ی پرداخت‌ یا پزشکی) مورد پویش قرار بگیرد. در این شرایط با پویش پیوسته برنامه‌ها در زمان ساخت آنها، در چرخه‌ی CI/CD، می‌توان در فاز ساخت ایمیج کانتینر بخشی از آسیب‌پذیری‌ها را شناسایی کرد و از انتشار نسخه‌ی ناامن و برپاسازی آن در محیط عملیاتی جلوگیری کرد. در این نوشتار برای پویش امنیتی ایمیج‌ها به معرفی ابزار Trivy و نحوه‌ی استفاده‌ی آن در چرخه‌ی CI/CD در Gitlab می‌پردازیم.معرفی TrivyTrivy یک ابزار متن باز است که در ابتدا به عنوان یک پروژه‌ی شخصی برای رفع نیازمندی پویش امنیتی ایمیج کانتینرها در بستر کوبرنتیز توسعه داده شد. پس از انتشار نسخه‌های اولیه در کامیونتی‌های متن‌باز به صورت گسترده مورد استقبال قرار گرفت. انتشار Trivy به صورت یک فایل باینری مستقل که وابستگی به هیچ پایگاه داده کتابخانه و یا سیستم‌عامل خاصی ندارد باعث شده که استقرار و بکارگیری آن بسیار ساده و مطلوب شود.Trivy توانایی شناسایی آسیب‌پذیری در سطح ایمیج برنامه‌‌های کانتینری شده، فایل سیستم، مخزن مبتنی بر Git و همچنین فایل‌های تنظیمات (Configuration) را داراست. به طور دقیق‌تر با استفاده از Trivy می‌توان آسیب‌پذیری‌هایی را که در سطح بسته‌های (Package) سیستم‌عامل یا کتابخانه‌‌های یک زبان برنامه‌نویسی وجود دارد را شناسایی کرد.  در تصویر زیر نمای کلی Trivy نمایش داده شده است. منبع: https://aquasecurity.github.io/trivy/v0.17.0/imgs/overview.pngپویشگر‌های امنیتی برای شناسایی آسیب‌پذیری‌ها نیاز دارند که نسخه‌ی بسته‌ها و کتابخانه‌های نصب شده را شناسایی کنند. سپس با استفاده از فهرستی از آسیب‌پذیری‌هایی که در اختیار دارند (مثلا دیتابیس  NVD, Red Hat) بسته‌ها و کتابخانه‌های آسیب‌پذیر را شناسایی و گزارش می‌کنند. برای مثال برای استخراج فهرست بسته‌های موجود در سیستم‌عامل‌ها می‌توانند از مسیرهای /var/lib/dpkg/ یا /lib/apk/db/ اطلاعات لازم را بدست بیاورند. در تصویر زیر یک نمونه از محتویات فایل /var/lib/dpkgstatus نمایش داده شده است. $ grep Package -A9 /var/lib/dpkg/statusاستخراج فهرست و مشخصات بسته‌های نصب شدهاگر ایمیج یک کانتینر به جهت کاهش حجم ایمیج strip شده باشد و اطلاعاتی نظیر اطلاعات فوق از آن حذف شده باشد احتمالا Trivy و سایر پویشگر‌های مشابه در این فاز نمی‌توانند به درستی عمل کنند.  برای استخراج فهرست کتابخانه‌های استفاده شده نیز Trivy از فایل‌های معینی استفاده می‌کند. فهرست این فایل‌ها بر اساس زبان‌های برنامه‌نویسی در این لینک آورده شده است. برای مثال در پایتون فایل‌های Pipfile.lock, poetry.lock و requirements.txt در زمان پویش مخزن یا فایل‌سیستم مورد استفاده قرار می‌گیرد.برای پویش امنیتی ایمیج کانتینر‌ها ابزارهای جایگزین دیگری نظیر Clair, Anchore وجود دارد. در اینجا، اینجا و اینجا مقایسه‌هایی بین این ابزارها صورت گرفته است. غیر از ویژگی‌هایی که در صفحه‌ی معرفی پروژه در گیت‌هاب درج شده است، بر اساس تجربه‌ی ما ویژگی‌های زیر در Trivy قابل توجه است.- ساده بودن استقرار و بکارگیری- سرعت بالا در اجرای پویش- صحت عملکرد و میزان False/Positive کمتر نسبت به ابزارهای مشابه- انطباق با فرآیند CI/CDبررسی قابلیت‌های مهم Trivyدر این قسمت قابلیت‌های مهم Trivy نظیر پویش ایمیج کانتینر، پویش فایل سیستم و پویش تنظیمات ناامن در مانیفیست‌ها را با مثال‌ مرور می‌کنیم. شما هم می‌توانید با نصب کردن Trivy از طریق دستور زیر مثال‌های که در بخش بعدی آورده شده است را امتحان کنید. با اجرای دستور زیر نسخه‌ی ۰.۲۱.۲ بر روی سیستم‌عامل شما نصب خواهد شد.curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.21.2- پویش ایمیج کانتینرهمان‌طور که اشاره کردیم Trivy یک ابزار برای پویش آسیب‌پذیری‌های شناخته شده در ایمیج کانتینرها می‌باشد. برای پویش یک ایمیج می‌توانیم از دستور زیر استفاده کنیم.$ trivy image hub.hamdocker.ir/library/httpd:2.4.43 | jq &amp;quot.Results[].Vulnerabilities[].VulnerabilityID&amp;quot
&amp;quotCVE-2021-33574&amp;quot
&amp;quotCVE-2021-35942&amp;quot
&amp;quotCVE-2020-1751&amp;quot
&amp;quotCVE-2020-1752&amp;quot
...در مثال بالا فهرست آسیب‌پذیری‌های شناخته شده ایمیج httpd نسخه‌ی ۲.۴.۴۳ استخراج شده است. در زمان اجرا می‌توان از سوییچ‌های زیر برای فیلتر کردن پویش استفاده کرد.- استفاده از ignore-unfixed برای نادیده گرفتن آسیب‌پذیری‌هایی که فاقد وصله هستند و تاکنون رفع نشده اند. مثلا:$ trivy  image hub.hamdocker.ir/library/httpd:2.4.43 --ignore-unfixed- فیلتر کردن آسیب‌پذیری‌ها بر اساس شدت با استفاده از severityمثلا:$ trivy  image hub.hamdocker.ir/library/httpd:2.4.43 --severity HIGH,CRITICAL --ignore-unfixed- مشخص کردن یک فهرست برای نادیده گرفتن آسیب‌پذیری‌های خاص در زمان پویش برای اینکار باید در یک فایل به نام .trivyignore شناسه‌ی آسیب‌پذیری‌ها را وارد کنیم. مثلا:$ cat .trivyignore
CVE-2021-33574
CVE-2021-35942
$ trivy  image hub.hamdocker.ir/library/httpd:2.4.43در مثال بالا در زمان پویش، آسیب‌پذیری‌های CVE-2021-33574 و CVE-2021-35942 نادیده گرفته می‌شود. همچنین با استفاده از OPA می‌توانید فیلتر کردن آسیب‌پذیری‌ها را انجام دهد یا بر عکس مثال بالا، تعیین کنید که فقط یک آسیب‌پذیری خاص مثل log4shell در ایمیج‌ها بررسی شود.- فیلتر کردن نمایش و ذخیره کردن خروجی در یک فایل با استفاده از output و formatبه صورت پیش‌فرض Trivy نتیجه‌ی آزمایش را در حالت جدول مانندی در خروجی نمایش می‌دهد. با استفاده از format , output می‌توانید فرمت خروجی را تغییر دهید. مثلا:$ trivy  image hub.hamdocker.ir/library/httpd:2.4.43 --format json --output result.jsonهمچنین با استفاده از فرمت template می‌توانید فرمت خروجی اختصاصی خودتان را بسازید.- پویش فایل سیستمیکی دیگر از قابلیت‌های مهم Trivy امکان پویش فایل سیستم می‌باشد. با استفاده از این قابلیت می‌توان پکیج‌های مورد استفاده در یک پروژه (به جای کانتینر) را مورد پویش قرار داد. برای مثال در پروژه‌ی زیر نسخه‌های آسیب‌پذیر کتابخانه‌های پرکاربرد requests و pillow مورد استفاده قرار گرفته است.محتویات فایل requirements.txt پروژهبا استفاده از دستور زیر پروژه مورد آزمایش قرار گرفته است. Trivy به صورت خودکار فایل requirements.txt را شناسایی و تجزیه می‌کند و سپس اقدام به شناسایی آسیب‌پذیری در پکیج‌ها می‌نماید. مسیر قرار گرفتن فایل requirements.txt و بقیه‌ی فایل‌های مشابه برای Trivy اهمیتی ندارد.$ trivy fs /tmp/vulnerable_appشناسایی آسیب‌پذیری‌های شناخته‌شده در کتابخانه‌های استفاده شده در پروژه از همین ویژگی پویش فایل سیستم می‌توان برای اجرای عملیات پویش در زمان ساخت ایمیج یا در داخل یک کانتینر نیز استفاده کرد. برای مثال یک فایل requirements.txt و  یک Dockerfile با محتویات زیر ایجاد کنید:#requirements.txt
requests==2.6.0#Dockerfile
FROM hub.hamdocker.ir/library/python:3.7-alpine3.11
COPY requirements.txt .
RUN apk add curl \
 &amp;&amp; curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/master/contrib/install.sh | sh -s -- -b /usr/local/bin  &amp;&amp; trivy fs --exit-code 1 --no-progress /سپس با دستور زیر فرایند ساختن (build) ایمیج را فراخوانی کنید:docker build -t test-fs .بعد از اجرای دستور فوق فرایند ساختن ایمیج به علت وجود آسیب‌پذیری در بسته‌های سیستم‌عامل (نسخه‌ی قدیمی Alpine) و همین‌طور آسیب‌پذیری CVE-2018-18074 در کتابخانه‌ی requests با خطا خاتمه می‌باید. در تصاویر زیر این مورد نمایش داده شده است.پویش بسته‌های سیستم‌عامل توسط Trivyپویش کتابخانه‌های معین شده در requirements.txt  توسط Trivy- پویش تنظیمات ناامن (Misconfiguration)توانایی شناسایی misconfiguration در سطح فایل‌های تنظیمات (مانیفست‌های) مربوط به Docker, Kubernetes, Terrafrom و ... قابلیت بسیار مهمی دیگری است که در Trivy پیاده‌سازی شده است. با استفاده از conf می‌توان تنظیمات خطرناک در این فایل‌ها را شناسایی کرد.  برای مثال در زیر مانیفست ساخت یک پاد در Kubernetes نشان داده شده است. در تعریف این پاد دو مورد ناامن استفاده شده است.استفاده از capability خطرناک SYS_ADMIN و حالت privileged در تعریف pod مورد اول استفاده از capability SYS_ADMIN و مورد دوم اجرای کانتینر در حالت privileged می‌باشد. با استفاده از conf در مسیر جاری که فایل تعریف پاد در آن قرار دارد را مورد آزمایش قرار می‌دهیم:$ trivy conf --severity HIGH .شناسایی موارد خطرناک توسط Trivyهمان‌طور که در تصویر بالا مشاهده می‌کنید Trivy فایل‌های موجود در مسیر جاری را تجزیه کرده و نوع آن‌ها را نیز به درستی از نوع مانیفست‌های Kubernetes تشخیص داده و هر دو تنظیم ناامن را نیز شناسایی کرده است. در مسیری که برای پویش تعیین می‌کنیم اگر فایل‌های دیگری نیز وجود داشته باشد Trivy می‌تواند آنها را شناسایی و تحلیل کند. برای تسلط بیشتر بر این قابلیت پیشنهاد می‌کنم مثال‌هایی که در مخزن پروژه آورده شده است را مطالعه کنید. همچنین برای آشنایی با سایر ویژگی‌ها نظیر حالت client/server و همچنین مطالعه‌ی دقیق‌تر راجع به آنها می‌توانید به آخرین نسخه‌ی مستندات پروژه Trivy در اینجا مراجعه کنید.استفاده از Trivy در فرایند CI/CDدر چرخه‌ی توسعه‌ی نرم‌افزار اگر عملیات تست امنیت در گام‌های اولیه‌ی و به صورت مدوام انجام شود اثرگذاری بسیار زیادی خواهد داشت. برای خودکار کردن فرآیند پویش ایمیج کانتینرها می‌توانید در چرخه‌ی CI/CD در زمان ساخت ایمیج‌ها بررسی‌های لازم را انجام دهید. در صورتی که پویش با کشف آسیب‌پذیری همراه بود از انتشار نسخه‌ی ناامن جلوگیری کنید.برای استفاده از Trivy در فرایند CI/CD در Gitlab یا هم‌گیت باید در فایل gitlab-ci.yml پروژه یک فاز برای پویش آسیب‌پذیری‌ها تعریف کنید. در مثال زیر این عملیات در فاز test بعد از build شدن ایمیج و push شدن آن در registry صورت می‌گیرد. stages:
  - build
  - test

build:
  stage: build
  image: docker:stable
  script:
  - export IMAGE=&amp;quotregistry.hamdocker.ir/GROUP_NAME/PROJECT_NAME&amp;quot
  - docker login -u &amp;quot$REGISTRY_USER&amp;quot -p &amp;quot$REGISTRY_PASSWORD&amp;quot &amp;quot$REGISTRY&amp;quot 
  - docker build -t PROJECT_NAME:$CI_COMMIT_SHORT_SHA .
  - docker image tag PROJECT_NAME:$CI_COMMIT_SHORT_SHA $IMAGE:$CI_COMMIT_SHORT_SHA
  - docker image push $IMAGE:$CI_COMMIT_SHORT_SHA

container_scanning:
  stage: test
  image:
    name: hub.hamdocker.ir/aquasec/trivy:latest
    entrypoint: [&amp;quot&amp;quot]
  variables:
    GIT_STRATEGY: none
    TRIVY_USERNAME: &amp;quot$REGISTRY_USER&amp;quot
    TRIVY_PASSWORD: &amp;quot$REGISTRY_PASSWORD&amp;quot
    TRIVY_AUTH_URL: &amp;quot$REGISTRY&amp;quot
    FULL_IMAGE_NAME: registry.hamdocker.ir/GROUP_NAME/PROJECT_NAME:$CI_COMMIT_SHORT_SHA
  script:
    - trivy --version
    # cache cleanup is needed when scanning images with the same tags, it does not remove the database
    - trivy image --clear-cache
    # update vulnerabilities db
    - trivy image --download-db-only --no-progress --cache-dir .trivycache/
    # Builds report and puts it in the default workdir $CI_PROJECT_DIR, so `artifacts:` can take it from there
    - trivy image --exit-code 0 --cache-dir .trivycache/ --no-progress --format template --template &amp;quot@/contrib/gitlab.tpl&amp;quot --output &amp;quotgl-container-scanning-report.json&amp;quot &amp;quot$FULL_IMAGE_NAME&amp;quot
    # Fails on high and critical vulnerabilities
    - trivy image --exit-code 1 --cache-dir .trivycache/ --severity CRITICAL --no-progress &amp;quot$FULL_IMAGE_NAME&amp;quot
  cache:
    paths:
      - .trivycache/
  artifacts:
    when: always
    paths:
      - gl-container-scanning-report.json
    reports:
      container_scanning: gl-container-scanning-report.json
  only:
    refs:
      - masterبرای استفاده از این مثال باید در قسمت variables در تعریف FULL_IMAGE_NAME نام گروه و نام پروژه را وارد کنید. مثلا به صورت زیرFULL_IMAGE_NAME: registry.hamdocker.ir/milad/myapp:$CI_COMMIT_SHORT_SHAپس از اضافه کردن این فاز پس از هر commit در مخزن فرآیند build اجرا می‌شود و بعد از آن در فرآیند test عملیات پویش امنیتی ایمیج کانتینر صورت می‌گیرد. در این فاز بعد از آپدیت کردن دیتابیس Trivy پویش کامل ایمیج صورت می‌گیرد که نتیجه‌ی اجرای آن در فایل gl-container-scanning-report.json ذخیره می‌شود.  در تصویر زیر مشاهده می‌کنیم که فرآیند پویش امنیتی به دلیل وجود آسیب‌پذیری با خطا خاتمه یافته است. در سمت راست در قسمت Job artifact می‌توانید گزارش پویش را دانلود و مشاهده کنید.فرآیند test مربوط به پویش امنیتی با شکست خاتمه یافته استهمچنین گزارش این پویش در بخش Security Dashboard &gt; Vulnerability Report در دسترس می‌باشد. نمایش فهرست آسیب‌پذیری‌های کشف شده در این پروژه در قسمت Vulnerability Reportدر تصویر بالا مشاهده می‌کنیم که آسیب‌پذیری‌های کشف شده در فرآیند CI/CD در قسمت Vulnerability Report آورده شده است که برای افراد دخیل در پروژه قابل پیگیری می‌باشد.همان‌طور که اشاره شد با هربار commit کردن در مخزن این فرآیند اجرا خواهد شد و اگر پروژه دارای آسیب‌پذیری با درجه‌ی CRITICAL باشد، job فعلی با خطا خاتمه می‌یابد و فرآیند deploy صورت نخواهد گرفت.فرآیند test با خطا مواجه شده است.نتیجه‌گیریدر این نوشتار دیدیم که استفاده از ابزار Trivy ساده است و به راحتی می‌توان از آن در توسعه‌ی یک پروژه‌ و فرآیند CI/CD استفاده کرد. بروز بودن این ابزارها و قدرت‌شان در تشخیص پکیج‌ها و وابستگی‌ها در سطح سیستم‌عامل و زبان‌های برنامه‌نویسی بسیار قابل اتکاست، که با بهره‌گیری از آنها بخش زیادی از آسیب‌پذیری‌ها به سرعت در فاز توسعه کشف می‌شوند و از انتشار نسخه‌ی ناامن جلوگیری خواهد شد. در نظر داشته باشید که ممکن است حتی پس از انتشار یک نسخه نیز آسیب‌پذیری‌های در بسته‌ها و کتابخانه‌ها کشف شود. در این شرایط پیشنهاد می‌شود که با خودکار کردن فرآیند تست، به صورت پیوسته در زمان‌های معینی در طول روز همه‌ی کانتینر‌های در حال اجرا در کلاستر را از جنبه‌ی امنیت تست کنید.</description>
                <category>میلاد بهاری</category>
                <author>میلاد بهاری</author>
                <pubDate>Mon, 20 Dec 2021 16:50:24 +0330</pubDate>
            </item>
                    <item>
                <title>فضانام‌ها و ایزوله کردن پردازه‌ها در لینوکس - قسمت ۲</title>
                <link>https://virgool.io/hamravesh/%D9%81%D8%B6%D8%A7%D9%86%D8%A7%D9%85-%D9%87%D8%A7-%D9%88-%D8%A7%DB%8C%D8%B2%D9%88%D9%84%D9%87-%DA%A9%D8%B1%D8%AF%D9%86-%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D9%87-%D9%87%D8%A7-%D8%AF%D8%B1-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-%D9%82%D8%B3%D9%85%D8%AA-%DB%B2-flzi2y0gjewa</link>
                <description>در این نوشتار در دو قسمت به بررسی فضانام‌ها در لینوکس و جزئیات ایزوله کردن پردازه پرداخته‌ایم. آشنایی با این جزئیات کمک می‌کند که درک درست‌تری از کانتینری کردن یک پردازه توسط تکنولوژی‌هایی مثل داکر داشته باشیم. در قسمت اول این نوشتار فضانام‌های uts، pid، mount و network را مورد بررسی قرار دادیم. در این قسمت به بررسی فضانام‌های user، ipc، cgroup و time می‌پردازیم.فضانام کاربر(user)این فضا‌نام به پردازه‌ها اجازه می‌دهد که User ID و Group ID جدا از میزبان داشته باشند. مهم‌ترین مزیتی که این سطح از ایزوله کردن فراهم می‌کند این است که در داخل کانتینر می‌توان کاربر یک root داشت که خارج از کانتینر یک کاربر غیر root باشد. یکی از چالش‌های امنیتی کانتینرها دور زدن مکانیزم‌های امنیتی (مثلا container escape) و دسترسی به میزبان است.  از منظر امنیت این یک ویژگی کلیدی است که اجازه می‌دهد پردازه‌ی داخل کانتینر که وابسته به کاربر root است اجرا شود ولی حتی اگر به نحوی پردازه‌ بتواند از محیط ایزوله خارج شود سطح دسترسی آن در میزبان کم‌تر از کاربر root می‌باشد.برای آزمایش این ویژگی دستورات زیر را اجرا می‌کنیم.$ unshare --user bash
nobody@Milad-PC:/tmp$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
nobody@Milad-PC:/tmp$ capsh --print | grep Current
Current: =همان‌طور که می‌بینیم در فضانام user که ساختیم کاربر دارای شناسه‌ی nobody است و همین‌طور هیچ capability نیز به آن تخصیص نیافته است.برای ادامه‌ی کار به pid پردازه‌ی bash در این فضانام نیاز داریم. در اینجا باید یک نگاشت بین شناسه‌ی کاربر در داخل فضانام و داخل میزبان ایجاد کنیم. این نگاشت باید در فایل proc/&lt;pid&gt;/uid_map/ اعمال شود. برای اینکه بدانیم چه مقادیری وارد شود نیاز است که ساختار آن را بدانیم.nobody@Milad-PC:/tmp$ echo $$
27391$ man user_namespaces... Each line in the uid_map file specifies a 1-to-1 mapping of a range of contiguous user IDs between  two  user  namespaces.   (When  a  user namespace  is first created, this file is empty.)  The specification in each line takes the form of three numbers delimited by white space. The first two numbers specify the starting user ID in each of the two user namespaces.  The third number specifies the length of the mapped range.  
…با توجه به توضیحات موجود در راهنمای user_namespaces در این فایل باید سه مقدار معین شود. مقدار اول مشخص کننده‌ی شناسه‌ی کاربر در فضانام ایجاد شده می‌باشد. مقدار دوم مشخص کننده‌ی شناسه‌ی کاربر در میزبان می‌باشد و سومین مقدار تعداد شناسه‌ها برای نگاشت را مشخص می‌کند. به طور خلاصه:UID-inside-namespace    UID-outside-namespace    lengthبرای مثال اگر بخواهیم کاربر milad را به کاربر root در داخل فضانام بایند کنیم باید به ترتیب مقادیر 1000 (شناسه‌ی کاربر milad در میزبان)، 0 (شناسه‌ی کاربر root در فضانام) و 1 (فقط یک نگاشت می‌خواهیم انجام بدیم).$ id
uid=1000(milad) gid=1000(milad) groups=1000(milad),27(sudo),104(input)
$ sudo echo &#039;0 1000 1&#039; &gt; /proc/31196/uid_mapمشابه همین نگاشت برای شناسه‌ی گروه (gid) نیز انجام می‌شود.$ sudo echo &#039;0 1000 1&#039; &gt; /proc/27391/gid_mapسپس مجددا در ترمینال ایجاد شده در فضانام دستور id را اجرا می‌کنیم.nobody@Milad-PC:/tmp$ id
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
nobody@Milad-PC:/tmp$ cat /proc/self/uid_map
0       1000          1
nobody@Milad-PC:/tmp$ cat /proc/self/gid_map
0       1000          1
nobody@Milad-PC:/tmp$ capsh --print | grep Current
Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+epبا توجه به خروجی بالا مشاهده می‌شود که کاربر در داخل فضانام root است و به capabilityها دسترسی دارد و در خارج از فضانام همان ‌کاربر milad با شناسه کاربری 1000 می‌باشد.فضانام ارتباط بین پردازه‌ای(IPC)در سیستم‌عامل لینوکس دو پردازه‌ می‌توانند از طریق حافظه‌ی مشترک یا صف پیام مشترک (mq_open) با یکدیگر پیام تبادل کنند. برای اینکار این دو پردازه باید عضو یک فضا‌نام IPC یکسان باشند. از طرفی به طور پیش‌فرض ما انتظار داریم که پردازه‌های موجود در کانتینرهای مختلف نتوانند به حافظه‌ی مشترک یکدیگر دسترسی داشته باشند برای همین برای آن‌ها فضانام‌های IPC مجزا ایجاد می‌کنیم.برای نمونه می‌بینیم که به صورت پیش‌فرض کانتینرها در داکر دارای فضانام ipc اختصاصی هستند:$ docker ps --quiet --all | xargs docker inspect --format &#039;{{ .Id }}: IpcMode={{ .HostConfig.IpcMode }}&#039;                        

037ad3a550a7de78ac9a929159b627e765cf753a314f9f4c7f564127b7ac9ccb: IpcMode=private
8676c058096d7337cd497457da25a596f2cc6f317b01d033b2c53329fc6e2619: IpcMode=private
d1704e1cb4f280d5e5afeabb8064526fc09f297183006086354fe443c5359b42: IpcMode=privateبرای آزمایش فضانام ipc ابتدا یک حافظه‌ی مشترک ایجاد می‌کنیم سپس با دستور ipcs فهرست ipcهای موجود را بررسی می‌کنیم:$ ipcmk -M 1000
Shared memory id: 2044428296
$ ipcs
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 2033451008 milad      600        524288     2          dest 
...      
0xaac7b1b4 2044428296 milad      644        1000       0                       
...
0x00000000 849346606  milad      600        524288     2          dest         
------ Semaphore Arrays --------
key        semid      owner      perms      nsems     
0xe93c17d9 131072     milad      666        1         
0xcdbd64db 163841     milad      600        1         سپس با استفاده از unshare یک فضانام ipc ایجاد می‌کنیم و با دستور ipcs فهرست ipcها را بررسی می‌کنیم.$ sudo unshare --ipc /bin/bash                                                                                          root@Milad-PC:~# ipcs
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
------ Semaphore Arrays --------
key        semid      owner      perms      nsems     همان‌طور که مشاهده می‌کنیم پردازه‌ی موجود در داخل فضانام جدید به فهرست ipcهای موجود در میزبان دسترسی ندارد. فضانام cgroupدر سیستم‌عامل منابعی مانند پردازنده (CPU)، حافظه‌ی اصلی (RAM)، پهنای‌باند شبکه و ... به صورت مشترک بین پردازه‌ها استفاده می‌شود. در این شرایط یک پردازه می‌تواند به صورت ناعادلانه بخش زیادی از این منابع را تصرف نماید. برای محدود کردن میزان مصرف این منابع توسط پردازه‌ها در سیستم‌عامل لینوکس قابلیتی به نام control groups یا به اختصار cgroups وجود دارد. با بهره‌برداری از cgroups مدیر سیستم می‌تواند به صورت دقیق و بهینه بر روی تخصیص و محدود کردن (Resource limiting)، اولویت‌بندی (Prioritization)، مدیریت (Control) و حسابرسی (Accounting) منابع (زیر سیستم‌ها) کنترل داشته باشد.تنظیمات cgroupها در قالب یک فایل سیستم مجازی و به صورت سلسله مراتبی نگه‌داری می‌شود. این ساختار مشابه اطلاع پردازه‌ها در  مسیر proc/ می‌باشد. در این ساختار سلسله‌ مراتبی می‌توان cgroup‌های متعددی تعریف کرد که هر کدام از آن‌ها می‌تواند اطلاعاتی را از پدرش به ارث ببرد. همین‌طور هر کدام از cgroupها می‌تواند برای محدود کردن یک یا چند منابع (RAM, CPU, ...) تعریف شده باشند. منبع: https://twitter.com/b0rk/status/1214341831049252870در لینوکس ۱۲ نوع کنترلر (زیرسیستم) برای cgroup وجود دارد که جزئیات دقیق آن‌ها را می‌توانید در اینجا مطالعه کنید. با استفاده از دستور زیر می‌توانید فهرست آن‌ها را مشاهده کنید:$ cat /proc/cgroups                                                                                                            #subsys_name	hierarchy	num_cgroups	enabled
cpuset	9	2	1
cpu	10	94	1
cpuacct	10	94	1
blkio	3	94	1
memory	4	132	1
devices	12	95	1
freezer	5	2	1
net_cls	8	2	1
perf_event	7	2	1
net_prio	8	2	1
hugetlb	11	2	1
pids	2	102	1
rdma	6	1	1وقتی شما از یک تکنولوژی کانتینری استفاده می‌کنید به صورت خودکار عملیات لازم و مرتبط با تنظیمات شما اجرا خواهد شد. برای مثال در داکر با استفاده از دستور زیر یک کانتینر ایجاد کنید:$ docker run -d --cpus=&amp;quot1.0&amp;quot --memory=&amp;quot1g&amp;quot hub.hamdocker.ir/library/alpine sleep 6000                                           bdd23fa5e49a88476f711a75e55a4ad5bd0d52fb3469a4c9d75b3f1e40a84cd1 سپس با استفاده از شناسه‌ی (ID) کانتینر ایجاد شده در داخل مسیر مربوط به cgroupها در داخل سیستم میزبان شناسه‌ی پردازه‌‌های مربوط به این cgroup را مشاهده می‌کنیم. مقدار pid درج شده در این فایل مربوط به پردازه‌ی sleep اجرا شده در داخل کانتینر است. $ cat /sys/fs/cgroup/devices/docker/bdd23fa5e49a88476f711a75e55a4ad5bd0d52fb3469a4c9d75b3f1e40a84cd1/tasks
29881با بررسی پردازه‌ها از طریق سیستم میزبان صحت این موضوع را بررسی می‌کنیم.$ ps -eaf | grep 29881                                                                                                       
root     29881 29849  0 02:07 ?        00:00:00 sleep 6000
milad    29954  7914  0 02:08 pts/1    00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn 29881فضانام cgroup برای جلوگیری از دسترسی پردازه‌ها به تنظیمات cgroup یکدیگر می‌باشد.  هر پردازه در فضانام cgroup مسیر ریشه‌ی مختص به خود را خواهد داشت. این جداسازی هم از منظر امنیت جهت جلوگیری از نشت اطلاعات میزبان و هم از منظر صحت عملکرد به دلیل وجود قابلیت ارث‌بری و عدم تصادم نام‌ها مهم است.برای بررسی قابلیت فضانام cgroup، یک فضانام از این نوع ایجاد می‌کنیم سپس محتویات فایل /proc/self/cgroup را در داخل فضانام و داخل ماشین میزبان بررسی می‌کنیم.در داخل میزبان: $ cat /proc/self/cgroup                                                                                                   
12:devices:/user.slice
11:hugetlb:/
10:cpu,cpuacct:/user.slice
9:cpuset:/
8:net_cls,net_prio:/
7:perf_event:/
6:rdma:/
5:freezer:/
4:memory:/user.slice
3:blkio:/user.slice
2:pids:/user.slice/user-1000.slice/session-2.scope
1:name=systemd:/user.slice/user-1000.slice/session-2.scope0::/user.slice/user-1000.slice/session-2.scopeدر داخل فضانام:$ sudo unshare --cgroup /bin/bash                                                                                              root@Milad-PC:/proc/7914# cat /proc/self/cgroup
12:devices:/
11:hugetlb:/
10:cpu,cpuacct:/
9:cpuset:/
8:net_cls,net_prio:/
7:perf_event:/
6:rdma:/
5:freezer:/
4:memory:/
3:blkio:/
2:pids:/
1:name=systemd:/
0::/همان‌طور که مشاهده می‌کنیم محتویات این دو فایل متفاوت است.فضانام timeیکی دیگر از فضانام‌ها در لینوکس که اخیرا در کرنل نسخه‌ی ۵.۶ اضافه شده است فضانام زمان یا time است. با استفاده از این فضانام پردازه‌ها می‌توانند مقادیر دلخواهی برای CLOCK_MONOTONIC و CLOCK_BOOTTIME داشته باشد. بنابراین زمان جاری و مقدار uptime میزبان می‌تواند با پردازه‌ی داخل این فضانام متفاوت باشد. داکر و تکنولوژی‌های مشابه آن فعلا از این ویژگی در زمان ایجاد کانتینر استفاده نمی‌کنند. برای مثال با استفاده از دستور زیر می‌توانید یک کانتینر ایجاد کنید و مقدار uptime را در داخل کانیتنر و میزبان مقایسه کنید.در داخل کانتینر:$ docker run --rm -it hub.hamdocker.ir/library/alpine sh                                                                        
/ # uptime
 23:03:49 up 1 day, 13:16,  load average: 1.11, 0.74, 0.63در داخل میزبان:$ uptime                                                                                                                       
02:34:01 up 1 day, 13:17,  4 users,  load average: 1.02, 0.74, 0.64این تفاوت ساعت در داخل کانتینر و میزبان به علت تفاوت timezone می‌باشد.جمع‌بندیبعد از آشنایی با فضانام‌ها در لینوکس و cgroups حالا درک درست‌تری از کانتینر‌ها یا کانتینری کردن یک پردازه داریم. الان می‌دانیم که در داخل یک کانتینر یک پردازه‌ در حال اجرا است که توسط فضانام‌ها ایزوله شده و آستانه‌ی مصرف منابع آن‌ها توسط قابلیت cgroups محدود شده است. تصویر زیر به خوبی نحوه‌ی عملکرد این ویژگی‌ها را نمایش می‌دهد. منبع: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/overview_of_containers_in_red_hat_systems/introduction_to_linux_containersالبته باید توجه داشت که همه‌ی این پردازه‌های کانتینری شده بر روی یک کرنل مشترک اجرا می‌شوند و مفهوم ایزوله شدن نبست به اجرا در یک ماشین مجازی (virtual machine) به معنای واقعی اینجا رعایت نمی‌شود که می‌تواند از منظر امنیت مخاطراتی داشته باشد. برای مثال یک آسیب‌پذیری یا تنظیمات غیر امن می‌تواند منجر به خارج شدن از داخل کانتینر شود و در نتیجه دسترسی به تمامی کانتینرها فراهم شود. در نوشتارهای آتی به بررسی این نوع حملات می‌پردازیم.</description>
                <category>میلاد بهاری</category>
                <author>میلاد بهاری</author>
                <pubDate>Sun, 07 Mar 2021 13:25:07 +0330</pubDate>
            </item>
                    <item>
                <title>فضانام‌ها و ایزوله کردن پردازه‌ها در لینوکس - قسمت اول</title>
                <link>https://virgool.io/hamravesh/%D9%81%D8%B6%D8%A7%D9%86%D8%A7%D9%85-%D9%87%D8%A7-%D9%88-%D8%A7%DB%8C%D8%B2%D9%88%D9%84%D9%87-%DA%A9%D8%B1%D8%AF%D9%86-%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D9%87-%D9%87%D8%A7-%D8%AF%D8%B1-%D9%84%DB%8C%D9%86%D9%88%DA%A9%D8%B3-erxh3dvb0ek2</link>
                <description>در این نوشتار می‌خواهیم چگونگی ایزوله کردن یک پردازه در سیستم‌عامل لینوکس را بررسی کنیم. اگر با Docker یک کانتینر ایجاد کرده باشید، در زمان کار با آن احساس کرده‌اید که داخل آن مشابه محیط یک ماشین مجازی است. مثلاً متوجه شده‌اید که از دید یک پردازه‌ی در حال اجرا در داخل کانتینر، فهرست پردازه‌ها، شبکه و فایل‌سیستم با ماشین میزبان متفاوت است، همچنین میزان منابعی مانند RAM و CPU از دید پردازه‌های داخل کانتینر محدودتر از کل مقدار در اختیار میزبان می‌باشد. این سطح از ایزوله ‌کردن در سیستم‌عامل لینوکس توسط ویژگی‌های namespace (فضانام)، cgroups، pivot_root و ... پیاده‌سازی می‌شود. ایزوله کردن پردازه‌ها موضوع کلیدی در مورد نحوه‌ی عمل‌کرد کانتینرها می‌باشد. فضا‌نام‌ها منابعی را به کانتینر اختصاص می‌دهند که کاملاً مستقل از میزبان (host) و بقیه‌ی کانتینر‌های مجاور می‌باشد.این نوشتار در دو قسمت تنظیم شده است که در ادامه قسمت اول آن را می‌خوانید. قسمت دوم این مطلب را می‌توانید از اینجا دنبال کنید.فضا‌نام‌ها (namespaces) در لینوکسفضانام یک ابزار برای محدود کردن دید پردازه‌ها نسبت به ماشین میزبان است. در kernel لینوکس فضانام‌های مختلفی وجود دارد که استفاده از هر کدام از آن‌ها اجازه می‌دهد یک پردازه در همان فضانام (مثلا شبکه) دید مختص به خود را داشته باشد. مثلاً دو پردازه‌ی در حال اجرا در میزبان می‌توانند فایل سیستم مشترکی داشته باشند ولی دید آن‌ها نسبت به کارت شبکه و تنظیمات آن متفاوت باشد و احساس کنند در دو شبکه‌ی مجزا قرار دارند. به خاطر همین سطح از ایزوله کردن، فضانام‌ها یکی از ابزارهای کلیدی برای کانتینری کردن برنامه‌ها هستند. منبع: https://twitter.com/b0rk/status/1240364585766576128در سیستم‌عامل لینوکس فضانام‌های زیر وجود دارد:Unix Time Sharing (uts)Process ID (pid)Mount (mnt)Network (net)User ID - Group ID (user)Inter-process communications (ipc)Control groups (cgroup)Time   برای مشاهده فضانام‌های موجود در سیستم‌عامل می‌توانید از دستور lsns استفاده کنید.$ sudo lsns
NS TYPE   NPROCS   PID USER             COMMAND
4026531835 cgroup    405     1 root             /sbin/init splash
4026531836 pid       354     1 root             /sbin/init splash
4026531837 user      361     1 root             /sbin/init splash
4026531838 uts       397     1 root             /sbin/init splash
4026531839 ipc       397     1 root             /sbin/init splash
4026531840 mnt       385     1 root             /sbin/init splash
4026532009 net       353     1 root             /sbin/init splash
...به صورت پیش‌فرض در ماشین میزبان از هر نوع فضانام یک مورد وجود دارد که توسط پردازه‌ها مورد استفاده قرار می‌گیرد. پردازه‌ها می‌توانند فضانام‌های بیشتری از نو‌ع‌های مختلفی ایجاد کنند و به آن متصل شوند. البته هر پردازه فقط می‌تواند در یک فضانام از یک نوع باشد. همچنین در صورتی که فضانام خالی باشد (مثلا هیچ‌ پردازه‌ای به آن متصل نشده باشد یا هیچ bind mount در آن وجود نداشته باشد و ...) کرنل به صورت خودکار آن را حذف می‌کند. در ادامه به بررسی فضانام‌ها می‌پردازیم.Unshare چیست؟در فضای سیستم‌عامل وقتی شما درخواست اجرای یک برنامه را صادر می‌کنید، سیستم‌عامل با اجرای یک سری روال‌ها و سپس کپی‌کردن کد برنامه در حافظه‌ی اصلی (رم) یک پردازه‌ی جدید ایجاد می‌کند و به اصطلاح آن برنامه را اجرا می‌کند. در این فضا دو مفهوم پدر (parent) و فرزند (child) وجود دارد که به صورت پیش‌فرض با هم داده‌های مشترکی دارند (برای اطلاعات بیشتر به fork و  clone مراجعه کنید). برای ایزوله‌ کردن پردازه‌ها و حذف این نقاط مشترک می‌توان از یک systemcall به نام unshare استفاده کرد. در ‌واقع با استفاده از unshare می‌توان یک برنامه را با فضانام‌هایی مختص به خودش که با پدرش  یا دیگر پردازه‌های در حال اجرا مشترک نباشد، اجرا نمود.اگر علاقه‌مند هستید جزئیات بیشتری بدانید راجع به set_ns ،clone ،nsenter و pivot_root مطالعه کنید.فضانام UTSهر ماشین دارای یک شناسه‌ است که به آن hostname گفته می‌شود. درست مانند URL هر وب‌سایت از این شناسه می‌توان برای اشاره به آن ماشین در داخل آن ماشین یا شبکه استفاده کرد. اگر یک ترمینال بر روی سیستم‌عامل لینوکس باز کنید با استفاده از دستور hostname می‌توانید مقدار hostname فعلی را ببینید:$ hostname
Milad-PCبا قرار دادن یک پردازه در یک فضانام UTS اختصاصی، پردازه صاحب hostname و domainname اختصاصی خواهد شد و می‌توان مقادیر دلخواهی برای hostname و domainname برای آن پردازه تنظیم کرد که این تغییر تاثیری در مقادیر مربوطه در ماشین میزبان نخواهد داشت.تکنولوژی‌های کانتینری‌کردن (مانند داکر) به هر کانتینر یک شناسه‌ی تصادفی اختصاص می‌دهند که به صورت پیش‌فرض همین شناسه به عنوان hostname در آن کانتینر استفاده می‌شود. برای بررسی این موضوع با استفاده از دستور زیر می‌توان یک کانتینر ایجاد کرد و مقدار hostname داخل کانتینر را مشاهده نمود.$ docker run --rm -it --name hostname-test hub.hamdocker.ir/library/alpine sh
/ # hostname
a6b9c92876b7با استفاده از unshare می‌توانیم یک فضانام جدید UTS ایجاد کنیم و این مورد را آزمایش کنیم. برای اینکار باید unshare را با دسترسی کاربر root اجرا کنیم. در زمان فراخوانی unshare نوع فضانام و نام‌ برنامه‌ای که می‌خواهیم اجرا کنیم را باید وارد کنیم. در صورتی که نام برنامه وارد نشود به صورت پیش‌فرض از مقدار {SHELL}$ استفاده خواهد شد.$ sudo unshare --uts /bin/bash
root@Milad-PC:~# hostname
Milad-PC
root@Milad-PC:~# hostname xyz-hostname
root@Milad-PC:~# hostname
xyz-hostname
root@Milad-PC:~# exit
exit
$ hostname
Milad-PCاین کار باعث شده که bash داخل یک پردازه‌ی جدید که فضانام UTS مختص به خودش را دارد اجرا شود. هر برنامه‌ای که در این شل اجرا شود نیز این فضانام را به ارث خواهد برد. برای مثال همان‌طور که در بالا می‌بینید با اجرای hostname ابتدا همان مقدار تنظیم شده در ماشین میزبان نمایش داده می‌شود، سپس با تنظیم یک مقدار جدید، hostname در این فضانام تغییر می‌کند ولی در میزبان تغییر اعمال نشده است. این ایزوله کردن باعث می‌شود که میزبان و مهمان بدون تأثیر بر روی همدیگر مقادیر hostname را به مقداری دلخواه تغییر دهند.فضانام شناسه‌ی پردازه‌ها(PID)اگر شما دستور ps را داخل یک کانتینر اجرا کنید فقط پردازه‌های در حال اجرا در همان کانتینر را می‌بینید و به فهرست پردازه‌های در حال اجرا در ماشین میزبان دسترسی نخواهید داشت.$ docker run --rm -it --name pid-test hub.hamdocker.ir/library/alpine sh
/ # ps -eaf
PID   USER     TIME  COMMAND
1 root      0:00 sh
7 root      0:00 ps -eafدر ‌واقع با بهره‌برداری از فضانام PID قابلیت محدود کردن امکان دسترسی به پردازه‌های در حال اجرا در میزبان برای کانتینرها با ایزوله کردن فهرست شناسه‌ی پردازه‌ها فراهم می‌شود. برای آزمایش فضانام PID مجدداً از unshare استفاده می‌کنیم:$ sudo unshare --pid sh
# id
uid=0(root) gid=0(root) groups=0(root)
# id
sh: 2: Cannot fork
# ls
sh: 3: Cannot fork
# id
sh: 4: Cannot forkاگه به خروجی دستورات بالا دقت کنید به نظر مشکلی وجود دارد. به غیر از دستور اول، بقیه دستور‌ها با خطا مواجه شده‌اند. اگه به متن خطا دقت کنید قالب آن از چپ به راست به صورت نام دستور، شناسه‌ی پردازه و متن خطا می‌باشد. با اجرای‌ هر دستور، شناسه‌‌ی پردازه‌ها در حال افزایش است و این نشان دهنده‌ی  اعمال ‌شدن فضانام PID است، اما اگر نتوان بیش از یک پردازه در این فضانام اجرا کرد، کاملاً بلااستفاده باقی می‌ماند. متن خطای دریافتی و همچنین توضیحات unshare نشان می‌دهند که:$ man unshare
-f, --fork
Fork  the  specified  program as a child process of unshare rather than running it directly.  This is useful when creating a new PID namespace.پس با استفاده از fork-- پردازه‌ی جدید مستقیماً به صورت یک فرزند از unshare اجرا خواهد شد. حال مجدداً یک فضانام PID  ایجاد می‌کنیم. با اجرای چند دستور مشاهده می‌کنیم خطای قبل رفع شده است:$ sudo unshare --pid --fork /bin/bash
root@Milad-PC:/tmp# id
uid=0(root) gid=0(root) groups=0(root)
root@Milad-PC:/tmp# cat /etc/hostname
Milad-PCسپس برای فهرست کردن پردازه‌های موجود در فضانام جدید از دستور ps استفاده می‌کنیم:root@Milad-PC:/tmp# ps -eaf
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 فوریه18 ? 00:00:09 /sbin/init splash
root         2     0  0 فوریه18 ? 00:00:00 [kthreadd]
root         4     2  0 فوریه18 ? 00:00:00 [kworker/0:0H]
...
root      6210  9375  0 02:02 pts/2    00:00:00 sudo unshare --pid --fork /bin/bash
root      6211  6210  0 02:02 pts/2    00:00:00 unshare --pid --fork /bin/bash
root      6212  6211  0 02:02 pts/2    00:00:00 /bin/bash
root      6421  6212  0 02:03 pts/2    00:00:00 ps -eaf
…
milad     7089     1  0 فوریه18 ? 00:00:06 /lib/systemd/systemd --user
milad     7090  7089  0 فوریه18 ? 00:00:00 (sd-pam)
milad     8536  8426  1 فوریه18 tty2 01:24:19 /usr/lib/chromium-browser/chromium-browser --type=renderer --field-trial-handle=1178073432432703370
milad    10327  7677  0 فوریه18 pts/1 00:00:11 /usr/bin/zshاگر در یک کانتینر ایجاد شده مثلاً با داکر دستور ps را وارد کنید فقط پردازه‌های موجود در همان کانتینر را مشاهده خواهید کرد. با توجه به خروجی دستور ps شاید این‌طور به نظر برسد که فضانام PID جدید به درستی پردازه‌ی جدید را ایزوله نکرده و پردازه‌ی جدید به فهرست پردازه‌های در حال اجرا در میزبان دسترسی دارد اما در‌ واقع این‌طور نیست. فهرست پردازه‌های میزبان به این علت در دسترس است که دستور ps اطلاعات را از روی فایل‌های موجود در مسیر proc/ می‌خواند و پردازش می‌کند. اگه از مسیر proc/ در میزبان ls بگیرید فهرستی از دایرکتوری‌ها را مشاهده خواهید کرد که متناظر با پردازه‌های در حال اجرا در سیستم‌عامل می‌باشد که در داخل آن‌ها اطلاعات کامل پردازه‌ها به صورت فهرستی از فایل‌ها وجود دارد.$ ls /proc
1      132    1483   1943   2052   239    2566   272    321   4510  513   540   6635  7433  7575  817   9136           fs           pagetypeinfo
…برای اینکه در فضانام جدید دستور ps فقط اطلاعات پردازه‌های موجود در همین فضانام را برگردانند باید یک مسیر proc/ مجزا برای همین فضانام وجود داشته باشد که کرنل اطلاعات پردازه‌های موجود در آن را مدیریت کند که برای پیاده‌سازی آن می‌توان از chroot استفاده کرد.در زمان ایجاد یک کانتینر به طور پیش‌فرض به جای دسترسی کامل به فایل‌سیستم میزبان، پردازه‌ها به بخش کوچکی از فایل سیستم دسترسی خواهند داشت، چون درست بعد از ایجاد کانتینر دایرکتوری root برای پردازه‌ی اصلی داخل کانتینر تغییر می‌کند. در سیستم‌عامل لینوکس این عملیات با استفاده از chroot انجام می‌شود.در توضیحات chroot اشاره شده است که chroot یک دستور یا shell را در دایرکتوری جدید اجرا می‌کند و همچنین اگر دستوری وارد نشود به صورت پیش‌فرض از مقدار متغیر SHELL$ استفاده خواهد کرد.$ man chroot
NAME
chroot - run command or interactive shell with special root directory
…
If no command is given, run &#039;&amp;quot$SHELL&amp;quot -i&#039; (default: &#039;/bin/sh -i&#039;).برای درک بهتر این فرآیند دستورات زیر را اجرا می‌کنیم:$ mkdir /tmp/new_root_dir
$ sudo chroot /tmp/new_root_dir
chroot: failed to run command ‘/usr/bin/zsh’: No such file or directory
$ sudo chroot /tmp/new_root_dir id
chroot: failed to run command ‘id’: No such file or directory
$ sudo chroot /tmp/new_root_dir ls
chroot: failed to run command ‘ls’: No such file or directoryبا توجه به متن‌ خطا به نظر می‌رسد که بعد از تغییر دایرکتوری root دسترسی به برنامه‌های موجود در دایرکتوری bin/ امکان‌پذیر نیست. بنابراین حتی امکان استفاده از دستوراتی مثل ls و id فراهم نیست. بنابراین تمامی فایل‌‌های مورد نیاز، باید به دایرکتوری جدید انتقال داده شود؛ کاملاً مشابه زمانی که یک کانتینر واقعی ایجاد می‌شود. یک کانتینر از روی یک image ایجاد می‌شود که آن image حاوی تمامی فایل‌هایی است که پردازه‌های موجود در آن کانتینر به آن نیاز دارند. در‌ واقع آن image دقیقاً حاوی فایل‌سیستمی است که پردازه‌ها آن را می‌بینند.بنابراین اگر ما فایل‌سیستم یک سیستم‌عامل کوچک مثل Alpine Linux را داشته باشیم‌ می‌توانیم به آن chroot کنیم و آن را در فضانام جدید اجرا کنیم. برای انجام این کار دستورات زیر را اجرا می‌کنیم که ابتدا یک دایرکتوری جدید ایجاد می‌شود، سپس آخرین نسخه‌ی فعلی فایل‌سیستم را دانلود و استخراج می‌کنیم.$ mkdir alpine
$ cd alpine
$ curl -o alpine.tar.gz http://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.0-x86_64.tar.gz
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
Dload  Upload   Total   Spent    Left  Speed
100 2664k  100 2664k    0     0  15768      0  0:02:53  0:02:53 --:--:-- 18207
$ tar -xzf alpine.tar.gz
$ ls
alpine.tar.gz  bin  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
$ rm -rf alpine.tar.gzسپس با chroot در این دایرکتوری می‌توانیم دستورات را در مسیر جدید اجرا کنیم.$ cd ..
$ sudo chroot alpine ls
bin    dev    dst    etc    home   lib    media  mnt    opt    proc   root   run    sbin   src    srv    sys    tmp    usr    var ...با اتمام اجرای پردازه (یا دستور) فرزند، مجدداً کنترل به پردازه‌ی پدر برمی‌گردد. برای اینکه بتوانیم دستورات بیشتری در دایرکتوری جدید اجرا کنیم می‌توانیم یک شل را به عنوان پردازه‌ی فرزند اجرا کنیم.$ sudo chroot alpine sh
/ # id
uid=0(root) gid=0(root) groups=0(root)
/ # ls
bin    dev    dst    etc    home   lib    media  mnt    opt    proc   root   run    sbin   src    srv    sys    tmp    usr    var
/ # exitحالا با بهره‌برداری از قابلیت chroot و فضانام‌ها می‌توانیم یک فضانام PID ایجاد کرده و در زمان فراخوانی unshare دستور chroot را اجرا کنیم و سپس در داخل فضانام دایرکتوری proc/ فایل‌سیستم (image) را mount کنیم. با انجام این گام‌ها یک قدم در ایزوله کردن پردازه‌های داخل کانتینر برداشته می‌شود و جزئیات پردازه‌های میزبان از دید پردازه‌های در حال اجرا در فضانام مخفی خواهد بود. برای آزمایش این موضوع دستورات زیر را اجرا می‌کنیم:$ sudo unshare --pid --fork chroot alpine sh
/ # mount -t proc proc proc
/ # ps -eaf
PID   USER     TIME  COMMAND
1 root      0:00 sh
3 root      0:00 ps -eafفضانام Mountبرای اینکه پردازه‌های داخل یک کانتینر به فایل سیستم میزبان دسترسی نداشته باشد، باید بین آن‌ها مرزی ایجاد شود. با استفاده از فضانام mount می‌توان این قابلیت را برای پردازه‌ها فراهم کرد.برای مثال در زیر ما در یک فضانام mount جدید یک bind mount ایجاد می‌کنیم. Bind mounts این قابلیت را فراهم می‌کند که بخشی از یک فایل سیستم که قبلاً mount شده را در یک دایرکتوری دیگه مجدداً mount کنید. با بهره‌برداری از این قابلیت می‌شود عملیات مختلفی مثل اشتراک گذاری فقط خواندنی، chroot jail یا کانتینری کردن را پیاده‌سازی کرد.$ sudo unshare --mount /bin/bash
root@Milad-PC:~# mkdir src
root@Milad-PC:~# echo &amp;quotsample&amp;quot &gt; src/test.txt
root@Milad-PC:~# ls src
test.txt
root@Milad-PC:~# mkdir dst
root@Milad-PC:~# ls dst
root@Milad-PC:~# mount --bind src dst
root@Milad-PC:~# ls dst
test.txt
root@Milad-PC:~# cat dst/test.txt
sampleهمان‌طور که می‌بینیم بعد از اعمال bind محتوای دایرکتوری src در dst نیز در دسترس است. با استفاده از findmnt می‌توانیم جزئیات بیشتری را ببینیم که این mount در این فضانام ایجاد شده است و از دید میزبان مخفی می‌باشد.root@Milad-PC:~# findmnt dst
TARGET          SOURCE                FSTYPE OPTIONS
/home/milad/dst /dev/sda5[/milad/src] ext4   rw,relatime,data=orderedبرای مثال در یک ترمینال دیگر در میزبان و خارج از این فضانام همین دستور را اجرا می‌کنیم.$ findmnt dstحالا اگر همین دستور findmnt را در فضانام ساخته شده مجدداً بدون پارامتر اجرا کنیم فهرست کاملی از mountهای میزبان را مشاهده خواهیم کرد. همان‌طور که در مورد فضانام PID اشاره کردیم، انتظار داریم این موارد از دید یک کانتینر مخفی شده باشد. مشابه شناسه‌ی پردازه‌ها کرنل از مسیر proc/ID/mounts/ اطلاعات مربوط به mountهای هر پردازه را می‌خواند. بنابراین وقتی که یک پردازه با یک فضانام اختصاصی ایجاد کنیم ولی همچنان از مسیر proc/ میزبان استفاده کند، پردازه می‌تواند به اطلاعات میزبان دسترسی داشته باشد.برای ایزوله کردن یک پردازه‌ نیاز است که ساخت یک فضانام جدید همراه با ایجاد یک فایل‌سیستم root و یک proc mount انجام شود.$ sudo unshare --mount chroot alpine sh
/ # ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
/ # mount -t proc proc proc
/ # mount
proc on /proc type proc (rw,relatime)
/ # mkdir src
/ # echo &amp;quotsample&amp;quot &gt; src/test.txt
/ # mkdir dst
/ # mount --bind src dst
/ # ls dst
test.txt
/ # cat dst/test.txt
sample
/ # mount
proc on /proc type proc (rw,relatime)
/dev/sda1 on /dst type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/ #به طور مشابه وقتی شما یک دایرکتوری در سیستم میزبان را در یک کانتینر mount می‌کنید (مثلاً در داکر: docker run -v path_in_host:path_in_container) ابتدا فایل‌سیستم root کانتینر در محل مناسب قرار می‌گیرد. سپس دایرکتوری مقصد در کانتینر ایجاد شده و در نهایت دایرکتوری مبدأ در مقصد bind mount می‌شود.فضانام شبکه (Network)یکی دیگر از سطوح ایزوله کردن، مربوط به فضای شبکه می‌باشد. فضانام شبکه به پردازه‌ها اجازه می‌دهد که دید اختصاصی نسبت به کارت شبکه و جدول مسیریابی داشته باشند.با استفاده از دستور زیر می‌توان یک فضانام شبکه ایجاد کرد.$ sudo unshare –net /bin/bashبا استفاده از دستور lsns و تعیین نوع net می‌توانیم جزئیات فضانام ایجاد شده را ببینیم. شناسه‌ی پردازه را به خاطر بسپارید.root@Milad-PC:/tmp# lsns -t net
NS TYPE NPROCS   PID USER  COMMAND
...
4026532516 net       2  5268 root  /bin/bash
...به صورت پیش‌فرض وقتی که یک پردازه را در فضانام شبکه‌ی مختص به خودش قرار می‌دهیم، فقط یک کارت شبکه loopback دارد.root@Milad-PC:~# ip a
1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00برای اینکه پردازه‌ی در حال اجرا در کانتینر بتواند انتقال داده داشته باشد باید یک کارت شبکه‌ی مجازی ایجاد کنیم که مثل دو سر یک کابل شبکه عمل می‌کند. در‌ واقع فضانام شبکه‌ی اختصاصی ایجاد شده برای پردازه را به فضانام شبکه میزبان (پیش‌فرض) متصل می‌کند. برای این کار در یک ترمینال دیگر دستور زیر را وارد می‌کنیم:$ ip link add myeth1 netns 5268 type veth peer name myeth2 netns 1اگر بخواهیم دستور بالا را به زبان ساده بیان کنیم، ip link add اعلام می‌کند که می‌خواهیم یک اتصال ایجاد کنیم که در فضانام مربوط به پردازه‌ی ۵۲۶۸ یک کارت شبکه‌ی مجازی به اسم myeth1 ایجاد کند و آن را به فضانام پردازه‌ی ۱ وصل کند و نام کارت شبکه‌ی مجازی را myeth2 تنظیم کند. حالا اگر در یک ترمینال در میزبان و همچنین در داخل فضانام جدید فهرست کارت شبکه‌ها را بررسی کنیم این دو کارت شبکه را خواهیم دید.در داخل فضانام شبکه‌ی جدید:root@Milad-PC:/tmp# ip a
1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: myveth1@if18: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 5e:f7:93:bf:19:80 brd ff:ff:ff:ff:ff:ff link-netnsid 0در داخل میزبان:$ ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 
…
18: myveth2@if2: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether ea:4d:95:01:8c:db brd ff:ff:ff:ff:ff:ff link-netnsid 1در حالت فعلی هر دو کارت شبکه‌ی جدید در وضعیت Down هستند و برای اینکه امکان انتقال داده فراهم شود باید وضعیت هر دو کارت به Up تغییر کند و به آن‌ها آدرس IP تخصیص داده شود.در ترمینال میزبان:$ sudo ip link set myveth2 up
$ sudo ip addr add 192.168.30.100/24 dev myveth2
$ ip a s myveth2
18: myveth2@if2: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000 link/ether ea:4d:95:01:8c:db brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet 192.168.30.100/24 scope global myveth2 valid_lft forever preferred_lft foreverدر فضانام جدید:$ sudo ip link set myveth1 up
$ sudo ip addr add 192.168.30.101/24 dev myveth1
$ ip a s myveth1 
2: myveth1@if18: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 5e:f7:93:bf:19:80 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.30.101/24 scope global myveth1valid_lft forever preferred_lft foreverهمان‌طور که اشاره کردیم با ایجاد یک فضانام شبکه، جدول مسیر‌یابی و کارت شبکه‌ها ایزوله خواهد شد و پردازه‌ی موجود در کانتینر به اطلاعات میزبان دسترسی نخواهد داشت.root@Milad-PC:/tmp# ip route 
192.168.30.0/24 dev myveth1 proto kernel scope link src 192.168.30.101حالا هم در ترمینال ماشین میزبان و هم در فضانام جدید می‌توانیم اتصال را تست کنیم. در ترمینال ماشین میزبان این دستور را اجرا کنید:$ ping 192.168.30.101
PING 192.168.30.101 (192.168.30.101) 56(84) bytes of data.
64 bytes from 192.168.30.101: icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from 192.168.30.101: icmp_seq=2 ttl=64 time=0.079 ms
^C
--- 192.168.30.101 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1020ms
rtt min/avg/max/mdev = 0.043/0.061/0.079/0.018 msهمین‌طور در فضانام:root@Milad-PC:/tmp# ping 192.168.30.100
PING 192.168.30.100 (192.168.30.100) 56(84) bytes of data.
64 bytes from 192.168.30.100: icmp_seq=1 ttl=64 time=0.078 ms
64 bytes from 192.168.30.100: icmp_seq=2 ttl=64 time=0.100 ms
^C
--- 192.168.30.100 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1015ms
rtt min/avg/max/mdev = 0.078/0.089/0.100/0.011 msمطابق خروجی بالا می‌بینیم که اتصال بین دو طرف برقرار شده است. در قسمت اول با فضانام‌های uts، pid، mount و network آشنا شدیم. در قسمت دوم این نوشتار فضانام‌های user، ipc، cgroup و time را مورد بررسی قرار داده‌ایم.</description>
                <category>میلاد بهاری</category>
                <author>میلاد بهاری</author>
                <pubDate>Tue, 02 Mar 2021 13:04:26 +0330</pubDate>
            </item>
            </channel>
</rss>