برنامه نویسی

Docker Container Security Best Practices

Docker Container Security Best Practices

14 دقیقه زمان برای خواندن این مطلب نیاز است.


جدول محتوا


داکر انقلابی در نحوه توسعه، تحویل و اجرای برنامه‌ها ایجاد کرده است. اما با قدرت بزرگ، مسئولیت بزرگ هم همراه است. کانتینرها به دلیل ماهیت سبک و اشتراک کرنل میزبان، سطح حمله جدیدی معرفی می‌کنند که اگر به درستی مدیریت نشود، می‌تواند فاجعه‌بار باشد. آیا می‌دانستید که یک کانتینر با دسترسی root می‌تواند به راحتی به کل سیستم میزبان نفوذ کند؟ یا اینکه ایمیج‌های عمومی از Docker Hub ممکن است حاوی بدافزار یا آسیب‌پذیری‌های شناخته شده باشند؟

در این راهنمای جامع، تمام جنبه‌های امنیت کانتینرهای داکر را پوشش می‌دهیم. از ساخت ایمیج‌های امن گرفته تا پیکربندی runtime، شبکه، ذخیره‌سازی و نظارت. این بهترین روش‌ها حاصل تجربه تیم‌های امنیتی و توسعه‌دهندگان حرفه‌ای در سطح جهان است. اگر از داکر در محیط تولید استفاده می‌کنید یا قصد دارید شروع کنید، این مقاله را از دست ندهید.

آموزش Node js برای مبتدیان

Docker Container Security Best Practices

امنیت کانتینر چیست و چرا با امنیت سنتی تفاوت دارد؟

در محیط مجازی‌سازی سنتی، هر ماشین مجازی کرنل و فضای کاربری جداگانه دارد. این انزوا بسیار قوی است اما سنگین. در مقابل، کانتینرها از کرنل مشترک میزبان استفاده می‌کنند و فقط فضای کاربری خود را ایزوله می‌کنند. این یعنی یک نقص امنیتی در کرنل میزبان، یا یک اشتباه در پیکربندی کانتینر، می‌تواند به فرار از کانتینر (container breakout) و دسترسی به کل سیستم منجر شود.

علاوه بر این، کانتینرها معمولاً با سرعت بالا جابه‌جا می‌شوند، از رجیستری‌های عمومی دانلود می‌گردند، و توسط ابزارهای orchestration مثل Kubernetes مدیریت می‌شوند. این پویایی، سطح حمله را چند برابر می‌کند. بنابراین امنیت کانتینر باید در تمام چرخه حیات آن – از ساخت ایمیج تا اجرا و نظارت – پیاده شود.

تفاوت بین TypeScript و JavaScript


بخش اول: امنیت در مرحله ساخت ایمیج

ایمیج، بسته قابل حمل برنامه شماست. اگر ایمیج ناامن باشد، مهم نیست که محیط runtime چقدر خوب محافظت می‌شود.

از ایمیج‌های پایه معتبر و به‌روز استفاده کنید

هرگز از تگ latest استفاده نکنید. تگ latest به سرعت تغییر می‌کند و نمی‌توانید مطمئن باشید چه نسخه‌ای در حال اجراست. همیشه از تگ‌های دقیق مثل python:3.11-slim-bullseye استفاده کنید. همچنین از ایمیج‌های رسمی و تأیید شده در Docker Hub استفاده کنید. ایمیج‌های رسمی توسط تیم داکر یا خود توسعه‌دهندگان اصلی اسکن می‌شوند و آسیب‌پذیری کمتری دارند.

برای کاهش سطح حمله، تا حد امکان از ایمیج‌های minimals استفاده کنید. مثلاً alpine یا slim به جای ایمیج کامل ubuntu. این کار نه تنها امنیت را بالا می‌برد، بلکه حجم ایمیج را هم کاهش می‌دهد.

اسکن آسیب‌پذیری ایمیج‌ها

قبل از اینکه ایمیج را به رجیستری بفرستید یا در تولید اجرا کنید، حتماً آن را از نظر آسیب‌پذیری‌های شناخته شده اسکن کنید. ابزارهای معروف عبارتند از:

  • docker scan (که از Snyk استفاده می‌کند)
  • Trivy (محبوب و متن‌باز)
  • Clair (قدیمی اما قدرتمند)
  • Grype

