امنیت Docker؛ راهنمای امن‌سازی Docker Server

امنیت Docker؛ راهنمای امن‌سازی Docker Server

جدول محتوا 👇

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

مدل امنیتی Docker در یک نگاه

کانتینرها برخلاف ماشین‌های مجازی، هسته (Kernel) سیستم‌عامل میزبان را به اشتراک می‌گذارند. ایزوله‌سازی با قابلیت‌های هسته لینوکس مثل Namespaceها، Cgroupها، Capabilityها و Seccomp انجام می‌شود. این یعنی:

  • یک آسیب‌پذیری در هسته می‌تواند همه کانتینرها را تحت تأثیر قرار دهد.
  • کاربر root داخل کانتینر، به‌طور پیش‌فرض همان کاربر root میزبان است، با دسترسی‌های محدودشده.
  • هر تنظیمی که این محدودیت‌ها را بردارد، مثل --privileged، عملاً مرز بین کانتینر و میزبان را حذف می‌کند.

هدف سخت‌سازی Docker این است که اگر یک برنامه داخل کانتینر هک شد، مهاجم در همان کانتینر محدود بماند.

مهم‌ترین دام: Docker و فایروال UFW

این رایج‌ترین اشتباه امنیتی در سرورهای Docker است. وقتی پورتی را با -p 5432:5432 یا ports: در Compose منتشر می‌کنید، Docker قوانین خود را مستقیماً در iptables می‌نویسد و این قوانین قبل از قوانین UFW بررسی می‌شوند. نتیجه: حتی اگر UFW پورت ۵۴۳۲ را بسته باشد، دیتابیس شما از اینترنت در دسترس است.

راه‌حل‌های درست:

  1. پورت‌های داخلی را منتشر نکنید. سرویس‌هایی مثل دیتابیس و Redis که فقط کانتینرهای دیگر به آن‌ها نیاز دارند، اصلاً به بخش ports نیاز ندارند و از طریق شبکه داخلی Docker در دسترس هستند.
  2. پورت را فقط روی localhost منتشر کنید. اگر سرویس باید پشت Nginx میزبان باشد:
    ports:
      - "127.0.0.1:5678:5678"
  3. قوانین را در زنجیره DOCKER-USER بنویسید. Docker این زنجیره را برای قوانین کاربر در نظر گرفته و قبل از قوانین خودش بررسی می‌کند.

غیرفعال کردن مدیریت iptables توسط Docker با "iptables": false توصیه نمی‌شود؛ این کار شبکه و دسترسی کانتینرها به اینترنت را مختل می‌کند. بعد از هر تغییر، پورت‌های باز را از یک سرور دیگر یا با ss -tlnp روی خود سرور بررسی کنید. تفاوت ابزارهای فایروال را در UFW یا iptables یا nftables ببینید.

از docker.sock محافظت کنید

فایل /var/run/docker.sock رابط کنترل Docker است. هر کسی به آن دسترسی داشته باشد، می‌تواند کانتینری بسازد که کل فایل‌سیستم میزبان را با دسترسی root مانت کند. پس:

  • این فایل را داخل کانتینرهای غیرضروری مانت نکنید. اگر ابزاری مثل Traefik یا Portainer به آن نیاز دارد، آن را با حالت فقط‌خواندنی یا ترجیحاً از طریق یک پروکسی محدودکننده مثل docker-socket-proxy در دسترس قرار دهید.
  • عضویت در گروه docker را معادل دسترسی root بدانید و فقط به کاربران مورد اعتماد بدهید.
  • API داکر را هرگز بدون TLS روی شبکه (پورت‌های ۲۳۷۵ یا ۲۳۷۶) باز نکنید.

کانتینر را با کاربر root اجرا نکنید

در Dockerfile، برنامه را با یک کاربر عادی اجرا کنید:

FROM node:22-alpine
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --omit=dev
USER node
CMD ["node", "server.js"]

برای ایمیج‌های آماده هم می‌توانید در Compose کاربر را تعیین کنید (user: "1000:1000")، به شرط اینکه برنامه با آن سازگار باشد. لایه حفاظتی قوی‌تر، User Namespace Remapping یا اجرای Docker در حالت Rootless است که در آن root داخل کانتینر به یک کاربر بی‌اختیار روی میزبان نگاشت می‌شود.

کاهش دسترسی‌ها: Capabilities و Read-only

اصل «کمترین دسترسی» را در Compose پیاده کنید:

services:
  app:
    image: myapp:1.4.2
    read_only: true
    tmpfs:
      - /tmp
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
  • read_only فایل‌سیستم کانتینر را فقط‌خواندنی می‌کند تا مهاجم نتواند ابزار یا بدافزار در آن بنویسد. پوشه‌هایی که برنامه باید در آن‌ها بنویسد را با ولوم یا tmpfs مشخص کنید.
  • cap_drop: ALL همه قابلیت‌های ویژه هسته را حذف می‌کند. اگر برنامه به قابلیتی نیاز دارد (مثلاً NET_BIND_SERVICE برای پورت‌های زیر ۱۰۲۴)، فقط همان را با cap_add برگردانید.
  • no-new-privileges از افزایش دسترسی با فایل‌های setuid جلوگیری می‌کند.
  • از privileged: true و network_mode: host جز در موارد کاملاً ضروری پرهیز کنید.

