تشغيل الحاويات كمستخدم جذر هو أحد أكثر التكوينات الخاطئة شيوعاً — وأخطرها — في بيئات الإنتاج. فهو يوسع سطح الهجوم بصمت لكل عبء عمل، ومعظم الفرق لا تدرك ذلك حتى يجبرها حادث على مواجهة المشكلة.
ماذا يعني "التشغيل كمستخدم جذر" فعلياً
بشكل افتراضي، تقوم العديد من صور الحاويات (خاصة الصور البسيطة أو القديمة) بتنفيذ العملية الرئيسية لها باسم UID 0 داخل الحاوية. لأن الحاويات تشترك في kernel المضيف مع حاويات أخرى والمضيف نفسه، فإن المستخدم جذر داخل الحاوية ليس مثل المستخدم جذر على آلة افتراضية معزولة بالكامل — لكنه لا يزال أقوى بكثير مما يجب أن يكون. إذا حقق المهاجم تنفيذ رمز داخل حاوية يملكها المستخدم جذر، فسيرث:
- إمكانية وصول كاملة للقراءة والكتابة إلى أي ملفات محملة في الحاوية، بغض النظر عن الأذونات المقصودة
- القدرة على تثبيت الحزم وتعديل الملفات الثنائية أو العبث بحالة التطبيق
- مسار أسهل بكثير نحو الهروب من الحاوية إذا كان هناك ثغرة في kernel أو runtime قابلة للاستغلال
- نفوذ أكبر عند دمجه مع وحدات تخزين مُعدة بشكل خاطئ، مثل socket Docker محمل أو مسار نظام الملفات للمضيف
حتى بدون استغلال kernel، يزيد الوصول جذر داخل الحاوية بشكل كبير من نطاق الضرر المحتمل لأي ثغرة على مستوى التطبيق (SSRF أو أخطاء فك التسلسل أو الكتابة في ملف عشوائي، إلخ).
لماذا يكون هذا مهماً أكثر في بيئات التنسيق
في مجموعات Kubernetes، يمكن لحاوية جذر مدمجة مع قدرات Linux مفرطة أو سياق أمان متساهل أن تسمح للمهاجم بـ:
- تعديل
/procأو/sysبطرق تؤثر على المضيف - تصعيد الامتيازات إذا كان
hostPIDأوhostNetworkأوhostIPCمفعلاً - الاستفادة من token حساب الخدمة المحمل للالتفاف جانبياً عبر المجموعة
- الهروب إلى العقدة إذا تم تعيين
privileged: trueأو تم منح قدرات خطيرة مثلSYS_ADMIN
المستخدم جذر نفسه ليس دائماً هو الثغرة — بل هو مزيج من جذر بالإضافة إلى قدرات kernel سخية جداً أو mounts على المضيف أو namespace sharing الذي يحول مساومة محتواة إلى مساومة على مستوى المجموعة.
خطوات التقسية العملية
1. قم بتعيين مستخدم غير جذر في الصورة
حدد بوضوح مستخدماً غير جذر في Dockerfile بدلاً من الاعتماد على الافتراضيات:
FROM node:20-slim
RUN useradd --uid 10001 --shell /usr/sbin/nologin appuser
USER appuser
2. فرضه على مستوى Orchestrator
لا تثق فقط في الصورة — فرض السياسة في وقت التشغيل. في Kubernetes، استخدم securityContext:
securityContext:
runAsNonRoot: true
runAsUser: 10001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
runAsNonRoot: true يسبب فشل pod عند القبول إذا حاولت الصورة التشغيل باسم UID 0، مما يعطيك ضماناً قوياً بدلاً من عرف أفضل الممارسات.
3. أسقط القدرات غير الضرورية
معظم التطبيقات لا تحتاج إلى أي من قدرات Linux الافتراضية الممنوحة للحاويات. أسقط كل شيء وأضف فقط ما هو مطلوب بصرامة (الحالات النادرة مثل الربط بمنافذ منخفضة قد تحتاج NET_BIND_SERVICE).
4. تجنب الوضع المتميز و Host Namespace Sharing
privileged: true و hostNetwork: true و hostPID: true يجب أن تكون محفوظة لأعباء العمل البنية التحتية المحددة جداً (مثل وكلاء CNI أو المراقبة المحددة) — أبداً لحاويات التطبيقات العامة.
5. امسح وفرض باستخدام أدوات السياسة
استخدم admission controllers أو محركات السياسات (مثل Kyverno أو OPA/Gatekeeper) لرفض النشرات التي تنتهك هذه القواعد تلقائياً، بدلاً من الاعتماد على المراجعة اليدوية للرمز. اجمع هذا مع فحص الصور في CI لاكتشاف صور المستخدم جذر قبل وصولها إلى مجموعة.
دفاع متعدد الطبقات، وليس مثالياً
التشغيل كمستخدم غير جذر لا يلغي الخطر تماماً — هروب container على مستوى kernel موجود بشكل مستقل عن المستخدم داخل الحاوية — لكنه يزيل فئة ضخمة من تقنيات تصعيد الامتيازات منخفضة الجهد والحركة الجانبية. مدمجة مع نظام الملفات للقراءة فقط والقدرات المسقطة والسياسات الشبكية المقيدة، تشكل أحد أرخص وأكثر الطبقات فعالية في استراتيجية أمان الحاويات الدفاعية المتعمقة.
هل تريد الذهاب أعمق في تقسية أعباء العمل الأصلية للسحابة؟ استكشف مقاطع Korra Studio ذات الصلة حول أمان السحابة وتقسية خط أنابيب DevOps لبناء بقية استراتيجيتك الدفاعية المتعمقة.