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 پورت ۵۴۳۲ را بسته باشد، دیتابیس شما از اینترنت در دسترس است.
راهحلهای درست:
- پورتهای داخلی را منتشر نکنید. سرویسهایی مثل دیتابیس و Redis که فقط کانتینرهای دیگر به آنها نیاز دارند، اصلاً به بخش
portsنیاز ندارند و از طریق شبکه داخلی Docker در دسترس هستند. - پورت را فقط روی localhost منتشر کنید. اگر سرویس باید پشت Nginx میزبان باشد:
ports: - "127.0.0.1:5678:5678" - قوانین را در زنجیره 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 آمادهاند. برای سختسازی و مدیریت هم پشتیبانی تخصصی سرور در دسترس است.