این ابزارها لایه‌های ایمیج را بررسی کرده و بسته‌های نصب شده را با پایگاه داده آسیب‌پذیری‌ها (مثل NVD یا CVE) مقایسه می‌کنند. اسکن را در خط لوله CI/CD خود ادغام کنید تا هرگز ایمیج ناامن منتشر نشود.

کمینه کردن لایه‌ها و حذف ابزارهای غیرضروری

هر دستور RUN در Dockerfile یک لایه جدید ایجاد می‌کند. چندین دستور جداگانه را با && ترکیب کنید تا لایه‌ها کاهش یابد. همچنین بعد از نصب بسته‌ها، حتماً کش پکیج منیجر را پاک کنید. مثلاً برای apt:

dockerfile

RUN apt-get update && apt-get install -y --no-install-recommends curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

هرگز ابزارهایی مثل compilers, debuggers, یا package managers را در ایمیج نهایی نگه ندارید. اگر برای کامپایل نیاز دارید، از multi-stage builds استفاده کنید. در مرحله آخر، فقط فایل‌های باینری لازم را کپی کنید.

از کاربر root استفاده نکنید

به طور پیش‌فرض، کانتینرها با کاربر root اجرا می‌شوند. اگر مهاجمی بتواند به کانتینر نفوذ کند، با root دسترسی کامل به منابعی که به کانتینر mount شده و حتی به برخی قابلیت‌های کرنل خواهد داشت. در Dockerfile، یک کاربر غیراختصاصی بسازید:

dockerfile

RUN addgroup --system appgroup && adduser --system --no-create-home --ingroup appgroup appuser
USER appuser

برای برنامه‌هایی که نیاز به پورت پایین (مثل ۸۰) دارند، می‌توانید بعداً در زمان اجرا پورت را map کنید (مثلاً 8080:80) یا از قابلیت cap_net_bind_service استفاده کنید.

لایه‌های غیرقابل تغییر و پیمایش (Distroless)

ایمیج‌های Distroless (مثل gcr.io/distroless/static) فقط شامل برنامه و وابستگی‌های runtime هستند، بدون پوسته، package manager، یا هر ابزار دیگری. این کار سطح حمله را به شدت کاهش می‌دهد. اما اشکال آن این است که نمی‌توانید به کانتینر متصل شده و دستور بزنید. برای debug باید از ابزارهای جانبی مثل kubectl exec با کانتینر debugger استفاده کنید.

فریمورک React چیست و چرا باید آن را یاد بگیریم


بخش دوم: امنیت در زمان اجرا (Runtime)

حتی اگر ایمیج کاملاً امن باشد، نحوه اجرای کانتینر می‌تواند آسیب‌پذیری ایجاد کند.

از محدودیت‌های منابع استفاده کنید

یک کانتینر سرکش می‌تواند تمام CPU یا حافظه میزبان را مصرف کند و باعث خرابی سایر کانتینرها شود. هنگام اجرا، از --memory و --cpus استفاده کنید:

bash

docker run --memory="512m" --cpus="1.0" myapp

در docker-compose یا Kubernetes هم می‌توانید limits و requests تعریف کنید.

پرایولج (Privileged) را هرگز فعال نکنید

فلاگ --privileged به کانتینر تمام قابلیت‌های root روی میزبان را می‌دهد. این معادل اجرای داکر با دسترسی root روی خود میزبان است. حتی برای کارهایی که فکر می‌کنید نیاز به دسترسی بالا دارید، به دنبال جایگزین باشید. مثلاً به جای --privileged برای دسترسی به دستگاه، از --device استفاده کنید.

قابلیت‌های لینوکس (Linux Capabilities) را محدود کنید

داکر به طور پیش‌فرض فقط subset امن از قابلیت‌های لینوکس را به کانتینر می‌دهد. اما می‌توانید با --cap-drop قابلیت‌های پیش‌فرض را حذف کنید و با --cap-add فقط موارد ضروری را اضافه کنید. بهترین روش: تمام قابلیت‌ها را drop کنید و فقط یکی یکی اضافه کنید:

bash

docker run --cap-drop=ALL --cap-add=NET_ADMIN myapp

namespace‌های کاربر (User Namespace) را فعال کنید

با فعال کردن user namespace، می‌توانید کاربر root داخل کانتینر را به یک کاربر غیرپریویلیج روی میزبان map کنید. برای فعال کردن، باید دیمون داکر را با --userns-remap=default راه‌اندازی کنید. این کار یک لایه امنیتی قوی اضافه می‌کند.

