إدارة الأسرار والبنية التحتية للمفاتيح

الشهادات الآلية

18 دقيقة الدرس 8 من 28

الشهادات الآلية

تُعدّ إدارة شهادات TLS يدوياً مصدراً موثوقاً للانقطاعات الإنتاجية على نطاق واسع. ينسى المهندسون مواعيد التجديد، ويستبدلون الشهادة الخاطئة، أو يفقدون تتبع الخدمة المالكة لكل شهادة. الحل الذي توصّلت إليه الصناعة هو الأتمتة الكاملة: تطلب الآلة الشهادات وتجدّدها وتنشرها دون تدخل بشري. يتناول هذا الدرس بروتوكول ACME، وخدمة Let's Encrypt، والتطبيق المعياري في Kubernetes عبر cert-manager.

بروتوكول ACME

ACME (بيئة إدارة الشهادات الآلية، RFC 8555) هو البروتوكول الذي بنته Let's Encrypt وأصبح مدعوماً من كل مرجع تصديق عام تقريباً. يُعرّف سير عمل آلي بين العميل ومرجع التصديق، حيث يُثبت العميل السيطرة على النطاق ويحصل على شهادة موقّعة — دون لوحة تحكم بشرية أو بطاقة ائتمان أو وقت انتظار.

أنواع التحديات الأساسية التي يستخدمها ACME لإثبات الملكية:

  • HTTP-01 — يطلب مرجع التصديق من العميل وضع رمز مميز في http://<domain>/.well-known/acme-challenge/<token>. بسيط ويعمل مع معظم النطاقات العامة. لا يدعم الشهادات الشاملة (wildcard) أو الشبكات الداخلية.
  • DNS-01 — ينشئ العميل سجل TXT على _acme-challenge.<domain>. يدعم الشهادات الشاملة (*.example.com) والنطاقات الداخلية. يتطلب وصولاً عبر API إلى مزود DNS.
  • TLS-ALPN-01 — يُجري مرجع التصديق مصافحة TLS على المنفذ 443 باستخدام امتداد ALPN خاص. مفيد حين يكون المنفذ 443 هو الوحيد المفتوح. نادراً ما يُحتاج إليه عملياً.
حدود معدل Let's Encrypt مهمة في الإنتاج. الحدود الرئيسية هي 50 شهادة لكل نطاق مسجّل أسبوعياً و5 شهادات مكررة أسبوعياً. إن كنت تُصدر شهادات لكل Pod أو خدمة مؤقتة، ستصل إلى هذه الحدود بسرعة. استخدم الشهادات الشاملة أو CA داخلياً لأي حجم استخدام مرتفع.

cert-manager: مشغّل الشهادات في Kubernetes

cert-manager هو مشغّل Kubernetes يُؤتمت دورة حياة الشهادات بالكامل: الطلب، والتخزين كـ Secrets، ومراقبة انتهاء الصلاحية، والتجديد قبل 30 يوماً من الانتهاء. يتكامل مع Let's Encrypt وVault PKI وAWS ACM وVenafi والCAs الموقّعة ذاتياً من خلال API موحّد من كائنات Issuer وClusterIssuer.

ثبّته عبر مخطط Helm الرسمي (الطريقة الإنتاجية المدعومة الوحيدة منذ cert-manager v1.14+):

# تثبيت CRDs الخاصة بـ cert-manager والمشغّل helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.14.5 \ --set crds.enabled=true # التحقق من تشغيل الـ Pods الثلاثة kubectl get pods -n cert-manager # NAME READY STATUS RESTARTS AGE # cert-manager-xxxx 1/1 Running 0 60s # cert-manager-cainjector-xxxx 1/1 Running 0 60s # cert-manager-webhook-xxxx 1/1 Running 0 60s

المُصدِرون: ربط cert-manager بمرجع تصديق

ClusterIssuer يعمل على مستوى الكلاسر ويمكنه إصدار شهادات لأي namespace — الخيار المفضّل لفرق المنصة. أما Issuer المحدد بـ namespace فمفيد حين تحتاج الفرق إلى تكوينات CA مستقلة.

