DevSecOps وأمن سلسلة التوريد

مشروع: خط تسليم آمن

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

مشروع: خط تسليم آمن

تناولت الدروس العشرة في هذه الوحدة كل طبقة أمنية على حدة — ثقافة التحول اليساري في الأمن، ونمذجة التهديدات، وتحليل الشيفرة الساكن (SAST)، وفحص التبعيات (SCA)، والاختبار الديناميكي (DAST)، وفحص الحاويات والبنية التحتية كود، وقوائم مكونات البرمجيات (SBOM)، والتوقيع والتحقق، وإدارة الأسرار. يجمع هذا الدرس الختامي كل ذلك في تصميم خط إنتاج واحد احترافي، ويشرح كيفية تشابك البوابات الأمنية، وكيف تكوّن سلسلة الشهادات سجلاً قابلاً للتدقيق يصمد أمام أي تحقيق في سلسلة التوريد.

يعكس النموذج المقدم هنا الطريقة التي تُنظّم بها شركات من أمثال Google وGitHub وShopify نهج DevSecOps فعلياً: الأمن ليس مجرد فحص يوقف طلب سحب — بل هو سلسلة من الادعاءات الموقّعة حول البرمجيات تتراكم من أول إيداع حتى التشغيل الفعلي. إن غاب أي حلقة في تلك السلسلة أو كانت غير صالحة، رفضت بوابة النشر القطعة المبنية.

نموذج البوابات الخمس

يُنظّم خط التسليم الآمن الناضج ضوابطه في خمس بوابات مرتبة. كل بوابة إما تُنتج شهادة موقّعة (ادعاء تشفيري حول القطعة المبنية) أو تستهلك شهادات البوابات السابقة. لا يتقدم شيء دون أن تكون شهادة البوابة موجودة وصالحة.

  • البوابة الأولى — سلامة الكود: فحص تسرب الأسرار بـGitleaks + تحليل SAST بـSemgrep/CodeQL + فحص تراخيص التبعيات. تعمل على كل إيداع في طلب السحب بشكل متوازٍ. تُنتج شهادة code-scan موقّعة بهوية OIDC لمنظومة التكامل المستمر.
  • البوابة الثانية — ثقة التبعيات: فحص SCA بـTrivy/Grype مقابل قواعد بيانات OSV وCVE، وتوليد SBOM بـSyft مرفقاً بطلب السحب. تحجب عند وجود أي ثغرة حرجة يتوفر لها إصلاح. تُنتج شهادة sbom وشهادة vuln-scan.
  • البوابة الثالثة — سلامة البناء: بناء قابل للتكرار في مُشغّل مؤقت معزول عن الشبكة. فحص IaC بـCheckov/tfsec على تغييرات Terraform/Helm. بناء صورة الحاوية وتوقيعها بـCosign (بلا مفاتيح محلية، باستخدام Sigstore). توليد شهادة منشأ SLSA بواسطة المُنشئ. لا تُرسل الصورة إلى السجل إلا بعد إرفاق جميع الشهادات.
  • البوابة الرابعة — التحقق قبل النشر: تفحص سياسات Kyverno أو OPA/Gatekeeper الصورةَ للتأكد من وجود جميع الشهادات المطلوبة قبل السماح بها في أي فضاء أسماء Kubernetes. يعمل اختبار DAST (فحص ZAP API) على بيئة التجهيز بعد النشر. لا تمر البوابة إلا حين لا يجد DAST أي ثغرات عالية أو حرجة.
  • البوابة الخامسة — الضمان المستمر في وقت التشغيل: تراقب قواعد أمان Falco السلوكَ غير الطبيعي للعمليات. تُدير Vault الأسرار الديناميكية وتُدوّر الاعتمادات قبل كل نشر. تراقب Dependency-Track قائمة SBOM الإنتاجية للثغرات المنشورة حديثاً وتُنبّه المناوب عند ظهور ثغرة حرجة.
Five-Gate Secure Delivery Pipeline with Attestation Chain Gate 1 Code Integrity Gitleaks · Semgrep CodeQL · License ⟶ code-scan attest Gate 2 Dependency Trust Trivy SCA · Syft SBOM OSV · Grype ⟶ sbom + vuln attest Gate 3 Build Integrity Reproducible Build Cosign · SLSA L3 ⟶ provenance attest Gate 4 Pre-Deploy Verify Kyverno attest check ZAP DAST · OPA ⟶ deploy-approval Gate 5 Runtime Assurance Falco · Vault Rotate Dep-Track · Alerts ⟶ continuous CVE watch Attestation Chain — each gate signs a claim; Gate 4 verifies ALL prior attestations exist on the image before deploy Trigger: PR commit Trigger: PR commit Trigger: merge to main Trigger: CD deploy job Trigger: continuous Any gate failure → artifact is quarantined; deployment is blocked; on-call paged if severity ≥ HIGH Vault Dynamic Secrets OCI Registry Image + Cosign Attestations Dependency-Track SBOM + CVE Feed
نموذج خط التسليم الآمن ذو البوابات الخمس: تعمل البوابتان 1 و2 على كل طلب سحب، وتبني البوابة 3 وتوقّع عند الدمج، وتتحقق البوابة 4 من جميع الشهادات قبل النشر على Kubernetes، وترصد البوابة 5 بيئة التشغيل باستمرار.