سیستم فایل را فقط خواندنی (Read-Only) mount کنید

اگر کانتینر نیازی به نوشتن فایل در سیستم فایل خود ندارد (و اغلب برنامه‌ها همینطور هستند)، لایه writable را حذف کنید. با --read-only اجرا کنید:

bash

docker run --read-only myapp

برای مناطقی که نیاز به نوشتن دارند (مثل /tmp یا /var/log)، از volumeهای درون حافظه (tmpfs) استفاده کنید.

جاوااسکریپت چیست و چه کاربردی دارد


بخش سوم: امنیت شبکه و ارتباطات

کانتینرها باید فقط به آنچه نیاز دارند دسترسی داشته باشند.

از شبکه‌های ایزوله استفاده کنید

به جای استفاده از شبکه پیش‌فرض bridge، شبکه‌های مجزا تعریف کنید و کانتینرهای مرتبط را در یک شبکه قرار دهید. کانتینرهایی که به اینترنت نیاز ندارند را در شبکه‌ای بدون دروازه (internal) قرار دهید.

هرگز پورت‌های دیمون داکر را در معرض اینترنت قرار ندهید

سوکت داکر (/var/run/docker.sock) را به کانتینر mount نکنید مگر در موارد بسیار خاص (مثل ابزارهای نظارتی مجاز). اگر کانتینر به سوکت داکر دسترسی داشته باشد، می‌تواند هر دستوری روی میزبان اجرا کند – معادل root کامل.

از TLS برای ارتباط با داکر دیمون استفاده کنید

اگر نیاز به دسترسی remote به داکر دیمون دارید (مثلاً از CI/CD)، حتماً از TLS با گواهی‌های معتبر استفاده کنید و احراز هویت را فعال کنید. هرگز پورت 2375 را بدون رمزگذاری باز نکنید.

محدود کردن دسترسی خروجی با فایروال

یک کانتینر مخرب می‌تواند از کانال خروجی برای برقراری ارتباط با سرورهای فرماندهی و کنترل (C2) یا استخراج داده استفاده کند. از پروفایل‌های شبکه (مثل Calico یا Cilium در Kubernetes) یا ابزارهای مثل iptables برای محدود کردن ترافیک خروجی استفاده کنید.

بهترین زبان برنامه نویسی برای شروع در ۲۰۲۵


بخش چهارم: مدیریت اسرار (Secrets) و متغیرهای محیطی

رمزهای عبور، توکن‌های API و کلیدهای SSH را هرگز در Dockerfile یا متغیرهای محیطی ساده قرار ندهید.

از Secrets مدیریت شده استفاده کنید

در Swarm یا Kubernetes، از سیستم secrets داخلی استفاده کنید. برای docker-compose، از فایل‌های secrets استفاده کنید (با secrets در docker-compose.yml). برای اجرای ساده، می‌توانید رمزها را از فایل بخوانید:

bash

docker run --env-file=secrets.env myapp

اما مطمئن شوید فایل secrets.env به درستی محافظت می‌شود (مثلاً از ansible-vault یا git-crypt استفاده کنید).

متغیرهای محیطی را در لاگ‌ها پنهان کنید

بسیاری از برنامه‌ها (مثل وب سرورها) ممکن است متغیرهای محیطی را در لاگ ارورها یا صفحات خطا چاپ کنند. مطمئن شوید برنامه شما این کار را نمی‌کند. در داکر، می‌توانید با --log-driver محدودیت‌هایی اعمال کنید.

آموزش کامل برنامه نویسی پایتون از صفر تا صد


بخش پنجم: پاکسازی و نگهداری مداوم

امنیت یک فرآیند یکباره نیست.

ایمیج‌های بلااستفاده و کانتینرهای متوقف شده را حذف کنید

ایمیج‌های قدیمی و آسیب‌پذیر، حتی اگر اجرا نشوند، فضای دیسک اشغال می‌کنند و ممکن است به اشتباه دوباره استفاده شوند. به طور مرتب اجرا کنید:

bash

docker system prune -a --volumes

در Kubernetes، از policies برای garbage collection استفاده کنید.

به‌روزرسانی منظم ایمیج‌های پایه

هفته‌ای یکبار، ایمیج‌های پایه خود را بازسازی کنید تا آخرین وصله‌های امنیتی را دریافت کنید. برای اتوماسیون، از ابزارهایی مثل Dependabot یا Renovate استفاده کنید که می‌توانند pull request برای به‌روزرسانی ایمیج ایجاد کنند.

