Seccomp في Kubernetes: 7 أشياء تحتاج إلى معرفتها منذ البداية

ملحوظة. ترجمة.: نلفت انتباهكم إلى ترجمة مقال لأحد كبار مهندسي أمن التطبيقات في شركة ASOS.com البريطانية. به، يبدأ سلسلة من المنشورات المخصصة لتحسين الأمان في Kubernetes من خلال استخدام seccomp. إذا أعجب القراء المقدمة، فسنتابع المؤلف ونواصل مواده المستقبلية حول هذا الموضوع.

Seccomp في Kubernetes: 7 أشياء تحتاج إلى معرفتها منذ البداية

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

يوفر نظام Kubernetes البيئي مجموعة واسعة من الطرق لتأمين الحاويات وعزلها. تتناول المقالة وضع الحوسبة الآمنة، المعروف أيضًا باسم سيكومب. جوهرها هو تصفية مكالمات النظام المتاحة للتنفيذ حسب الحاويات.

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

تحدد ملفات تعريف seccomp مكالمات النظام التي يجب السماح بها أو تعطيلها. يقوم وقت تشغيل الحاوية بتنشيطها عند بدء التشغيل حتى تتمكن النواة من مراقبة تنفيذها. يتيح لك استخدام ملفات التعريف هذه الحد من ناقل الهجوم وتقليل الضرر إذا بدأ أي برنامج داخل الحاوية (أي تبعياتك أو تبعياتها) في القيام بشيء غير مسموح له بالقيام به.

الوصول إلى الأساسيات

يتضمن ملف تعريف seccomp الأساسي ثلاثة عناصر: defaultAction, architectures (أو archMap) و syscalls:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "sched_yield",
                "futex",
                "write",
                "mmap",
                "exit_group",
                "madvise",
                "rt_sigprocmask",
                "getpid",
                "gettid",
                "tgkill",
                "rt_sigaction",
                "read",
                "getpgrp"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(المتوسطة الأساسية-seccomp.json)

defaultAction يحدد المصير الافتراضي لأي استدعاء نظام غير محدد في القسم syscalls. ولتسهيل الأمور، دعونا نركز على القيمتين الرئيسيتين اللتين سيتم استخدامهما:

  • SCMP_ACT_ERRNO - يمنع تنفيذ استدعاء النظام،
  • SCMP_ACT_ALLOW - يسمح.

في القسم architectures يتم سرد البنى المستهدفة. وهذا أمر مهم لأن المرشح نفسه، المطبق على مستوى النواة، يعتمد على معرفات مكالمات النظام، وليس على أسمائهم المحددة في ملف التعريف. سيقوم وقت تشغيل الحاوية بمطابقتها مع المعرفات قبل الاستخدام. الفكرة هي أن مكالمات النظام يمكن أن يكون لها معرفات مختلفة تمامًا اعتمادًا على بنية النظام. على سبيل المثال، استدعاء النظام recvfrom (يستخدم لتلقي المعلومات من المقبس) له معرف = 64 على أنظمة x64 ومعرف = 517 على أنظمة x86. ومن يمكنك العثور على قائمة بجميع استدعاءات النظام لبنيات x86-x64.

في القسم syscalls يسرد جميع مكالمات النظام ويحدد ما يجب فعله بها. على سبيل المثال، يمكنك إنشاء قائمة بيضاء عن طريق الإعداد defaultAction في SCMP_ACT_ERRNO، ويدعو في القسم syscalls ملائم SCMP_ACT_ALLOW. وبالتالي، فإنك تسمح فقط بالمكالمات المحددة في القسم syscalls، وحظر جميع الآخرين. بالنسبة للقائمة السوداء يجب عليك تغيير القيم defaultAction والافعال عكس ذلك .

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

1.AllowPrivilegeEscalation=false

В securityContext تحتوي الحاوية على معلمة AllowPrivilegeEscalation. إذا تم تثبيته في false، ستبدأ الحاويات بـ (on) قليل no_new_priv. معنى هذه المعلمة واضح من الاسم: فهو يمنع الحاوية من إطلاق عمليات جديدة بامتيازات أكثر مما تتمتع به نفسها.

يتم تعيين أحد الآثار الجانبية لهذا الخيار على true (افتراضي) هو أن وقت تشغيل الحاوية يطبق ملف تعريف seccomp في بداية عملية بدء التشغيل. وبالتالي، يجب تمكين كافة استدعاءات النظام المطلوبة لتشغيل عمليات وقت التشغيل الداخلية (على سبيل المثال، تعيين معرفات المستخدم/المجموعة، وإسقاط قدرات معينة) في ملف التعريف.