أكثر إعداد إنتاجي شيوعاً هو Let's Encrypt مع DNS-01 عبر Route 53. HTTP-01 أبسط لكنه لا يدعم الشهادات الشاملة وينكسر حين تكون الـ ingress خلف جدار حماية. إليك مانيفست ClusterIssuer الكامل للبيئة التجريبية (دائماً اختبر هنا أولاً) والإنتاجية:

# cluster-issuer.yaml --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: platform@example.com privateKeySecretRef: name: letsencrypt-staging-account-key solvers: - dns01: route53: region: us-east-1 # استخدم IRSA — لا تضع مفاتيح مباشرة أبداً role: arn:aws:iam::123456789012:role/cert-manager-dns01-role --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: platform@example.com privateKeySecretRef: name: letsencrypt-prod-account-key solvers: - dns01: route53: region: us-east-1 role: arn:aws:iam::123456789012:role/cert-manager-dns01-role
تحقّق دائماً من CA التجريبي قبل التحويل إلى الإنتاج. يُصدر CA التجريبي شهادات غير موثوقة لكنها صحيحة هيكلياً — يتيح لك اكتشاف أخطاء DNS والإذونات وأخطاء المحلّلات دون استنزاف حصة معدل الإنتاج. انتقل إلى letsencrypt-prod فقط بعد أن يصل كائن Certificate التجريبي إلى الحالة Ready=True.

طلب شهادة

بمجرد أن يصبح المُصدِر جاهزاً، تُعلن عن مورد Certificate. يُنشئ cert-manager كائن CertificateRequest، يُجري تحدي ACME، ويخزّن زوج المفاتيح الناتج في Secret الذي حُدد اسمه في secretName. يقوم الـ Ingress أو عبء العمل بتثبيت ذلك Secret بعدها.

cert-manager ACME certificate issuance flow Engineer / GitOps cert-manager Certificate CRD CertificateRequest Route 53 DNS-01 solver Let\'s Encrypt ACME CA K8s Secret tls.crt / tls.key Ingress / Gateway apply create TXT ACME order verify signed cert store mount
سير إصدار شهادة ACME في cert-manager: من CRD الشهادة إلى Secret التشفير المثبَّت في Ingress.
# certificate.yaml — طلب شهادة شاملة لـ *.example.com apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: wildcard-example-com namespace: ingress-nginx spec: secretName: wildcard-example-com-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - "example.com" - "*.example.com" duration: 2160h # 90 يوماً (الحد الأقصى لـ Let's Encrypt) renewBefore: 720h # التجديد قبل 30 يوماً من الانتهاء # فحص حالة الإصدار kubectl describe certificate wildcard-example-com -n ingress-nginx kubectl get secret wildcard-example-com-tls -n ingress-nginx \ -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates

اختصار تعليق توضيحي على Ingress

للشهادات البسيطة لكل خدمة، يراقب cert-manager كائنات Ingress المزوّدة بـ cert-manager.io/cluster-issuer. يُنشئ تلقائياً كائن Certificate للمضيفين المُدرجين ويخزّنه في Secret محدد الاسم في tls.secretName. مفيد للنطاقات ذاتية الخدمة حيث تدير كل فريق Ingress الخاص به.

# ingress-with-tls.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: api-ingress namespace: payments annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: ingressClassName: nginx tls: - hosts: - api.payments.example.com secretName: api-payments-tls rules: - host: api.payments.example.com http: paths: - path: / pathType: Prefix backend: service: name: payments-api port: number: 8080

أتمتة التجديد والمراقبة

يستطلع cert-manager تلقائياً كل كائن Certificate ويبدأ التجديد حين تقل الصلاحية المتبقية عن renewBefore. لا وظائف cron، ولا مسرحيات Ansible، ولا تذكيرات بشرية. لكنك يجب أن تراقب الأتمتة نفسها — أمر ACME الفاشل يعيد المحاولة بصمت بتراجع أسّي، وإن لم تُنبّه عليه، ستكتشف الفشل حين تنتهي صلاحية الشهادة وينقطع الإنتاج.

