مقدمة
إن فهم كيفية مهاجمة CI/CD pipelines ليس سوى نصف الصورة. يمنحنا نمذجة التهديدات وتصنيف الهجمات خريطة لساحة المعركة، لكن بدون أنماط دفاعية ملموسة وتدابير هندسية للتخفيف، تظل تلك المعرفة نظرية. يسدّ هذا الدليل الفجوة بين الوعي والعمل.
الهدف ليس بناء حصن منيع — فهذا غير موجود. بدلاً من ذلك، نركز على تقليل سطح الهجوم، والحد من نطاق الضرر عندما يحدث خطأ ما، وجعل الـ pipelines مرنة بما يكفي للتعافي بسرعة. كل عنصر تحكم موصوف هنا يرتبط بأنماط هجوم حقيقية: الـ pipelines المسمومة، وسرقة بيانات الاعتماد، واختطاف التبعيات، والتلاعب بالمخرجات.
سنستعرض الدفاعات طبقة بطبقة — من الكود المصدري إلى وقت التشغيل — ثم نغطي قدرات الكشف والاستجابة للحوادث التي تُغلق الحلقة. سواء كنت تؤمّن GitHub Actions أو GitLab CI أو Jenkins أو أي منصة CI/CD أخرى، تظل المبادئ واحدة.
الدفاع المتعدد الطبقات لـ CI/CD
لا يكفي عنصر تحكم أمني واحد لحماية CI/CD pipeline. المهاجمون مبدعون، وسيجدون الثغرة في أي دفاع أحادي الطبقة. الاستراتيجية الوحيدة القابلة للتطبيق هي الدفاع المتعدد الطبقات: عناصر تحكم متداخلة في كل مرحلة من دورة حياة تسليم البرمجيات.
ربط الدفاعات بقائمة OWASP Top 10 CI/CD Security Risks
توفر قائمة OWASP Top 10 CI/CD Security Risks إطاراً منظماً لفهم ما يمكن أن يحدث من أخطاء. كل خطر — من CICD-SEC-1 (آليات التحكم في التدفق غير الكافية) حتى CICD-SEC-10 (عدم كفاية التسجيل والرؤية) — يتطلب تدابير تخفيف محددة. تم تنظيم الدفاعات في هذا الدليل لمعالجة هذه المخاطر بشكل منهجي.
الركائز الثلاث: الوقاية، الكشف، الاستجابة
- الوقاية: عناصر تحكم توقف الهجمات قبل نجاحها — حماية الفروع، الصلاحيات الدنيا، المخرجات الموقّعة، المشغّلات المؤقتة.
- الكشف: المراقبة والتنبيه التي تكشف الشذوذ — سلوك pipeline غير متوقع، انحراف الإعدادات، تبعيات جديدة، تسريب الأسرار.
- الاستجابة: خطط وإجراءات عندما تفشل الدفاعات — إلغاء بيانات الاعتماد، تحليل نطاق الضرر، التحقق من سلامة المخرجات، التحقيق الجنائي.
الدفاع في كل طبقة
فكّر في CI/CD pipeline كسلسلة من حدود الثقة:
- المصدر: حيث يدخل الكود والإعدادات إلى الـ pipeline
- البناء: حيث يتم تجميع الكود واختباره وتعبئته
- المخرجات: حيث يتم تخزين مخرجات البناء وتوزيعها
- النشر: حيث تصل المخرجات إلى بنية الإنتاج التحتية
- وقت التشغيل: حيث يتم تنفيذ البرمجيات المنشورة ومراقبتها
لكل طبقة تهديدات مميزة وتتطلب دفاعات مميزة. لا ينبغي أن يتسلسل الاختراق في طبقة واحدة تلقائياً إلى الطبقة التالية.
دفاعات طبقة المصدر — حماية مدخلات الـ Pipeline
طبقة المصدر هي حيث تبدأ معظم هجمات CI/CD. المهاجم الذي يمكنه تعديل الكود أو تعريفات الـ pipeline أو ملفات الإعدادات يتحكم فيما ينفذه الـ pipeline. تضمن دفاعات طبقة المصدر أن التغييرات المُصرّح بها والمُراجَعة والمُتحقق منها فقط هي التي تدخل الـ pipeline.
قواعد حماية الفروع
حماية الفروع هي خط الدفاع الأول. كحد أدنى، يجب أن تفرض فروع main والإصدار:
- مراجعات pull request مطلوبة: لا دفع مباشر إلى الفروع المحمية. جميع التغييرات تمر عبر مراجعة الكود.
- فحوصات الحالة المطلوبة: يجب أن يمر CI قبل الدمج. هذا يمنع دمج كود معطل أو خبيث يتجاوز الاختبارات.
- لا force pushes: الدفع القسري يعيد كتابة التاريخ ويمكن استخدامه لإزالة أدلة الالتزامات الخبيثة.
- تاريخ خطي مطلوب: يمنع merge commits التي يمكن أن تخفي تغييرات خبيثة في فروق معقدة.
CODEOWNERS للمسارات الحساسة
ليست كل الملفات في المستودع تحمل نفس المخاطر. تعريفات الـ pipeline وقوالب البنية التحتية كـ code وإعدادات الحاويات هي أهداف عالية القيمة. استخدم CODEOWNERS لطلب مراجعة من فرق محددة للمسارات الحساسة:
# .github/CODEOWNERS
# Pipeline definitions require security team review
.github/workflows/ @org/security-team
.gitlab-ci.yml @org/security-team
Jenkinsfile @org/security-team
# Infrastructure as code
terraform/ @org/platform-team @org/security-team
pulumi/ @org/platform-team @org/security-team
# Container definitions
Dockerfile* @org/security-team
docker-compose*.yml @org/security-team
# Dependency manifests
package.json @org/security-team
requirements.txt @org/security-team
go.sum @org/security-team
الالتزامات الموقّعة والتحقق
يوفر توقيع الالتزامات دليلاً تشفيرياً على التأليف. بدونه، يمكن للمهاجم الذي يخترق رمز وصول مطور أن يدفع التزامات تبدو وكأنها من أي شخص. فعّل التحقق من توقيع الالتزامات على الفروع المحمية لضمان توقيع كل التزام بمفتاح GPG أو SSH موثق.
# Configure Git to sign commits with SSH key
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
# Verify a commit signature
git verify-commit HEAD
سياسات مراجعة PR
مراجعة الكود هي تحكم بشري، ويحتاج إلى حواجز حماية:
- لا موافقة ذاتية: لا ينبغي أن يكون مؤلف PR قادراً على الموافقة على تغييراته الخاصة.
- مراجعون مطلوبون من فريق الأمان للتغييرات في ملفات pipeline أو إعدادات الأسرار أو بيانات النشر.
- إلغاء المراجعات القديمة: إذا تم دفع التزامات جديدة بعد الموافقة، يجب إلغاء الموافقات السابقة لفرض إعادة المراجعة.
- طلب مراجعة من مالكي الكود: اقرن هذا مع CODEOWNERS لفرض متطلبات المراجعة الخاصة بالمجال.
تقييد محفزات الـ Pipeline
ليس كل حدث يجب أن يُشغّل تشغيلاً كاملاً للـ pipeline، خاصة واحداً يملك صلاحية الوصول إلى الأسرار:
- قيود Fork: يجب أن تعمل PRs من الـ forks في سياق مقيد بدون صلاحية الوصول إلى أسرار المستودع.
- صلاحيات المساهمين: فقط المتعاونون الذين لديهم صلاحية الكتابة يجب أن يتمكنوا من تشغيل workflows التي تصل إلى موارد حساسة.
- الموافقة للمساهمين الجدد: اطلب الموافقة اليدوية قبل تشغيل pipelines للمساهمين الجدد.
دفاعات طبقة البناء — تأمين عملية البناء
طبقة البناء هي حيث يصبح الكود قابلاً للتنفيذ. الاختراق هنا يعني أن المهاجم يمكنه حقن منطق خبيث في مخرجاتك دون تعديل الكود المصدري. تركز دفاعات طبقة البناء على العزل والطبيعة المؤقتة والصلاحيات الدنيا.
المشغّلات المؤقتة (Ephemeral Runners)
تتراكم في مشغّلات CI الدائمة حالة: بيانات اعتماد مخزنة مؤقتاً، وملفات متبقية من بناءات سابقة، ومتغيرات بيئة تتسرب بين المهام. تقضي المشغّلات المؤقتة على هذه الفئة من المخاطر تماماً من خلال توفير VM أو حاوية جديدة لكل مهمة وتدميرها فوراً بعد ذلك.
# GitHub Actions: Self-hosted ephemeral runner with actions-runner-controller
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
name: ephemeral-runners
spec:
replicas: 5
template:
spec:
ephemeral: true
repository: your-org/your-repo
labels:
- self-hosted
- ephemeral
- linux
dockerdWithinRunnerContainer: false
image: ghcr.io/actions/actions-runner:latest
resources:
limits:
cpu: "2"
memory: "4Gi"
بيئات البناء المعزولة
حتى مع المشغّلات المؤقتة، يمكن للبناءات التي تتشارك ذاكرة التخزين المؤقت أو نطاقات الشبكة أن تسرّب معلومات بين المهام. تأكد من:
- لا ذاكرة تخزين مؤقت مشتركة بين البناءات غير الموثوقة: تسميم ذاكرة التخزين المؤقت هو ناقل هجوم حقيقي. اعزل ذاكرة التخزين المؤقت لكل فرع أو لكل PR.
- مجموعات مشغّلات منفصلة: لا ينبغي أن تُشارَك مشغّلات نشر الإنتاج مع مشغّلات التحقق من PR.
- عزل الحاويات: استخدم حاويات rootless أو microVMs (مثل Firecracker و gVisor) لعزل أقوى من Docker القياسي.
قيود الشبكة أثناء البناء
يمكن لخطوة بناء مخترقة ذات صلاحية وصول غير مقيدة إلى الشبكة أن تسرّب الأسرار إلى بنية تحتية يتحكم فيها المهاجم. قيّد صلاحية الوصول الصادر إلى الشبكة:
- لا وصول صادر إلى الإنترنت: الخيار الأكثر صرامة. يجب أن تأتي جميع التبعيات من مرايا داخلية أو صور مخزنة مسبقاً.
- نطاقات مسموحة فقط: إذا كان الوصول إلى الإنترنت ضرورياً، قيّده إلى سجلات ومستودعات حزم معروفة وموثوقة.
- تصفية DNS: استخدم سياسات DNS لحظر الوصول إلى النطاقات غير المصرح بها أثناء البناء.
# Kubernetes NetworkPolicy for CI runner pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ci-runner-egress-restricted
namespace: ci-runners
spec:
podSelector:
matchLabels:
role: ci-runner
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/8 # Internal network only
ports:
- protocol: TCP
port: 443 # HTTPS to internal registries
- protocol: TCP
port: 53 # DNS
- protocol: UDP
port: 53 # DNS
صور البناء المصغّرة
كل أداة مثبتة في صورة البناء هي سطح هجوم محتمل. جرّد صور البناء إلى الحد الأدنى:
- استخدم صور distroless أو صور Alpine كقواعد للبناء.
- أزل الـ shells ومديري الحزم وأدوات الشبكة من صور بناء الإنتاج حيث أمكن.
- ثبّت image digests وليس tags لمنع هجمات سلسلة التوريد القائمة على الـ tags.
# Pin by digest, not by tag
FROM golang:1.22@sha256:a3b21c5d8e... AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o /app/binary
# Use distroless for the final image
FROM gcr.io/distroless/static-debian12@sha256:f4e8b1c2d9...
COPY --from=builder /app/binary /binary
ENTRYPOINT ["/binary"]
تعطيل أوضاع التصحيح في pipelines الإنتاج
التسجيل التفصيلي والمخرجات المطولة لا تقدر بثمن أثناء التطوير لكنها خطيرة في pipelines الإنتاج. يمكنها تسريب الأسرار والمسارات الداخلية وتفاصيل البنية التحتية. تأكد من تعطيل ACTIONS_STEP_DEBUG و CI_DEBUG_TRACE والعلامات المكافئة في إعدادات pipeline الإنتاج.
دفاعات بيانات الاعتماد والهوية — تقييد ما يمكن للـ Pipelines الوصول إليه
بيانات الاعتماد هي الهدف الأكثر قيمة في أي CI/CD pipeline. المهاجم الذي يحصل على مفتاح وصول سحابي أو رمز نشر أو سر API يمكنه التحول بعيداً عن الـ pipeline نفسه. تركز دفاعات بيانات الاعتماد على تقليل ما هو موجود، وما يمكن الوصول إليه، ولكم من الوقت.
صلاحيات الرموز الدنيا
يمتلك GITHUB_TOKEN الافتراضي في GitHub Actions صلاحيات واسعة. قيّده دائماً إلى الحد الأدنى المطلوب:
# GitHub Actions: Restrict default token permissions
permissions:
contents: read
packages: read
id-token: write # Only if using OIDC
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- run: make build
deploy:
runs-on: ubuntu-latest
needs: build
permissions:
contents: read
id-token: write # For OIDC authentication
steps:
- name: Authenticate to cloud
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy-role
aws-region: us-east-1
OIDC وهوية أعباء العمل
الأسرار طويلة الأمد المخزنة في أنظمة CI/CD هي قنابل موقوتة. استبدلها بـ OIDC-based workload identity federation حيثما أمكن:
- GitHub Actions إلى AWS: استخدم
aws-actions/configure-aws-credentialsمع OIDC role assumption. - GitHub Actions إلى GCP: استخدم
google-github-actions/authمع Workload Identity Federation. - GitHub Actions إلى Azure: استخدم
azure/loginمع federated credentials. - GitLab CI إلى AWS/GCP/Azure: استخدم رمز OIDC الأصلي لـ GitLab (
CI_JOB_JWT_V2) مع federation مزود السحابة.
مع OIDC، تصدر منصة CI/CD رمز JWT قصير الأمد، ويستبدله مزود السحابة ببيانات اعتماد مؤقتة. لا يتم تخزين أسرار ثابتة في أي مكان.
بيانات اعتماد لكل بيئة ولكل مرحلة
مجموعة واحدة من بيانات الاعتماد مشتركة عبر جميع البيئات تعني نطاق ضرر كارثي. قسّم بيانات الاعتماد:
- يجب أن تستخدم بيئات التطوير والتجهيز والإنتاج حسابات خدمة منفصلة بصلاحيات منفصلة.
- لا ينبغي أن تملك مراحل البناء صلاحية الوصول إلى بيانات اعتماد النشر.
- يجب أن تستخدم مراحل الاختبار بنية تحتية للاختبار معزولة، وليس بيئات مشتركة.
لا أسرار في workflows الـ PR/Fork
لا ينبغي أبداً أن تملك pull requests من الـ forks صلاحية الوصول إلى أسرار المستودع. هذا خطأ شائع في الإعدادات يمكّن المهاجمين من تسريب الأسرار بتقديم PR خبيث. في GitHub Actions، استخدم pull_request (وليس pull_request_target) للكود غير الموثوق، ولا تمرر أبداً الأسرار إلى الخطوات التي تنفذ كود PR.
تكامل Vault مع الأسرار الديناميكية
لبيانات الاعتماد التي لا يمكنها استخدام OIDC (كلمات مرور قواعد البيانات، مفاتيح API لخدمات الطرف الثالث)، استخدم مدير أسرار مثل HashiCorp Vault مع أسرار ديناميكية قصيرة الأمد:
# HashiCorp Vault: Generate short-lived database credentials
vault read database/creds/ci-readonly
# Returns:
# Key Value
# --- -----
# lease_id database/creds/ci-readonly/abc123
# lease_duration 1h
# username v-ci-readonly-xyz789
# password A1B2-C3D4-E5F6-G7H8
تُنشأ الأسرار الديناميكية عند الطلب، ومحددة النطاق للهوية الطالبة، وتُلغى تلقائياً عند انتهاء صلاحيتها. حتى لو تسربت، تُقاس نافذة التعرض بالدقائق، وليس بالأشهر.
تسجيل تدقيق جميع عمليات الوصول إلى الأسرار
يجب أن تولّد كل عملية استرداد سر إدخالاً في سجل التدقيق. إذا لم يسجل مدير الأسرار الخاص بك عمليات الوصول، فليس لديك طريقة للتحقيق في الاختراق. تأكد من أن السجلات تلتقط: من وصل إلى ماذا، ومتى، ومن أي تشغيل pipeline، ومن أي عنوان IP.
دفاعات طبقة المخرجات — ضمان سلامة المخرجات
مخرجات البناء — صور الحاويات والثنائيات والحزم — هي الجسر بين الـ pipeline الخاص بك والإنتاج. إذا تمكن المهاجم من التلاعب بالمخرجات بعد بنائها، تصبح جميع الدفاعات السابقة بلا جدوى. تضمن دفاعات طبقة المخرجات السلامة والمنشأ وعدم القابلية للتغيير.
توقيع جميع المخرجات باستخدام Sigstore/Cosign
يوفر توقيع المخرجات دليلاً تشفيرياً على أن المخرج أُنتج بواسطة الـ pipeline الخاص بك ولم يُعدّل منذ ذلك الحين. يجعل Cosign من Sigstore التوقيع بدون مفتاح عملياً:
# Sign a container image using Cosign (keyless, OIDC-based)
cosign sign --yes ghcr.io/your-org/your-app:v1.2.3@sha256:abc123...
# Verify the signature
cosign verify \
--certificate-identity=https://github.com/your-org/your-app/.github/workflows/build.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
ghcr.io/your-org/your-app:v1.2.3@sha256:abc123...
مع التوقيع بدون مفتاح، يكون مفتاح التوقيع مؤقتاً ومرتبطاً بهوية OIDC لـ workflow الـ CI/CD. لا يوجد مفتاح توقيع طويل الأمد يمكن سرقته.
إنشاء وتخزين SLSA Provenance
يسجل SLSA (Supply-chain Levels for Software Artifacts) provenance كيف وأين ومن بنى المخرج. في SLSA Level 3، يتم إنشاء الـ provenance بواسطة منصة البناء نفسها ولا يمكن تزويره من عملية البناء:
# GitHub Actions: Generate SLSA provenance for container images
- uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
with:
image: ghcr.io/your-org/your-app
digest: ${{ steps.build.outputs.digest }}
secrets:
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
تخزين المخرجات غير القابل للتغيير
لا ينبغي أبداً الكتابة فوق المخرجات المنشورة. إذا تمكن المهاجم من استبدال إصدار منشور، يمكنه حقن كود خبيث في كل عملية نشر تشير إلى ذلك الإصدار. اضبط سجلاتك لعدم القابلية للتغيير:
- سجلات الحاويات: فعّل tag immutability (تدعمها ECR و GCR و ACR جميعها).
- سجلات الحزم: امنع إعادة نشر الإصدارات الموجودة.
- تخزين الثنائيات: استخدم سياسات التخزين للكتابة مرة واحدة (S3 Object Lock أو سياسات احتفاظ GCS).
إنشاء SBOM والتصديق
تسرد قائمة مواد البرمجيات (SBOM) كل مكون في المخرج الخاص بك. إنشاء SBOM في وقت البناء والتصديق عليها مع المخرج ينشئ جرداً قابلاً للتحقق لإدارة الثغرات:
# Generate SBOM with Syft and attest with Cosign
syft ghcr.io/your-org/your-app:v1.2.3 -o spdx-json > sbom.spdx.json
cosign attest --predicate sbom.spdx.json --type spdxjson \
ghcr.io/your-org/your-app:v1.2.3@sha256:abc123...
وحدات التحكم في القبول للتحقق من التوقيع
توقيع المخرجات مفيد فقط إذا تحققت من التوقيعات قبل النشر. استخدم وحدات التحكم في القبول في Kubernetes لفرض ذلك تلقائياً:
# Kyverno: Require signed images
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
background: false
rules:
- name: verify-cosign-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "ghcr.io/your-org/*"
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/your-org/*"
مع هذه السياسة المعمول بها، سيتم رفض أي صورة حاوية تفتقر إلى توقيع Cosign صالح من workflows GitHub Actions الخاصة بك في وقت القبول — قبل أن تعمل في مجموعتك.
دفاعات طبقة النشر — التحكم فيما يصل إلى الإنتاج
طبقة النشر هي البوابة الأخيرة قبل وصول التغييرات إلى الإنتاج. تضمن الدفاعات هنا أن المخرجات المُتحقق منها والمعتمدة فقط يتم نشرها، وأن عملية النشر نفسها مُتحكم بها وقابلة للتدقيق.
الموافقات اليدوية المطلوبة
لعمليات نشر الإنتاج، يجب أن تتوقف الـ pipelines الآلية وتتطلب موافقة بشرية صريحة. يوفر هذا نقطة فحص نهائية حيث يمكن للإنسان التحقق من أن التغيير متوقع ومختبر ومُصرّح به.
# GitHub Actions: Environment with required reviewers
jobs:
deploy-production:
runs-on: ubuntu-latest
environment:
name: production
url: https://your-app.example.com
steps:
- name: Deploy to production
run: ./deploy.sh production
في إعدادات مستودع GitHub، اضبط بيئة “production” لتتطلب الموافقة من المراجعين المعينين قبل متابعة المهمة.
GitOps مع النشر القائم على السحب
تدفع pipelines CI/CD التقليدية إلى الإنتاج: يمتلك الـ pipeline بيانات اعتماد لتعديل بنية الإنتاج التحتية. هذا سطح هجوم كبير. يعكس GitOps مع النشر القائم على السحب النموذج:
- الـ Pipeline يحدّث مستودع Git بالحالة المطلوبة (image tags والبيانات الوصفية).
- المجموعة تشغّل وحدة تحكم (Flux أو ArgoCD) تراقب مستودع Git وتسحب التغييرات.
- الـ Pipeline لا يملك أبداً وصولاً مباشراً إلى المجموعة. المجموعة تسحب من Git، وGit هو مصدر الحقيقة الوحيد.
# Flux: GitRepository and Kustomization for pull-based deployment
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: app-manifests
namespace: flux-system
spec:
interval: 1m
url: https://github.com/your-org/app-manifests
ref:
branch: main
secretRef:
name: git-credentials
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app-production
namespace: flux-system
spec:
interval: 5m
path: ./environments/production
prune: true
sourceRef:
kind: GitRepository
name: app-manifests
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: your-app
namespace: production
النشر التدريجي والتراجع الآلي
حتى مع جميع الدفاعات السابقة، يمكن لعملية النشر أن تسبب مشاكل. يحد النشر التدريجي (Canary) من التعرض بنشر التغييرات إلى نسبة صغيرة من حركة المرور أولاً. إذا تدهورت المقاييس، يعيد التراجع الآلي التغيير قبل أن يؤثر على جميع المستخدمين.
- استخدم أدوات التسليم التدريجي مثل Flagger أو Argo Rollouts أو ميزات canary الأصلية لمزود السحابة.
- حدد معايير نجاح واضحة: معدل الأخطاء، زمن الاستجابة، مقاييس التشبع.
- أتمت محفزات التراجع — لا تعتمد على البشر للملاحظة والتفاعل في الوقت المناسب.
تجميد عمليات النشر
أثناء الحوادث النشطة أو نوافذ الصيانة أو فترات حركة المرور العالية، يجب تجميد عمليات النشر. نفّذ سياسات تجميد النشر التي تمنع عمليات النشر التي يبدأها الـ pipeline خلال نوافذ محددة، وتأكد من أن مديري الحوادث المعينين فقط يمكنهم تجاوز التجميد.
الكشف والمراقبة — معرفة متى يكون هناك خطأ
ستفشل الوقاية في النهاية. تحدد قدرات الكشف ما إذا كنت ستلتقط الاختراق في دقائق أو أشهر. مراقبة CI/CD هي نقطة عمياء لدى العديد من المؤسسات — تستوعب SIEM الخاصة بهم سجلات التطبيقات والبنية التحتية لكنها تتجاهل القياسات عن بعد للـ pipeline تماماً.
كشف شذوذ تنفيذ الـ Pipeline
أنشئ خطوط أساس لسلوك pipeline الطبيعي ونبّه عند الانحرافات:
- أوقات تشغيل غير عادية: بناء يستغرق عادةً 5 دقائق يستغرق فجأة 30 دقيقة قد يشير إلى تعدين العملات المشفرة أو تسريب البيانات.
- خطوات غير متوقعة: خطوات pipeline جديدة تظهر بدون تغييرات PR مقابلة.
- التنفيذ خارج ساعات العمل: تشغيل pipeline خارج ساعات العمل العادية بواسطة حسابات غير عادية.
- ارتفاع فشل المصادقة: محاولات وصول فاشلة متعددة إلى الأسرار من تشغيل pipeline واحد.
تنبيه فرق التبعيات
يجب أن تُطلق التبعيات الجديدة المضافة في PRs مراجعة آلية وتنبيهاً. يمكن لأداة فرق التبعيات أن:
- تضع علامة على التبعيات الجديدة المضافة في PR للمراجعة اليدوية.
- تتحقق من التبعيات الجديدة مقابل قواعد بيانات الحزم الخبيثة المعروفة.
- تتحقق من أن إصدارات التبعيات تتطابق مع تلك الموجودة في ملفات القفل المعروفة بأنها جيدة.
- تنبّه عن التبعيات ذات تواريخ النشر الحديثة جداً (typosquatting محتمل).
فحص الأسرار
تتسرب الأسرار من خلال الالتزامات والسجلات والمخرجات. طبّق عدة مناهج فحص متطابقة:
- خطافات Pre-commit: أدوات مثل
gitleaksأوtrufflehogتلتقط الأسرار قبل دخولها المستودع. - الفحص داخل الـ Pipeline: افحص مخرجات البناء والسجلات بحثاً عن بيانات اعتماد مكشوفة عرضياً.
- GitHub secret scanning / GitLab secret detection: الفحص الأصلي للمنصة الذي يغطي أحداث الدفع والالتزامات التاريخية.
- تنبيهات برنامج الشركاء: يُخطر برنامج شركاء فحص الأسرار في GitHub مزودي الخدمة عند كشف رموزهم، مما يتيح الإلغاء التلقائي.
# Pre-commit hook with gitleaks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
مراقبة انحراف الإعدادات
يجب أن تتغير تعريفات الـ Pipeline من خلال عملية PR العادية. راقب التغييرات غير المتوقعة:
- نبّه عندما تتغير ملفات workflow أو إعدادات CI أو بيانات النشر خارج PRs المعتمدة.
- تتبع تغييرات صلاحيات pipeline بمرور الوقت.
- اكتشف أسرار pipeline جديدة تُضاف بدون طلبات تغيير مقابلة.
تكامل SIEM مع سجلات تدقيق CI/CD
أعد توجيه سجلات تدقيق CI/CD إلى SIEM الخاص بك جنباً إلى جنب مع سجلات التطبيقات والبنية التحتية. تشمل مصادر السجلات الرئيسية:
- GitHub Audit Log (مستوى المنظمة والمؤسسة)
- GitLab Audit Events
- سجلات نظام Jenkins وسجلات البناء
- سجلات تدقيق مزود السحابة لاستدعاءات API التي يبدأها الـ pipeline (CloudTrail و Cloud Audit Logs و Azure Activity Log)
اربط نشاط الـ pipeline بتغييرات البنية التحتية السحابية. إذا تزامن تشغيل pipeline مع تعديلات غير متوقعة في سياسات IAM أو إنشاء موارد، فهذا تنبيه ذو أولوية عالية.
الاستجابة للحوادث في CI/CD — عندما تفشل الدفاعات
عندما يتم اكتشاف اختراق CI/CD — أو الاشتباه به — تكون السرعة مهمة. قد يكون لدى المهاجم وصول نشط لا يزال، وكل دقيقة تأخير توسع نطاق الضرر. دليل استجابة للحوادث مُعد مسبقاً لسيناريوهات CI/CD المحددة أمر ضروري.
الإجراءات الفورية: احتواء الاختراق
- إلغاء بيانات الاعتماد المخترقة فوراً. قم بتدوير جميع الأسرار التي كان الـ pipeline المخترق يملك صلاحية الوصول إليها. يشمل ذلك بيانات اعتماد مزود السحابة ورموز API وكلمات مرور قواعد البيانات ورموز منصة CI/CD نفسها.
- تعطيل الـ pipeline المخترق. امنع المزيد من عمليات التنفيذ حتى يكتمل التحقيق.
- عزل المشغّلات المتأثرة. إذا كنت تستخدم مشغّلات دائمة، اعزلها عن الشبكة للتحليل الجنائي.
تحليل نطاق الضرر
حدد ما كان يمكن للمهاجم الوصول إليه:
- ما الأسرار التي كانت متاحة للمهمة المخترقة؟
- ما الموارد السحابية التي يمكن لبيانات الاعتماد تلك الوصول إليها؟
- ما المخرجات التي أُنتجت خلال الفترة المخترقة؟
- ما البيئات التي تم النشر إليها من الـ pipeline المخترق؟
التحقق من سلامة المخرجات
تحقق مما إذا تم التلاعب بالمخرجات المنشورة:
- تحقق من التوقيعات على جميع المخرجات المنشورة خلال النافذة المخترقة.
- قارن checksums المخرجات مع البناءات المعروفة بأنها جيدة.
- إذا تعذر التحقق من سلامة المخرجات، أعد البناء وإعادة النشر من التزامات مصدر معروفة بأنها جيدة.
- أخطر المستهلكين النهائيين إذا تم توزيع مخرجات يُحتمل أنها مخترقة.
التحقيق الجنائي
اجمع الأدلة من مصادر متعددة:
- سجلات المشغّلات: ما الأوامر التي تم تنفيذها؟ ما اتصالات الشبكة التي أُجريت؟
- سجلات تدقيق API: ما استدعاءات API التي أجراها المهاجم باستخدام بيانات اعتماد الـ pipeline؟
- تاريخ Git: هل تم تعديل أي التزامات أو فروع؟ تحقق من عمليات force push أو إعادة كتابة التاريخ.
- سجلات تدقيق السحابة: ما تغييرات البنية التحتية التي أجرتها حسابات خدمة الـ pipeline؟
التعافي بعد الحادث
بعد الاحتواء والتحقيق، استعد العمليات الآمنة:
- قم بتدوير جميع الأسرار التي كانت في متناول الـ pipeline المخترق، حتى لو لم يكن هناك دليل على تسريبها.
- راجع وشدد صلاحيات الـ pipeline. من المرجح أن الحادث كشف نطاقات صلاحيات كانت أوسع مما هو ضروري.
- حدّث قواعد المراقبة بناءً على مؤشرات الاختراق المكتشفة خلال التحقيق.
- أجرِ مراجعة ما بعد الحادث بدون لوم تركز على التغييرات النظامية التي تمنع التكرار.
نموذج دليل الاستجابة لحوادث CI/CD
## CI/CD Security Incident Playbook
### Phase 1: Detection & Triage (0-15 minutes)
- [ ] Confirm the alert is a true positive
- [ ] Classify severity (P1: active compromise, P2: suspected compromise, P3: policy violation)
- [ ] Notify the incident commander and security team
### Phase 2: Containment (15-60 minutes)
- [ ] Revoke compromised credentials
- [ ] Disable affected pipelines
- [ ] Isolate affected runners
- [ ] Block attacker's access (revoke tokens, disable accounts)
### Phase 3: Investigation (1-24 hours)
- [ ] Collect runner logs, audit logs, git history
- [ ] Determine blast radius (credentials, artifacts, deployments)
- [ ] Identify attack vector (how did the attacker get in?)
- [ ] Check artifact integrity for the compromised period
### Phase 4: Recovery (24-72 hours)
- [ ] Rotate all potentially compromised secrets
- [ ] Rebuild and republish affected artifacts from known-good source
- [ ] Redeploy affected environments from verified artifacts
- [ ] Restore pipeline operations with tightened controls
### Phase 5: Post-Incident (1-2 weeks)
- [ ] Conduct blameless post-mortem
- [ ] Document lessons learned and update this playbook
- [ ] Implement systemic improvements to prevent recurrence
- [ ] Update detection rules based on IOCs discovered
الخاتمة
أمان CI/CD ليس قائمة مراجعة تُكملها مرة وتنساها. إنه ممارسة هندسية مستمرة تتطور مع الـ pipelines والبنية التحتية ومشهد التهديدات. سيستمر المهاجمون في استهداف سلسلة توريد البرمجيات لأنها توفر رافعة عالية — pipeline واحد مخترق يمكن أن يؤثر على كل عملية نشر وكل بيئة وكل عميل.
الدفاعات في هذا الدليل منظمة حسب الطبقة، لكن نقاط البداية الأكثر تأثيراً تتقاطع عبر الطبقات:
- المشغّلات المؤقتة (Ephemeral runners) تقضي على فئات كاملة من هجمات الاستمرارية وتسريب الحالة.
- الصلاحيات الدنيا (تحديد نطاق الرموز، OIDC، بيانات اعتماد لكل بيئة) تحد مما يمكن للمهاجم فعله حتى بعد الحصول على صلاحية الوصول إلى الـ pipeline.
- المخرجات الموقّعة مع التحكم في القبول تضمن عدم وصول المخرجات المعدلة إلى الإنتاج.
- الكشف وتسجيل التدقيق يسدان فجوة الرؤية التي تسمح للاختراقات بالمرور دون ملاحظة لأشهر.
ابدأ بعناصر التحكم عالية التأثير هذه. أضف دفاعات إضافية مع نضج برنامجك الأمني. وافترض دائماً أن الـ pipeline الخاص بك سيكون مستهدفاً — لأنه سيكون كذلك.
في المنشور التالي في هذه السلسلة، سنستعرض تنفيذ هذه الدفاعات في GitHub Actions pipeline حقيقي، مع مثال عملي كامل يمكنك تكييفه لمستودعاتك الخاصة.