إلى حاوية تفعل أشياء تافهة echo hi، ستكون الأذونات التالية مطلوبة:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "brk",
                "capget",
                "capset",
                "chdir",
                "close",
                "execve",
                "exit_group",
                "fstat",
                "fstatfs",
                "futex",
                "getdents64",
                "getppid",
                "lstat",
                "mprotect",
                "nanosleep",
                "newfstatat",
                "openat",
                "prctl",
                "read",
                "rt_sigaction",
                "statfs",
                "setgid",
                "setgroups",
                "setuid",
                "stat",
                "uname",
                "write"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(hi-pod-seccomp.json)

...بدلاً من هذه:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "brk",
                "close",
                "execve",
                "exit_group",
                "futex",
                "mprotect",
                "nanosleep",
                "stat",
                "write"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(hi-container-seccomp.json)

ولكن مرة أخرى، لماذا هذه مشكلة؟ أنا شخصياً سأتجنب إدراج مكالمات النظام التالية في القائمة البيضاء (ما لم تكن هناك حاجة حقيقية لها): capset, set_tid_address, setgid, setgroups и setuid. ومع ذلك، فإن التحدي الحقيقي هو أنه من خلال السماح بالعمليات التي لا يمكنك التحكم فيها مطلقًا، فإنك تربط الملفات التعريفية بتنفيذ وقت تشغيل الحاوية. بمعنى آخر، قد تجد يومًا ما أنه بعد تحديث بيئة تشغيل الحاوية (إما بواسطتك، أو على الأرجح بواسطة موفر الخدمة السحابية)، تتوقف الحاويات عن العمل فجأة.

نصيحة رقم 1: تشغيل الحاويات مع AllowPrivilegeEscaltion=false. سيؤدي هذا إلى تقليل حجم ملفات تعريف seccomp وجعلها أقل حساسية للتغييرات في بيئة تشغيل الحاوية.

2. إعداد ملفات تعريف seccomp على مستوى الحاوية

يمكن تعيين ملف تعريف seccomp على مستوى الكبسولة:

annotations:
  seccomp.security.alpha.kubernetes.io/pod: "localhost/profile.json"

...أو على مستوى الحاوية:

annotations:
  container.security.alpha.kubernetes.io/<container-name>: "localhost/profile.json"

يرجى ملاحظة أن بناء الجملة أعلاه سيتغير عندما يقوم Kubernetes seccomp سوف تصبح GA (هذا الحدث متوقع في الإصدار التالي من Kubernetes - 1.18 - تقريبًا.).

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

المشكلة هي أن هذه الحاوية تبدأ دائمًا بـ AllowPrivilegeEscalation=trueمما يؤدي إلى المشاكل المذكورة في الفقرة 1، وهذا لا يمكن تغييره.

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

نصيحة رقم 2: قم بتعيين ملفات تعريف seccomp على مستوى الحاوية.

من الناحية العملية، عادة ما تكون هذه القاعدة بمثابة إجابة عالمية على السؤال: "لماذا يعمل ملف تعريف seccomp الخاص بي docker runولكن لا يعمل بعد النشر في مجموعة Kubernetes؟

3. استخدم وقت التشغيل/الافتراضي فقط كملاذ أخير

لدى Kubernetes خياران للملفات الشخصية المضمنة: runtime/default и docker/default. يتم تنفيذ كلاهما بواسطة وقت تشغيل الحاوية، وليس بواسطة Kubernetes. لذلك، قد تختلف وفقًا لبيئة التشغيل المستخدمة وإصدارها.

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

البيانات الشخصية docker/default تم إهماله منذ Kubernetes 1.11، لذا تجنب استخدامه.

في رأيي، الملف الشخصي runtime/default مناسب تمامًا للغرض الذي تم إنشاؤه من أجله: حماية المستخدمين من المخاطر المرتبطة بتنفيذ الأمر docker run على سياراتهم. ومع ذلك، عندما يتعلق الأمر بتطبيقات الأعمال التي تعمل على مجموعات Kubernetes، أجرؤ على القول بأن مثل هذا الملف الشخصي مفتوح للغاية ويجب على المطورين التركيز على إنشاء ملفات تعريف لتطبيقاتهم (أو أنواع التطبيقات).

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

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

4. غير المحدود ليس خيارًا.

من أول تدقيق أمني لـ Kubernetes اتضح أنه افتراضيا تم تعطيل seccomp. وهذا يعني أنه إذا لم تقم بتعيين PodSecurityPolicy، والذي سيمكنه في المجموعة، ستعمل جميع القرون التي لم يتم تحديد ملف تعريف seccomp لها seccomp=unconfined.

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

نصيحة رقم 4: لا ينبغي تشغيل أي حاوية في المجموعة seccomp=unconfinedوخاصة في بيئات الإنتاج.

5. "وضع التدقيق"

هذه النقطة ليست فريدة بالنسبة لـ Kubernetes، ولكنها لا تزال تندرج ضمن فئة "الأشياء التي يجب معرفتها قبل البدء".

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

