هيكل سياسة IAM الأساسي: الفرق بين Effect وAction وResource وCondition

عندما تفتح سياسة IAM لأول مرة وترى كتلة JSON تحتوي على مفاتيح مثل Effect وAction وResource وCondition، قد يبدو الأمر بسيطاً — لكن الفهم الخاطئ لأي عنصر منها يؤدي إلى ثغرات أمنية أو رفض وصول غير متوقع في الإنتاج. هيكل سياسة IAM هو اللغة التي تتحدث بها AWS لتحديد من يفعل ماذا وأين ومتى.

ملخص سريع (TL;DR) — هيكل سياسة IAM

العنصر الغرض القيم الممكنة إلزامي؟
Effect هل تسمح أم ترفض؟ Allow أو Deny نعم
Action ما العملية المستهدفة؟ مثل s3:GetObject نعم
Resource على أي مورد تنطبق؟ ARN أو * نعم
Condition متى تنطبق القاعدة؟ شروط سياقية مثل IP أو MFA لا

كيف تعمل سياسة IAM داخلياً

سياسة IAM هي وثيقة JSON تحتوي على عنصر Statement — وهو مصفوفة من الجمل. كل جملة تصف قاعدة واحدة. عندما تصل طلب API إلى AWS، يقوم محرك تقييم السياسات بفحص جميع الجمل المنطبقة ويتخذ قراراً نهائياً وفق منطق محدد: الرفض الصريح يتغلب دائماً على السماح، وغياب السماح يعني الرفض الضمني.

graph TD A["طلب API يصل إلى AWS"] --> B["جمع جميع السياسات المنطبقة"] B --> C{"هل يوجد Deny صريح؟"} C -- نعم --> D["رفض الطلب فوراً"] C -- لا --> E{"هل يوجد Allow صريح؟"} E -- نعم --> F["السماح بالطلب"] E -- لا --> G["رفض ضمني — الطلب مرفوض"]
  1. الطلب يصل: يرسل المستخدم أو الدور طلب API إلى AWS.
  2. جمع السياسات: يجمع AWS كل السياسات المنطبقة (سياسات الهوية، سياسات الموارد، SCPs).
  3. فحص الرفض الصريح: إذا وُجدت جملة Deny منطبقة، يُرفض الطلب فوراً بغض النظر عن أي Allow.
  4. فحص السماح الصريح: إذا وُجدت جملة Allow منطبقة دون رفض، يُسمح بالطلب.
  5. الرفض الضمني: إذا لم تنطبق أي جملة Allow، يُرفض الطلب تلقائياً.

تشريح عناصر هيكل سياسة IAM الأربعة

1. العنصر Effect — السماح أم الرفض؟

هذا هو القرار الثنائي الوحيد في الجملة. القيمتان الوحيدتان المقبولتان هما Allow وDeny. الخطأ الشائع هو الاعتقاد بأن Allow وDeny متساويان في الأولوية — لكنهما ليسا كذلك. الرفض الصريح يتغلب دائماً على أي سماح، بما في ذلك السماح الممنوح من سياسة أخرى على نفس الحساب.

فكر في Deny كقفل فيزيائي على الباب — حتى لو كان لديك مفتاح (Allow)، القفل يمنعك. هذا التصميم يجعل Deny أداة قوية لفرض حدود صارمة لا يمكن تجاوزها.

{
  "Effect": "Deny",
  "Action": "s3:DeleteBucket",
  "Resource": "*"
}

هذه الجملة ترفض حذف أي bucket S3 بغض النظر عن أي سياسة أخرى تمنح هذا الإذن.

2. العنصر Action — ما العملية المستهدفة؟

يحدد Action عملية API واحدة أو أكثر. الصيغة دائماً هي namespace:OperationName — مثل s3:GetObject أو ec2:DescribeInstances. يمكن استخدام حرف البدل * للإشارة إلى جميع العمليات في namespace معين أو جميع العمليات بشكل مطلق.

