المدونة

أي العملاء يحتاجون فعلاً إلى VM خاص بهم؟ خطة عزل Docker متدرجة

VM لكل عميل مبالغة. إليك كيفية تحديد مقدار العزل الذي يحتاجه كل مستأجر، وأتمتة القرار.

الملخص

غالبًا ما تشعر الوكالات بالذعر عندما يسأل العميل عن مدى عزل بياناته عن المستأجرين الآخرين. توفر مساحات أسماء Docker و cgroups عزلًا حقيقيًا، لكنها ليست نفس الحدود المادية. بدلاً من تشغيل كل عميل على VM—أو الأسوأ، معاملة كل عميل بنفس الطريقة—قم ببناء مجموعة صغيرة من مستويات العزل وقم بمطابقة كل عميل مع مستوى بناءً على حساسية البيانات والثقة والامتثال. حاوية مقفلة (non-root، إسقاط الصلاحيات، seccomp، نظام ملفات جذر للقراءة فقط) تغطي معظم المواقع؛ أما أعباء العمل المنظمة أو المعادية فتحصل على VM أو هجين حاوية داخل VM. يقدم هذا المنشور تدفق قرار قابل للتكرار، وجدول مقارنة، ونظرة صادقة حول متى يكون العزل الإضافي مبالغًا فيه.

هل وصلت إلى نقطة في مكالمة المبيعات حيث يقول العميل الجديد “نحن في مجال الرعاية الصحية، أرني أن بياناتنا معزولة عن عملائك الآخرين” وتفضل الحديث عن أي شيء آخر؟

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

انتظر، أليست الحاويات معزولة بالفعل؟

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

خذ تطبيق PHP بسيطًا في الحاوية A. إنه يرى نظام الملفات الخاص به، وواجهة الشبكة الخاصة به، ومعرف العملية 1 الخاص به. الحاوية B لديها نفس الشيء، ولكن برؤية مختلفة. هذا هو مساحات الأسماء. الآن ابتعد وتخطى حد الذاكرة: يمكن للحاوية A ملء ذاكرة الوصول العشوائي للمضيف وجعل الحاوية B تزحف. هذا ما توجد cgroups لمنعه. لكن حاويتين يمكن أن تكونا معزولتين عن بعضهما البعض بواسطة مساحات الأسماء وتظلان تشاركان نواة المضيف، وهذا هو الجزء الذي تدور حوله كل قصة هروب من الحاوية. يمكن أن يصل استغلال إلى النواة وربما يصل إلى كل مستأجر على هذا المضيف.

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

فلماذا يحتاج بعض العملاء إلى أكثر من مساحات الأسماء؟

الإجابة الصادقة هي أن العزل ليس مفتاحًا، بل طيف. في أحد الطرفين لديك حاوية مشتركة بالكامل حيث يكون الجميع فعليًا في تطبيق واحد. في الطرف الآخر لديك VM منفصل لكل مستأجر بنواته الخاصة. تعيش معظم أعمال الوكالات في الوسط غير المريح، والوسط ليس خيارًا ثنائيًا بين “Docker جيد” و “شغّل VM للجميع.”

ما يدفع العميل إلى اليمين ليس حجمه. إنها أربعة أسئلة:

  • هل يخزنون بيانات منظمة؟ سجلات صحية، تفاصيل بطاقات الدفع، أي شيء يعتبره المنظم حساسًا.
  • هل يوجد مسار واقعي لاختراق مستأجرهم إلى مستأجر آخر؟ إذا كان بإمكانهم تشغيل كود عشوائي، نعم.
  • هل تثق في الكود والأشخاص الذين ينشرونه؟ العميل الذي يوظف أرخص مستقل ليس بنفس مستوى الثقة الذي يتمتع به العميل الذي تعرف فريق التطوير الخاص به.
  • هل ينص عقدهم على “مخصص” أو “معزول” أو “خاص”؟ إذا كان كذلك، فأنت قد وعدت بالفعل بمستوى؛ المهمة الوحيدة الآن هي اختيار المستوى الصحيح.

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

كيف أقرر لكل عميل دون إجراء تدقيق أمني في كل مرة؟

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

وضع العميلما يفصلهم فعليًااستخدم عندما
المستوى 1: تطبيق/حاوية مشتركةمنطق التطبيق فقطأدوات داخلية، بيانات منخفضة المخاطر، مشاريع حيث الجميع صراحة في نظام تسجيل دخول واحد
المستوى 2: نفس المضيف، حاويات منفصلةمساحات الأسماء و cgroupsمعظم مواقع التسويق، نماذج الاتصال، لا توجد بيانات حساسة
المستوى 3: حاوية مقفلةالمستوى 2 + غير جذر، إسقاط الصلاحيات، seccomp، جذر للقراءة فقط، تقسيم الشبكةالتجارة الإلكترونية، المعلومات الشخصية (PII)، كود مخصص لا تثق به تمامًا
المستوى 4: VM لكل مستأجرHypervisor ونواة منفصلةالرعاية الصحية، التمويل، أوراق الامتثال، كود غير موثوق، جيران مزعجون

