Lambda لا تتصل بـ RDS في الشبكة الخاصة — دليل التشخيص الكامل

أكثر سؤال يتكرر عند بناء تطبيقات Serverless: لماذا لا تستطيع Lambda الاتصال بـ RDS رغم أن كل شيء يبدو صحيحاً في الكود؟ الجواب دائماً في طبقة الشبكة، وتحديداً في إعدادات VPC التي يغفلها كثير من المطورين عند تهيئة Lambda لأول مرة.

TL;DR — ملخص سريع

المشكلةالسبب الجذريالحل
Lambda لا تصل إلى RDSLambda خارج VPC أو في Subnet خاطئةربط Lambda بـ VPC وSubnets الصحيحة
Connection timeoutSecurity Group لا يسمح بالمنفذ 5432/3306إضافة Inbound Rule في SG الخاص بـ RDS
Lambda تتجمد ولا تعودلا يوجد NAT Gateway أو VPC Endpointإضافة NAT أو تهيئة Endpoints للخدمات الأخرى
خطأ في الصلاحياتExecution Role لا تملك صلاحيات VPCإضافة AWSLambdaVPCAccessExecutionRole

كيف تعمل Lambda مع VPC — الأساس قبل التشخيص

Lambda بطبيعتها تعمل خارج VPC الخاص بك. عندما تُفعّل VPC Configuration، تقوم AWS بإنشاء Elastic Network Interface داخل الـ Subnet التي تحددها، وتربطها بالـ Security Group الذي تختاره. من هذه اللحظة، تصبح Lambda تتصرف كأي مورد داخل الـ VPC — تخضع لنفس قواعد الـ Security Groups والـ Network ACLs وجداول التوجيه.

فكر في الأمر كالتالي: Lambda بدون VPC تعمل من مكتب AWS العام. عندما تُضيف VPC Configuration، تنقلها AWS إلى مكتبك الخاص — لكنها الآن تخضع لجميع قواعد الدخول والخروج في مبناك.

النقطة الحرجة التي يُخطئ فيها كثيرون: ربط Lambda بـ VPC لا يعني تلقائياً أنها تستطيع الوصول إلى الإنترنت. إذا كانت Lambda في Private Subnet بدون NAT Gateway، فلن تستطيع الوصول إلى أي خدمة خارجية — بما فيها Secrets Manager وCloudWatch Logs — إلا عبر VPC Endpoints.