الربط الكامل: سير عمل GitHub Actions

يُظهر الهيكل التالي كيف تُترجَم البوابات الخمس إلى سير عمل GitHub Actions حقيقي. تعمل الوظائف في المرحلة نفسها بشكل متوازٍ. تستخدم وظيفة build-and-sign التوجيه needs: لفرض ترتيب البوابات — لن تعمل ما لم تنجح البوابتان الأولى والثانية.

# .github/workflows/secure-pipeline.yml name: Secure Delivery Pipeline on: push: branches: [main] pull_request: permissions: contents: read id-token: write # مطلوب للتوقيع بلا مفاتيح محلية عبر Cosign + SLSA packages: write # الدفع إلى GHCR security-events: write jobs: # ── البوابة 1: سلامة الكود ────────────────────────────────────────────── secrets-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} sast: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: github/codeql-action/init@v3 with: { languages: python, javascript } - uses: github/codeql-action/autobuild@v3 - uses: github/codeql-action/analyze@v3 with: { category: /language:python } # ── البوابة 2: ثقة التبعيات ──────────────────────────────────────────── sca-and-sbom: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: فحص SCA بـTrivy — توقف عند الثغرات الحرجة التي يوجد لها إصلاح uses: aquasecurity/trivy-action@master with: scan-type: fs exit-code: "1" severity: CRITICAL ignore-unfixed: true - name: توليد SBOM بـSyft uses: anchore/sbom-action@v0 with: format: cyclonedx-json output-file: sbom.cdx.json - uses: actions/upload-artifact@v4 with: { name: sbom, path: sbom.cdx.json } # ── البوابة 3: سلامة البناء ───────────────────────────────────────────── build-and-sign: needs: [secrets-scan, sast, sca-and-sbom] runs-on: ubuntu-latest outputs: image-digest: ${{ steps.push.outputs.digest }} steps: - uses: actions/checkout@v4 - name: إعداد QEMU & Buildx uses: docker/setup-buildx-action@v3 - name: تسجيل الدخول إلى GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: بناء ودفع الصورة (قابلة للتكرار، provenance=true) id: push uses: docker/build-push-action@v6 with: push: true tags: ghcr.io/${{ github.repository }}:${{ github.sha }} sbom: true provenance: mode=max - name: تثبيت Cosign uses: sigstore/cosign-installer@v3 - name: توقيع الصورة (بلا مفاتيح محلية — يستخدم رمز OIDC) run: | cosign sign --yes \ ghcr.io/${{ github.repository }}@${{ steps.push.outputs.digest }} - name: إرفاق شهادة SBOM run: | cosign attest --yes \ --predicate sbom.cdx.json \ --type cyclonedx \ ghcr.io/${{ github.repository }}@${{ steps.push.outputs.digest }} # ── البوابة 4: التحقق قبل النشر ─────────────────────────────────────── pre-deploy-verify: needs: [build-and-sign] runs-on: ubuntu-latest steps: - name: التحقق من توقيع Cosign والشهادات run: | cosign verify \ --certificate-identity-regexp \ "https://github.com/${{ github.repository }}/.github/workflows/.*" \ --certificate-oidc-issuer \ "https://token.actions.githubusercontent.com" \ ghcr.io/${{ github.repository }}@${{ needs.build-and-sign.outputs.image-digest }} - name: النشر على بيئة التجهيز run: kubectl set image deployment/myapp myapp=ghcr.io/${{ github.repository }}@${{ needs.build-and-sign.outputs.image-digest }} -n staging - name: DAST — فحص ZAP API uses: zaproxy/action-api-scan@v0.9.0 with: target: https://staging.myapp.example.com/openapi.json fail_action: true
لماذا نمرر الـdigest لا العلامة (tag)؟ العلامات قابلة للتغيير — يمكن أن تشير :latest غداً إلى صورة مختلفة. أما الـdigest (sha256:abc…) فهو مرجع ثابت لهاش طبقة صورة محددة. كل خطوة في خط الإنتاج بعد مرحلة البناء تستخدم الـdigest لا العلامة، مما يغلق نافذة هجوم استبدال العلامة حيث يستبدل المهاجم صورة السجل بين خطوة التوقيع وخطوة النشر.

سياسة Kyverno للقبول: إغلاق الحلقة

