لماذا يُعدّ أمان GitLab CI مهمًّا
تُعدّ خطوط أنابيب GitLab CI/CD أدوات قوية — لكن القوة تأتي مع المخاطر. متغيّر واحد خاطئ التكوين قد يسرّب أسرارًا حساسة. مُنفّذ غير محدّد النطاق قد ينفّذ شيفرة خبيثة. بيئة غير محمية قد تسمح لمطوّر مبتدئ بالنشر مباشرة في الإنتاج. تمنحك هذه الورقة المرجعية أكواد YAML جاهزة للنسخ واللصق لكل ضوابط الأمان الحرجة في GitLab CI، من المتغيرات المحمية إلى اتحاد OIDC.
احفظ هذه الصفحة في مفضلتك. استخدمها كمرجع أساسي في كل مرة تُهيّئ فيها مشروعًا جديدًا أو تُدقّق مشروعًا قائمًا.
1. المتغيرات المحمية، المُقنّعة، والمخفية
تتحكّم متغيرات GitLab CI/CD في كيفية تدفّق الأسرار إلى خطوط الأنابيب الخاصة بك. الخطأ في ضبطها هو السبب الأول لتسريب بيانات الاعتماد في CI/CD. يجب أن تكون كل قيمة حساسة محمية (متاحة فقط على الفروع/العلامات المحمية)، ومُقنّعة (مخفية من سجلات المهام)، وحيث يكون ذلك مدعومًا، مخفية (غير مرئية في واجهة المستخدم بعد الإنشاء).
ضبط المتغيرات عبر واجهة برمجة التطبيقات (API)
# Create a protected + masked variable via the GitLab API
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/variables" \
--form "key=AWS_SECRET_ACCESS_KEY" \
--form "value=$MY_SECRET" \
--form "protected=true" \
--form "masked=true" \
--form "variable_type=env_var"
استخدام المتغيرات في .gitlab-ci.yml
variables:
# Group or project-level variables are injected automatically.
# File-type variables are written to a temp path.
DEPLOY_TOKEN:
description: "Token for deploying to production"
value: "" # Intentionally blank — set in CI/CD Settings
deploy_production:
stage: deploy
script:
- echo "Deploying with masked token..."
- ./deploy.sh --token "$DEPLOY_TOKEN"
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
القواعد الأساسية:
- لا تضع الأسرار مباشرة في
.gitlab-ci.ymlأبدًا — استخدم دائمًا إعدادات متغيرات CI/CD. - اضبط
protected=trueحتى تكون الأسرار متاحة فقط على الفروع المحمية. - اضبط
masked=trueحتى يتم إخفاء القيم من سجلات المهام. - استخدم متغيرات مستوى المجموعة للأسرار المشتركة عبر المشاريع (مثل بيانات اعتماد السحابة).
2. أنواع المُنفّذات وتحديد النطاق
تنفّذ المُنفّذات (Runners) مهام CI/CD الخاصة بك. إذا كان أي مُنفّذ يمكنه تنفيذ أي مهمة، فقد يستغلّ طلب دمج خبيث ذلك لسرقة الأسرار من مُنفّذ الإنتاج. تحديد النطاق بشكل صحيح أمر ضروري.
تسجيل المُنفّذ مع العلامات والحماية
# Register a runner scoped to protected branches only
gitlab-runner register \
--non-interactive \
--url "https://gitlab.example.com" \
--token "$RUNNER_REG_TOKEN" \
--executor docker \
--docker-image alpine:latest \
--tag-list "production,protected" \
--access-level ref_protected
تحديد نطاق المهام لمُنفّذات محددة
# .gitlab-ci.yml — ensure production jobs only run on protected runners
deploy_production:
stage: deploy
tags:
- production
- protected
script:
- kubectl apply -f k8s/production/
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
# Development jobs use a separate, unprivileged runner
test:
stage: test
tags:
- shared
- development
script:
- pytest tests/
أفضل الممارسات:
- استخدم
--access-level ref_protectedلتقييد المُنفّذات بالفروع والعلامات المحمية. - استخدم مُنفّذات خاصة بالمشروع لأحمال العمل الحساسة — لا تشارك مُنفّذات الإنتاج أبدًا عبر مشاريع غير مرتبطة.
- فضّل المُنفّذات المؤقتة (مُنفّذات Docker أو Kubernetes) حتى يتم تدمير البيئة بعد كل مهمة.
- عطّل المُنفّذات المشتركة في المشاريع التي تتعامل مع عمليات نشر حساسة.
3. البيئات المحمية مع الموافقات
تضيف البيئات المحمية بوابة بشرية قبل عمليات النشر. هذا هو خط دفاعك الأخير ضد التغييرات غير المصرّح بها في الإنتاج.
تهيئة البيئة في .gitlab-ci.yml
# .gitlab-ci.yml — deployment with environment protection
deploy_staging:
stage: deploy
script:
- ./deploy.sh staging
environment:
name: staging
url: https://staging.example.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
deploy_production:
stage: deploy
script:
- ./deploy.sh production
environment:
name: production
url: https://example.com
deployment_tier: production
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
allow_failure: false
إعداد قواعد الموافقة عبر واجهة برمجة التطبيقات (API)
# Protect the production environment with required approvals
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/protected_environments" \
--data '{"name": "production", "deploy_access_levels": [{"group_id": 9899826}], "required_approval_count": 2, "approval_rules": [{"group_id": 9899826, "required_approvals": 2}]}'
قم بتهيئة ذلك ضمن Settings > CI/CD > Protected Environments في واجهة مستخدم GitLab. اطلب موافقتين على الأقل لعمليات نشر الإنتاج. قيّد وصول النشر لمجموعات أو مستخدمين محددين — لا تستخدم أبدًا “All maintainers”.
4. تحديد نطاق CI_JOB_TOKEN
CI_JOB_TOKEN هو رمز مميز تلقائي يحقنه GitLab في كل مهمة. افتراضيًا، يمكنه الوصول إلى مشاريع أخرى في مجموعتك — وهذا خطر جدّي للتحرّك الجانبي. منذ GitLab 16.0، يجب عليك تقييد نطاقه.
تقييد وصول الرمز المميز
# Check current CI_JOB_TOKEN access scope
curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/job_token_scope"
# Limit CI_JOB_TOKEN to only access specific projects
curl --request PATCH \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/job_token_scope" \
--data '{"enabled": true}'
# Add an allowlisted project
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/job_token_scope/allowlist" \
--data '{"target_project_id": 12345}'
استخدام CI_JOB_TOKEN بأمان في خطوط الأنابيب
# .gitlab-ci.yml — using CI_JOB_TOKEN for cross-project triggers
trigger_deploy:
stage: deploy
trigger:
project: my-group/deploy-project
branch: main
strategy: depend
# CI_JOB_TOKEN is used automatically for the trigger.
# The target project must allowlist this project's token.
القواعد الأساسية: فعّل حدّ نطاق رمز مهمة CI/CD في كل مشروع. أضف فقط المشاريع المحددة التي تحتاج فعلًا للوصول عبر المشاريع إلى القائمة المسموحة. راجع القوائم المسموحة كل ثلاثة أشهر.
5. رموز OIDC id_tokens لـ AWS وGCP
يُلغي اتحاد OIDC الحاجة إلى بيانات اعتماد السحابة طويلة الأمد في متغيرات CI/CD الخاصة بك نهائيًّا. يُصدر GitLab رمز JWT قصير الأمد، ويستبدله مزوّد السحابة الخاص بك ببيانات اعتماد مؤقتة. هذا هو المعيار الذهبي لمصادقة السحابة في خطوط الأنابيب.
اتحاد OIDC مع AWS
# .gitlab-ci.yml — OIDC authentication with AWS
deploy_aws:
stage: deploy
image: amazon/aws-cli:latest
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.example.com
variables:
ROLE_ARN: arn:aws:iam::123456789012:role/gitlab-ci-deploy
script:
- >
export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
$(aws sts assume-role-with-web-identity
--role-arn $ROLE_ARN
--role-session-name "GitLabCI-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
--web-identity-token "$GITLAB_OIDC_TOKEN"
--duration-seconds 3600
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
--output text))
- aws s3 sync ./build s3://my-production-bucket/
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
اتحاد هوية أحمال العمل مع GCP
# .gitlab-ci.yml — OIDC authentication with GCP
deploy_gcp:
stage: deploy
image: google/cloud-sdk:latest
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.example.com
script:
- echo "$GITLAB_OIDC_TOKEN" > /tmp/gitlab_token.txt
- >
gcloud iam workload-identity-pools create-cred-config
projects/$GCP_PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID
--service-account="$GCP_SERVICE_ACCOUNT"
--output-file=/tmp/gcp_creds.json
--credential-source-file=/tmp/gitlab_token.txt
- export GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcp_creds.json
- gcloud config set project $GCP_PROJECT_ID
- gcloud run deploy my-service --image gcr.io/$GCP_PROJECT_ID/my-app:$CI_COMMIT_SHA
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
على جانب السحابة، قم بتهيئة سياسة الثقة للتحقق من المطالبات مثل project_path وref وref_protected بحيث يمكن فقط لمشاريع وفروع محددة تولّي الدور.
6. أمان خط أنابيب طلبات الدمج
تعمل خطوط أنابيب طلبات الدمج (Merge Request) على شيفرة لم تتم مراجعتها بعد. عاملها على أنها غير موثوقة. لا تكشف أبدًا أسرار الإنتاج لخطوط أنابيب طلبات الدمج.
# .gitlab-ci.yml — separate rules for MR vs. branch pipelines
test:
stage: test
script:
- pytest tests/
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
deploy_production:
stage: deploy
script:
- ./deploy.sh production
rules:
# NEVER run on merge request pipelines
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: never
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
الضوابط الحرجة:
- استخدم
rules:لضمان عدم تشغيل مهام النشر أبدًا على خطوط أنابيبmerge_request_event. - اطلب نجاح خط الأنابيب قبل الدمج (Settings > Merge Requests).
- فعّل “Pipelines must succeed” و“All discussions must be resolved.”
- فكّر في تفعيل merged results pipelines لاختبار الحالة بعد الدمج.
7. قالب كشف الأسرار
يلتقط ماسح كشف الأسرار المدمج في GitLab بيانات الاعتماد المُرسلة عن طريق الخطأ قبل وصولها إلى الفرع الافتراضي.
# .gitlab-ci.yml — include the secret detection template
include:
- template: Jobs/Secret-Detection.gitlab-ci.yml
# Override to make the pipeline fail if secrets are found
secret_detection:
variables:
SECRET_DETECTION_HISTORIC_SCAN: "true" # Scan full git history
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
allow_failure: false # Block the pipeline on detection
لمسح أكثر شمولًا، أضف قوالب SAST وفحص التبعيات (dependency scanning) أيضًا:
include:
- template: Jobs/Secret-Detection.gitlab-ci.yml
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
راجع النتائج في Security Dashboard (المتاح على GitLab Ultimate) أو حلّل ملفات JSON الناتجة في المستويات الأدنى.
8. قواعد الدفع (Push Rules)
تفرض قواعد الدفع سياسات على مستوى Git — قبل أن تدخل الشيفرة حتى في خط الأنابيب. استخدمها لمنع دفع الأسرار، وفرض معايير رسائل الإيداع، وتقييد أنواع الملفات.
# Set push rules via the API
curl --request PUT \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/push_rule" \
--data '{"deny_delete_tag": true, "prevent_secrets": true, "commit_message_regex": "^(feat|fix|chore|docs|refactor|test|ci)\\(.*\\):.*", "max_file_size": 50, "member_check": true, "reject_unsigned_commits": true}'
قواعد الدفع الموصى بها:
prevent_secrets: true— يرفض عمليات الدفع التي تحتوي على ملفات تبدو كأسرار (مفاتيح، رموز مميزة، شهادات).reject_unsigned_commits: true— يتطلب إيداعات موقّعة بـ GPG (GitLab Premium وأعلى).commit_message_regex— يفرض رسائل إيداع تقليدية لمسارات تدقيق نظيفة.max_file_size— يمنع إرسال ملفات ثنائية كبيرة عن طريق الخطأ.member_check: true— يرفض الإيداعات من غير أعضاء المشروع.
9. مهلة المهام وinterruptible
تهدر المهام الخارجة عن السيطرة الموارد ويمكن استغلالها في التعدين الخفي للعملات الرقمية. اضبط مهلات زمنية صريحة وعلّم المهام غير الحرجة على أنها قابلة للمقاطعة حتى يتم إلغاؤها عند بدء خط أنابيب جديد على نفس الفرع.
# .gitlab-ci.yml — timeouts and interruptible
default:
timeout: 30m # Global default timeout for all jobs
interruptible: true # Cancel running jobs when a new commit is pushed
retry:
max: 1
when:
- runner_system_failure
- stuck_or_timeout_failure
test:
stage: test
timeout: 15m
interruptible: true
script:
- pytest tests/ --timeout=600
deploy_production:
stage: deploy
timeout: 20m
interruptible: false # NEVER cancel a running production deployment
script:
- ./deploy.sh production
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
environment:
name: production
إرشادات:
- اضبط مهلة زمنية على مستوى المشروع في Settings > CI/CD > General Pipelines (الموصى به: 60 دقيقة كحد أقصى).
- اضبط مهلات زمنية على مستوى المهمة أكثر صرامة من الافتراضي على مستوى المشروع.
- علّم مهام الاختبار والتنسيق على أنها
interruptible: trueلتوفير سعة المُنفّذات. - علّم مهام النشر على أنها
interruptible: falseلمنع عمليات النشر الجزئية. - استخدم
retryلأعطال البنية التحتية المؤقتة فقط — ليس أبدًا لفشل الاختبارات.
جدول مرجعي سريع
| الضابط | مكان التهيئة | الحد الأدنى للمستوى |
|---|---|---|
| المتغيرات المحمية/المُقنّعة | Settings > CI/CD > Variables | Free |
| تحديد نطاق المُنفّذات | Settings > CI/CD > Runners | Free |
| البيئات المحمية | Settings > CI/CD > Protected Environments | Premium |
| نطاق CI_JOB_TOKEN | Settings > CI/CD > Token Access | Free |
| OIDC id_tokens | .gitlab-ci.yml |
Free |
| كشف الأسرار | include: template |
Free (Ultimate للوحة المعلومات) |
| قواعد الدفع | Settings > Repository > Push Rules | Premium |
| مهلة المهام | Settings > CI/CD + .gitlab-ci.yml |
Free |
قراءات إضافية ومختبرات عملية
واصل تعزيز أمان خطوط أنابيب GitLab CI/CD الخاصة بك مع هذه الموارد ذات الصلة:
- دليل أمان GitLab CI/CD — شرح شامل لكل إعدادات الأمان في GitLab CI/CD.
- أفضل ممارسات إدارة الأسرار في CI/CD — تعمّق في تكامل vault، والتدوير، وأسرار الحد الأدنى من الصلاحيات.
- مصادقة OIDC في خطوط أنابيب CI/CD — مختبر عملي خطوة بخطوة لتهيئة OIDC مع AWS وGCP وAzure.
- قائمة التحقق من أمان خطوط أنابيب CI/CD — قائمة التدقيق الكاملة التي تغطي GitHub Actions وGitLab CI وJenkins.
- وثائق GitLab CI/CD الرسمية — المرجع الرسمي لجميع ميزات GitLab CI/CD.
الأمان ليس عملية تهيئة تتم مرة واحدة — بل هو ممارسة مستمرة. راجع إعدادات أمان خطوط الأنابيب كل ثلاثة أشهر، وقم بتدوير بيانات الاعتماد، وتدقيق وصول المُنفّذات، وحافظ على تحديث نسخة GitLab الخاصة بك. تمنحك هذه الورقة المرجعية اللبنات الأساسية. الآن اذهب وأمّن خطوط أنابيبك.