هيكل سياسة 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، يقوم محرك تقييم السياسات بفحص جميع الجمل المنطبقة ويتخذ قراراً نهائياً وفق منطق محدد: الرفض الصريح يتغلب دائماً على السماح، وغياب السماح يعني الرفض الضمني.
- الطلب يصل: يرسل المستخدم أو الدور طلب API إلى AWS.
- جمع السياسات: يجمع AWS كل السياسات المنطبقة (سياسات الهوية، سياسات الموارد، SCPs).
- فحص الرفض الصريح: إذا وُجدت جملة
Denyمنطبقة، يُرفض الطلب فوراً بغض النظر عن أيAllow. - فحص السماح الصريح: إذا وُجدت جملة
Allowمنطبقة دون رفض، يُسمح بالطلب. - الرفض الضمني: إذا لم تنطبق أي جملة
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>"
}
}
مثل: StringEquals, Bool, IpAddress"] B --> C["Condition Key
مثل: aws:SourceIp, aws:MultiFactorAuthPresent"] C --> D["Condition Value
القيمة المقارَن بها"]
- مشغل الشرط (Condition Operator): يحدد نوع المقارنة — مثل
StringEqualsللمقارنة الحرفية، أوIpAddressللتحقق من نطاق IP، أوBoolللقيم المنطقية. - مفتاح الشرط (Condition Key): المتغير السياقي المراد فحصه — مثل
aws:SourceIpأوaws:MultiFactorAuthPresentأو مفاتيح خاصة بالخدمة مثلs3:prefix. - قيمة الشرط (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 وتقيد الحد الأقصى للصلاحيات |
تعليقات
إرسال تعليق