فحص الحاويات والبنية التحتية كرمز
فحص الحاويات والبنية التحتية كرمز
ملف Dockerfile ليس مجرد سكريبت بناء — بل هو مواصفة لحدود الأمان. كل سطر FROM يرث سطح هجوم. كل RUN apt-get install يثبّت إصدار حزمة ستنجرف نحو نطاق CVE في اليوم الذي تتوقف فيه عن إعادة البناء. ملفات البنية التحتية كرمز (Terraform، وبيانيات Kubernetes، وملفات Helm، وقوالب CloudFormation) تحمل مخاطر موازية: حقل مُهيأ خطأً مثل privileged: true، أو حاوية S3 مكشوفة للعموم مُعرَّفة في HCL، خطيرة بالقدر نفسه الذي تكون فيه المكتبة الثغرة. تعلّمك هذه الدرس كيفية اكتشاف كلتا الفئتين في CI — قبل أن تصل الصورة أو المورد إلى أي بيئة حقيقية.
فحص CVE للصور: كيف يعمل فعلاً
تعمل ماسحات صور الحاويات باستخراج مخزون البرامج من نظام ملفات طبقي — حزم نظام التشغيل من /var/lib/dpkg/status أو /var/lib/rpm، وحزم اللغة من package-lock.json وgo.sum وPipfile.lock وما إلى ذلك — ثم مطابقة هذا المخزون مع قواعد بيانات الثغرات: NVD، وقاعدة بيانات استشارات GitHub، وتوصيات RedHat، وتغذيات خاصة بالتوزيعات. الأداتان المفتوحتا المصدر السائدتان هما Trivy (من Aqua Security) وGrype (من Anchore). تدعم كلتاهما الفحص بالاسم أو بملف tar أو مباشرةً من نظام الملفات — وهذا مهم لأنك تريد الفحص في CI قبل دفع الصورة، لا بعده.
Trivy هو المعيار الفعلي في خطوط الأنابيب الحديثة. إنه ثنائي واحد بدون daemon، يتعامل مع صور الحاويات وأنظمة الملفات ومستودعات git وملفات IaC في أداة واحدة، ويُصدر مخرجات SARIF تتكامل مع GitHub Advanced Security ولوحات أمان GitLab.
--exit-code 1 هو ما يجعل الماسح بوابة لا مجرد مُقرِّر. بدونه، سيسرد Trivy كل CVE ويخرج بـ0 — يبدو خط الأنابيب أخضر بينما يُشحن RCE حرجي. اضبط دائماً كود خروج صريح؛ اضبط عتبة الخطورة لتتوافق مع اتفاقية مستوى الخدمة لمؤسستك (عادةً HIGH,CRITICAL للحجب، MEDIUM للتحذير فقط).
استراتيجية الصورة الأساسية: أكبر رافعة
أسرع طريقة للقضاء على CVEs هي تصغير الصورة الأساسية. صورة نموذجية مبنية على ubuntu:22.04 تحمل 200 إلى 400 حزمة نظام تشغيل. صورة gcr.io/distroless/base-debian12 تحمل نحو 20. ثنائي Go مبني على scratch لا يحمل أي حزمة. في Google، تُعدّ صور distroless الافتراض الافتراضي لجميع أحمال عمل الإنتاج — ليس لأنها رائجة بل لأن تقليص سطح الهجوم دراماتيكي وقابل للقياس.
يحقق نمط Dockerfile متعدد المراحل المعياري هذا دون التضحية بسهولة المطورين: البناء في صورة SDK كاملة، ونسخ الأداة المُجمَّعة فقط إلى صورة تشغيل مُصغَّرة.
FROM golang:1.22-alpine قابل للتغيير — يمكن إعادة كتابة التاغ بصمت إلى صورة مختلفة (ربما ثغرة). استخدم FROM golang:1.22-alpine@sha256:<digest> في Dockerfiles الإنتاج. يتعامل Dependabot وRenovate مع تحديثات الصور الأساسية المُثبَّتة بالـ digest تلقائياً.
فحص IaC: اكتشاف الأخطاء قبل التطبيق
تُرمَّز وضعيتك الأمنية في Terraform وبيانيات Kubernetes وملفات Helm وقوالب CloudFormation كرمز. privileged: true في DaemonSet، أو حاوية S3 مع block_public_acls = false، أو قاعدة مجموعة أمان مع cidr_blocks = ["0.0.0.0/0"] على المنفذ 22، كلها أخطاء إعداد ستصل إلى الإنتاج لحظة تشغيل terraform apply أو kubectl apply — ما لم تفحصها أولاً.
الماسحان الرائدان لـ IaC هما Checkov (من Bridgecrew/Prisma Cloud) وماسح الإعدادات المدمج في Trivy. يدعم كلاهما Terraform HCL وKubernetes YAML وHelm وDockerfile وCloudFormation وقوالب ARM. للتحكم الدقيق بسياسة كرمز، يتيح لك OPA Conftest كتابة سياسات Rego مخصصة ضد أي ملف إعداد منظّم.
معمارية الفحص في CI
على النطاق الإنتاجي، تعمل مهام فحص الصور وIaC بالتوازي مع مراحل CI الأخرى لتجنب إضافة كمون على المسار الحرج. التخطيط المعياري لخط أنابيب GitHub Actions:
أبرز النتائج الحرجة الشائعة وكيفية إصلاحها
فهم أكثر النتائج عالية الخطورة شيوعاً يساعدك في تحديد أولوية المعالجة. هذه الأنماط التي تظهر باستمرار عبر المؤسسات الهندسية الكبرى:
- التشغيل كمستخدم root — الافتراض في تقريباً كل Dockerfile. الإصلاح: أضف
USER 1001:1001أو استخدمUSER nonrootمن distroless. في Kubernetes: فرّض ذلك بسياسة PodSecurity (runAsNonRoot: true). - نظام ملفات جذر قابل للكتابة — يتيح لمهاجم يحقق تنفيذ كود الإصرار على التغييرات. الإصلاح:
readOnlyRootFilesystem: trueفيsecurityContextالحاوية، مع مُركَّباتemptyDirصريحة للمسارات القابلة للكتابة التي يحتاجها التطبيق. - الحاوية المميزة — مكافئة لامتلاك صلاحيات root على عقدة المضيف. لا يجب أن تظهر خارج إضافات CNI/التخزين المحددة جداً. تسامح صفري:
privileged: falseيجب أن يكون سياسة لا تذكيراً. - حدود الموارد المفقودة — ليست CVE لكنها HIGH في Checkov: حاوية غير مقيّدة يمكنها قتل جيرانها بنفاد الذاكرة. اضبط دائماً
resources.limits.cpuوresources.limits.memory. - حزم نظام تشغيل قديمة في الصورة الأساسية — المصدر الأكثر شيوعاً لـ CVEs. الإصلاح: أعد البناء من أساس حالي أسبوعياً عبر طلبات سحب Dependabot/Renovate الآلية، أو استخدم صورة distroless للقضاء على طبقة نظام التشغيل كلياً.
.trivyignore يجب أن يحمل تاريخ انتهاء (exp:YYYY-MM-DD) وتذكرة مرتبطة. بدون انتهاء صلاحية، تتراكم CVEs المُخمَّتة بصمت. نمط حادثة شائع: فريق يُخمَّت CVE بانتظار ترقية صورة أساسية، الترقية تُؤجَّل، تُستغَلّ الثغرة بعد ستة أشهر — ويكشف ما بعد الحادثة أن الماسح كان يُبلّغ عنها باللون الأخضر طوال الوقت.
الفحص في التحكم بالقبول: الجدار الأخير
بوابات فحص CI ضرورية لكنها غير كافية وحدها. يمكن للمهندسين دفع صور عبر CLI، ويمكن تجاوز خطوط أنابيب CI، وقد تدخل صور طرف ثالث إلى مجموعتك من ملفات Helm. يضيف نهج الدفاع المتعمق فحصاً عند وقت القبول عبر سياسات Kyverno أو OPA Gatekeeper التي تتحقق من مصدر الصورة وحالة الفحص قبل جدولة الـ pods.
سياسة Kyverno تحجب الصور غير المفحوصة بـ Trivy في آخر 24 ساعة (باستخدام تعليق التوثيق الذي يضعه CI) تبدو هكذا:
على النطاق الكبير، تتكامل الفرق مع سجل حاويات يدعم الفحص المستمر في الخلفية — Docker Hub وECR وGCR وArtifact Registry جميعها تقدم هذا. يفحص السجل كل صورة عند الدفع ويعيد الفحص يومياً مقابل تغذيات CVE الجديدة، لذا حتى الصور التي اجتازت CI أمس تُشير إليها إذا ظهرت توصية حرجة جديدة بين عشية وضحاها. تبقى وضعية وقت التشغيل حديثة دون الحاجة إلى بناء جديد.
الوضعية الشاملة للفحص — بوابة CI تحجب عند البناء، وبوابة IaC تحجب عند التخطيط، وتحكم القبول يحجب عند الجدولة، وفحص السجل يُشير عند ظهور CVEs جديدة — تغلق النافذة من إنشاء الصورة إلى النشر إلى وقت التشغيل دون أي نقطة فشل منفردة. كل طبقة تصطاد ما فاتت الطبقة السابقة.