نظارت و لاگ‌گیری در زمان اجرا

رفتار غیرعادی کانتینرها را رصد کنید. مثلاً افزایش ناگهانی مصرف CPU، باز شدن اتصالات شبکه غیرمنتظره، یا دسترسی به فایل‌های حساس. ابزارهای زیر را در نظر بگیرید:

  • Falco: ابزار متن‌باز برای نظارت بر رفتار runtime کانتینرها
  • Sysdig Falco (نسخه تجاری)
  • Auditd در لینوکس برای ثبت رویدادهای خاص

همچنین لاگ‌های داکر دیمون (/var/log/syslog یا journalctl) را برای رویدادهایی مثل container kill یا exec غیرمنتظره بررسی کنید.


بخش ششم: امنیت در orchestration (Kubernetes)

اگر از Kubernetes استفاده می‌کنید، نکات زیر را اضافه کنید:

  • Pod Security Standards: از Admission Controller برای اعمال خط مشی‌های امنیتی (مثل عدم اجرا با root، عدم استفاده از privileged) استفاده کنید.
  • Network Policies: فقط ترافیک مجاز بین Podها را مجاز کنید.
  • Service Mesh (مثل Istio): رمزگذاری mTLS بین سرویس‌ها و کنترل دسترسی مبتنی بر هویت.
  • PodDisruptionBudget و ResourceQuota: جلوگیری از حملات DoS با مصرف منابع.

همچنین از ImagePullPolicy: Always استفاده کنید تا مطمئن شوید هر بار که Pod راه‌اندازی می‌شود، آخرین نسخه ایمیج (با وصله‌های امنیتی) را از رجیستری می‌کشد.


ابزارهای مفید برای امنیت کانتینر

برای تسهیل پیاده‌سازی این بهترین روش‌ها، ابزارهای زیر را بشناسید:

ابزارکاربرد
Docker Bench Securityبررسی پیکربندی میزبان و داکر دیمون بر اساس CIS benchmarks
Trivyاسکن آسیب‌پذیری ایمیج‌ها و فایل‌های سیستم
Clairاسکن لایه‌های ایمیج
Falcoنظارت بر رفتار runtime و تشخیص ناهنجاری
Notary (یا Docker Content Trust)امضای دیجیتال ایمیج‌ها برای اطمینان از اصالت
Open Policy Agent (OPA)اعمال سیاست‌های امنیتی به صورت declarative در Kubernetes

اشتباهات مخرب رایج که باید همین امروز برطرف کنید

  1. استفاده از تگ latest در production: شما دقیقاً نمی‌دانید چه نسخه‌ای اجرا می‌شود و نمی‌توانید rollback کنید.
  2. اجرای کانتینر با کاربر root: این بزرگ‌ترین اشتباه امنیتی است.
  3. Mount کردن سوکت داکر به کانتینر: معادل دادن کلید خانه به غریبه.
  4. ذخیره رمزها در متغیرهای محیطی ساده: هر کسی که به docker inspect دسترسی داشته باشد می‌تواند آنها را ببیند.
  5. غیرفعال کردن AppArmor یا SELinux: این ابزارها لایه دفاعی حیاتی هستند.
  6. اجازه دسترسی پیش‌فرض به شبکه host (با --network host): کانتینر می‌تواند تمام پورت‌های میزبان را ببیند.
  7. اسکن نکردن ایمیج‌ها قبل از استقرار: بسیاری از آسیب‌پذیری‌های بحرانی ماه‌ها در ایمیج‌های عمومی می‌مانند.

جمع‌بندی: امنیت یک سفر است نه مقصد

امنیت کانتینرهای داکر ترکیبی از فرهنگ، فرآیند و ابزار است. هیچ راه حل جادویی وجود ندارد. اما با رعایت روش‌های ذکر شده در این مقاله – از ایمیج‌های minimals و اسکن آسیب‌پذیری گرفته تا اجرای بدون root و محدودیت منابع – می‌توانید ریسک را به طور قابل توجهی کاهش دهید. به یاد داشته باشید: امنیت باید در هر مرحله از چرخه حیات کانتینر یکپارچه شود. امروز، یک قدم بردارید: یک ایمیج موجود را اسکن کنید، یا Dockerfile خود را بازنویسی کنید تا از کاربر غیرroot استفاده کند. فردا، نظارت runtime را اضافه کنید. به مرور زمان، این عادت‌ها بخشی از فرآیند طبیعی شما خواهند شد و برنامه‌های کانتینری شما در برابر تهدیدها مقاوم‌تر خواهند ایستاد.

