تخطَّ إلى المحتوى
المدونة
الأمن السيبراني

تأمين Docker وتقويته: دليل عملي لحماية الحاويات

دليل عملي لتأمين Docker وتقوية الحاويات: صور آمنة، وبناء دون أسرار، وتشغيل بأقل الصلاحيات، وحماية المضيف والشبكة، مع أوامر وأمثلة جاهزة للتطبيق.

فريق سايبربيديا

6 دقائق قراءة

غلاف مقال: تأمين Docker وتقويته: دليل عملي لحماية الحاويات

تأمين Docker يعني تقليل الصلاحيات وسطح الهجوم في أربع طبقات: صورة صغيرة موثوقة ومفحوصة، وبناء بمستخدم غير جذري ودون أسرار، وتشغيل بخيارات مثل --cap-drop ALL و--read-only و no-new-privileges، ومضيف محدّث يعمل بالوضع غير الجذري ولا يكشف مقبس Docker لأي حاوية.

تعمل Docker اليوم في قلب معظم بيئات التطوير والإنتاج، لكن سهولة تشغيل حاوية بأمر واحد تخفي إعدادات افتراضية لم تُصمَّم لأقصى درجات الأمان. تقوية الأمان (Hardening) تعني أن تغلق هذه الثغرات طبقة بعد طبقة: من الصورة، إلى البناء، إلى التشغيل، وصولاً إلى المضيف نفسه.

لماذا لا تكون حاويات Docker آمنة افتراضياً؟

لأن الحاوية ليست آلة افتراضية: كل الحاويات تتشارك نواة (Kernel) نظام المضيف نفسه، وأي ثغرة في النواة أو إعداد متساهل قد يفتح طريقاً للهروب من الحاوية (Container Escape) إلى المضيف.

وتزيد بعض الإعدادات الافتراضية من هذا الخطر:

  • العملية داخل الحاوية تعمل بصلاحيات root ما لم تحدد مستخدماً آخر.
  • خدمة Docker (Docker Daemon) تعمل بصلاحيات root على المضيف في التثبيت العادي.
  • عضوية مجموعة docker تكافئ عملياً صلاحيات root على المضيف، لأنها تسمح بتشغيل أي حاوية بأي إعدادات.

وإذا كنت جديداً على مفهوم التقوية عموماً، فابدأ بمقال Cybersecurity Hardening النهج الاستباقي لحماية الأنظمة.

أين تضع الحماية في دورة حياة الحاوية؟

تحتاج الحماية إلى أربع طبقات متتالية، وضعف أي طبقة منها قد يُسقط فائدة الطبقات الأخرى.

مخطط يوضح طبقات تأمين Docker الأربع: الصورة ثم البناء ثم التشغيل ثم المضيف

أربع طبقات لتأمين Docker: الصورة والبناء والتشغيل والمضيف

كيف تؤمّن صورة الحاوية (Docker Image)؟

ابدأ بصورة أساس (Base Image) صغيرة ومن مصدر موثوق، لأن كل حزمة إضافية في الصورة ثغرة محتملة. الصور الرسمية (Official Images)، والصور المصغّرة مثل alpine وslim وصور Distroless، تقلل سطح الهجوم كثيراً.

ثبّت الصورة بدل الوسم المتغير

الوسم latest قد يشير غداً إلى صورة مختلفة عن اليوم. ثبّت الإصدار، والأفضل أن تثبّت البصمة (Digest) حتى تضمن أنك تبني دائماً من الصورة نفسها:

FROM python:3.12-slim@sha256:<digest>

هذا مهم أيضاً للحماية من هجمات سلاسل التوريد، حيث يُستبدل مكوّن موثوق بآخر خبيث.

افحص الصورة من الثغرات قبل النشر

استخدم أداة فحص مثل Trivy أو Docker Scout، واجعل الفحص خطوة إلزامية في خط النشر (CI/CD) تمنع نشر أي صورة فيها ثغرات حرجة:

trivy image myapp:1.4.0
docker scout cves myapp:1.4.0

كيف تبني صورة آمنة في Dockerfile؟

القاعدة: الصورة النهائية تحتوي ما يحتاجه التطبيق ليعمل فقط، وتعمل بمستخدم عادي. البناء متعدد المراحل (Multi-stage Build) يحقق ذلك: المرحلة الأولى build تحتوي أدوات الترجمة وتُخرج الملف التنفيذي، والمرحلة الثانية تنسخ هذا الملف وحده إلى صورة إنتاج صغيرة لا تحتوي حتى على Shell.

FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/server

FROM gcr.io/distroless/static-debian12
COPY --from=build /app /app
USER 10001:10001
ENTRYPOINT ["/app"]

وانتبه لثلاث نقاط أخرى أثناء البناء:

  1. لا تضع كلمات المرور أو المفاتيح في ENV أو في ملفات تنسخها إلى الصورة، فكل طبقة يمكن استخراجها لاحقاً.
  2. أضف ملف .dockerignore يستبعد ملفات مثل .env و.git ومفاتيح SSH.
  3. إذا احتجت سراً أثناء البناء فقط، مرّره عبر BuildKit حتى لا يُحفظ في أي طبقة.
RUN --mount=type=secret,id=npm_token \
    NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
docker build --secret id=npm_token,src=./npm_token.txt -t myapp .

كيف تشغّل الحاوية بأقل صلاحيات ممكنة؟

مبدأ أقل الصلاحيات (Least Privilege) هو جوهر تأمين التشغيل: امنح الحاوية ما تحتاجه فقط، واسحب الباقي.

مقارنة بين تشغيل حاوية Docker بالإعدادات الافتراضية وتشغيلها بخيارات التقوية

الفرق بين أمر التشغيل الافتراضي وأمر التشغيل المُحصَّن

الخيار ما الذي يحميك منه
--user 10001 يمنع تشغيل التطبيق بصلاحيات root داخل الحاوية
--read-only يمنع المهاجم من تعديل الملفات أو زرع أدوات داخل الحاوية
--cap-drop ALL يسحب قدرات لينكس (Linux Capabilities) كلها، ثم تضيف ما يلزم فقط بـ --cap-add
--security-opt no-new-privileges يمنع العمليات من رفع صلاحياتها عبر ملفات setuid
--memory و--cpus و--pids-limit تحدّ من استنزاف موارد المضيف، مثل هجمات Fork Bomb

وإذا احتاج التطبيق مكاناً مؤقتاً للكتابة مع --read-only، فأضف --tmpfs /tmp.

إعدادات يجب ألا تراها في بيئة الإنتاج

  • الخيار --privileged: يمنح الحاوية صلاحيات شبه كاملة على المضيف ويعطّل معظم طبقات العزل.
  • تعطيل ملفات الحماية بخيار --security-opt seccomp=unconfined أو apparmor=unconfined. أبقِ ملف Seccomp الافتراضي وملف AppArmor أو SELinux مفعّلين.
  • ربط مقبس Docker (/var/run/docker.sock) داخل الحاوية، فمن يصل إليه يتحكم بخدمة Docker، أي بالمضيف كاملاً.
  • مشاركة نطاقات المضيف مثل --pid=host و--network=host دون حاجة حقيقية.

الإعدادات نفسها في Docker Compose

services:
  web:
    image: myapp:1.4.0
    user: "10001:10001"
    read_only: true
    tmpfs:
      - /tmp
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    mem_limit: 512m
    pids_limit: 100

كيف تحمي مضيف Docker وخدمته؟

المضيف هو الهدف الأخير لأي هجوم على الحاويات، وحمايته تبدأ بالتحديث المستمر لـ Docker Engine ولنواة النظام، لأن ثغرات الهروب من الحاوية تُصلَح عادةً هناك.

ثم طبّق هذه الإعدادات:

  1. شغّل Docker في الوضع غير الجذري (Rootless Mode)، فتعمل الخدمة والحاويات بمستخدم عادي، ولا يحصل المهاجم على root حتى لو هرب من الحاوية.
  2. إن لم يناسبك الوضع غير الجذري، فعّل عزل نطاق المستخدمين (User Namespaces) ليصبح root داخل الحاوية مستخدماً عادياً على المضيف.
  3. لا تفتح واجهة Docker على الشبكة عبر TCP دون تشفير TLS ومصادقة بالشهادات، فالمنفذ 2375 غير المشفّر يعني تحكماً كاملاً بالمضيف لأي شخص يصل إليه.
  4. قيّد عضوية مجموعة docker بأضيق نطاق ممكن.

مثال لملف إعدادات الخدمة /etc/docker/daemon.json:

{
  "userns-remap": "default",
  "no-new-privileges": true,
  "icc": false
}

