Docker المتقدم وأمن الحاويات

فحص الصور واكتشاف الثغرات الأمنية

18 دقيقة الدرس 4 من 28

فحص الصور واكتشاف الثغرات الأمنية

كل صورة حاوية تطرحها للنشر هي قطعة أثرية من سلسلة توريد البرمجيات. تحتوي على طبقة نظام التشغيل، ومكتبات النظام، وبيئات تشغيل اللغات، وتبعيات تطبيقك — أي منها قد يحمل ثغرات أمنية معروفة (CVEs). على نطاق الشركات الكبرى، تقوم فرق الأمن باعتراض عمليات النشر عادةً عند وجود CVEs حرجة، ويتلقى مهندسو الاستجابة للطوارئ تنبيهات عندما تظهر ثغرة zero-day في صورة أساسية مُشغَّلة بالفعل في الإنتاج.

يغطي هذا الدرس أكثر أداتَي فحص استخداماً في الأنظمة الاحترافية — Trivy وGrype — وكيفية قراءة نتائجهما وتصنيفها، وكيفية تحديد CVEs التي تمثل خطراً فعلياً، واستراتيجية تحديث الصورة الأساسية التي تبقي أسطولك آمناً دون كسر الإنتاج.

لماذا ينتمي فحص الصور إلى CI وليس فقط مرحلة ما قبل النشر

الغريزة الأولى هي الفحص مرة واحدة قبل الدفع. لكن الواقع أن CVE منشورة في أي يوم ثلاثاء قد تؤثر على صور بنيتها ونشرتها منذ أشهر. يتطلب الموقف الأمني في الشركات الكبرى:

  • فحص مبكر (Shift-left) — إيقاف البناء في CI عند ظهور CVEs حرجة أو عالية الخطورة في صورتك.
  • الفحص المستمر للسجل — إعادة فحص كل وسم في الإنتاج ليلياً، لأن قواعد بيانات CVE تُحدَّث يومياً.
  • إعادة البناء التلقائية — تُطلَق عند نشر الصورة الأساسية الأولية لـ digest مُصحَّح.

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

Trivy — أداة الفحص المعيارية في الصناعة

Trivy (من Aqua Security) هي المعيار الفعلي في معظم الأنظمة. تفحص حزم نظام التشغيل (Alpine apk، Debian apt، RHEL rpm)، وملفات بيئات اللغات (package-lock.json، go.sum، requirements.txt، Gemfile.lock، pom.xml)، ويمكنها أيضاً فحص ملفات Dockerfile وملفات Kubernetes manifests للكشف عن إعدادات خاطئة.

# تثبيت Trivy (macOS) brew install trivy # تثبيت Trivy (Linux — سطر واحد عبر السكريبت الرسمي) curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin # فحص صورة محلية — إخراج جدولي، كل مستويات الخطورة trivy image myapp:latest # فحص صورة من سجل بعيد trivy image nginx:1.27-alpine # تقرير Critical وHigh فقط، الخروج بكود غير صفري عند إيجاد أي منها (بوابة CI) trivy image --severity CRITICAL,HIGH --exit-code 1 myapp:latest # فحص ملف tarball (مفيد لمشغّلات CI المعزولة) docker save myapp:latest | trivy image --input - # الإخراج بصيغة SARIF لـ GitHub Advanced Security trivy image --format sarif --output trivy-results.sarif myapp:latest # فحص نظام الملفات (ممتاز لفحص كود المصدر دون بناء) trivy fs --severity CRITICAL,HIGH ./

Grype — البديل من Anchore

Grype (من Anchore) هو المنافس الرئيسي لـ Trivy. كلاهما يستهلك قواعد بيانات CVE ذاتها (NVD، GitHub Advisory، استشارات بائعي نظام التشغيل)، لكن Grype يتكامل مع Syft لتوليد SBOM قابل لإعادة الاستخدام (قائمة مواد البرمجيات) يمكن لأي أداة متوافقة فحصه — وهو متطلب رئيسي في البيئات المنظَّمة والمشتريات الفيدرالية الأمريكية (NIST SSDF، EO 14028).

