المدونة

مغالطة الثقة: كيف تسربت بياناتنا بسبب إعداد Docker متعدد المستأجرين (وكيف أصلحناها)

تعلم كيف أدى إعداد Docker الساذج لفريق واحد إلى تسرب بيانات عبر المستأجرين واستراتيجية العزل متعدد الطبقات التي منعته.

ملخص

حاويات Docker ليست معزولة افتراضيًا - فهي تشارك نواة المضيف، وبدون تكوين متعمد، يمكن للمستأجرين التداخل مع بعضهم البعض. يستعرض هذا المقال سيناريو حقيقي حيث اكتشف مزود استضافة متعدد المستأجرين أن حاويات العملاء يمكنها الوصول إلى قواعد بيانات بعضهم البعض بسبب الشبكات المشتركة والإعدادات الأمنية الضعيفة. نعرض التغييرات خطوة بخطوة التي أصلحت الثغرة: شبكات محددة من قبل المستخدم لكل مستأجر، مستخدمون غير جذر، إسقاط القدرات، أنظمة ملفات للقراءة فقط، وملفات تعريف seccomp. افتراض شائع هو أن الحاويات توفر عزلًا قويًا بطبيعتها؛ نحن نناقش ذلك من خلال شرح لماذا لا تزال الأجهزة الافتراضية تقدم حدودًا أكثر صرامة ومتى ينبغي النظر في نهج هجين. يؤكد الاستنتاج أن العزل هو تمرين متعدد الطبقات، وليس مربع اختيار واحد.

الحادثة: عندما تتحدث الحاويات كثيرًا

لقد قمت بإعداد Docker على مضيف واحد لتشغيل مواقع ويب متعددة للعملاء. لكل عميل حاويته الخاصة - بيئة نظيفة ومعزولة، أليس كذلك؟ هذا ما اعتقدناه. حتى كشف تدقيق أمني روتيني أن حاوية العميل (أ) كانت تقرأ مقبس MySQL لحاوية العميل (ب) على نفس المضيف. لقد شاركوا شبكة bridge الافتراضية. والأسوأ من ذلك، أن الحاويات كانت تعمل كجذر، لذلك يمكن للمهاجم الذي يخترق واحدة أن يعبث بمقبس Docker للمضيف أو نظام ملفات حاوية أخرى. لم يكن الاختراق استغلالًا متطورًا؛ بل كان سوء تكوين أساسي. تسربت البيانات. انهارت الثقة.

سيناريو الفشل ليس نادرًا. تفترض العديد من الفرق أن مساحات الأسماء ومجموعات cgroups في Docker تعزل المستأجرين تلقائيًا، لكنهم يقللون من عدد مخارج الهروب التي تظل مفتوحة افتراضيًا. شبكات bridge الافتراضية لا تقدم أي عزل شبكي بين الحاويات. تشغيل الحاوية كجذر يمنحها قوة أكثر من اللازم. وبدون حدود موارد صريحة، يمكن لجار مزعج أن يحرم الآخرين من وحدة المعالجة المركزية أو الذاكرة.

الخطوة 1: التوقف عن مشاركة شبكة واحدة

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

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

للتعمق في استراتيجيات عزل الشبكة، راجع قائمة التحقق الأمني لعزل Docker العملي للاستضافة متعددة المستأجرين.

الخطوة 2: إسقاط الامتيازات غير الضرورية

افتراضيًا، تعمل حاويات Docker بمجموعة محدودة من قدرات Linux، لكنها لا تزال تمتلك أكثر مما تحتاجه معظم التطبيقات. كانت حاوياتنا تعمل كجذر، مما سمح للعمليات داخلها بتنفيذ إجراءات مثل تحميل أنظمة الملفات أو تغيير معلمات kernel. انتقلنا إلى تشغيل التطبيق كمستخدم غير جذر داخل الحاوية (باستخدام توجيه USER في Dockerfile) وأسقطنا جميع القدرات باستثناء تلك المطلوبة تمامًا. لتطبيق ويب نموذجي، قد تكون فقط NET_BIND_SERVICE (لربط المنافذ تحت 1024) و CHOWN (للكتابة إلى الدلائل). أضفنا أيضًا --security-opt no-new-privileges لمنع تصعيد الامتيازات.