Docker Container Security Best Practices

سوالات متداول (FAQ)

۱. آیا استفاده از داکر در محیط تولید ذاتاً ناامن است؟
خیر، داکر طراحی امنیتی خوبی دارد اما مانند هر ابزار دیگری، نحوه استفاده آن اهمیت دارد. اگر بهترین روش‌ها (مثل ایمیج‌های به‌روز، کاربر غیرroot، محدودیت منابع) رعایت شود، داکر می‌تواند به اندازه ماشین‌های مجازی ایمن باشد. بسیاری از شرکت‌های بزرگ (Google, Netflix, Spotify) با موفقیت از داکر در مقیاس بالا استفاده می‌کنند.

۲. تفاوت بین USER در Dockerfile و --user در زمان اجرا چیست؟
USER در Dockerfile کاربر پیش‌فرض را برای زمان اجرا تعیین می‌کند. --user در زمان اجرا می‌تواند آن را override کند. اگر در Dockerfile کاربر را تعیین نکنید، root خواهد بود. بهترین روش تعیین USER در Dockerfile است؛ آنگاه حتی اگر کسی --user ندهد، امن باقی می‌ماند.

۳. آیا می‌توان از ابزارهای امنیتی لینوکس مثل SELinux با داکر استفاده کرد؟
بله، داکر به طور کامل از SELinux و AppArmor پشتیبانی می‌کند. شما می‌توانید با --security-opt label=type:mytype پروفایل SELinux سفارشی به کانتینر اختصاص دهید. بسیاری از توزیع‌ها (مانند RedHat/CentOS) به طور پیش‌فرض SELinux فعال دارند و داکر با آن هماهنگ است.

۴. هر چند وقت یک بار باید ایمیج‌های پایه را به‌روزرسانی کنم؟
حداقل هفته‌ای یک بار. برای ایمیج‌هایی که در معرض اینترنت هستند (وب سرورها، APIها)، بهتر است هر ۲-۳ روز یک بار. می‌توانید از ابزارهای اتوماسیون مانند Renovate یا Dependabot استفاده کنید تا به طور خودکار Pull Request برای به‌روزرسانی ایمیج ایجاد کنند. همچنین پس از انتشار وصله امنیتی بحرانی برای یک بسته محبوب (مثل OpenSSL)، ظرف ۲۴ ساعت به‌روزرسانی کنید.

۵. آیا ابزاری برای تجزیه و تحلیل رفتار کانتینر در زمان اجرا وجود دارد؟
بله، Falco (متن‌باز، بنیاد CNCF) استاندارد واقعی است. شما می‌توانید قوانینی مثل «هرگز نباید apt-get در کانتینر اجرا شود» یا «هرگز نباید به /etc/shadow دسترسی پیدا کرد» تعریف کنید. Falco رویدادهای سیستمی را از کرنل می‌گیرد و در صورت نقض قانون، هشدار می‌دهد.

۶. تفاوت --cap-drop=ALL و --privileged چیست؟
--privileged تمام قابلیت‌ها را می‌دهد و علاوه بر آن محدودیت‌های device cgroup را هم حذف می‌کند. --cap-drop=ALL تمام قابلیت‌ها را می‌گیرد. اجرای کانتینر بدون هیچ قابلیتی معمولاً هنوز می‌تواند کار کند مگر اینکه نیاز به عملیات خاص شبکه، mount، یا تغییر زمان سیستم داشته باشد. امن‌ترین حالت: --cap-drop=ALL و فقط --cap-add برای نیازهای ضروری.

۷. آیا استفاده از داکر روی ویندوز امنیت متفاوتی دارد؟
بله، در ویندوز، داکر از Hyper-V isolation استفاده می‌کند که لایه امنیتی قوی‌تری نسبت به کانتینرهای لینوکسی (که از namespace و cgroup استفاده می‌کنند) ارائه می‌دهد. اما روش‌های پایه (ایمیج امن، کاربر غیرroot، محدودیت منابع) یکسان است. همچنین در ویندوز، به جای Docker Hub از رجیستری‌های داخلی یا Azure Container Registry استفاده کنید.

دیدگاهتان را بنویسید