# تثبيت Grype curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin # فحص أساسي grype myapp:latest # Critical/High فقط، الخروج بكود غير صفري عند إيجاد ثغرات grype --fail-on high myapp:latest # توليد SBOM بـ Syft، ثم فحص SBOM بـ Grype (نهج منفصل) syft myapp:latest -o spdx-json > sbom.json grype sbom:sbom.json --fail-on critical # Grype يقرأ أيضاً تارات OCI grype docker-archive:myapp.tar
الفحص المعتمد على SBOM هو المعيار الناشئ. ولّد SBOM مرة واحدة عند البناء (أرفقه بالصورة عبر syft attest أو خزّنه في سجلك)، ثم أعد فحص ذلك SBOM ليلياً دون إعادة بناء الصورة. هذا أرخص بكثير من إعادة سحب وفحص صور ضخمة كل ليلة.

قراءة نتائج الفحص — تصنيف CVE

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

  1. الخطورة — CRITICAL وHigh إلزامية؛ MEDIUM تُتابَع؛ LOW وUNKNOWN لا تُعالَج تقريباً إلا إذا كانت المكتبة مستدعاة مباشرة في كودك.
  2. الإصدار المُصحَّح المتاح — إذا لم يتوفر إصلاح، لا يمكنك تصحيحه بالترقية؛ يمكنك فقط تخفيفه بإزالة المكون أو قبول الخطر. CVEs بدون إصلاح تُصنَّف "مراقبة" لا "إيقاف".
  3. قابلية الوصول — هل مسار الكود الضعيف مستدعى فعلاً بتطبيقك؟ Trivy وGrype يجريان تحليلاً ثابتاً لا ديناميكياً. مُحلِّل XML ضعيف في حزمة تستخدمها فقط لـ JSON منخفض الخطورة الفعلية.
  4. CVSS مقابل EPSS — تُعيّن درجات CVSS تسميات الخطورة (Critical = 9.0–10.0). EPSS (نظام تنبؤ الاستغلال) يعطي احتمالية الاستغلال الفعلي خلال 30 يوماً القادمة. CVSS 9.8 مع EPSS 0.001 أولوية أقل بكثير من CVSS 7.5 مع EPSS 0.45. Grype يشحن بيانات EPSS الآن؛ Trivy يدعمها عبر --vex.
CVE Triage Decision Flow New CVE Finding Severity CRITICAL or HIGH? Low / Medium Track & review No Yes Fix version available? No Fix Yet Accept + monitor No Yes EPSS > 5% or CVSS >= 9.0? Schedule fix next sprint No Yes Block deploy / urgent patch Rebase image within 24h Triage Legend Block deploy Track / schedule Low priority
مخطط قرار تصنيف CVE: تحدد الخطورة وتوفر الإصلاح واحتمالية الاستغلال EPSS معاً مستوى إلحاح الاستجابة.

دمج Trivy في نظام GitHub Actions

النمط الإنتاجي الأكثر شيوعاً هو مهمة من خطوتين: بناء الصورة، فحصها، والفشل عند وجود ثغرات Critical/High. إرفاق تقرير SARIF بـ GitHub Advanced Security يمنح فريق أمنك لوحة CVE موحدة وقابلة للبحث عبر كل المستودعات.

name: Build & Scan on: push: branches: [main] pull_request: jobs: build-and-scan: runs-on: ubuntu-latest permissions: contents: read security-events: write # مطلوب لرفع SARIF steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t myapp:${{ github.sha }} . # أداة Trivy الرسمية — تخزّن قاعدة البيانات بين التشغيلات - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} format: sarif output: trivy-results.sarif severity: CRITICAL,HIGH exit-code: 1 # يُفشل المهمة عند وجود ثغرات - name: Upload SARIF to GitHub Security tab if: always() # رفع حتى لو وجد الفحص ثغرات uses: github/codeql-action/upload-sarif@v3 with: sarif_file: trivy-results.sarif
ثبّت أداة Trivy عند SHA بدلاً من @master في الإنتاج: aquasecurity/trivy-action@a20de5420d57c4102486cdd9349b532d1d638e94. هجمات سلسلة التوريد على GitHub Actions حقيقية — أداة مُخترَقة بصلاحيات كتابة يمكنها تسريب بيانات اعتماد السجل من بيئة مشغّلك.

استراتيجية تحديث الصورة الأساسية