graph LR LambdaNoVPC["Lambda بدون VPC
بيئة AWS العامة"] --"لا يمكن الوصول"--> RDS["RDS
Private Subnet"] LambdaVPC["Lambda مع VPC Config
ENI داخل Subnet"] --"اتصال مباشر"--> RDS LambdaVPC --- SG["Security Group
يتحكم في الوصول"] SG --> RDS
  1. Lambda بدون VPC: تعمل في بيئة AWS المُدارة، لا تستطيع الوصول إلى موارد Private Subnet.
  2. Lambda مع VPC: تحصل على ENI داخل الـ Subnet المحددة، وتخضع لقواعد SG وNACL.
  3. RDS في Private Subnet: لا يملك IP عام، ولا يمكن الوصول إليه إلا من داخل الـ VPC.
  4. Security Group: يجب أن يسمح SG الخاص بـ RDS بالاتصالات الواردة من SG الخاص بـ Lambda.

الخطوة الأولى: تفعيل VPC Configuration في Lambda

إذا كانت Lambda لا تملك VPC Configuration أصلاً، فهذا هو السبب الوحيد والكافي لفشل الاتصال. لا توجد طريقة للوصول إلى RDS في Private Subnet بدون هذا الإعداد.

تحقق من الوضع الحالي أولاً:

aws lambda get-function-configuration \
  --function-name my-function \
  --query 'VpcConfig' \
  --output json

إذا كانت النتيجة {"VpcId": "", "SubnetIds": [], "SecurityGroupIds": []}، فـ Lambda خارج VPC تماماً. يجب تهيئتها:

aws lambda update-function-configuration \
  --function-name my-function \
  --vpc-config SubnetIds=subnet-0abc1234,subnet-0def5678,SecurityGroupIds=sg-0lambda1234

استخدم Subnets في نفس Availability Zones التي يعمل فيها RDS، ويُفضل تحديد أكثر من Subnet لضمان التوفر العالي. السبب: Lambda تحتاج إلى ENI في كل AZ لتجنب فشل الاتصال عند توسع الـ Concurrency.

الخطوة الثانية: التحقق من Execution Role

Lambda تحتاج صلاحيات IAM لإنشاء وإدارة Network Interfaces داخل VPC. بدون هذه الصلاحيات، ستفشل عملية الإطلاق نفسها قبل أن يصل الكود إلى سطر الاتصال بـ RDS.

تحقق من الـ Role المرتبطة بـ Lambda:

aws lambda get-function-configuration \
  --function-name my-function \
  --query 'Role' \
  --output text

تحقق من أن الـ Role تملك الـ Policy المطلوبة:

aws iam list-attached-role-policies \
  --role-name my-lambda-execution-role \
  --output json

الـ Policy المطلوبة هي AWSLambdaVPCAccessExecutionRole أو ما يعادلها. إذا لم تكن موجودة، أضفها:

aws iam attach-role-policy \
  --role-name my-lambda-execution-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole

هذه الـ Policy تمنح الصلاحيات اللازمة لإنشاء ec2:CreateNetworkInterface وحذفه والاستعلام عنه — وهي العمليات التي تنفذها AWS تلقائياً عند تشغيل Lambda داخل VPC.

الخطوة الثالثة: ضبط Security Groups — هنا تكمن معظم المشاكل

هذه هي النقطة التي تضيع فيها معظم الساعات. المنطق صحيح في الذهن، لكن التطبيق يكون خاطئاً في الاتجاه.

القاعدة الأساسية: يجب أن يسمح Security Group الخاص بـ RDS بالاتصالات الواردة من Security Group الخاص بـ Lambda — وليس من IP محدد.

تحقق من Inbound Rules في SG الخاص بـ RDS:

aws ec2 describe-security-groups \
  --group-ids sg-0rds1234 \
  --query 'SecurityGroups[*].IpPermissions' \
  --output json

إذا لم يكن هناك Rule يسمح بالمنفذ 5432 (PostgreSQL) أو 3306 (MySQL) من SG الخاص بـ Lambda، أضفه:

aws ec2 authorize-security-group-ingress \
  --group-id sg-0rds1234 \
  --protocol tcp \
  --port 5432 \
  --source-group sg-0lambda1234

استخدام SG كمصدر بدلاً من IP أفضل بكثير من الناحية التشغيلية — لا تحتاج لتحديث القواعد عند تغيير عناوين IP الخاصة بـ Lambda ENIs.

تحقق أيضاً من Outbound Rules في SG الخاص بـ Lambda. بشكل افتراضي، Security Groups تسمح بجميع حركة المرور الصادرة، لكن إذا كانت Outbound Rules مقيدة:

aws ec2 describe-security-groups \
  --group-ids sg-0lambda1234 \
  --query 'SecurityGroups[*].IpPermissionsEgress' \
  --output json

الخطوة الرابعة: فحص Network ACLs — الطبقة التي يُنساها الجميع

Security Groups تعمل على مستوى الـ Resource وهي Stateful — أي أن الرد يُسمح تلقائياً. Network ACLs تعمل على مستوى الـ Subnet وهي Stateless — يجب السماح بالاتجاهين صراحةً.

هذا الفرق هو سبب حالات غريبة: الاتصال يبدأ لكن لا يصل رد، أو الاتصال يفشل بشكل متقطع.

تحقق من NACL المرتبطة بـ Subnet الخاصة بـ Lambda:

aws ec2 describe-network-acls \
  --filters Name=association.subnet-id,Values=subnet-0abc1234 \
  --query 'NetworkAcls[*].{Inbound:Entries[?Egress==`false`],Outbound:Entries[?Egress==`true`]}' \
  --output json
graph TD Problem["Connection Timeout"] --> Check1["هل Lambda في VPC؟"] Check1 --"لا"--> Fix1["أضف VPC Configuration
Subnets + Security Group"] Check1 --"نعم"--> Check2["هل RDS SG يسمح
بالدخول من Lambda SG؟"] Check2 --"لا"--> Fix2["أضف Inbound Rule في RDS SG
المنفذ 5432 أو 3306"] Check2 --"نعم"--> Check3["هل NACL تسمح
بالاتجاهين؟"] Check3 --"لا"--> Fix3["أضف Outbound Rule لمنفذ RDS
وInbound للـ Ephemeral Ports"] Check3 --"نعم"--> Check4["هل الخدمات الخارجية
يمكن الوصول إليها؟"] Check4 --"لا"--> Fix4["أضف NAT Gateway
أو VPC Endpoints"] Check4 --"نعم"--> Fix5["تحقق من IAM Role
AWSLambdaVPCAccessExecutionRole"]
  1. Lambda SG Outbound: يجب السماح بالخروج على منفذ RDS (5432 أو 3306).
  2. Lambda Subnet NACL Outbound: يجب السماح بالخروج على منفذ RDS.
  3. RDS Subnet NACL Inbound: يجب السماح بالدخول على منفذ RDS.
  4. RDS SG Inbound: يجب السماح بالدخول من SG الخاص بـ Lambda.
  5. RDS SG Outbound + RDS Subnet NACL Outbound: يجب السماح بالرد على المنافذ العشوائية (Ephemeral Ports: 1024-65535).
  6. Lambda Subnet NACL Inbound: يجب السماح بالرد الوارد على المنافذ العشوائية.

الخطوة الخامسة: التحقق من Route Tables وإمكانية الوصول إلى الشبكة

Lambda وRDS يجب أن يكونا في نفس VPC، أو متصلَين عبر VPC Peering مع Route Tables صحيحة. إذا كانا في نفس VPC، تحقق أن Subnets الخاصة بـ Lambda لها Route إلى Subnets الخاصة بـ RDS.

aws ec2 describe-route-tables \
  --filters Name=association.subnet-id,Values=subnet-0abc1234 \
  --query 'RouteTables[*].Routes' \
  --output json

إذا كانا في نفس VPC، فالـ Local Route يكفي ولا تحتاج إلى إعداد إضافي. المشكلة تظهر فقط عند استخدام VPCs مختلفة أو عند تقسيم الشبكة بشكل غير معتاد.

تجربة حقيقية: الخطأ الذي يضيع فيه الوقت

الأعراض: Lambda تُطلق بنجاح، الـ Logs تُظهر بداية التنفيذ، ثم تتجمد تماماً حتى تنتهي مدة الـ Timeout. لا يوجد خطأ واضح، لا Connection Refused، مجرد صمت.

التشخيص الأول الخاطئ: الجميع يبدأ بفحص Security Groups، ويجد أن الـ Rules صحيحة. يُعدّل المنافذ، يُعيد النشر، نفس النتيجة.

السبب الفعلي: Lambda كانت في Private Subnet بدون NAT Gateway. الكود يحاول الاتصال بـ Secrets Manager لجلب كلمة مرور قاعدة البيانات قبل الاتصال بـ RDS — وهذا الاتصال يتجمد لأن Secrets Manager خدمة خارجية لا يمكن الوصول إليها من Private Subnet بدون NAT أو VPC Endpoint.

الحل: إضافة VPC Endpoint لـ Secrets Manager أسرع وأرخص من NAT Gateway في هذا السياق:

aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0abc1234 \
  --service-name com.amazonaws.us-east-1.secretsmanager \
  --vpc-endpoint-type Interface \
  --subnet-ids subnet-0abc1234 subnet-0def5678 \
  --security-group-ids sg-0lambda1234 \
  --private-dns-enabled

الدرس: عندما تضع Lambda في Private Subnet، كل خدمة AWS تستخدمها تحتاج إلى مسار وصول — إما NAT Gateway أو VPC Endpoint. هذا ليس واضحاً في رسائل الخطأ.

سيناريو الاتصال بـ RDS — الصورة الكاملة

sequenceDiagram participant L as Lambda ENI participant LSG as Lambda SG participant LNACL as Lambda Subnet NACL participant RNACL as RDS Subnet NACL participant RSG as RDS SG participant R as RDS Instance L->>LSG: طلب اتصال TCP منفذ 5432 LSG->>LNACL: Outbound مسموح؟ LNACL->>RNACL: Outbound مسموح؟ RNACL->>RSG: Inbound مسموح؟ RSG->>R: اتصال مقبول R->>RSG: رد على Ephemeral Port RSG->>RNACL: Outbound للرد RNACL->>LNACL: Inbound Ephemeral مسموح؟ LNACL->>L: الرد يصل إلى Lambda
  1. Lambda Execution: عند الاستدعاء، تُنشئ AWS ENI في الـ Subnet المحددة.
  2. DNS Resolution: Lambda تحل اسم RDS Endpoint إلى IP خاص داخل VPC.
  3. TCP Connection: تمر عبر SG وNACL قبل الوصول إلى RDS.
  4. RDS Response: يعود عبر نفس المسار مع ضرورة السماح بـ Ephemeral Ports في NACL.
  5. الخدمات الخارجية: Secrets Manager وCloudWatch تحتاج NAT أو VPC Endpoints منفصلة.

قائمة التحقق النهائية — Lambda إلى RDS

العنصرما يجب التحقق منهأمر التحقق
VPC ConfigLambda مرتبطة بـ VPC وSubnets وSGget-function-configuration --query VpcConfig
IAM Roleتملك AWSLambdaVPCAccessExecutionRolelist-attached-role-policies
RDS SG Inboundيسمح بالمنفذ من SG الخاص بـ Lambdadescribe-security-groups --group-ids sg-rds
Lambda SG Outboundيسمح بالخروج على منفذ RDSdescribe-security-groups --group-ids sg-lambda
NACLStateless — يجب السماح بالاتجاهينdescribe-network-acls
Route Tableمسار موجود بين Subnetsdescribe-route-tables
الخدمات الخارجيةNAT أو VPC Endpoints للخدمات الأخرىdescribe-vpc-endpoints

الخلاصة والخطوات التالية

ربط Lambda بـ RDS في Private Subnet يتطلب تهيئة VPC Configuration بشكل صريح — هذا ليس اختيارياً. الخطوات بالترتيب: تفعيل VPC Config، التحقق من IAM Role، ضبط Security Groups في الاتجاهين، فحص Network ACLs كطبقة Stateless، ثم التأكد من وجود مسار للخدمات الخارجية التي يستخدمها كودك.

للتعمق أكثر، راجع توثيق AWS الرسمي لـ Lambda VPC Configuration وتوثيق Network ACLs.

مسرد المصطلحات

المصطلحالتعريف
ENI (Elastic Network Interface)واجهة شبكة افتراضية تُنشئها AWS لربط Lambda بـ VPC
Security Groupجدار حماية Stateful على مستوى الـ Resource، يتذكر حالة الاتصال
Network ACLطبقة تصفية Stateless على مستوى الـ Subnet، تتطلب قواعد صريحة للاتجاهين
Ephemeral Portsمنافذ عشوائية (1024-65535) يستخدمها TCP للردود، يجب السماح بها في NACL
VPC Endpointاتصال خاص بخدمات AWS بدون المرور عبر الإنترنت أو NAT Gateway

Related Posts

تعليقات

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

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

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

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