أمن السحابة والحاويات وسلسلة التوريد
درس 2 من 5
2أمن السحابة والحاويات وسلسلة التوريد
الصورة الكبيرةحين انتقلت الشركات للسحابة لم يختفِ الخطر، بل تغيّر شكله. لم يعد المهاجم يكسر جدارًا، بل يجد مفتاح وصول منسيًا في مستودع كود، أو حاوية تخزين مفتوحة للعالم، أو صلاحية * أعطاها مطوّر مستعجل. وفي مارس 2024 كاد باب خلفي في مكتبة ضغط صغيرة اسمها XZ Utils يدخل أغلب خوادم Linux في العالم، بعد سنتين من بناء الثقة مع صاحب المشروع. الأمن الحديث أن تعرف هوياتك، وإعداداتك، وكل سطر لم تكتبه أنت.
ماذا تشاهد في الرسم: أربع طبقات تحميها أنت مهما كانت الخدمة، ومراقبة آلية فوقها كلها لأن الإعدادات تتغير كل يوم.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
استأجرت شقة في برج فاخر. المالك مسؤول عن الأساسات والمصاعد وحارس البوابة (مسؤولية المزوّد). لكن إن تركت باب شقتك مفتوحًا، أو أعطيت نسخة مفتاح لكل عامل توصيل (صلاحيات واسعة)، أو أدخلت أثاثًا لا تعرف ما بداخله (سلسلة التوريد)، فهذا عليك. وأذكى لص لا يكسر الباب، بل ينتظر من يعطيه المفتاح.
المسؤولية المشتركة: في IaaS أنت مسؤول عن النظام والتطبيق والبيانات والهويات والشبكة الافتراضية؛ في PaaS عن التطبيق والبيانات والهويات؛ في SaaS عن البيانات والهويات والإعدادات. IAM: الصلاحيات الأقل، ولا Action: "*" ولا Resource: "*"، وأدوار بمفاتيح مؤقتة (STS أو هويات أحمال العمل) بدل المفاتيح الدائمة، وحدود صلاحيات وسياسات مؤسسية (SCP). CSPM يفحص الإعدادات باستمرار مقابل معايير مثل CIS Benchmarks، وCNAPP يجمع CSPM مع حماية أحمال العمل والهويات. Kubernetes: معايير Pod Security بثلاثة مستويات (Privileged وBaseline وRestricted) يفرضها Pod Security Admission، وRestricted يطلب runAsNonRoot ومنع رفع الصلاحية وإسقاط كل الـ capabilities وseccompProfile: RuntimeDefault؛ وRBAC بأقل صلاحية، وNetworkPolicy تمنع افتراضيًا. سلسلة التوريد: SBOM بصيغة SPDX أو CycloneDX، وSLSA v1.0 بمستويات البناء L1 إلى L3، وتوقيع الحزم والصور بـ Sigstore (cosign). CVE-2024-3094: باب خلفي في XZ Utils 5.6.0 و5.6.1، اكتشفه Andres Freund في 29 مارس 2024 بسبب نصف ثانية تأخير في SSH.
قبل أن تبدأ
🧱أمن الأنظمة والشبكات
عرفت المسؤولية المشتركة باختصار.
🏛️معمارية انعدام الثقة
الدرس السابق.
الفكرة الجوهرية
1من المسؤول عن ماذا؟
كلما صعدت من IaaS إلى SaaS أخذ المزوّد طبقات أكثر، لكن ثلاثة أشياء تبقى عليك في كل الحالات: بياناتك، وهوياتك، وإعداداتك. أغلب حوادث السحابة المنشورة في هذه الثلاثة.
| الطبقة | IaaS | PaaS | SaaS |
|---|---|---|---|
| البيانات والهويات والإعدادات | أنت | أنت | أنت |
| التطبيق | أنت | أنت | المزوّد |
| نظام التشغيل والترقيع | أنت | المزوّد | المزوّد |
| الشبكة الافتراضية والجدران | أنت | مشتركة | المزوّد |
| العتاد ومراكز البيانات | المزوّد | المزوّد | المزوّد |
2الهوية هي المحيط الجديد
في السحابة كل شيء API، وكل API يُستدعى بهوية. فالمهاجم الذي يملك مفتاح هوية بصلاحية * يملك الحساب كله. القواعد: لا مفاتيح دائمة في الكود أو الحاسوب (أدوار مؤقتة بدلها)، ولا نجمة في الأفعال أو الموارد، وMFA لكل إنسان، وحساب الجذر مقفل لا يُستخدم. والمراجعة الآلية تكشف ما يفوت العين:
أدوات مثل IAM Access Analyzer وCSPM تفعل هذا على كل السياسات في الحساب، كل يوم.
import json
policy = json.loads("""{
"Version": "2012-10-17",
"Statement": [
{"Sid": "ReadReports", "Effect": "Allow", "Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::finance-reports/*"},
{"Sid": "QuickFix", "Effect": "Allow", "Action": "s3:*", "Resource": "*"},
{"Sid": "Admin", "Effect": "Allow", "Action": "*", "Resource": "*"},
{"Sid": "PassAny", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "*"}
]
}""")
def listify(x):
return x if isinstance(x, list) else [x]
for st in policy["Statement"]:
if st["Effect"] != "Allow":
continue
actions, resources = listify(st["Action"]), listify(st["Resource"])
problems = []
if "*" in actions:
problems.append("CRITICAL every action: full admin")
elif any(a.endswith(":*") for a in actions):
problems.append("HIGH every action of a service")
if "*" in resources:
problems.append("HIGH every resource")
if "iam:PassRole" in actions and "*" in resources:
problems.append("HIGH can hand any role to a service: privilege escalation")
print(f"{st['Sid']:<12}", "; ".join(problems) or "ok: narrow action and resource").env رُفع إلى GitHub. البوتات تمسح المستودعات العامة بحثًا عن المفاتيح خلال دقائق من رفعها. استخدم أدوارًا مؤقتة وفحص الأسرار قبل كل دفع.3الحاويات وKubernetes
الحاوية ليست آلة افتراضية: كلها تشترك في نواة واحدة. حاوية تعمل كجذر وبصلاحيات خاصة قد تهرب للمضيف وتصل لكل الحاويات الأخرى. لهذا وضع Kubernetes ثلاثة مستويات: Privileged (بلا قيود، لأدوات النظام فقط)، وBaseline (يمنع أخطر الإعدادات)، وRestricted (أفضل الممارسات، وهو هدفك لكل تطبيق عادي). يُفرض المستوى بوسم على مساحة الأسماء: pod-security.kubernetes.io/enforce: restricted.
مخالفة واحدة لـ Baseline تكفي ليُرفض الـ Pod في مساحة أسماء مفروض عليها Baseline أو Restricted.
pod = { # a pod spec as the cluster sees it, simplified
"name": "reports-api",
"hostNetwork": True,
"containers": [{
"name": "api", "image": "registry.local/reports:latest",
"securityContext": {"privileged": False, "runAsNonRoot": False,
"allowPrivilegeEscalation": True,
"capabilities": {"add": ["NET_ADMIN"]}},
}],
}
def check(pod):
out = []
if pod.get("hostNetwork"):
out.append(("baseline", "hostNetwork shares the node's network"))
for c in pod["containers"]:
sc = c.get("securityContext", {})
if sc.get("privileged"):
out.append(("baseline", f"{c['name']}: privileged container"))
if sc.get("capabilities", {}).get("add"):
out.append(("baseline", f"{c['name']}: adds {sc['capabilities']['add']}"))
if not sc.get("runAsNonRoot"):
out.append(("restricted", f"{c['name']}: may run as root"))
if sc.get("allowPrivilegeEscalation", True):
out.append(("restricted", f"{c['name']}: privilege escalation allowed"))
if "ALL" not in sc.get("capabilities", {}).get("drop", []):
out.append(("restricted", f"{c['name']}: capabilities not dropped"))
if not sc.get("seccompProfile"):
out.append(("restricted", f"{c['name']}: no seccomp profile"))
if c["image"].endswith(":latest"):
out.append(("advice", f"{c['name']}: pin the image by digest, not :latest"))
return out
for level, msg in check(pod):
print(f"[{level:<10}] {msg}")وفوق ذلك: RBAC بأقل صلاحية (لا تعطِ cluster-admin لحساب خدمة)، وNetworkPolicy تمنع كل حركة افتراضيًا ثم تسمح بما يلزم فقط، وأسرار في مدير أسرار لا في متغيرات نصية، وصور من سجل موثوق موقعة ومثبتة بالبصمة.
4سلسلة التوريد: كل سطر لم تكتبه
تطبيقك الحديث فيه مئات الحزم المفتوحة، وكل واحدة باب محتمل. ثلاثة أسئلة: ماذا في برمجياتي؟ (SBOM: قائمة مكونات بصيغة SPDX أو CycloneDX، تُقارن بقوائم الثغرات). من بناها وكيف؟ (SLSA: مستويات تثبت أن البناء جرى على منصة موثوقة ولم يُعدّل). هل هي نفسها التي وصلتني؟ (التوقيع بـ Sigstore والتحقق قبل النشر).
مثال محلول
المسألة: تنبيه من CSPM: حاوية تخزين فيها نسخ احتياطية لقاعدة بيانات العملاء صارت عامة قبل ساعتين، والسجلات تُظهر أن دور CI/CD الذي يملك s3:* على * هو من غيّر السياسة. ماذا تفعل الآن وماذا تغيّر بعدها؟
الحل: الآن: أغلق الوصول العام (Block Public Access على مستوى الحساب)، واحفظ سجلات CloudTrail وسجلات الوصول للحاوية كدليل، وابحث فيها: هل نزّل أحد من خارج الشركة شيئًا خلال الساعتين؟ إن نعم فهي حادثة تسرب بيانات شخصية تُبلّغ (نظام حماية البيانات الشخصية: خلال 72 ساعة). السبب الجذري: دور CI/CD يملك صلاحية أكبر بكثير مما يحتاج، والتغيير لم يمر بمراجعة. بعدها: ضيّق الدور إلى الحاويات والأفعال التي يحتاجها فقط، واجعل البنية ككود (Terraform) تمر بفحص سياسات قبل الدمج، واقفل الوصول العام بسياسة مؤسسية لا يستطيع أي دور تجاوزها، واجعل تنبيه CSPM هذا يصل لمناوب خلال دقائق لا ساعتين.
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| السحابة آمنة لأن المزوّد شركة كبيرة. | المزوّد يحمي طبقته. إعداداتك وهوياتك وبياناتك عليك دائمًا. |
| الحاوية معزولة مثل الآلة الافتراضية. | كل الحاويات تشترك في نواة المضيف؛ حاوية بصلاحيات واسعة قد تهرب إليه. |
| الحزم المفتوحة المشهورة آمنة. | XZ Utils كانت حزمة صغيرة في كل مكان تقريبًا. الشهرة لا تعني المراجعة. |
أين تقابله في العمل
🏦البنوك على السحابة
ضوابط الحوسبة السحابية تتطلب إدارة الهويات ومراقبة الإعدادات.
📦فرق المنصات
Kubernetes بمستوى Restricted افتراضيًا لكل فريق.
🛒شراء البرمجيات
طلب SBOM من المورّد صار ممارسة شائعة في العقود.
اختبر فهمك
في SaaS، ما الذي يبقى مسؤوليتك دائمًا؟
المزوّد يدير كل الطبقات تقريبًا، لكن من يصل ولماذا وكيف تُضبط الخدمة يبقى عليك.
سياسة فيها Action: "*" وResource: "*". ما المشكلة؟
من يملك هذه الهوية يملك الحساب كله.
أي مستوى من Pod Security هو هدف التطبيقات العادية؟
Privileged لأدوات النظام فقط، وRestricted أفضل الممارسات.
ما الذي يجيب عنه SBOM؟
قائمة المكونات تُقارن بقوائم الثغرات فتعرف فورًا هل أنت متأثر.
كيف اكتُشف باب XZ Utils الخلفي؟
Andres Freund لاحظ نصف ثانية تأخير واستهلاك معالج غريب، فتتبع السبب.
بطاقات مراجعة سريعة
تحقق من فهمك
لماذا الأدوار المؤقتة أفضل من المفاتيح الدائمة؟
لأن المفتاح المؤقت ينتهي خلال ساعات، فتسريبه أقل ضررًا، ولا يُنسى في ملف لسنوات.
ما خطورة حاوية تعمل كجذر بصلاحيات خاصة؟
قد تهرب إلى المضيف عبر النواة المشتركة وتصل لكل الحاويات الأخرى.
ما الأسئلة الثلاثة لسلسلة التوريد؟
ماذا في برمجياتي؟ من بناها وكيف؟ هل هي نفسها التي وصلتني؟
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.