معظم CVEs في صورة الحاوية مصدرها طبقة نظام التشغيل — وليس كود تطبيقك. الإصلاح هو إعادة البناء فوق صورة أساسية مُصحَّحة. في الشركات الكبرى، هذه العملية مُؤتمتة:

  • Dependabot / Renovate لـ Docker — فتح PR تلقائياً عند تغيير digest الصورة الأساسية الأولية. Renovate أكثر قابلية للتهيئة وأكثر استخداماً على نطاق واسع.
  • مهام إعادة البناء الليلية — نظام جدولي يعيد بناء كل صورة من وسمها الأساسي المثبّت. إذا حصل alpine:3.20 على تصحيح، إعادة البناء الليلية تمنحك الإصلاح صباح اليوم التالي.
  • تثبيت Digest + تحديثات مؤتمتة — ثبّت على FROM alpine:3.20@sha256:abc123 لضمان قابلية تكرار البناء، لكن دع Renovate يحدّث ذلك SHA عند نشر digest جديد.
# مثال إعداد Renovate في renovate.json — تحديث تلقائي لـ Docker digests { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:base"], "docker": { "enabled": true }, "packageRules": [ { "matchManagers": ["dockerfile"], "matchUpdateTypes": ["digest", "patch", "minor"], "automerge": true, "automergeType": "pr", "requiredStatusChecks": ["build-and-scan"] } ] } # تثبيت الصورة الأساسية عند digest في Dockerfile FROM python:3.12-slim@sha256:4afe3b39b7f1bc61f946ba769ebd5ce48e61d0bda340b2daef34437d32b5f61f
لا تدمج تحديثات الصورة الأساسية تلقائياً بدون مهمة فحص ناجحة مطلوبة. يمكن أن يُدخل digest صورة أساسية جديدة CVEs جديدة أثناء إصلاح قديمة. بوابة requiredStatusChecks في Renovate (أو قاعدة حماية فرعك في CI) تضمن نجاح الفحص قبل دمج PR. تجاهل هذا تسبب في حوادث إنتاجية متعددة حيث أدخل "تصحيح أمني" انحداراً.

استثناءات الثغرات (VEX / .trivyignore)

في نظام ناضج، بعض CVEs مقبولة بشكل مشروع — المكتبة موجودة لكن مسار الكود الضعيف غير قابل للوصول، أو لا يتوفر إصلاح بعد والخطر مقبول رسمياً. تسجيل هذه القرارات كـ كود يمنع نسيانها بصمت وإعادة فتحها عند كل تشغيل فحص.

# .trivyignore — إسكات CVEs محددة مع توثيق المبرر # الصيغة: CVE-ID [تاريخ-انتهاء] [تعليق] # CVE-2023-44487 (HTTP/2 Rapid Reset) — مخفَّف بقاعدة WAF لـ ALB الأولية CVE-2023-44487 # CVE-2024-21626 (رunc container escape) — ثابت في إصدار runc المثبّت لدينا # إيجابي زائف من Trivy بسبب عدم تطابق سلسلة إصدار حزمة OS؛ ينتهي 2025-01-01 CVE-2024-21626 exp:2025-01-01 # المعادل لـ Grype: .grype.yaml # ignore: # - vulnerability: CVE-2023-44487 # reason: "Mitigated at ALB layer; expires 2025-06-01" # expires: "2025-06-01T00:00:00Z"
تعامل مع كل CVE مُسكَّت باعتباره ديناً تقنياً. ضع تاريخ انتهاء، وأضف رابطاً لتذكرة JIRA أو GitHub حيث أُقرِّرت الإعفاء رسمياً، وعيّن مالكاً. تقوم فرق الأمن في الشركات الناضجة بمراجعة قوائم الإسكات ربع سنوياً — الإسكات غير الموثَّق أو المنتهي الصلاحية هو إشكالية امتثال، وليس فجوة في الممارسات الجيدة فحسب.

ملخص

فحص الصور ليس خانة اختيار — بل هو عملية مستمرة. استخدم Trivy أو Grype في CI كبوابة صارمة للنتائج Critical/High التي لها إصلاح متاح. صنّف بشكل مكثف باستخدام EPSS جنباً إلى جنب مع خطورة CVSS. أتمت تحديثات الصورة الأساسية بـ Renovate، مع بوابة من مهمة الفحص. سجّل الخطر المقبول في ملفات إسكات مُحكمة بإصدار مع تواريخ انتهاء. هذا الموقف — فحص، تصنيف، أتمتة، توثيق — هو ما يُميز أمن الحاوية الاحترافي عن مسرحية أمنية.