المقاييس الأساسية للاستطلاع (يعرض cert-manager نقطة نهاية Prometheus افتراضياً):

  • certmanager_certificate_expiration_timestamp_seconds — أنبّه حين يقل الانتهاء عن 14 يوماً (دليل على فشل التجديد رغم المحاولات)
  • certmanager_certificate_ready_status — أنبّه حين تكون ready=False أكثر من 10 دقائق
  • certmanager_http_acme_client_request_count — راقب معدلات الأخطاء لاكتشاف انقطاعات ACME API
شغّل شهادة كاشفة في بيئة التجربة. تحتفظ فرق SRE في الشركات الكبرى بشهادة مخصصة في namespace منخفض الحركة، غرضها الوحيد ممارسة خط إصدار الشهادات الكامل بشكل مستمر. إن انكسر تجديد شهادة التجربة (سياسة شبكة جديدة تغلق المنفذ 53، أو دور IRSA انجرف، أو تغيّر API مزود DNS)، ستكتشفه قبل أن يؤثر على شهادات الإنتاج.

أنماط الفشل الإنتاجية

فهم سبب فشل الأتمتة بالغ الأهمية كإعدادها. أكثر أنماط الفشل شيوعاً في بيئات الإنتاج:

  • تأخر انتشار DNS — ينشئ cert-manager سجل TXT ويطلب من Let's Encrypt التحقق فوراً. إن كانت TTL لـ DNS مرتفعة أو يخزّن المحلّل استجابات سلبية، يفشل التحدي. ارفع قيمة waitForRecordToPropagate، أو استخدم cmctl لفحص حالة التحدي.
  • انجراف أذونات IAM — أدوار IRSA ذات أذونات Route 53 تُعاد تدويرها أو تُقيَّد، مما يكسر محلّلات DNS-01 بصمت. راقب وأنبّه على تغييرات سياسة الأدوار.
  • عدم توفر Webhook — يجب أن يكون webhook قبول cert-manager متاحاً لإصدار الشهادات. إن كان cert-manager نفسه معطلاً أثناء فشل عقدة، لا يمكن إصدار شهادات جديدة. شغّل cert-manager مع PodDisruptionBudget وعبر مناطق توفر متعددة.
  • عدم تحديث Secret في عبء العمل — يُدير cert-manager Secret عند التجديد، لكن Pods التي ثبّتته كـ volume لا تُعيد التحميل تلقائياً. استخدم stakater/Reloader أو ابنِ منطق إعادة التحميل في تطبيقك.
Reloader ضروري في الإنتاج. يُحدّث cert-manager Secret عند تجديد الشهادة، لكن Pods الجارية تحتفظ بالشهادة القديمة في الذاكرة. بدون متحكم مثل stakater/Reloader يراقب Secrets التشفير ويُطلق تحديث Deployment، سيخدم تطبيقك الشهادة المنتهية حتى بعد تجديد cert-manager لها بنجاح. هذه أكثر حوادث "cert-manager يعمل لكن الشهادة انتهت" شيوعاً.

ما وراء CAs العامة: PKI داخلي مع cert-manager

ليست كل شهادة بحاجة إلى Let's Encrypt. يستخدم mTLS بين الخدمات داخل كلاسر Kubernetes والأدوات الداخلية والبيئات المعزولة CA داخلياً — عادةً Vault PKI (الدرس 7) أو نوع المُصدِر CA الخاص بـ cert-manager. سير العمل متطابق: يُعلن المهندسون عن CRDs لـ Certificate، يُصدر cert-manager من الواجهة الخلفية المهيأة، وتُدار Secrets تلقائياً. الفرق أنك تتحكم في جذر الثقة ومدة الصلاحية (كثيراً ما تكون أقصر — 24 ساعة لشهادات الخدمات الداخلية)، ولا حدود معدل خارجية.

إدارة الشهادات الآلية ليست ميزة تُشغّلها وتنساها — بل نظام حيّ يتطلب مراقبة وسيناريوهات فشل مختبرة وتحقق دوري من عمل الأتمتة فعلياً. حين تعمل بشكل صحيح، تتوقف فرقتك تماماً عن التفكير في انتهاء صلاحية TLS. هذا هو الهدف.