بعد إصدار Linux kernel 4.14، أصبح من الممكن تشغيل أجزاء من ملف التعريف في وضع التدقيق، وتسجيل المعلومات حول جميع مكالمات النظام في سجل النظام، ولكن دون حظرها. يمكنك تنشيط هذا الوضع باستخدام المعلمة SCMT_ACT_LOG:

SCMP_ACT_LOG: لن يؤثر seccomp على مؤشر الترابط الذي يقوم باستدعاء النظام إذا لم يتطابق مع أي قاعدة في عامل التصفية، ولكن سيتم تسجيل معلومات حول استدعاء النظام.

إليك إستراتيجية نموذجية لاستخدام هذه الميزة:

  1. السماح بمكالمات النظام المطلوبة.
  2. حظر المكالمات من النظام الذي تعلم أنه لن يكون مفيدًا.
  3. تسجيل معلومات حول كافة المكالمات الأخرى في السجل.

المثال المبسط يبدو كالتالي:

{
    "defaultAction": "SCMP_ACT_LOG",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "sched_yield",
                "futex",
                "write",
                "mmap",
                "exit_group",
                "madvise",
                "rt_sigprocmask",
                "getpid",
                "gettid",
                "tgkill",
                "rt_sigaction",
                "read",
                "getpgrp"
            ],
            "action": "SCMP_ACT_ALLOW"
        },
        {
            "names": [
                "add_key",
                "keyctl",
                "ptrace"
            ],
            "action": "SCMP_ACT_ERRNO"
        }
    ]
}

(متوسطة-مختلطة-seccomp.json)

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

ومع ذلك، هناك صيد واحد. بالرغم من SCMT_ACT_LOG بدعم من Linux kernel منذ نهاية عام 2017، لم يدخل النظام البيئي Kubernetes إلا مؤخرًا نسبيًا. لذلك، لاستخدام هذه الطريقة، ستحتاج إلى إصدار Linux kernel 4.14 وإصدار runC ليس أقل الإصدار 1.0.0-rc9.

نصيحة رقم 5: يمكن إنشاء ملف تعريف وضع التدقيق للاختبار في الإنتاج من خلال الجمع بين القوائم السوداء والبيضاء، ويمكن تسجيل جميع الاستثناءات.

6. استخدم القوائم البيضاء

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

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

بالنسبة لتطبيقات Go، قمت بتطوير أداة خاصة تصاحب التطبيق وتجمع كافة المكالمات التي تتم أثناء التنفيذ. على سبيل المثال للتطبيق التالي:

package main

import "fmt"

func main() {
	fmt.Println("test")
}

... فلننطلق gosystract على النحو التالي:

go install https://github.com/pjbgf/gosystract
gosystract --template='{{- range . }}{{printf ""%s",n" .Name}}{{- end}}' application-path

...ونحصل على النتيجة التالية:

"sched_yield",
"futex",
"write",
"mmap",
"exit_group",
"madvise",
"rt_sigprocmask",
"getpid",
"gettid",
"tgkill",
"rt_sigaction",
"read",
"getpgrp",
"arch_prctl",

في الوقت الحالي، هذا مجرد مثال، وسيتبع ذلك المزيد من التفاصيل حول الأدوات.

نصيحة رقم 6: السماح فقط لتلك المكالمات التي تحتاجها حقًا وحظر جميع المكالمات الأخرى.

7. ضع الأسس الصحيحة (أو استعد لسلوك غير متوقع)

ستقوم النواة بفرض ملف التعريف بغض النظر عما تكتبه فيه. حتى لو لم يكن بالضبط ما أردت. على سبيل المثال، إذا قمت بحظر الوصول إلى المكالمات مثل exit أو exit_groupلن تتمكن الحاوية من إيقاف التشغيل بشكل صحيح وحتى بأمر بسيط مثل echo hi علقهo إلى أجل غير مسمى. ونتيجة لذلك، سوف تحصل على استخدام عالي لوحدة المعالجة المركزية في المجموعة:

Seccomp في Kubernetes: 7 أشياء تحتاج إلى معرفتها منذ البداية

في مثل هذه الحالات، يمكن أن تأتي الأداة المساعدة للإنقاذ strace - سيظهر ما هي المشكلة:

Seccomp في Kubernetes: 7 أشياء تحتاج إلى معرفتها منذ البداية
sudo strace -c -p 9331

تأكد من أن ملفات التعريف تحتوي على كافة استدعاءات النظام التي يحتاجها التطبيق في وقت التشغيل.

نصيحة رقم 7: انتبه إلى التفاصيل وتأكد من إدراج جميع مكالمات النظام الضرورية في القائمة البيضاء.

بهذا نختتم الجزء الأول من سلسلة المقالات حول استخدام seccomp في Kubernetes بروح SecDevOps. سنتحدث في الأجزاء التالية عن سبب أهمية ذلك وكيفية أتمتة العملية.

PS من المترجم

اقرأ أيضًا على مدونتنا:

المصدر: www.habr.com

إضافة تعليق