نقطة دقيقة يغفل عنها كثيرون: بعض عمليات القراءة مثل List وDescribe تتطلب "Resource": "*" لأنها لا تعمل على مورد محدد بل على مستوى الخدمة. إذا حاولت تقييدها بـ ARN محدد، ستفشل السياسة في منح الإذن الفعلي.

{
  "Effect": "Allow",
  "Action": [
    "s3:GetObject",
    "s3:PutObject",
    "s3:ListBucket"
  ],
  "Resource": [
    "arn:aws:s3:::my-app-bucket",
    "arn:aws:s3:::my-app-bucket/*"
  ]
}

لاحظ أن s3:ListBucket ينطبق على الـ bucket نفسه (arn:aws:s3:::my-app-bucket)، بينما s3:GetObject وs3:PutObject ينطبقان على الكائنات داخله (arn:aws:s3:::my-app-bucket/*). الخلط بين المستويين خطأ شائع يسبب أخطاء AccessDenied مربكة.

3. العنصر Resource — على أي مورد تنطبق؟

يحدد Resource المورد أو الموارد التي تنطبق عليها الجملة، ويُعبَّر عنه بـ ARN (Amazon Resource Name) أو بحرف البدل *. صيغة ARN القياسية هي:

arn:aws:<service>:<region>:<account-id>:<resource>

أمثلة عملية:

# Lambda function محددة
arn:aws:lambda:us-east-1:123456789012:function:my-function

# جميع functions في الحساب
arn:aws:lambda:us-east-1:123456789012:function:*

# IAM role محدد (خدمة عالمية — بدون region)
arn:aws:iam::123456789012:role/MyRole

# جميع الموارد (استخدم بحذر)
*

بعض الإجراءات لا تدعم تقييد الموارد بـ ARN — وهذا موثق في مرجع Service Authorization Reference. في هذه الحالات، استخدام ARN محدد لن يمنح الإذن بل سيتسبب في رفض ضمني.

4. العنصر Condition — متى تنطبق القاعدة؟

هذا هو العنصر الأكثر قوة والأكثر تعقيداً. Condition يضيف شرطاً سياقياً يجب تحققه لكي تنطبق الجملة. إذا لم يتحقق الشرط، تُتجاهل الجملة كلياً — كأنها غير موجودة.

هيكل Condition يتبع نمطاً ثلاثي المستويات:

"Condition": {
  "<ConditionOperator>": {
    "<ConditionKey>": "<ConditionValue>"
  }
}
graph LR A["Condition"] --> B["Condition Operator
مثل: StringEquals, Bool, IpAddress"] B --> C["Condition Key
مثل: aws:SourceIp, aws:MultiFactorAuthPresent"] C --> D["Condition Value
القيمة المقارَن بها"]
  1. مشغل الشرط (Condition Operator): يحدد نوع المقارنة — مثل StringEquals للمقارنة الحرفية، أو IpAddress للتحقق من نطاق IP، أو Bool للقيم المنطقية.
  2. مفتاح الشرط (Condition Key): المتغير السياقي المراد فحصه — مثل aws:SourceIp أو aws:MultiFactorAuthPresent أو مفاتيح خاصة بالخدمة مثل s3:prefix.
  3. قيمة الشرط (Condition Value): القيمة المقارَن بها.

مثال عملي — السماح بالوصول فقط عند تفعيل MFA:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:*",
      "Resource": "*",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

مثال آخر — تقييد الوصول بنطاق IP محدد:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-sensitive-bucket",
        "arn:aws:s3:::my-sensitive-bucket/*"
      ],
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "203.0.113.0/24",
            "198.51.100.0/24"
          ]
        }
      }
    }
  ]
}

هذه الجملة ترفض الوصول إلى الـ bucket من أي IP خارج النطاقين المحددين.

سياسة IAM كاملة — تجميع العناصر معاً

هذا مثال واقعي لسياسة تمنح Lambda function صلاحية قراءة من S3 وكتابة logs في CloudWatch، مع تقييد البيئة:

🔽 اضغط لعرض السياسة الكاملة
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3ReadAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-app-data-bucket",
        "arn:aws:s3:::my-app-data-bucket/*"
      ],
      "Condition": {
        "StringEquals": {
          "s3:prefix": "production/"
        }
      }
    },
    {
      "Sid": "AllowCloudWatchLogs",
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/my-function:*"
    },
    {
      "Sid": "DenyDeleteOperations",
      "Effect": "Deny",
      "Action": [
        "s3:DeleteObject",
        "s3:DeleteBucket"
      ],
      "Resource": "*"
    }
  ]
}

تجربة حقيقية: تشخيص خاطئ أوقع فريقاً كاملاً

في بيئة إنتاج، كانت Lambda function تحصل على AccessDenied عند محاولة قراءة كائنات من S3. السياسة تحتوي على s3:GetObject مع ARN صحيح للـ bucket. الفريق أمضى ساعتين يفحص السياسة ويعيد تطبيقها.

المشكلة الفعلية لم تكن في السياسة المرفقة بالـ role — بل في سياسة الـ bucket نفسه (Bucket Policy) التي تحتوي على جملة Deny صريحة لجميع الطلبات التي لا تأتي من VPC endpoint محدد. الرفض الصريح في سياسة المورد تغلب على السماح في سياسة الهوية.

الدرس: عند تشخيص AccessDenied، افحص جميع طبقات السياسات — سياسة الهوية، سياسة المورد، SCPs — وليس فقط السياسة المرفقة بالـ role.

للتحقق من السياسة الفعلية المطبقة، استخدم IAM Policy Simulator أو AWS CLI:

# محاكاة تقييم السياسة
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/MyLambdaRole \
  --action-names s3:GetObject \
  --resource-arns arn:aws:s3:::my-app-data-bucket/production/file.json
# فحص سياسة bucket محددة
aws s3api get-bucket-policy \
  --bucket my-app-data-bucket

التحقق من هيكل سياسة IAM عبر CLI

بعد كتابة سياسة، تحقق من صحتها قبل تطبيقها:

# التحقق من صحة بنية السياسة
aws iam get-policy-version \
  --policy-arn arn:aws:iam::123456789012:policy/MyPolicy \
  --version-id v1
# عرض السياسات المرفقة بـ role محدد
aws iam list-attached-role-policies \
  --role-name MyLambdaRole
# عرض تفاصيل سياسة inline مرفقة بـ role
aws iam get-role-policy \
  --role-name MyLambdaRole \
  --policy-name MyInlinePolicy

الخلاصة والخطوات التالية لفهم هيكل سياسة IAM

العناصر الأربعة — Effect وAction وResource وCondition — تشكل معاً لغة كاملة للتحكم في الوصول. الفهم العميق لمنطق التقييم (الرفض الصريح أولاً، ثم السماح الصريح، ثم الرفض الضمني) يوفر ساعات من التشخيص في الإنتاج.

للتعمق أكثر، راجع:

قاموس المصطلحات الأساسية

المصطلح التعريف
ARN Amazon Resource Name — معرف فريد لكل مورد في AWS بصيغة arn:aws:service:region:account:resource
Explicit Deny رفض صريح مكتوب في سياسة — يتغلب على أي سماح في أي سياسة أخرى
Implicit Deny الرفض الافتراضي — يُطبق تلقائياً عند غياب أي جملة Allow منطبقة
Condition Key متغير سياقي يُستخدم في عنصر Condition مثل aws:SourceIp أو aws:MultiFactorAuthPresent
SCP Service Control Policy — سياسة تُطبق على مستوى الحساب أو الـ OU في AWS Organizations وتقيد الحد الأقصى للصلاحيات

Related Posts

تعليقات

المشاركات الشائعة من هذه المدونة

استرجاع معرّف نسخة EC2 عبر خدمة البيانات الوصفية IMDSv2

أوضاع سعة DynamoDB: متى تختار On-Demand ومتى تختار Provisioned؟

فهم مهلة الرؤية في SQS: لماذا تُعالَج رسائلك مرتين؟