يفعّل هذا الملف عزل نطاق المستخدمين، ويمنع رفع الصلاحيات في كل الحاويات افتراضياً، ويوقف الاتصال المفتوح بين الحاويات على الشبكة الافتراضية.

وللتدقيق الدوري، شغّل أداة docker-bench-security التي تفحص المضيف وفق معيار CIS Docker Benchmark، وتعطيك تقريراً بالإعدادات المخالفة.

كيف تؤمّن شبكة الحاويات؟

افصل الحاويات في شبكات مستقلة حسب وظيفتها، ولا تنشر إلا المنافذ التي يجب أن يصل إليها أحد من الخارج.

  • أنشئ شبكات خاصة (User-defined Networks) لكل تطبيق بدل الشبكة الافتراضية bridge، واجعل قاعدة البيانات في شبكة داخلية لا يصل إليها إلا التطبيق.
  • انشر المنافذ الداخلية على العنوان المحلي فقط: -p 127.0.0.1:5432:5432 بدل -p 5432:5432.
  • انتبه إلى أن المنافذ التي تنشرها Docker تتجاوز قواعد جدار الحماية UFW على لينكس، لأن Docker تضيف قواعد iptables خاصة بها. لا تعتمد على UFW وحده لإغلاق منفذ نشرته بنفسك.

كيف تتعامل مع الأسرار؟

تجنّب تمرير كلمات المرور عبر متغيرات البيئة (Environment Variables)، لأنها تظهر في docker inspect وقد تظهر في سجلات بعض الأدوات. استخدم أسرار Docker Compose أو Swarm، فهي تُركَّب ملفات داخل /run/secrets/ ولا تُحفظ في الصورة:

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: ./db_password.txt

وفي البيئات الكبيرة، يُفضَّل مدير أسرار مخصص مثل HashiCorp Vault أو خدمات إدارة الأسرار لدى مزوّد الحوسبة السحابية.

قائمة تحقق سريعة لتأمين Docker

  1. صورة أساس صغيرة وموثوقة ومثبّتة بالبصمة.
  2. فحص الثغرات في كل بناء، ومنع نشر الصور ذات الثغرات الحرجة.
  3. مستخدم غير جذري عبر USER في كل Dockerfile.
  4. لا أسرار في الصورة أو في متغيرات البيئة.
  5. الخيارات --cap-drop ALL وno-new-privileges و--read-only وحدود الموارد عند التشغيل.
  6. لا --privileged ولا ربط لمقبس docker.sock داخل الحاويات.
  7. Docker والنواة محدّثان، مع الوضع غير الجذري أو عزل نطاق المستخدمين.
  8. شبكات منفصلة ومنافذ منشورة على الحد الأدنى.
  9. تدقيق دوري بأداة docker-bench-security، ومراقبة سلوك الحاويات أثناء التشغيل بأدوات مثل Falco.

أسئلة شائعة

هل حاويات Docker معزولة تماماً عن المضيف؟

لا، فكل الحاويات تتشارك نواة المضيف، وثغرة في النواة أو إعداد متساهل مثل --privileged قد يسمح بالهروب من الحاوية إلى المضيف.

لماذا لا يجب تشغيل الحاوية بصلاحيات root؟

لأن من يخترق التطبيق يحصل على root داخل الحاوية، فيصبح الهروب إلى المضيف أسهل بكثير عند وجود ثغرة أو إعداد خاطئ.

ما خطورة ربط docker.sock داخل الحاوية؟

من يصل إلى المقبس يتحكم بخدمة Docker ويستطيع تشغيل حاوية بصلاحيات كاملة، أي أنه يسيطر عملياً على المضيف.

كيف أفحص صور Docker من الثغرات؟

استخدم أدوات مثل Trivy أو Docker Scout لفحص حزم الصورة وعرض الثغرات المعروفة فيها، واجعل الفحص خطوة إلزامية في خط النشر.

هل يكفي جدار الحماية UFW لحماية منافذ الحاويات؟

لا، فالمنافذ التي تنشرها Docker تتجاوز قواعد UFW، لذا انشر المنافذ الداخلية على العنوان 127.0.0.1 فقط.

المصادر

  1. OWASP Docker Security Cheat Sheet
  2. Docker Docs: Docker Engine security
  3. Docker Docs: Rootless mode
  4. Docker Docs: Packet filtering and firewalls
  5. CIS Docker Benchmark
  6. docker-bench-security