Lambda لا تتصل بـ RDS في الشبكة الخاصة — دليل التشخيص الكامل
أكثر سؤال يتكرر عند بناء تطبيقات Serverless: لماذا لا تستطيع Lambda الاتصال بـ RDS رغم أن كل شيء يبدو صحيحاً في الكود؟ الجواب دائماً في طبقة الشبكة، وتحديداً في إعدادات VPC التي يغفلها كثير من المطورين عند تهيئة Lambda لأول مرة.
TL;DR — ملخص سريع
| المشكلة | السبب الجذري | الحل |
|---|---|---|
| Lambda لا تصل إلى RDS | Lambda خارج VPC أو في Subnet خاطئة | ربط Lambda بـ VPC وSubnets الصحيحة |
| Connection timeout | Security 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.
بيئة AWS العامة"] --"لا يمكن الوصول"--> RDS["RDS
Private Subnet"] LambdaVPC["Lambda مع VPC Config
ENI داخل Subnet"] --"اتصال مباشر"--> RDS LambdaVPC --- SG["Security Group
يتحكم في الوصول"] SG --> RDS
- Lambda بدون VPC: تعمل في بيئة AWS المُدارة، لا تستطيع الوصول إلى موارد Private Subnet.
- Lambda مع VPC: تحصل على ENI داخل الـ Subnet المحددة، وتخضع لقواعد SG وNACL.
- RDS في Private Subnet: لا يملك IP عام، ولا يمكن الوصول إليه إلا من داخل الـ VPC.
- 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
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"]
- Lambda SG Outbound: يجب السماح بالخروج على منفذ RDS (5432 أو 3306).
- Lambda Subnet NACL Outbound: يجب السماح بالخروج على منفذ RDS.
- RDS Subnet NACL Inbound: يجب السماح بالدخول على منفذ RDS.
- RDS SG Inbound: يجب السماح بالدخول من SG الخاص بـ Lambda.
- RDS SG Outbound + RDS Subnet NACL Outbound: يجب السماح بالرد على المنافذ العشوائية (Ephemeral Ports: 1024-65535).
- 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 — الصورة الكاملة
- Lambda Execution: عند الاستدعاء، تُنشئ AWS ENI في الـ Subnet المحددة.
- DNS Resolution: Lambda تحل اسم RDS Endpoint إلى IP خاص داخل VPC.
- TCP Connection: تمر عبر SG وNACL قبل الوصول إلى RDS.
- RDS Response: يعود عبر نفس المسار مع ضرورة السماح بـ Ephemeral Ports في NACL.
- الخدمات الخارجية: Secrets Manager وCloudWatch تحتاج NAT أو VPC Endpoints منفصلة.
قائمة التحقق النهائية — Lambda إلى RDS
| العنصر | ما يجب التحقق منه | أمر التحقق |
|---|---|---|
| VPC Config | Lambda مرتبطة بـ VPC وSubnets وSG | get-function-configuration --query VpcConfig |
| IAM Role | تملك AWSLambdaVPCAccessExecutionRole | list-attached-role-policies |
| RDS SG Inbound | يسمح بالمنفذ من SG الخاص بـ Lambda | describe-security-groups --group-ids sg-rds |
| Lambda SG Outbound | يسمح بالخروج على منفذ RDS | describe-security-groups --group-ids sg-lambda |
| NACL | Stateless — يجب السماح بالاتجاهين | describe-network-acls |
| Route Table | مسار موجود بين Subnets | describe-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 |
تعليقات
إرسال تعليق