SBOM وCosign بالعربي: اعرف إيه دخل الإنتاج قبل النشر
مستوى القارئ: متوسط
بعد المقال ده هتعرف تعمل gate بسيط في الـ CI يمنع صورة container مجهولة المصدر من الوصول للإنتاج. الفكرة مش إنك تزود خطوة شكلية، الفكرة إنك تعرف المكونات، التوقيع، ومين بنى الصورة قبل ما تعمل deploy.
المشكلة باختصار
الطريقة الشائعة إن الفريق يبني Docker image، يرفعها على registry، وبعدها Kubernetes يسحبها. الطريقة دي بتفشل لما يحصل incident بسبب package قديمة أو image اتبنت من branch غلط. وقتها السؤال بيبقى: الصورة دي فيها إيه بالظبط؟ ومين بناها؟ وهل حد غيّرها بعد الـ CI؟
افترض إن عندك API عليه 50K زائر يوميًا، وبتطلع 8 releases في الأسبوع. لو vulnerability ظهرت في مكتبة زي OpenSSL أو lodash، البحث اليدوي داخل كل صورة ممكن ياخد 2 إلى 4 ساعات. وجود SBOM يقلل السؤال من “ندور فين؟” إلى “افحص الملف ده وشوف التأثير”. الرقم هنا تقديري، لكنه قريب من فرق صغيرة عندها 10 إلى 20 service.
يعني إيه SBOM وSigning بمثال واضح
ركز في المثال ده. اعتبر الـ container زي شحنة داخلة مخزن. الـ SBOM هو كشف المحتويات: اسم كل package، نسختها، ونوعها. التوقيع بـ Cosign هو ختم الاستلام: مين بنى الشحنة، وإمتى، وعلى أي digest. من غير كشف المحتويات أنت شايف الصندوق فقط. ومن غير الختم أنت مش واثق إن الصندوق هو نفسه اللي خرج من المصنع.
علميًا، SBOM اختصار Software Bill of Materials. أدوات مثل Trivy تستطيع توليد SBOM بصيغتين شائعتين: SPDX وCycloneDX، وتقدر تفحص SBOM لاحقًا لاكتشاف ثغرات أو مشاكل license حسب توثيق Trivy الرسمي. Cosign من Sigstore يضيف توقيعًا أو attestation مرتبطًا بصورة الحاوية، ويمكن استخدام OIDC من GitHub بدل مفاتيح ثابتة مخزنة في secrets.
Workflow عملي على GitHub Actions
الهدف هنا بسيط: ابنِ الصورة، طلّع SBOM، ارفع الصورة، وقّعها، ثم احفظ attestation. المثال مبني على GitHub Actions وGHCR وTrivy وCosign. الافتراض إن عندك repository على GitHub وصورة Dockerfile في الجذر.
name: build-secure-image
on:
push:
branches: ["main"]
permissions:
contents: read
packages: write
id-token: write
attestations: write
artifact-metadata: write
env:
IMAGE: ghcr.io/${{ github.repository }}/api
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
- name: Build image
run: |
docker build -t "$IMAGE:${{ github.sha }}" .
docker push "$IMAGE:${{ github.sha }}"
- name: Generate SBOM with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.IMAGE }}:${{ github.sha }}
format: spdx-json
output: sbom.spdx.json
- name: Attest SBOM
uses: actions/attest@v4
with:
subject-path: sbom.spdx.json
sbom-path: sbom.spdx.json
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Sign image with keyless Cosign
run: cosign sign --yes "$IMAGE:${{ github.sha }}"
بعد أول run، جرّب تتحقق محليًا أو داخل job تاني:
IMAGE="ghcr.io/OWNER/REPO/api:COMMIT_SHA"
cosign verify "$IMAGE" \
--certificate-identity-regexp "https://github.com/OWNER/REPO/.github/workflows/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
trivy image --format table "$IMAGE"
trivy sbom sbom.spdx.json
الأرقام التي تراقبها
لا تقيس نجاح الخطوة بإحساس الأمان. قِس 3 أرقام واضحة. أول رقم: زمن الـ CI بعد إضافة الفحص. في مشروع Node متوسط، Trivy scan للصورة قد يضيف 30 إلى 90 ثانية حسب حجم الصورة والكاش. ثاني رقم: عدد الثغرات الحرجة المسموح بها. الأفضل إن critical = 0 في main. ثالث رقم: نسبة الصور الموقعة في الإنتاج. استهدف 100% للـ services الجديدة، ثم ارجع للقديم تدريجيًا.
الـ trade-off هنا واضح. بتكسب traceability وفحص أسرع وقت الحوادث. بتخسر دقيقة تقريبًا في كل build، ومحتاج تضبط صلاحيات OIDC والـ registry. لو الـ CI عندك أصلاً بياخد 3 دقائق، الزيادة مقبولة. لو بياخد 25 دقيقة، ابدأ بتحسين الكاش قبل ما تزود scanning كثيف على كل branch.
متى لا تستخدم هذه الطريقة
لا تبدأ بـ SBOM وCosign لو الفريق لسه بينشر يدويًا من جهاز المطور. في الحالة دي أصلح مسار النشر الأول، لأن توقيع صورة مبنية محليًا من غير CI موحد هيضيف إحساس أمان زائف. كمان لا تجعل الـ build يفشل على كل medium vulnerability في أول أسبوع. هتغرق في noise. ابدأ بـ critical فقط، وبعد أسبوعين أضف high للصور الحساسة.
لا تعتمد على SBOM وحده كبديل عن تحديث dependencies. SBOM بيقولك الموجود، لكنه لا يصلحه. ولا تعتمد على توقيع الصورة كدليل إن الكود آمن. التوقيع يثبت المصدر والسلامة، لكنه لا يثبت جودة الكود.
مصادر اعتمد عليها
- توثيق Trivy عن توليد وفحص SBOM بصيغ SPDX وCycloneDX: trivy.dev/docs/latest/supply-chain/sbom
- توثيق Sigstore Cosign عن توقيع صور الحاويات وkeyless signing: docs.sigstore.dev/cosign/signing/signing_with_containers
- توثيق GitHub actions/attest عن attestation وصلاحيات OIDC: github.com/actions/attest
- توثيق SLSA لمفهوم provenance في سلسلة التوريد البرمجية: slsa.dev/spec
الخطوة التالية
الخطوة التالية: افتح workflow البناء الأساسي عندك، وأضف Trivy SBOM فقط على main لمدة أسبوع. لو زمن الـ CI زاد أقل من 90 ثانية، أضف Cosign signing بعدها واجعل النشر يقبل الصور الموقعة فقط.