نظرة عامة
إذا كانت سير عمل GitHub Actions الخاصة بك تتصل بـ AWS باستخدام AWS_ACCESS_KEY_ID و AWS_SECRET_ACCESS_KEY المخزنة كأسرار في المستودع، فأنت تواجه مشكلة أمنية خطيرة. هذه البيانات طويلة الأمد لا تنتهي صلاحيتها من تلقاء نفسها، ويمكن لأي خطوة في سير العمل استخراجها (بما في ذلك الإجراءات من أطراف ثالثة)، وتمنح المهاجمين وصولاً دائماً إلى حساب AWS الخاص بك في حال اختراقها.
يقضي اتحاد OpenID Connect (OIDC) على هذا الخطر تماماً. بدلاً من تخزين بيانات اعتماد AWS الثابتة في GitHub، يطلب سير العمل الخاص بك رمز OIDC قصير الأمد من مزود هوية GitHub. تتحقق AWS من صحة هذا الرمز، وتتحقق من المطالبات (المستودع، الفرع، البيئة)، وتصدر بيانات اعتماد مؤقتة تنتهي صلاحيتها في دقائق. لا يتم تخزين أي أسرار في أي مكان — يتم إنشاء علاقة الثقة بين مزود OIDC الخاص بـ GitHub ودور IAM في AWS الخاص بك.
في هذا المختبر العملي، ستقوم بـ:
- إعداد الأساس غير الآمن (مفاتيح AWS الثابتة) لفهم ما ستستبدله
- إنشاء مزود هوية OIDC في AWS يثق بـ GitHub Actions
- إنشاء دور IAM مع سياسة ثقة محددة النطاق لمستودعك وفرعك المحددين
- تحديث سير عمل GitHub Actions لاستخدام مصادقة OIDC
- تنفيذ ضوابط الوصول القائمة على الفروع والبيئات
- تدقيق أحداث مصادقة OIDC في CloudTrail
- حذف بيانات الاعتماد الثابتة القديمة لإتمام الترحيل
بنهاية هذا المختبر، سيكون خط أنابيب CI/CD الخاص بك خالياً تماماً من بيانات اعتماد AWS المخزنة، وسيكون كل حدث مصادقة قابلاً للتتبع إلى مستودع وفرع و commit وتشغيل سير عمل محددين.
المتطلبات الأساسية
قبل البدء في هذا المختبر، تأكد من توفر ما يلي:
- حساب AWS مع صلاحيات إدارية لـ IAM (القدرة على إنشاء مزودي الهوية والأدوار والسياسات)
- حساب GitHub مع مستودع تتحكم فيه (الطبقة المجانية كافية)
- AWS CLI v2 مثبت ومُعد محلياً (يجب أن يُرجع
aws --versionالإصدار 2.x) - Terraform v1.5+ (اختياري لكن يُنصح به — يوفر هذا المختبر تعليمات لكل من Console و Terraform)
- فهم أساسي لأدوار IAM وسياسات الثقة وصيغة سير عمل GitHub Actions
الوقت المقدر: 60–90 دقيقة
إعداد البيئة: الأساس غير الآمن
قبل تنفيذ OIDC، لنقم بإنشاء النمط غير الآمن الذي ستستبدله. هذا يجعل التحسين الأمني ملموساً ويمنحك سير عمل عامل للترحيل منه.
الخطوة 1: إنشاء مستودع اختباري
أنشئ مستودع GitHub جديد يُسمى oidc-lab. قم بتهيئته مع README واستنسخه محلياً:
gh repo create oidc-lab --public --clone
cd oidc-lab
الخطوة 2: تخزين بيانات اعتماد AWS كأسرار GitHub (الطريقة غير الآمنة)
إذا كان لديك مستخدم IAM حالي مع وصول برمجي، قم بتخزين بيانات اعتماده كأسرار GitHub:
gh secret set AWS_ACCESS_KEY_ID --body "AKIAIOSFODNN7EXAMPLE"
gh secret set AWS_SECRET_ACCESS_KEY --body "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
لماذا هذا خطير:
- لا انتهاء صلاحية: هذه البيانات صالحة حتى يتم تدويرها أو حذفها يدوياً. إذا تسربت، يحصل المهاجم على وصول غير محدد المدة.
- تعرض واسع: كل تشغيل لسير العمل، وكل fork (إذا كان عاماً)، وكل إجراء من طرف ثالث في سير عملك يمكنه قراءة هذه الأسرار.
- لا مسار تدقيق دقيق: يُظهر CloudTrail مستخدم IAM، لكن ليس أي مستودع أو فرع أو سير عمل أطلق استدعاء API.
- عبء التدوير: يجب عليك تدوير هذه المفاتيح يدوياً وتحديث أسرار GitHub — وهي عملية غالباً ما يتم إهمالها.
الخطوة 3: إنشاء سير عمل الأساس غير الآمن
أنشئ .github/workflows/deploy.yml مع بيانات اعتماد ثابتة:
name: Deploy (Insecure - Static Keys)
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials (INSECURE)
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Verify Identity
run: aws sts get-caller-identity
- name: List S3 Buckets
run: aws s3 ls
قم بعمل commit ودفع سير العمل هذا. تأكد من أنه يعمل بنجاح — هذا هو الأساس الذي ستستبدله بـ OIDC.
التمرين 1: إنشاء مزود هوية OIDC في AWS
الخطوة الأولى في اتحاد OIDC هي إخبار AWS بالثقة في مزود هوية GitHub. هذا إعداد يتم مرة واحدة لكل حساب AWS.
الخيار أ: AWS Console
- افتح IAM Console ← Identity providers ← Add provider
- اختر OpenID Connect
- لـ Provider URL، أدخل:
https://token.actions.githubusercontent.com - انقر Get thumbprint (تقوم AWS بجلب شهادة TLS والتحقق منها)
- لـ Audience، أدخل:
sts.amazonaws.com - انقر Add provider
الخيار ب: AWS CLI
# Get the thumbprint for GitHub's OIDC provider
# As of 2024, GitHub's thumbprint is managed by AWS and auto-verified
# You can retrieve it with:
THUMBPRINT=$(openssl s_client -servername token.actions.githubusercontent.com \
-showcerts -connect token.actions.githubusercontent.com:443 < /dev/null 2>/dev/null \
| openssl x509 -fingerprint -noout \
| cut -d'=' -f2 \
| tr -d ':' \
| tr '[:upper:]' '[:lower:]')
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list "$THUMBPRINT"
الخيار ج: Terraform
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
tags = {
Name = "GitHub Actions OIDC"
Environment = "shared"
ManagedBy = "terraform"
}
}
ملاحظة: تتحقق AWS الآن تلقائياً من بصمة مزود OIDC الخاص بـ GitHub. قيمة البصمة في مورد Terraform مطلوبة من قبل API لكن AWS ستتحقق من سلسلة الشهادات بغض النظر عن القيمة المقدمة.
التحقق
تأكد من إنشاء المزود:
aws iam list-open-id-connect-providers
يجب أن ترى ARN مثل:
arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com
التمرين 2: إنشاء دور IAM مع سياسة الثقة
الآن أنشئ دور IAM يمكن لـ GitHub Actions تولّيه عبر OIDC. سياسة الثقة هي الجزء الأهم — فهي تحدد بالضبط أي المستودعات والفروع والبيئات يمكنها تولّي هذا الدور.
الخطوة 1: إنشاء سياسة الثقة
احفظ ما يلي كـ trust-policy.json. استبدل 123456789012 بمعرف حساب AWS الخاص بك، و myorg/myrepo بمنظمة GitHub ومستودعك:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/heads/main"
}
}
}
]
}
فهم حقول سياسة الثقة
Principal.Federated— معرف ARN لمزود GitHub OIDC الذي أنشأته في التمرين 1. هذا يُخبر AWS بأي مزود هوية يجب الوثوق به.Action: sts:AssumeRoleWithWebIdentity— إجراء STS المحدد لاتحاد OIDC. هذا يختلف عنsts:AssumeRole(المستخدم للأدوار عبر الحسابات) أوsts:AssumeRoleWithSAML(المستخدم لاتحاد SAML).Condition.StringEquals.aud— يتحقق من مطالبة الجمهور في رمز OIDC. يجب أن تكونsts.amazonaws.comلمطابقة ما يرسله إجراءconfigure-aws-credentials.Condition.StringLike.sub— يتحقق من مطالبة الموضوع. هذا هو أهم عنصر تحكم أمني. يحتوي الموضوع على المستودع ونوع المرجع وقيمة المرجع. استخدامStringLikeمع أحرف البدل يسمح بمطابقة مرنة، بينماStringEqualsيتطلب مطابقة تامة.
الخطوة 2: إنشاء دور IAM
aws iam create-role \
--role-name github-actions-deploy \
--assume-role-policy-document file://trust-policy.json \
--description "Role for GitHub Actions OIDC deployment" \
--max-session-duration 3600
الخطوة 3: إرفاق سياسة IAM بالحد الأدنى من الصلاحيات
اتبع مبدأ الحد الأدنى من الامتيازات. لهذا المختبر، أرفق سياسة تمنح وصول قراءة فقط إلى حاوية S3 محددة:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-deployment-bucket",
"arn:aws:s3:::my-deployment-bucket/*"
]
}
]
}
# Save the above as permissions-policy.json, then:
aws iam put-role-policy \
--role-name github-actions-deploy \
--policy-name S3ReadAccess \
--policy-document file://permissions-policy.json
معادل Terraform
data "aws_iam_policy_document" "github_actions_trust" {
statement {
effect = "Allow"
actions = ["sts:AssumeRoleWithWebIdentity"]
principals {
type = "Federated"
identifiers = [aws_iam_openid_connect_provider.github.arn]
}
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:aud"
values = ["sts.amazonaws.com"]
}
condition {
test = "StringLike"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:myorg/myrepo:ref:refs/heads/main"]
}
}
}
resource "aws_iam_role" "github_actions_deploy" {
name = "github-actions-deploy"
assume_role_policy = data.aws_iam_policy_document.github_actions_trust.json
max_session_duration = 3600
tags = {
Name = "GitHub Actions Deploy"
ManagedBy = "terraform"
}
}
resource "aws_iam_role_policy" "s3_read" {
name = "S3ReadAccess"
role = aws_iam_role.github_actions_deploy.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:ListBucket"
]
Resource = [
"arn:aws:s3:::my-deployment-bucket",
"arn:aws:s3:::my-deployment-bucket/*"
]
}
]
})
}
التحقق
# Confirm the role exists and has the correct trust policy
aws iam get-role --role-name github-actions-deploy \
--query 'Role.AssumeRolePolicyDocument' --output json
التمرين 3: تحديث سير عمل GitHub Actions
الآن استبدل سير عمل بيانات الاعتماد الثابتة بمصادقة OIDC. هذه هي خطوة الترحيل الأساسية.
الخطوة 1: تحديث سير العمل
استبدل محتويات .github/workflows/deploy.yml بما يلي:
name: Deploy (Secure - OIDC)
on:
push:
branches: [main]
permissions:
id-token: write # Required for OIDC token request
contents: read # Required for actions/checkout
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
role-session-name: github-actions-${{ github.run_id }}
aws-region: us-east-1
- name: Verify Identity
run: |
aws sts get-caller-identity
echo "Successfully authenticated via OIDC!"
- name: List S3 Bucket Contents
run: aws s3 ls s3://my-deployment-bucket/
شرح التغييرات الرئيسية
permissions: id-token: write— هذا إلزامي. يمنح سير العمل إذن طلب رمز OIDC من مزود هوية GitHub. بدون هذا، لا يستطيع إجراءconfigure-aws-credentialsالحصول على رمز.permissions: contents: read— عند تعيين أي إذن صريح، تكون جميع الأذونات الأخرى افتراضياًnone. يجب منحcontents: readصراحة ليعملactions/checkout.role-to-assume— معرف ARN لدور IAM الذي تم إنشاؤه في التمرين 2. سيستدعي الإجراءsts:AssumeRoleWithWebIdentityباستخدام رمز OIDC.role-session-name— اسم جلسة وصفي يظهر في CloudTrail. تضمينgithub.run_idيجعل كل جلسة قابلة للتتبع إلى تشغيل سير عمل محدد.- لا
aws-access-key-idأوaws-secret-access-key— تم إزالة هذه الحقول بالكامل. يكتشف الإجراء أنrole-to-assumeمُعيّن بدون بيانات اعتماد ثابتة ويستخدم OIDC تلقائياً.
الخطوة 2: الدفع والتحقق
git add .github/workflows/deploy.yml
git commit -m "Migrate to OIDC authentication"
git push origin main
انتقل إلى تبويب Actions في مستودع GitHub الخاص بك. يجب أن ترى سير العمل قيد التشغيل. في خطوة “Verify Identity”، سيبدو الإخراج كالتالي:
{
"UserId": "AROA3XFRBF23ZCEXAMPLE:github-actions-9876543210",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/github-actions-deploy/github-actions-9876543210"
}
لاحظ أن ARN يُظهر assumed-role/github-actions-deploy — هذا يؤكد أن سير العمل يتصل عبر دور OIDC، وليس مستخدم IAM.
التمرين 4: التقييد حسب الفرع والبيئة والعلامة
مطالبة sub في سياسة الثقة هي آلية التحكم في الوصول الأساسية الخاصة بك. تتبع مطالبة الموضوع من GitHub Actions تنسيقاً متوقعاً يشفّر المستودع ونوع المحفز والمرجع.
أنماط مطالبة الموضوع الشائعة
| المحفز | تنسيق مطالبة الموضوع |
|---|---|
| دفع إلى فرع | repo:OWNER/REPO:ref:refs/heads/BRANCH |
| طلب سحب | repo:OWNER/REPO:pull_request |
| بيئة | repo:OWNER/REPO:environment:ENV_NAME |
| دفع علامة | repo:OWNER/REPO:ref:refs/tags/TAG |
التقييد للفرع الرئيسي فقط
هذا هو الإعداد من التمرين 2. فقط سير العمل المُطلق بدفع إلى main يمكنه تولّي الدور:
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/heads/main"
}
التقييد لبيئة محددة
توفر GitHub Environments طبقة إضافية من التحكم في الوصول. عندما تحدد وظيفة ما environment، تتغير مطالبة الموضوع لتتضمن اسم البيئة:
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:environment:production"
}
التقييد للإصدارات المُعلّمة
السماح فقط للإصدارات المُعلّمة (مثل v1.0.0، v2.3.1) بتولّي الدور:
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/tags/v*"
}
اختبار القيود
أنشئ فرع ميزة وادفع تشغيل سير عمل:
git checkout -b feature/test-oidc-restriction
git commit --allow-empty -m "Test OIDC restriction"
git push origin feature/test-oidc-restriction
إذا كانت سياسة الثقة الخاصة بك تقيّد إلى refs/heads/main، فسيفشل سير العمل على فرع الميزة مع:
Error: Could not assume role with OIDC: Not authorized to perform
sts:AssumeRoleWithWebIdentity
AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
الآن ادفع نفس التغيير إلى main:
git checkout main
git merge feature/test-oidc-restriction
git push origin main
سير العمل على main ينجح. هذا يوضح التحكم في الوصول القائم على المطالبات — تقيّم سياسة الثقة في AWS المطالبات المضمنة في رمز OIDC لاتخاذ قرارات التفويض. لا توجد بيانات اعتماد متضمنة؛ الرمز نفسه يحمل سياق التفويض.
التمرين 5: أدوار لكل بيئة
يجب أن يكون لعمليات نشر الإنتاج ضوابط أكثر صرامة من بيئة التجهيز. في هذا التمرين، تنشئ أدوار IAM منفصلة لكل بيئة، مع سياسات ثقة وصلاحيات مختلفة.
الخطوة 1: إنشاء بيئات GitHub
في مستودعك، انتقل إلى Settings ← Environments:
- أنشئ بيئة staging (بدون قواعد حماية)
- أنشئ بيئة production مع:
- مراجعون مطلوبون: أضف عضو فريق واحد على الأقل
- فروع النشر: قيّد إلى
mainفقط
الخطوة 2: إنشاء دور IAM لبيئة التجهيز
دور التجهيز يثق بجميع الفروع في المستودع:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:*"
}
}
}
]
}
aws iam create-role \
--role-name github-actions-staging \
--assume-role-policy-document file://staging-trust-policy.json \
--description "Staging deployment role - all branches"
الخطوة 3: إنشاء دور IAM للإنتاج
دور الإنتاج يثق فقط ببيئة production على الفرع main:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:environment:production"
}
}
}
]
}
aws iam create-role \
--role-name github-actions-production \
--assume-role-policy-document file://production-trust-policy.json \
--description "Production deployment role - main branch + production environment only"
الخطوة 4: سير عمل متعدد البيئات
أنشئ سير عمل ينشر إلى التجهيز تلقائياً وإلى الإنتاج بموافقة يدوية:
name: Deploy Multi-Environment
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials (Staging)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-staging
role-session-name: staging-${{ github.run_id }}
aws-region: us-east-1
- name: Deploy to Staging
run: |
aws sts get-caller-identity
echo "Deploying to staging environment..."
# Your staging deployment commands here
deploy-production:
runs-on: ubuntu-latest
needs: deploy-staging
environment: production
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials (Production)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-production
role-session-name: production-${{ github.run_id }}
aws-region: us-east-1
- name: Deploy to Production
run: |
aws sts get-caller-identity
echo "Deploying to production environment..."
# Your production deployment commands here
عند تشغيل سير العمل هذا:
- تعمل وظيفة staging فوراً، وتتولّى
github-actions-staging، وتنشر - تنتظر وظيفة production اكتمال التجهيز ثم تتوقف للحصول على موافقة يدوية
- يوافق المراجع المطلوب على النشر في واجهة GitHub
- تعمل وظيفة الإنتاج، وتتولّى
github-actions-production، وتنشر
تستخدم سياسة ثقة دور الإنتاج StringEquals (وليس StringLike) مع الموضوع الدقيق repo:myorg/myrepo:environment:production. هذا يعني أن الوظائف التي تُعلن environment: production فقط يمكنها تولّي دور الإنتاج — وتفرض GitHub Environments أن عمليات نشر الفرع main فقط مع موافقة المراجع يمكنها استخدام تلك البيئة.
Terraform لكلا الدورين
locals {
github_oidc_arn = aws_iam_openid_connect_provider.github.arn
github_repo = "myorg/myrepo"
}
# Staging role - trusts all branches
resource "aws_iam_role" "github_actions_staging" {
name = "github-actions-staging"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = local.github_oidc_arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:${local.github_repo}:*"
}
}
}
]
})
}
# Production role - trusts only the production environment
resource "aws_iam_role" "github_actions_production" {
name = "github-actions-production"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = local.github_oidc_arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
"token.actions.githubusercontent.com:sub" = "repo:${local.github_repo}:environment:production"
}
}
}
]
})
}
التمرين 6: التحقق والتدقيق
تنشئ مصادقة OIDC مسارات تدقيق مفصلة في AWS CloudTrail. يتم تسجيل كل استدعاء AssumeRoleWithWebIdentity مع المجموعة الكاملة من مطالبات GitHub OIDC.
الخطوة 1: استعلام CloudTrail عن أحداث OIDC
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
--max-results 10 \
--query 'Events[].{Time:EventTime,Username:Username,Resources:Resources}' \
--output table
الخطوة 2: فحص حدث CloudTrail
يحتوي حدث AssumeRoleWithWebIdentity النموذجي في CloudTrail على الحقول الرئيسية التالية:
{
"eventName": "AssumeRoleWithWebIdentity",
"eventSource": "sts.amazonaws.com",
"requestParameters": {
"roleArn": "arn:aws:iam::123456789012:role/github-actions-deploy",
"roleSessionName": "github-actions-9876543210"
},
"requestID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"responseElements": {
"credentials": {
"accessKeyId": "ASIAEXAMPLE...",
"expiration": "Mar 23, 2026 2:00:00 PM"
},
"subjectFromWebIdentityToken": "repo:myorg/myrepo:ref:refs/heads/main",
"provider": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"additionalEventData": {
"WebIdFederationData": {
"federatedProvider": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com",
"attributes": {
"sub": "repo:myorg/myrepo:ref:refs/heads/main",
"aud": "sts.amazonaws.com",
"iss": "https://token.actions.githubusercontent.com",
"repository": "myorg/myrepo",
"ref": "refs/heads/main",
"sha": "abc123def456...",
"actor": "github-username",
"workflow": "Deploy (Secure - OIDC)",
"run_id": "9876543210"
}
}
}
}
لاحظ غنى مسار التدقيق هذا: يمكنك رؤية المستودع والفرع و commit SHA ومستخدم GitHub الذي أطلق سير العمل واسم سير العمل بالضبط. هذا أكثر تفصيلاً بكثير مما تحصل عليه مع بيانات اعتماد مستخدم IAM الثابتة.
الخطوة 3: إنشاء إنذار CloudWatch لمحاولات AssumeRole الفاشلة
قد تشير استدعاءات AssumeRoleWithWebIdentity الفاشلة إلى محاولات وصول غير مصرح بها أو سياسات ثقة خاطئة التكوين. قم بإعداد فلتر مقياس وإنذار:
# Create a CloudWatch Logs metric filter for failed AssumeRoleWithWebIdentity
aws logs put-metric-filter \
--log-group-name CloudTrail/DefaultLogGroup \
--filter-name FailedOIDCAssumeRole \
--filter-pattern '{ ($.eventName = "AssumeRoleWithWebIdentity") && ($.errorCode = "AccessDenied") }' \
--metric-transformations \
metricName=FailedOIDCAssumeRoleCount,metricNamespace=SecurityMetrics,metricValue=1
# Create a CloudWatch alarm that triggers when failures exceed threshold
aws cloudwatch put-metric-alarm \
--alarm-name FailedOIDCAssumeRole \
--alarm-description "Alert on failed OIDC AssumeRoleWithWebIdentity attempts" \
--metric-name FailedOIDCAssumeRoleCount \
--namespace SecurityMetrics \
--statistic Sum \
--period 300 \
--threshold 3 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:123456789012:security-alerts \
--treat-missing-data notBreaching
الخطوة 4: تدقيق المستودعات والفروع التي وصلت إلى الدور
استخدم CloudTrail Lake أو Athena للاستعلام عن أنماط الوصول التاريخية:
# Using CloudTrail lookup to find all OIDC authentications in the last 24 hours
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
--start-time $(date -u -d '24 hours ago' '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || date -u -v-24H '+%Y-%m-%dT%H:%M:%SZ') \
--end-time $(date -u '+%Y-%m-%dT%H:%M:%SZ') \
--query 'Events[].CloudTrailEvent' \
--output text | jq -r '.responseElements.subjectFromWebIdentityToken // "N/A"' | sort | uniq -c | sort -rn
هذا يعطيك عدد تكرار المستودعات والفروع التي تمت مصادقتها عبر OIDC — ضروري لمراجعات الوصول وعمليات تدقيق الامتثال.
التمرين 7: حذف مفاتيح الوصول القديمة
هذا هو أهم تمرين في المختبر بأكمله. الترحيل من بيانات الاعتماد الثابتة إلى OIDC غير مكتمل — ووضعك الأمني لم يتحسن — حتى يتم التخلص من مفاتيح الوصول القديمة. طالما أن كلتا طريقتي المصادقة موجودتان، يمكن للمهاجم استخدام المفاتيح الثابتة.
الخطوة 1: إزالة أسرار GitHub
احذف الأسرار القديمة من مستودع GitHub الخاص بك:
gh secret delete AWS_ACCESS_KEY_ID --repo myorg/myrepo
gh secret delete AWS_SECRET_ACCESS_KEY --repo myorg/myrepo
تحقق من إزالتها:
gh secret list --repo myorg/myrepo
يجب ألا ترى AWS_ACCESS_KEY_ID أو AWS_SECRET_ACCESS_KEY في القائمة بعد الآن.
الخطوة 2: تعطيل مفاتيح وصول IAM
قبل الحذف، قم بتعطيل المفاتيح أولاً. هذا يمنحك خيار التراجع في حالة حدوث خطأ:
# List the access keys for the IAM user
aws iam list-access-keys --user-name github-deploy-user
# Deactivate (not delete) the access key
aws iam update-access-key \
--user-name github-deploy-user \
--access-key-id AKIAIOSFODNN7EXAMPLE \
--status Inactive
الخطوة 3: التحقق من أن خط الأنابيب لا يزال يعمل
أطلق سير عمل OIDC وتأكد من اكتماله بنجاح:
git commit --allow-empty -m "Verify OIDC-only authentication"
git push origin main
تحقق من تبويب Actions — يجب أن ينجح سير العمل باستخدام OIDC فقط.
الخطوة 4: حذف مفاتيح الوصول نهائياً
بعد التأكد من أن خط الأنابيب يعمل بدون مفاتيح ثابتة (انتظر 24-48 ساعة على الأقل لتكون آمناً)، احذف المفاتيح نهائياً:
aws iam delete-access-key \
--user-name github-deploy-user \
--access-key-id AKIAIOSFODNN7EXAMPLE
إذا كان مستخدم IAM يُستخدم فقط لـ GitHub Actions، احذف المستخدم بالكامل:
aws iam delete-user-policy --user-name github-deploy-user --policy-name DeployPolicy
aws iam delete-user --user-name github-deploy-user
الترحيل الآن مكتمل. يتصل خط الأنابيب الخاص بك حصرياً عبر اتحاد OIDC بدون أي بيانات اعتماد مخزنة.
التنظيف
إذا كانت هذه بيئة مختبرية، قم بتنظيف جميع الموارد:
# Delete IAM roles
aws iam delete-role-policy --role-name github-actions-deploy --policy-name S3ReadAccess
aws iam delete-role --role-name github-actions-deploy
aws iam delete-role-policy --role-name github-actions-staging --policy-name StagingPolicy
aws iam delete-role --role-name github-actions-staging
aws iam delete-role-policy --role-name github-actions-production --policy-name ProductionPolicy
aws iam delete-role --role-name github-actions-production
# Delete the OIDC provider
OIDC_ARN=$(aws iam list-open-id-connect-providers \
--query "OpenIDConnectProviderList[?ends_with(Arn, 'token.actions.githubusercontent.com')].Arn" \
--output text)
aws iam delete-open-id-connect-provider --open-id-connect-provider-arn "$OIDC_ARN"
# Delete the test repository (optional)
gh repo delete myorg/oidc-lab --yes
إذا استخدمت Terraform، فالتنظيف أبسط:
terraform destroy -auto-approve
النقاط الرئيسية
- يقضي اتحاد OIDC على بيانات الاعتماد المخزنة. لا
AWS_ACCESS_KEY_IDأوAWS_SECRET_ACCESS_KEYفي GitHub — علاقة الثقة بين مزود هوية GitHub ودور IAM في AWS الخاص بك. - بيانات الاعتماد قصيرة الأمد تقلل نطاق الضرر. تنتهي صلاحية رموز OIDC وبيانات اعتماد جلسة AWS الناتجة في دقائق، وليس أشهر. الرمز المخترق لا فائدة منه بعد انتهاء الصلاحية.
- توفر سياسات الثقة تحكماً في الوصول قائماً على المطالبات. تشفّر مطالبة
subفي رمز OIDC المستودع والفرع والبيئة — استخدم شروطStringEqualsوStringLikeلفرض وصول دقيق. - تفرض الأدوار لكل بيئة فصل المهام. يجب أن تستخدم بيئتا التجهيز والإنتاج أدوار IAM مختلفة مع سياسات ثقة مختلفة ومستويات صلاحيات مختلفة.
- يوفر CloudTrail مسارات تدقيق كاملة. يسجل كل حدث مصادقة OIDC المستودع والفرع و commit والفاعل وسير العمل — أغنى بكثير من تدقيق بيانات الاعتماد الثابتة.
- الترحيل غير مكتمل حتى يتم حذف المفاتيح القديمة. تشغيل OIDC بالتوازي مع المفاتيح الثابتة لا يمنحك أي تحسين أمني. احذف بيانات الاعتماد القديمة بعد التحقق من عمل OIDC.
الخطوات التالية
واصل تعزيز وضع أمان CI/CD الخاص بك مع هذه الأدلة ذات الصلة:
- بيانات الاعتماد قصيرة الأمد واتحاد هوية عبء العمل — تعمق في أنماط اتحاد OIDC لـ AWS و GCP و Azure، بما في ذلك استراتيجيات هوية عبء العمل متعددة السحابات.
- إدارة الأسرار في خطوط أنابيب CI/CD — للأسرار التي لا يمكن استبدالها بـ OIDC (كلمات مرور قواعد البيانات، مفاتيح API)، تعلم كيفية دمج HashiCorp Vault و AWS Secrets Manager وحلول إدارة الأسرار الأخرى في خطوط الأنابيب الخاصة بك.