إليك كيف يتم ذلك عمليًا. عميل مخبز مع نموذج اتصال ورابط Instagram يذهب إلى المستوى 2: حاوية واحدة على مضيف مشترك، شبكات Docker الافتراضية، حدود الموارد، انتهت المهمة. متجر عبر الإنترنت يخزن أسماء العملاء وعناوينهم وتحويلات الدفع يذهب إلى المستوى 3: نفس المضيف المشترك، لكن الحاوية تعمل كمستخدم غير جذر، وليس لديها صلاحيات نواة إضافية، وتستخدم ملف تعريف seccomp، وتكشف فقط المنفذ 443. بوابة قبول طبي تخزن معلومات صحية محمية تذهب إلى المستوى 4: VM لكل مستأجر، لأن تكلفة الاختراق ليست “سوف ننظف الأمر” بل “لا يمكننا أن نظهر للعميل أننا أخذناهم على محمل الجد.”

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

كيف تبدو الحاوية المقفلة فعليًا؟

دعنا نتوقف عن قول “مقفلة” ونكون أكثر واقعية. هذا ما يعنيه المستوى 3 لعميل WordPress أو PHP نموذجي.

أولاً، غيّر المستخدم. معظم الصور الرسمية لا تزال تعمل كجذر افتراضيًا؛ في Dockerfile الخاص بك، أنشئ مستخدمًا غير جذر وقم بتشغيل التطبيق بهذا المستخدم. هذا يزيل على الفور الطريقة الأكثر شيوعًا التي يصبح بها اختراق الحاوية اختراقًا للمضيف. ثانيًا، أسقط الصلاحيات التي لا تحتاجها. قم بالتشغيل باستخدام --cap-drop ALL وأضف واحدة فقط، عادةً NET_BIND_SERVICE حتى يتمكن التطبيق من الاستماع على المنفذ 80. هذا وحده تغيير أكبر مما يتوقع معظم الناس. ثالثًا، اجعل نظام ملفات الجذر للقراءة فقط باستخدام --read-only، وقم بتركيب الدلائل القابلة للكتابة (الرفعات، دليل بيانات قاعدة البيانات) كوحدات تخزين أو tmpfs. رابعًا، طبق ملف تعريف seccomp، وإذا كان مضيفك يدعم ذلك، AppArmor أو SELinux. أخيرًا، ضع الحاوية على شبكة Docker مخصصة واكشف فقط المنافذ التي تحتاج فعليًا إلى أن تكون قابلة للوصول.

دعنا نستعرض مثال WordPress. الصورة الأساسية تعمل غالبًا كجذر، لذا تضيف خطوة useradd وتوجيه USER. تقوم بتشغيل الحاوية بحد ذاكرة وحد وحدة معالجة مركزية، بحيث لا يؤذي اندفاع زيارات الإضافات الجار. تقوم بتركيب /var/www/html/wp-content/uploads كوحدة تخزين قابلة للكتابة. تقوم بتعيين --read-only. تقوم بإرفاقها بشبكة لا تحتوي على علامة --privileged في أي مكان قريب. النتيجة هي حاوية كانت “موقع WordPress” وأصبحت الآن “موقع WordPress أكثر تقييدًا من معظم الخوادم الافتراضية الخاصة.”

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

متى أتوقف عن إضافة الطبقات وأعطيهم VM فقط؟

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

VM هو الإجابة الصحيحة عندما يكون الخطر لكل مستأجر أعلى من التكلفة التشغيلية لـ VM لكل مستأجر. وهذا يعني بيانات منظمة، متطلبات امتثال مكتوبة، كود طرف ثالث غير موثوق، أو عميل يحتاج إلى إزالة جار مزعج. كما أنه الإجابة الصحيحة عندما يعد عقد العميل حرفيًا ببيئة مخصصة، لأن “حاوية” ليس ما يتخيلونه عندما يوقعون على “مخصص”.

لكن VM لا يعذر عن حاوية قذرة. الفخ الشائع هو وضع العميل في VM ثم تخطي التقوية لأن “VM يحميهم”. يحمي VM المضيف من المستأجر، وليس المستأجر من صورته السيئة. ما زلت تريد غير الجذر، وإسقاط الصلاحيات، و seccomp داخل ذلك VM. النهج الهجين — الحاويات داخل VM — غالبًا ما يكون النقطة المثالية: يوفر VM الحدود لمحادثات الامتثال، وتمنحك الحاوية سير عمل النشر الذي تعرفه بالفعل. هناك نسخة أطول من هذا النقاش في هل يجب أن يحصل كل مستأجر على VM خاص به؟، لكن الإجابة المختصرة هي أن VM من أجل العقد، وليس من أجل الخوف.

كيف أجعل هذا قابلاً للتكرار عبر كل عميل؟

يمكنك جعله قابلاً للتكرار عن طريق جعل نظام المستويات قالبًا، وليس ذاكرة. احتفظ بدليل لملفات Compose، واحد لكل مستوى: tier2-baseline، tier3-locked، tier4-vm-hybrid. عندما يظهر عميل جديد، انسخ القالب، وغيّر متغيرات البيئة، وستعرف بالفعل شكل العزل قبل أن تكتب سطرًا واحدًا من البنية التحتية الجديدة.

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

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

لا شيء من هذا براق. لا يمكن لأي منشور مدونة أن يجعل “عزل المستأجر” يبدو مثيرًا مثل مخطط بنية من الصفر. لكن هذا هو الفرق بين وكالة تجيب على “كم نحن معزولون؟” بأصابع متقاطعة “تمامًا” ووكالة يمكنها إظهار مستوى، وتكوين، وسبب. الحاويات ليست جدارًا سحريًا. VMs ليست رصاصة سحرية. نظام المستويات هو مجرد قرار تكتبه وتعيد استخدامه — وبالنسبة للوكالة، القابلية للتكرار هي اللعبة بأكملها.

Sources (5)