تشغيل الحاويات بأمان
تشغيل الحاويات بأمان
الحاوية ليست آلة افتراضية. فهي تشارك نواة المضيف، وبالتالي فإن عملية مخترقة داخل حاوية بإعدادات تشغيل خاطئة قادرة على الهروب إلى المضيف، وقراءة الأسرار من حاويات أخرى، أو التحرك عبر المجموعة بأكملها. يتناول هذا الدرس ضوابط التشغيل الأربعة التي يطبقها كل فريق إنتاج بمعيار شركات التقنية الكبرى كخط أساسي: المستخدمون غير الجذريون، وأنظمة الملفات للقراءة فقط، وصلاحيات Linux، وملفات seccomp / AppArmor. كل طبقة تضيّق نطاق الضرر في حال الاختراق بشكل مستقل؛ ومجتمعةً تُنشئ دفاعاً متعمّق الطبقات يصعب اختراقه.
لماذا يُعدّ root داخل الحاوية خطيراً؟
افتراضياً، تعمل العمليات داخل حاوية Docker بصلاحيات UID 0 (root). توفر مساحات أسماء المستخدمين (User Namespaces) بعض العزل، لكن إن وُجدت ثغرة في الهروب من الحاوية — وقد حدث ذلك مراراً — فإن عملية حاوية بصلاحيات root تتطابق مع root على المضيف مباشرةً. وهذا يعني الوصول الكامل لكل ملف على المضيف، وكل حجم مُركّب، وكل عملية تعمل.
الحل هو تعريف مستخدم غير جذري في Dockerfile وإنشاء المستخدم بمعرف UID مرتفع وثابت. تستخدم صور شركات التقنية الكبرى باستمرار معرفات UID في النطاق 10000–65534 لتجنب التعارض مع حسابات نظام المضيف:
للصور التي تحتوي على shell (Alpine، Debian-slim)، أنشئ المستخدم صراحةً لضمان ثبات مجلده الرئيسي ومعرفه:
USER nobody. يُشارَك مستخدم nobody (UID 65534) من قِبَل كثير من خدمات النظام وقد يملك صلاحيات غير متوقعة على بعض إعدادات المضيف. استخدم بدلاً من ذلك مستخدماً مخصصاً بـ UID ثابت وموثّق.
أنظمة الملفات للقراءة فقط
حتى مع وجود مستخدم غير جذري، يمكن لعملية مخترقة كتابة ملفات ثنائية خبيثة في /tmp، أو الكتابة فوق ملفات التطبيق، أو تثبيت أدوات استمرارية، إذا كان نظام الملفات قابلاً للكتابة. يمنع تركيب نظام الملفات بالكامل للقراءة فقط باستخدام --read-only هذا على مستوى نظام التشغيل — لن ينجح أي chmod أو mv أو سكريبت shell مُسقَط بعد العملية الحالية.
معظم التطبيقات تحتاج إلى بعض المساحة القابلة للكتابة — لـ /tmp وملفات PID والذاكرة التخزينية. النمط الصحيح هو منح الكتابة فقط لمجلدات محددة ومعروفة باستخدام tmpfs، مع إبقاء كل شيء آخر ثابتاً:
في Kubernetes يُضبط المكافئ في سياق أمان الـ pod:
allowPrivilegeEscalation: false في Kubernetes ملفات setuid ثنائية وأوامر sudo داخل الحاوية، حتى لو كانت موجودة في الصورة. هذا مستقل عن نظام الملفات للقراءة فقط ويجب دائماً ضبطه جنباً إلى جنب.
صلاحيات Linux — تقليص الامتيازات بدقة
Root ليس مفتاحاً واحداً. تُقسّم نواة Linux امتياز root إلى نحو 40 صلاحية مستقلة — CAP_NET_BIND_SERVICE (ربط المنافذ أقل من 1024)، وCAP_SYS_PTRACE (إلحاق المحليات)، وCAP_SYS_ADMIN (كل شيء تقريباً)، وغيرها. يمنح Docker حاوية مجموعة افتراضية من نحو 14 صلاحية. هذه المجموعة أضيق من الجذر الكامل لكنها أوسع بكثير مما تحتاجه معظم عمليات التطبيق.
النهج الإنتاجي هو إسقاط جميع الصلاحيات، ثم إضافة ما تحتاجه العملية فعلاً فقط:
docker run --rm -it --cap-drop ALL ubuntu:24.04 capsh --print لفحص مجموعة الصلاحيات بشكل تفاعلي. استخدم pscap (من حزمة libcap-ng-utils) على المضيف للتحقق من الصلاحيات التي تمتلكها عمليات الحاوية فعلاً.
Seccomp — تصفية استدعاءات النظام
حتى مع إسقاط جميع الصلاحيات، يمكن لعملية داخل الحاوية استدعاء مئات استدعاءات نظام Linux. يمكن لعملية مخترقة استخدام استدعاءات مثل ptrace وkeyctl وclone بأعلام محددة لمحاولة رفع الامتيازات. Seccomp (Secure Computing Mode) هو ميزة في نواة Linux تُقيّد استدعاءات النظام التي يجوز للعملية استخدامها. يُوفّر Docker ملف seccomp افتراضي يحجب نحو 44 استدعاءاً خطيراً مع السماح بكل ما تحتاجه التطبيقات الطبيعية.
لضمان أعلى مستوى، أنشئ ملف شخصي ضيّقاً مخصصاً للتطبيق. سير العمل: شغّل تطبيقك في وضع SCMP_ACT_LOG لتسجيل كل استدعاءات النظام التي يُجريها، ثم أنشئ قائمة سماح من ذلك السجل. أدوات مثل oci-seccomp-bpf-hook أو Falco يمكنها أتمتة خطوة التسجيل:
ملف JSON لـ seccomp بنية الحد الأدنى تبدو كالتالي — يرفض افتراضياً ويسمح باستدعاءات محددة بالاسم (نهج قائمة السماح):
AppArmor — التحكم الإلزامي في الوصول للمسارات والشبكات
AppArmor (Application Armor) هو وحدة أمان Linux تفرض سياسة تحكم إلزامي في الوصول فوق صلاحيات Unix التقديرية. بينما يعمل seccomp على مستوى استدعاء النظام، يعمل AppArmor على مستوى المورد — يتحكم في الملفات والمجلدات والمقابس والعمليات الشبكية التي يُسمح لملف تنفيذي بعينه بالوصول إليها، بغض النظر عن مستخدم Unix الذي يُشغّله.
يُطبّق Docker ملف AppArmor افتراضي يُسمّى docker-default على كل حاوية في الأنظمة التي يعمل فيها AppArmor (Ubuntu، Debian، openSUSE). يمكنك تحميل ملف مخصص وتطبيقه لكل حاوية:
ملف AppArmor إنتاجي لخدمة Go HTTP يبدو كالتالي — يُدرج المسارات التي تمسّها العملية فعلاً فقط:
الجمع بين الضوابط — أمر تشغيل مُصلَّب بالكامل
تتكامل هذه الضوابط الأربعة بسلاسة. إليك أمر إطلاق حاوية إنتاجية يُطبّق جميعها في آنٍ واحد:
يستحق العلم --security-opt no-new-privileges:true إشارة خاصة: يضبط بتة PR_SET_NO_NEW_PRIVS في prctl، مما يمنع أي عملية في الحاوية — بما في ذلك العمليات الفرعية — من اكتساب امتيازات إضافية عبر execve أو الملفات الثنائية setuid أو صلاحيات نظام الملفات على الملفات التنفيذية. إنها شبكة الأمان الأخيرة بعد كل الضوابط السابقة.
ConstraintTemplate يرفض الـ pods التي تفتقر إلى readOnlyRootFilesystem: true وrunAsNonRoot: true وallowPrivilegeEscalation: false. أجرِ التحقق من السياسات في CI باستخدام conftest قبل أن تصل أي بيان إلى المجموعة.