هذه الخطوة وحدها قضت على العديد من نواقل الهروب من الحاوية الشائعة. المهاجم الذي يخترق خادم الويب لا يمكنه تثبيت الحزم أو تعديل الثنائيات النظامية أو الوصول إلى مقبس Docker للمضيف لأن العملية تفتقر إلى قدرات CAP_SYS_ADMIN أو CAP_DAC_OVERRIDE.

الخطوة 3: تأمين نظام الملفات

أنظمة الملفات القابلة للكتابة هي سطح هجوم شائع. جعلنا نظام الملفات الجذر للقراءة فقط (--read-only) لجميع الحاويات، ثم قمنا بتحميل أنظمة ملفات مؤقتة (tmpfs) للدلائل التي تحتاج إلى وصول للكتابة، مثل /tmp ودليل ذاكرة التخزين المؤقت للتطبيق. هذا يمنع المهاجم من تعديل كود التطبيق أو الاحتفاظ بالثنائيات الضارة.

بالإضافة إلى ذلك، استخدمنا خيار --mount في Docker لربط الدلائل الحساسة مثل مقبس Docker فقط عند الضرورة القصوى - وأبدًا على حاويات الإنتاج. المبدأ: إذا كانت الحاوية لا تحتاج إلى الكتابة إلى مسار، فاجعله للقراءة فقط.

الخطوة 4: تطبيق ملفات تعريف Seccomp و AppArmor

ملفات تعريف seccomp الافتراضية تمنع بالفعل العديد من استدعاءات النظام الخطيرة، لكننا قمنا بتخصيصها بشكل أكبر للسماح فقط باستدعاءات النظام التي يحتاجها تطبيقنا فعليًا. هذه مقايضة لأنها تتطلب تحديد ملف تعريف التطبيق. نهج أبسط هو استخدام ملف تعريف seccomp الافتراضي لـ Docker ثم إضافة --security-opt seccomp=path/to/profile.json إذا كنت بحاجة إلى قواعد أكثر صرامة. وبالمثل، يمكن لملفات تعريف AppArmor حصر عمليات الحاوية في مسارات وقدرات ملفات محددة. قمنا بتمكين AppArmor واستخدمنا ملف تعريف مخصص يحد من الوصول فقط إلى دلائل بيانات التطبيق.

للحصول على دليل شامل حول خطوات التقوية هذه، راجع تقوية حاويات Docker للاستضافة متعددة المستأجرين: دليل عزل خطوة بخطوة.

الرأي المخالف: أحيانًا تحتاج إلى أجهزة افتراضية

بغض النظر عن مدى التقوية، تشترك الحاويات في نواة المضيف. يمكن لثغرة في النواة أن تكسر كل العزل مرة واحدة. لهذا السبب تقوم العديد من المنصات المهتمة بالأمان بتشغيل الحاويات داخل أجهزة افتراضية خفيفة - يحصل كل مستأجر على نواته الخاصة. هذا يضيف عبئًا لكنه يوفر حدودًا على مستوى الأجهزة لا تستطيع الحاويات وحدها توفيرها. إذا كان المستأجرون يتعاملون مع بيانات بطاقة الائتمان أو السجلات الصحية، فقد يكون النهج الهجين (حاويات داخل أجهزة افتراضية) هو الخيار الصحيح. لا تفترض أن عزل الحاوية كافٍ لنموذج التهديد الخاص بك؛ قم بتقييم حساسية البيانات والمتطلبات التنظيمية.

لمقارنة أعمق لمستويات العزل، اقرأ تصميم بنية Docker متعددة المستأجرين: اختيار مستوى العزل المناسب.

الخلاصة: العزل هو مجموعة، وليس مفتاحًا

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

Sources (5)