کانتینر ماشین مجازی نیست؛ هستهی میزبان را با بقیهی کانتینرها به اشتراک میگذارد و ایزولهسازی آن به پیکربندی بستگی دارد. تنظیمات پیشفرض Docker برای سهولت کار طراحی شدهاند، نه برای سختترین سناریوی امنیتی. این راهنما ده اقدام عملی را که بیشترین اثر را دارند، به ترتیب اولویت فهرست میکند؛ بیشتر آنها با چند خط در Dockerfile یا Compose قابلاجرا هستند.
۱. دسترسی به Docker socket را به کانتینر ندهید
فایل /var/run/docker.sock رابط کنترل دیمن است و هر فرایندی که به آن دسترسی داشته باشد میتواند کانتینر دلخواه (حتی با دسترسی کامل به میزبان) بسازد. mount کردن آن در کانتینرهایی مثل ابزارهای مانیتورینگ یا CI، معادل دادن دسترسی root میزبان است.
# خطرناک مگر اینکه واقعاً لازم باشد
volumes:
- /var/run/docker.sock:/var/run/docker.sock
اگر ناچارید، از یک socket proxy که فقط فراخوانیهای لازم (مثلاً فقطخواندنی) را مجاز میکند استفاده کنید. گروه docker را هم مثل root در نظر بگیرید: کاربری که عضو آن است عملاً root میزبان است. API دیمن را هم هرگز روی tcp://0.0.0.0:2375 بدون TLS باز نکنید.
۲. با کاربر غیر root اجرا کنید
در Dockerfile یک کاربر بسازید و USER را تنظیم کنید، یا در Compose کاربر را مشخص کنید:
user: "10001:10001"
برای دسترسی به پورتهای زیر ۱۰۲۴ نیازی به root نیست؛ میتوانید پورت بالاتری را در کانتینر استفاده و آن را با ports روی پورت دلخواه میزبان منتشر کنید.
۳. capabilityها را حذف و ارتقای دسترسی را مسدود کنید
Docker بهطور پیشفرض چند capability لینوکس به کانتینر میدهد که اغلب برنامهها لازم ندارند. همه را حذف کنید و فقط لازمها را برگردانید:
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # فقط اگر برنامه باید پورت زیر ۱۰۲۴ را باز کند
security_opt:
- no-new-privileges:true
گزینهی no-new-privileges جلوی افزایش دسترسی فرایندها (مثلاً با باینریهای setuid) را میگیرد. پروفایلهای پیشفرض seccomp و AppArmor را هم غیرفعال نکنید (seccomp=unconfined)؛ این پروفایلها دهها فراخوان خطرناک سیستمی را مسدود میکنند.
۴. فایلسیستم را فقطخواندنی کنید
read_only: true
tmpfs:
- /tmp
- /run
volumes:
- appdata:/var/lib/app # فقط مسیرهایی که باید نوشته شوند
اگر مهاجم نتواند فایلی در کانتینر بنویسد، نصب ابزار و ماندگارکردن بدافزار سختتر میشود. برنامه را یکبار با این تنظیم اجرا کنید؛ پیامهای خطای «read-only file system» دقیقاً مسیرهایی را نشان میدهند که باید tmpfs یا volume شوند.
۵. ایمیج کوچک، ثابتشده و قابلاعتماد
هر بستهی اضافه یعنی احتمال یک آسیبپذیری بیشتر. با multi-stage و ایمیجهای slim یا distroless سطح حمله را کم کنید، تگ دقیق (یا digest) بنویسید و ایمیج پایه را فقط از منابع معتبر بگیرید. جزئیات در این مقاله نیامده؛ راهنمای نوشتن Dockerfile بهینه و امن آن را کامل توضیح میدهد.
IMGDocker Image Size Calculatorلایهها و حجم ایمیج را ببینید و Dockerfile را برای مواردی مثل اجرا با root بررسی کنید.۶. ایمیجها را اسکن کنید
آسیبپذیریهای شناختهشده در بستههای سیستمی و وابستگیهای برنامه روزانه کشف میشوند؛ ایمیجی که ماه پیش پاک بوده ممکن است امروز نباشد. اسکن را در CI و بهصورت دورهای برای ایمیجهای در حال اجرا انجام دهید:
trivy image --severity HIGH,CRITICAL --exit-code 1 registry.example.com/app:1.8.2
گزینهی --exit-code 1 باعث میشود پایپلاین با آسیبپذیریهای شدید متوقف شود. هر آسیبپذیری لزوماً قابلبهرهبرداری نیست؛ هدف، دیدن فهرست و اولویتبندی آن است، نه صفرکردن بیقیدوشرط آن.
۷. رمزها را در ایمیج و متغیر محیطی نگذارید
مقدار ENV و ARG در تاریخچهی ایمیج میماند و متغیرهای محیطی با docker inspect دیده میشوند. رمزها را با secret mount زمان build، یا در زمان اجرا با Docker secrets/فایل mountشده بدهید و در Git نگه ندارید:
services:
app:
secrets: [db_password]
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt
هنگام مقایسه یا بررسی یکپارچگی فایلهای دانلودشده (مثلاً باینریهایی که در Dockerfile دانلود میکنید)، checksum را بررسی کنید.
#Hash Generatorهش SHA-256 یک فایل را حساب کنید و با مقدار منتشرشدهی منبع مقایسه کنید.۸. منابع کانتینر را محدود کنید
یک کانتینر بدون سقف میتواند تمام حافظه، CPU یا تعداد فرایندهای میزبان را مصرف و بقیهی سرویسها را از کار بیندازد (چه بهدلیل باگ، چه حملهی انکار سرویس):
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
pids_limit: 256
۹. سطح شبکه را کم کنید
- فقط پورتهایی را منتشر کنید که از بیرون لازم است و در صورت امکان آنها را روی
127.0.0.1ببندید؛ پورت دیتابیسها را هرگز روی همهی اینترفیسها باز نکنید. - سرویسهای داخلی را در شبکهی
internal: trueبگذارید تا دسترسی به بیرون نداشته باشند. - از
network_mode: hostفقط با دلیل مشخص استفاده کنید؛ در آن حالت ایزولهسازی شبکه وجود ندارد.
توضیح کامل این موضوعها در راهنمای شبکه و Volume در Docker آمده است.
۱۰. میزبان را هم امن کنید
کانتینرها هستهی میزبان را به اشتراک میگذارند؛ پس امنیت میزبان بخشی از امنیت کانتینرهاست:
- هسته و Docker را بهروز نگه دارید، و برای سرورهای مشترک Docker را در حالت rootless اجرا کنید (
dockerd-rootless-setuptool.sh install). - ورود با SSH فقط با کلید، بدون ورود root و پشت فایروال.
- برای اجرای مجدد کانتینرها در زمان بهروزرسانی دیمن و کنترل لاگها، در
/etc/docker/daemon.jsonتنظیمات زیر را در نظر بگیرید:
{
"live-restore": true,
"no-new-privileges": true,
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
اگر این بستهها را روی سرور ایران نصب میکنید، راهنمای نصب Docker از مخزن داخلی مراحل کامل را دارد.
چکلیست سریع
| اقدام | تنظیم |
|---|---|
| بدون root | user: "10001:10001" |
| حذف capabilityها | cap_drop: [ALL] |
| جلوگیری از ارتقای دسترسی | no-new-privileges:true |
| فایلسیستم فقطخواندنی | read_only: true |
| سقف منابع | limits + pids_limit |
| اسکن ایمیج | trivy image … |
| بدون docker.sock در کانتینر | — |
| پورت دیتابیس منتشر نشود | 127.0.0.1:… |
برای بررسی خودکار بخشی از این موارد در فایل Compose خود، از اعتبارسنج زیر کمک بگیرید.
YMLDocker Compose Validatorساختار فایل Compose و کلیدهای ناشناخته یا مقدارهای نامعتبر را بررسی کنید.جمعبندی
امنیت Docker لایهای است: هیچکدام از این اقدامها بهتنهایی کافی نیستند، ولی ترکیب کاربر غیر root، حذف capabilityها، فایلسیستم فقطخواندنی، اسکن ایمیج و محدودکردن شبکه، اثر یک نفوذ را بهشدت کاهش میدهد. گام بعدی، بازبینی فایل Compose بر اساس این فهرست است.