البوابة الرابعة لا معنى لها ما لم يُنفّذها Kubernetes. بدون وحدة تحكم في القبول، يستطيع المطور دفع صورة أُنشئت يدوياً متجاوزاً كل الفحوصات ونشرها مباشرة بـkubectl. تشترط سياسة ClusterPolicy في Kyverno أن يحمل كل Pod توقيع Cosign صالحاً صادراً عن هوية OIDC لمنظومة CI الخاصة بك قبل أن يقبل خادم API مواصفة الـPod.

# kyverno/require-image-signature.yaml apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-signed-images spec: validationFailureAction: Enforce background: false rules: - name: check-image-signature match: any: - resources: kinds: [Pod] namespaces: [production, staging] verifyImages: - imageReferences: - "ghcr.io/myorg/*" attestors: - entries: - keyless: subject: "https://github.com/myorg/myapp/.github/workflows/secure-pipeline.yml@refs/heads/main" issuer: "https://token.actions.githubusercontent.com" rekor: url: https://rekor.sigstore.dev attestations: - predicateType: https://cyclonedx.org/bom

أنماط الفشل ومسارات الطوارئ

يجب أن تتعامل خطوط الإنتاج مع حالات الطوارئ دون التخلي تماماً عن الأمان. ثلاثة أنماط فشل شائعة وكيفية التعامل معها:

  • انقطاع خدمة فحص سلسلة التوريد: إذا تعذّر الوصول إلى خادم قاعدة بيانات Trivy، أخفق مفتوحاً (اسمح بالبناء) لكن أخطر فريق الأمن وحدد مهلة 24 ساعة للفحص اليدوي. لا تدع انقطاع خدمة موردٍ ما يُصبح عائقاً أمام نشر أولوية صفر — لكن لا تتخطى الفحص بصمت. سجّل التخطي كشهادة استثناء موقّعة.
  • ثغرة يوم صفر في تبعية متعدية بلا إصلاح: الحل الصحيح ليس كتم النتيجة. استخدم ملف .trivyignore بتاريخ انتهاء صلاحية ومرجع تذكرة Jira. يمكن إعداد Kyverno لقبول صورة تحمل شهادة vuln-exception تتضمن معرف التذكرة وتاريخ الانتهاء، موقّعة بمفتاح مهندس أمان.
  • إصلاح طارئ للإنتاج: حدد إجراء "كسر الزجاج": بيئة GitHub تتطلب موافقة مراجعين (مهندسان أوليان + مهندس أمان)، ومراجعة ما بعد الحادث إلزامية، وتذكرة Jira تلقائية. يمكن إعداد سياسة Kyverno للسماح بالصور الموقّعة بمفتاح كسر الزجاج بمدة صلاحية ساعتين. كل حدث من هذا القبيل مسجّل في سجل تدقيق ثابت.
ابدأ بوضع التدقيق ثم انتقل إلى الإلزام. عند طرح سياسات Kyverno للقبول على كتلة قائمة، اضبط validationFailureAction: Audit أولاً. هذا يُسجّل انتهاكات السياسة دون حجب عمليات النشر. شغّل في وضع التدقيق أسبوعين، وأصلح جميع الانتهاكات، ثم انتقل إلى Enforce. التبديل المباشر إلى Enforce على كتلة تحتوي صوراً قديمة غير موقّعة سيُسبب انقطاعاً فورياً في الخدمة.
تثبيت الشهادات وحده غير كافٍ. تُثبت توقيعات Cosign وشهادات SLSA أن الصورة بُنيت بواسطة منظومة CI الخاصة بك. لكنها لا تُثبت خلوّ الصورة من الثغرات التي نُشرت بعد البناء. لهذا السبب تُعدّ البوابة الخامسة (مراقبة Dependency-Track للـSBOM باستمرار) إلزامية — فصورة كانت نظيفة يوم البناء قد تُصبح ثغرتها حرجة في الصباح التالي عند نشر CVE جديد يطال أحد حزمها. الـSBOM يمنحك القائمة الكاملة لتعرف فوراً أي التطبيقات العاملة متأثرة.

قياس خط الإنتاج: مؤشرات الأداء الأمني

خط الإنتاج الذي لا يمكن قياسه لا يمكن تحسينه. أربعة مؤشرات تهم على نطاق الشركات الكبرى: متوسط وقت الاكتشاف (MTTD) — المدة من نشر ثغرة ما حتى إطلاق تنبيه Dependency-Track؛ متوسط وقت المعالجة (MTTR) — المدة من التنبيه حتى تشغيل صورة مُصلَحة في الإنتاج؛ معدل الإفلات من البوابات — نسبة الثغرات التي وصلت إلى الإنتاج دون أن تكتشفها البوابات 1-4 (الهدف: صفر إفلات حرج أو عالٍ)؛ وتغطية خط الإنتاج — نسبة الصور الإنتاجية التي تحمل سلسلة شهادات كاملة وصالحة (الهدف: 100%). تتبّع هذه المؤشرات في لوحة Grafana تتغذى من واجهة Dependency-Track البرمجية وخط أحداث التدقيق.