انتهاء مهلة اتصال SSH بـ EC2: تشخيص قواعد Security Group خطوة بخطوة
أطلقت نسخة EC2 جديدة، وعند محاولة الاتصال عبر SSH تظهر رسالة Connection timed out — لا رسالة رفض، لا استجابة، فقط صمت. هذا النمط تحديداً يشير في الغالب إلى أن الحزم تُسقط على مستوى الشبكة قبل أن تصل إلى نظام التشغيل، والمشتبه الأول دائماً هو Security Group.
ملخص سريع (TL;DR): انتهاء مهلة SSH في EC2
| السبب | الطبقة | الإجراء |
|---|---|---|
| قاعدة SSH غائبة في Security Group | Security Group | إضافة Inbound Rule: TCP/22 من مصدرك |
| Network ACL يحجب المنفذ 22 | Subnet ACL | مراجعة Inbound/Outbound rules في NACL |
| Instance في Subnet خاصة بدون NAT/Bastion | Routing | التحقق من Route Table وإمكانية الوصول العام |
| عدم تعيين Elastic IP أو Public IP | عنوان IP | التحقق من وجود Public IPv4 للنسخة |
| sshd غير مشغّل داخل النسخة | نظام التشغيل | الاتصال عبر Session Manager للتحقق |
كيف يعمل تصفية الشبكة في EC2
قبل الدخول في خطوات التشخيص، من الضروري فهم الطبقات التي تمر بها حزمة SSH قبل وصولها إلى النسخة. كثير من المهندسين يصلحون Security Group ويظنون المشكلة انتهت، ثم يفاجأون بأن NACL كان يحجب الاتصال طوال الوقت.
(Stateless)"] SG["Security Group
(Stateful)"] EC2["EC2 Instance
sshd :22"] Internet -->|"حزمة SSH TCP/22"| IGW IGW -->|"فحص المسار"| RT RT -->|"Subnet العامة"| NACL NACL -->|"Inbound Rule"| SG SG -->|"Inbound Rule"| EC2 style Internet fill:#f0f0f0,stroke:#999 style IGW fill:#FF9900,color:#fff,stroke:#FF9900 style RT fill:#1A73E8,color:#fff,stroke:#1A73E8 style NACL fill:#E53935,color:#fff,stroke:#E53935 style SG fill:#E53935,color:#fff,stroke:#E53935 style EC2 fill:#2E7D32,color:#fff,stroke:#2E7D32
- Internet Gateway: البوابة التي تربط الـ VPC بالإنترنت — إذا لم تكن موجودة أو غير مرتبطة بالـ Route Table، لن تصل أي حزمة.
- Route Table: يحدد إلى أين تتجه الحزم — يجب أن يوجد مسار
0.0.0.0/0 → igw-xxxxفي الـ Subnet العامة. - Network ACL (NACL): فلتر على مستوى الـ Subnet، يعمل بقواعد مرقمة، وهو Stateless — يجب السماح بالاتجاهين (Inbound وOutbound) صراحةً.
- Security Group: فلتر على مستوى النسخة، Stateful — إذا سمحت بالـ Inbound، يُسمح بالـ Outbound تلقائياً للاستجابة.
- EC2 Instance: آخر الطبقات — يجب أن يكون
sshdمشغلاً ويستمع على المنفذ الصحيح.
Security Group يشبه حارس المبنى: يتذكر من أذن له بالدخول ويسمح له بالخروج تلقائياً. NACL يشبه نقطة تفتيش الحي: لا يتذكر شيئاً، ويفحص كل سيارة في الاتجاهين بشكل مستقل.
الخطوة 1: التحقق من وجود Public IP للنسخة
قبل أي شيء آخر، تأكد أن للنسخة عنوان IP عام — إذا كانت في Subnet خاصة أو أُنشئت بدون تفعيل خيار تعيين IP تلقائي، فلا يوجد ما تتصل به أصلاً، وستحصل على Connection timed out بغض النظر عن باقي الإعدادات.
aws ec2 describe-instances \
--instance-ids i-0123456789abcdef0 \
--query 'Reservations[0].Instances[0].{PublicIP:PublicIpAddress,PrivateIP:PrivateIpAddress,State:State.Name,SubnetId:SubnetId}' \
--output table \
--region us-east-1
إذا كانت قيمة PublicIP فارغة أو None، فالنسخة لا يمكن الوصول إليها مباشرة من الإنترنت. الحل: تعيين Elastic IP أو التأكد من تفعيل Auto-assign public IP عند الإنشاء — هذا الخيار لا يمكن تغييره بعد الإنشاء، لكن يمكن تعيين Elastic IP في أي وقت.
# تخصيص Elastic IP جديد
aws ec2 allocate-address \
--domain vpc \
--region us-east-1
# ربطه بالنسخة (استبدل القيم بما يناسبك)
aws ec2 associate-address \
--instance-id i-0123456789abcdef0 \
--allocation-id eipalloc-0123456789abcdef0 \
--region us-east-1
الخطوة 2: فحص قواعد Security Group — جوهر مشكلة SSH في EC2
Security Group هو أكثر الأسباب شيوعاً لخطأ Connection timed out عند الاتصال بـ EC2 عبر SSH. القاعدة المطلوبة بسيطة: السماح بحركة TCP الواردة على المنفذ 22 من عنوان IP المصدر.
# عرض Security Groups المرتبطة بالنسخة
aws ec2 describe-instances \
--instance-ids i-0123456789abcdef0 \
--query 'Reservations[0].Instances[0].SecurityGroups' \
--output table \
--region us-east-1
# فحص القواعد الواردة لـ Security Group محدد
aws ec2 describe-security-groups \
--group-ids sg-0123456789abcdef0 \
--query 'SecurityGroups[0].IpPermissions' \
--output json \
--region us-east-1
ابحث في المخرجات عن كتلة تحتوي على "FromPort": 22 و"ToPort": 22 و"IpProtocol": "tcp". إذا لم تجدها، أضف القاعدة:
# إضافة قاعدة SSH للسماح من عنوان IP محدد (الأكثر أماناً)
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 22 \
--cidr 203.0.113.10/32 \
--region us-east-1
استخدام 0.0.0.0/0 يفتح المنفذ للعالم كله — مقبول للاختبار السريع، لكن في بيئات الإنتاج يجب تقييد المصدر بعنوان IP محدد أو نطاق CIDR ضيق. هذا ليس مجرد توصية، بل هو ما تفرضه معايير AWS Security Hub وAWS Foundational Security Best Practices.
TCP/22 Inbound؟"} Q2{"هل المصدر يشمل
عنوان IP الخاص بك؟"} Q3{"هل القاعدة في
الـ SG الصحيح؟"} OK["Security Group ✓
انتقل للخطوة التالية"] FIX1["أضف قاعدة:
TCP/22 من CIDR محدد"] FIX2["عدّل المصدر ليشمل
عنوان IP الصحيح"] FIX3["تحقق من SG المرتبط
بالنسخة فعلياً"] Q1 -->|نعم| Q2 Q1 -->|لا| FIX1 Q2 -->|نعم| Q3 Q2 -->|لا| FIX2 Q3 -->|نعم| OK Q3 -->|لا| FIX3 style OK fill:#2E7D32,color:#fff style FIX1 fill:#E53935,color:#fff style FIX2 fill:#E53935,color:#fff style FIX3 fill:#FF9900,color:#fff
الخطوة 3: فحص Network ACL على مستوى الـ Subnet
هنا يقع كثير من المهندسين في فخ: يضيفون قاعدة SSH في Security Group، يتحققون من وجود Public IP، ثم يستمر الـ Connection timed out. السبب في الغالب هو NACL. لأن NACL يعمل بشكل Stateless، يجب السماح صراحةً بحركة المرور في الاتجاهين.
# الحصول على Subnet ID للنسخة
aws ec2 describe-instances \
--instance-ids i-0123456789abcdef0 \
--query 'Reservations[0].Instances[0].SubnetId' \
--output text \
--region us-east-1
# الحصول على NACL المرتبط بالـ Subnet
aws ec2 describe-network-acls \
--filters Name=association.subnet-id,Values=subnet-0123456789abcdef0 \
--query 'NetworkAcls[0].{AclId:NetworkAclId,InboundRules:Entries[?Egress==`false`],OutboundRules:Entries[?Egress==`true`]}' \
--output json \
--region us-east-1
تحقق من وجود قاعدة Inbound تسمح بـ TCP/22، وقاعدة Outbound تسمح بالمنافذ العشوائية (Ephemeral Ports) التي يستخدمها العميل للرد — النطاق الموثق من AWS هو 1024-65535 لمعظم أنظمة التشغيل. إذا كان NACL يستخدم القواعد الافتراضية (ALLOW ALL)، فهو ليس المشكلة.
الخطوة 4: التحقق من Route Table والـ Internet Gateway
نسخة بـ Public IP وSecurity Group صحيح وNACL مفتوح — وما زالت لا تستجيب. هذا يعني أن الحزم لا تصل إلى الـ VPC أصلاً، أو لا تعرف كيف تخرج منه.
# فحص Route Table للـ Subnet
aws ec2 describe-route-tables \
--filters Name=association.subnet-id,Values=subnet-0123456789abcdef0 \
--query 'RouteTables[0].Routes' \
--output table \
--region us-east-1
يجب أن ترى مساراً بـ DestinationCidrBlock: 0.0.0.0/0 يشير إلى GatewayId يبدأ بـ igw-. إذا كان المسار يشير إلى nat- فالـ Subnet خاصة ولا يمكن الوصول إليها مباشرة من الإنترنت.
# التحقق من وجود Internet Gateway في الـ VPC
aws ec2 describe-internet-gateways \
--filters Name=attachment.vpc-id,Values=vpc-0123456789abcdef0 \
--query 'InternetGateways[0].{IgwId:InternetGatewayId,State:Attachments[0].State}' \
--output table \
--region us-east-1
الخطوة 5: التحقق من تشغيل sshd داخل النسخة عبر Session Manager
إذا اجتازت كل الطبقات السابقة ولا يزال الاتصال يفشل، فالمشكلة داخل نظام التشغيل. الطريقة الوحيدة للتحقق دون SSH هي AWS Systems Manager Session Manager — يعمل عبر وكيل SSM داخل النسخة بدون الحاجة لفتح أي منفذ.
# الاتصال بالنسخة عبر Session Manager
aws ssm start-session \
--target i-0123456789abcdef0 \
--region us-east-1
بعد الاتصال، تحقق من حالة sshd:
# داخل جلسة Session Manager
sudo systemctl status sshd
sudo ss -tlnp | grep :22
إذا كان sshd متوقفاً أو يستمع على منفذ مختلف، فهذا هو السبب الجذري. لتشغيله:
sudo systemctl start sshd
sudo systemctl enable sshd
ملاحظة: Session Manager يتطلب أن يكون SSM Agent مثبتاً ومشغلاً في النسخة، وأن يكون لها IAM Instance Profile يحتوي على صلاحيات AmazonSSMManagedInstanceCore.
تجربة حقيقية: التشخيص الخاطئ الذي يضيع الوقت
الموقف الكلاسيكي: مهندس يضيف قاعدة TCP/22 from 0.0.0.0/0 في Security Group، يتحقق من وجود Public IP، ثم يقضي ساعة يعيد تشغيل النسخة ويغير مفاتيح SSH ظناً أن المشكلة في الشهادة. المشكلة الفعلية كانت في NACL الذي ورثه من بيئة أخرى وكان يحتوي على قاعدة DENY ALL برقم أولوية منخفض تتجاوز كل قواعد السماح.
الدرس: Connection timed out لا يميز بين Security Group وNACL وRoute Table — كلها تنتج نفس الأعراض. الفرق الوحيد الذي يساعد في التشخيص السريع هو فحص الطبقات بالترتيب من الخارج للداخل.
نقطة غير واضحة من الوثائق المنفردة: Security Group هو Stateful، لذا لا تحتاج لقاعدة Outbound صريحة للرد على SSH. لكن NACL هو Stateless، وإذا أضفت قاعدة Inbound للمنفذ 22 دون قاعدة Outbound للمنافذ العشوائية، ستنجح مصافحة TCP لكن الجلسة ستتجمد فوراً — وهو عرض أكثر إرباكاً من مجرد Connection timed out.
IAM: الصلاحيات اللازمة لتنفيذ التشخيص
لتنفيذ أوامر التشخيص أعلاه، يحتاج المستخدم أو الدور إلى الصلاحيات التالية كحد أدنى:
🔽 عرض IAM Policy للتشخيص
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2NetworkDiagnostics",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeSecurityGroups",
"ec2:DescribeNetworkAcls",
"ec2:DescribeRouteTables",
"ec2:DescribeInternetGateways",
"ec2:DescribeAddresses"
],
"Resource": "*"
},
{
"Sid": "EC2SecurityGroupModify",
"Effect": "Allow",
"Action": [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:AllocateAddress",
"ec2:AssociateAddress"
],
"Resource": "*"
},
{
"Sid": "SSMSessionAccess",
"Effect": "Allow",
"Action": [
"ssm:StartSession",
"ssm:DescribeInstanceInformation"
],
"Resource": "*"
}
]
}
ملاحظة: أفعال Describe* في EC2 تتطلب "Resource": "*" لأنها لا تدعم تقييد الموارد على مستوى ARN — هذا موثق في AWS Service Authorization Reference.
قائمة فحص سريعة: انتهاء مهلة SSH في EC2
موجود؟"} C2{"Security Group
يسمح TCP/22؟"} C3{"NACL يسمح
Inbound/Outbound؟"} C4{"Route Table يحتوي
مسار IGW؟"} C5{"sshd يعمل
على المنفذ 22؟"} DONE(["الاتصال يعمل ✓"]) F1["عيّن Elastic IP"] F2["أضف Inbound Rule
TCP/22"] F3["أضف قواعد NACL
للاتجاهين"] F4["أضف مسار
0.0.0.0/0 → IGW"] F5["شغّل sshd
عبر Session Manager"] S --> C1 C1 -->|لا| F1 C1 -->|نعم| C2 F1 --> C2 C2 -->|لا| F2 C2 -->|نعم| C3 F2 --> C3 C3 -->|لا| F3 C3 -->|نعم| C4 F3 --> C4 C4 -->|لا| F4 C4 -->|نعم| C5 F4 --> C5 C5 -->|لا| F5 C5 -->|نعم| DONE F5 --> DONE style DONE fill:#2E7D32,color:#fff style F1 fill:#E53935,color:#fff style F2 fill:#E53935,color:#fff style F3 fill:#E53935,color:#fff style F4 fill:#E53935,color:#fff style F5 fill:#E53935,color:#fff
الخلاصة والخطوات التالية لحل مشكلة SSH في EC2
خطأ Connection timed out عند الاتصال بـ EC2 عبر SSH ليس مشكلة واحدة — هو عرض لأي طبقة من طبقات الشبكة تسقط الحزم بصمت. الترتيب الصحيح للتشخيص: Public IP ← Security Group ← NACL ← Route Table ← sshd. تخطي أي طبقة يعني احتمال إضاعة وقت في المكان الخطأ.
للمزيد من التعمق، راجع:
- توثيق AWS: التحكم في الوصول إلى نسخ EC2
- توثيق AWS: Network ACLs في VPC
- توثيق AWS: AWS Systems Manager Session Manager
مسرد المصطلحات
| المصطلح | التعريف |
|---|---|
| Security Group | جدار حماية افتراضي على مستوى النسخة، يعمل بشكل Stateful — يتذكر الاتصالات المصرح بها ويسمح بالردود تلقائياً |
| Network ACL (NACL) | فلتر شبكة على مستوى الـ Subnet، يعمل بشكل Stateless — يفحص كل حزمة في الاتجاهين بشكل مستقل |
| Internet Gateway (IGW) | مكوّن VPC يتيح الاتصال بين الموارد داخل VPC والإنترنت العام |
| Elastic IP | عنوان IPv4 عام ثابت يمكن تعيينه لنسخة EC2 أو موارد VPC أخرى |
| Session Manager | ميزة في AWS Systems Manager تتيح الاتصال بنسخ EC2 عبر متصفح أو CLI دون الحاجة لفتح منفذ SSH |
تعليقات
إرسال تعليق