محدود کردن منابع

کانتینری که بدون محدودیت اجرا شود، در صورت باگ یا حمله می‌تواند کل RAM یا CPU سرور را مصرف کند و همه سرویس‌ها را از کار بیندازد:

    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 2G
    pids_limit: 200

pids_limit از حمله Fork Bomb جلوگیری می‌کند. لاگ‌ها را هم محدود کنید تا دیسک پر نشود:

{
  "log-driver": "json-file",
  "log-opts": { "max-size": "20m", "max-file": "3" }
}

این تنظیم را در فایل /etc/docker/daemon.json قرار دهید و Docker را ری‌استارت کنید.

امنیت ایمیج‌ها

  • از منابع معتبر استفاده کنید: ایمیج‌های رسمی (Official) یا ایمیج‌های منتشرشده توسط سازنده نرم‌افزار.
  • نسخه را ثابت کنید: به‌جای latest از برچسب نسخه مشخص استفاده کنید تا به‌روزرسانی آگاهانه باشد.
  • ایمیج کوچک انتخاب کنید: ایمیج‌های alpine یا distroless بسته‌های کمتر و در نتیجه آسیب‌پذیری کمتری دارند.
  • آسیب‌پذیری‌ها را اسکن کنید: با ابزارهایی مثل Trivy یا Docker Scout:
    trivy image myapp:1.4.2
    docker scout quickview myapp:1.4.2
  • Multi-stage build: ابزارهای کامپایل را در ایمیج نهایی نگه ندارید.

مدیریت رمزها

رمزها را داخل Dockerfile یا ایمیج قرار ندهید؛ هر کسی که ایمیج را داشته باشد، با docker history می‌تواند آن‌ها را ببیند. رمزها را در فایل .env با دسترسی 600 نگه دارید و این فایل را در Git ثبت نکنید. برای امنیت بیشتر، از Docker Secrets استفاده کنید که رمز را به‌صورت فایل در /run/secrets/ در اختیار کانتینر می‌گذارد، نه به‌صورت متغیر محیطی.

امنیت سرور میزبان و به‌روزرسانی

امنیت کانتینرها به امنیت سرور میزبان وابسته است:

  • هسته و Docker Engine را مرتب به‌روز کنید؛ بسیاری از آسیب‌پذیری‌های فرار از کانتینر در هسته یا runc وصله می‌شوند.
  • SSH را طبق راهنمای امنیت SSH سخت‌سازی کنید.
  • تنظیمات پایه را از تنظیمات امنیتی ضروری VPS اعمال کنید.
  • ابزار Docker Bench for Security تنظیمات میزبان و کانتینرها را با توصیه‌های CIS مقایسه می‌کند.

چک‌لیست نهایی

  • هیچ پورت داخلی (دیتابیس، Redis، پنل‌ها) روی 0.0.0.0 منتشر نشده است.
  • docker.sock داخل کانتینرهای غیرضروری مانت نشده است.
  • کانتینرها با کاربر غیر root اجرا می‌شوند.
  • cap_drop، no-new-privileges و در صورت امکان read_only فعال است.
  • محدودیت CPU، RAM، PID و لاگ تعیین شده است.
  • ایمیج‌ها نسخه مشخص دارند و به‌صورت دوره‌ای اسکن می‌شوند.
  • رمزها در ایمیج یا مخزن کد نیستند.

سوالات متداول

آیا Docker فایروال UFW را دور می‌زند؟

بله، پورت‌هایی که با -p منتشر می‌شوند، از طریق قوانین iptables خود Docker باز می‌شوند و UFW روی آن‌ها اثری ندارد. پورت‌ها را فقط روی 127.0.0.1 منتشر کنید یا قوانین را در زنجیره DOCKER-USER بنویسید.

آیا کانتینر به اندازه ماشین مجازی امن است؟

خیر. ماشین مجازی هسته جداگانه دارد و ایزوله‌سازی آن قوی‌تر است. برای اجرای کد غیرقابل اعتماد یا جداسازی مشتریان مختلف، ماشین مجازی جداگانه انتخاب امن‌تری است.

Rootless Docker چیست و آیا باید از آن استفاده کنم؟

در حالت Rootless، خود Docker Engine هم با کاربر عادی اجرا می‌شود و حتی فرار از کانتینر به دسترسی root منجر نمی‌شود. محدودیت‌هایی در شبکه و برخی قابلیت‌ها دارد، اما برای سرورهای چندکاربره ارزش بررسی دارد.

هر چند وقت ایمیج‌ها را به‌روز کنم؟

حداقل ماهانه، و بلافاصله پس از اعلام آسیب‌پذیری‌های مهم. قبل از به‌روزرسانی سرویس‌های حیاتی، از داده‌ها بکاپ بگیرید.

سرور مناسب برای کانتینرها

سرورهای مجازی تراست هاست با دیسک NVMe و منابع قابل ارتقا برای استقرار Docker آماده‌اند. برای سخت‌سازی و مدیریت هم پشتیبانی تخصصی سرور در دسترس است.

سرور مجازی ابری تراست هاست

مشاوره تراست‌هاست​

با متخصصان و کارشناسان به صورت رایگان!

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

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *