أساسيات الشبكات لـ DevOps

TLS والشهادات الرقمية

18 دقيقة الدرس 5 من 30

TLS والشهادات الرقمية

بروتوكول أمان طبقة النقل (TLS) هو البروتوكول الذي يضع قفل الأمان على كل عنوان URL يحمل بادئة HTTPS. يقع بين طبقة TCP (التي تعرفتَ عليها في الدرس الأول) وطبقة التطبيق، ويوفر ثلاثة ضمانات في آنٍ واحد: السرية (لا يستطيع أحد قراءة حركة المرور)، وسلامة البيانات (لا يمكن لأحد التلاعب بها دون اكتشاف ذلك)، والمصادقة (أنت تتحدث فعلاً مع الخادم الذي تظنه). إتقان TLS أمرٌ لا غنى عنه لأي مهندس DevOps — ستصطدم بأخطاء الشهادات، وستُجري تجديدها عند انتهاء صلاحيتها، وستضبط أداء المصافحة باستمرار.

مصافحة TLS خطوة بخطوة

المصافحة هي عملية التفاوض التي تجري قبل أن يتدفق أي بايت من بيانات التطبيق. تعتمد النشرات الحديثة تقريباً على TLS 1.3 حصراً، وهو أسرع وأكثر أماناً من الإصدارات السابقة. إليك بالضبط ما يحدث:

TLS 1.3 Handshake Sequence Client Server ClientHello (supported ciphers, random, key share) ServerHello + Certificate + CertificateVerify + Finished Finished (client confirms handshake) Encrypted Application Data (HTTP/2, gRPC, etc.) 1-RTT 0-RTT possible on resumption
مصافحة TLS 1.3: رحلة واحدة ذهاباً وإياباً قبل تدفق البيانات المشفرة. كانت TLS 1.2 تحتاج رحلتين.

في TLS 1.3 يُرسل العميل حصته من المفتاح باستباق في الرسالة الأولى. يستطيع الخادم بذلك احتساب السر المشترك فوراً ويرسل شهادته ورسالة Finished في رحلة واحدة. يتحقق العميل من الشهادة ويرسل Finished الخاص به، ثم تتدفق البيانات المشفرة. هذا رحلة ذهاب وإياب واحدة — نصف كُمون TLS 1.2.

تبادل المفاتيح في TLS 1.3 يعتمد دائماً على Diffie-Hellman المؤقت (ECDHE). لا يوجد خيار لاستخدام تبادل مفاتيح RSA، مما يعني أن السرية المستقبلية إلزامية: اختراق المفتاح الخاص للخادم اليوم لا يتيح فك تشفير حركة المرور المسجلة سابقاً.

سلاسل الشهادات وسلسلة الثقة

الشهادة وحدها لا تثبت شيئاً ما لم يكن المتصفح أو نظام التشغيل يثق بالجهة التي وقّعتها. يعمل نموذج الثقة كسلسلة:

  • CA الجذر — موقّع ذاتياً، مُضمَّن في أنظمة التشغيل والمتصفحات. أمثلة: ISRG Root X1 (جذر Let's Encrypt)، DigiCert Global Root CA.
  • CA الوسيط — موقَّع من الجذر، يُستخدم للإصدار اليومي للشهادات. تُبقى الـ CA الجذرية دون اتصال؛ الوسطاء هم من يُجري التوقيع الفعلي.
  • شهادة الكيان الطرفي (الورقة) — شهادة خادمك، موقَّعة من الوسيط.

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

# التحقق من السلسلة التي يقدمها مضيف حي openssl s_client -connect api.example.com:443 -showcerts 2>/dev/null | openssl x509 -noout -text | grep -A2 "Issuer\|Subject\|Not After" # التحقق مما يرسله الخادم فعلاً (جميع الشهادات في السلسلة) openssl s_client -connect api.example.com:443 -showcerts </dev/null 2>/dev/null | \ awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/' | \ openssl x509 -noout -subject -issuer # التحقق من ملف شهادة محلي مقابل حزمة CA openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /etc/nginx/ssl/server.crt

شهادات SAN (أسماء بديلة للموضوع)

حقل CN (الاسم الشائع) في الشهادة هو حقل قديم ولا تعود المتصفحات تستخدمه للتحقق من اسم المضيف — إنها تتحقق فقط من امتداد اسم بديل للموضوع (SAN). يمكن لشهادة واحدة حماية أسماء مضيفين كثيرة عبر عدة SANs:

  • DNS:example.com
  • DNS:www.example.com
  • DNS:api.example.com
  • DNS:*.staging.example.com (حرف بدل — مستوى واحد فقط)

تغطي SANs ذات حرف البدل (*.example.com) مستوى نطاق فرعي واحداً فقط ولا تشمل النطاق الجذر (example.com) أو النطاقات الفرعية الأعمق (a.b.example.com). بالنسبة للخدمات المصغرة ذات الأسماء الكثيرة، تكون شهادة واحدة متعددة SANs أبسط بكثير من إدارة عشرات الشهادات المنفردة.

Let's Encrypt وإدارة الشهادات التلقائية (ACME)

تُصدر Let's Encrypt شهادات DV (التحقق من النطاق) مجانية لمدة 90 يوماً عبر بروتوكول ACME. العمر القصير مقصود — يُجبر على الأتمتة ويحدّ من الضرر الناجم عن اختراق المفتاح. في الإنتاج، لا تقوم أبداً بتنزيل شهادة يدوياً؛ تُشغّل عميل ACME الذي يتولى الإصدار والتجديد تلقائياً.

أسلوبا التحقق الشائعان:

  • HTTP-01 — يضع ACME رمزاً على المسار http://yourdomain/.well-known/acme-challenge/<token>. يعمل مع أي مضيف يمكن الوصول إليه على المنفذ 80. لا يمكن استخدامه لأحرف البدل.
  • DNS-01 — ينشئ ACME سجل TXT باسم _acme-challenge.yourdomain. يعمل مع أحرف البدل والمضيفين الداخليين والمضيفين غير المعرضين على المنفذ 80. يتطلب وصولاً إلى API الـ DNS.
# certbot: إصدار شهادة لمضيف nginx (HTTP-01، يضبط nginx تلقائياً) certbot --nginx -d example.com -d www.example.com # certbot: حرف بدل عبر DNS-01 (يتطلب إضافة DNS، مثل Route 53) certbot certonly \ --dns-route53 \ -d example.com \ -d "*.example.com" # تجديد جميع الشهادات (يُشغَّل من cron يومي أو مؤقت systemd) certbot renew --quiet --deploy-hook "systemctl reload nginx" # عرض الشهادات الحالية وتواريخ انتهائها certbot certificates
جدّد عند 60 يوماً، لا عند 89. شهادات Let's Encrypt تعيش 90 يوماً. نافذة التجديد الافتراضية في Certbot (30 يوماً قبل الانتهاء) معقولة، لكن المنصات الكبيرة غالباً تُطلق التجديد عند 60 يوماً لإتاحة هامش أمان واسع لأعطال الأتمتة وتأخيرات انتشار DNS وحدود المعدلات. دائماً أضف مراقبة على انتهاء الصلاحية بشكل مستقل عن أتمتة التجديد — يمكن للأتمتة أن تفشل بصمت.

إنهاء TLS في الإنتاج

يُنهى TLS عادةً عند الحافة — موازن تحميل، بوابة API، أو وكيل عكسي — بحيث تتواصل خدمات الخلفية عبر HTTP عادي على شبكة خاصة. يُسمى هذا تفريغ TLS. للخدمات التي تتطلب تشفيراً كاملاً من طرف لطرف (معالجات الدفع، الرعاية الصحية)، يُستخدم mTLS (TLS المتبادل): يُقدم كلٌّ من العميل والخادم شهادته، مما يمنح هوية قوية لكلا الطرفين. تُؤتمت شبكات الخدمات (Istio، Linkerd) mTLS بين كل Pod في المجموعة.

# nginx: إعداد TLS للإنتاج (TLS 1.2 كحد أدنى، TLS 1.3 هو المفضل) server { listen 443 ssl; server_name api.example.com; ssl_certificate /etc/nginx/ssl/api.example.com.crt; # الورقة + الوسطاء ssl_certificate_key /etc/nginx/ssl/api.example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers off; # TLS 1.3 يتجاهل هذا؛ أبقِه off لعدالة 1.2 ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # off = سرية مستقبلية كاملة للجلسات ssl_stapling on; # تثبيت OCSP يقلل رحلات العميل ssl_stapling_verify on; resolver 8.8.8.8 valid=60s; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; }

تشخيص أخطاء الشهادات

أكثر أخطاء الشهادات شيوعاً في الإنتاج وكيفية التحقيق فيها:

  • CERTIFICATE_VERIFY_FAILED / ERR_CERT_AUTHORITY_INVALID — الخادم لم يرسل السلسلة الكاملة. تحقق بـ openssl s_client -showcerts.
  • ERR_CERT_DATE_INVALID / certificate has expired — أتمتة التجديد توقفت. تحقق من certbot certificates وسجلات cron وما إذا كان hook إعادة التحميل قد نُفّذ.
  • ERR_CERT_COMMON_NAME_INVALID / hostname mismatch — اسم المضيف الذي تتصل به غير موجود في SANs الشهادة. افحص بـ openssl x509 -noout -ext subjectAltName.
  • SSL_ERROR_RX_RECORD_TOO_LONG — الخادم يستجيب بـ HTTP عادي على منفذ توقع العميل منه TLS. خطأ إعداد كلاسيكي: حركة مرور تصل على المنفذ 80 بدلاً من 443.
# سطر واحد للتشخيص: فحص الانتهاء والـ SANs والسلسلة لمضيف حي echo | openssl s_client -servername api.example.com -connect api.example.com:443 2>/dev/null \ | openssl x509 -noout -dates -ext subjectAltName # فحص حالة OCSP للشهادة المُقدَّمة openssl s_client -connect api.example.com:443 -status 2>/dev/null | grep -A 10 "OCSP Response" # curl المطوّل: اطلع على نسخة TLS والتشفير وسلسلة الشهادات في أمر واحد curl -vvI https://api.example.com 2>&1 | grep -E "SSL|TLS|issuer|expire|subject"
لا تعطّل التحقق من الشهادات في أدوات الإنتاج. خيارات مثل curl -k أو verify=False في Python أو PYTHONHTTPSVERIFY=0 مقبولة فقط في تصحيح الأخطاء المحلي المعزول. في بيئات التجهيز أو أنابيب CI، إنها تُخفي مشكلات حقيقية في الشهادات ستظهر في الإنتاج. إذا لم تكن PKI الداخلية موثوقة، ثبّت شهادة CA في مخزن الثقة بالنظام — لا تعطّل التحقق.

TLS هو أساس كل خدمة آمنة ستُشغّلها. اعتد على استخدام openssl s_client كأداة استجابة أولى؛ فهي تخبرك بأكثر مما تحتاجه عن اتصال TLS في خمس ثوانٍ مقارنةً بما توفره معظم الأدوات الرسومية في خمس دقائق.