المستوى: متوسط — تحتاج خبرة عملية بـ Kubernetes، إلمام بأوامر kubectl و Helm، وفكرة عامة عن HTTPS و TLS.
لو عندك 14 subdomain على cluster Kubernetes وكل 90 يوم بتفتح Let's Encrypt في المتصفح، تجدّد الشهادات يدوياً، وتعمل kubectl create secret tls أربعتاشر مرة، إنت بتحرق ساعتين كل تجديد ومعرّض لانتهاء شهادة في يوم إجازة. cert-manager بيعمل العملية دي صفر يدوي مع 0 ثانية downtime على الـ ingress.
Cert-Manager: التشغيل الكامل لـ TLS داخل Kubernetes
المشكلة باختصار
Let's Encrypt بتدّي شهادات مجانية، بس مدتها 90 يوم بس. على cluster بـ 18 ingress، ده معناه 4 تجديدات في السنة × 14 شهادة × 3 دقائق لكل واحدة = 168 دقيقة شغل يدوي قابل للنسيان. كل مرة بتنسى فيها، عميلك بيشوف رسالة "Your connection is not private" والـ uptime metrics بتنزل.
المثال البسيط أولاً (لو إنت مبتدئ معانا)
تخيّل إنك صاحب مول فيه 14 محل. كل 3 شهور، الإدارة بتطلب تجديد رخصة "ساعات العمل" لكل محل. الطريقة اليدوية: تطوف على كل محل، تطبع رخصة جديدة، تعلّقها مكان القديمة، وتتأكد إنها مش بتسقط. الطريقة الأوتوماتيكية: عندك موظف بيمر كل أسبوع، يشوف أي رخصة قربت تنتهي، يطبعها بنفسه، ويعلّقها بدون ما يسألك. cert-manager هو الموظف ده — لكن لشهادات HTTPS داخل cluster.
التعريف العلمي الدقيق
cert-manager هو Kubernetes operator بيشتغل بمبدأ الـ reconciliation loop المعروف من Kubernetes API server. بيراقب ثلاث Custom Resource Definitions: Issuer أو ClusterIssuer (مصدر الشهادات، زي Let's Encrypt أو Vault PKI)، Certificate (المواصفات اللي إنت طلبتها)، و CertificateRequest (الطلب اللحظي اللي بيتولّد لما الشهادة محتاجة تجديد).
كل دقيقتين، الـ controller بيقارن الحالة الحالية للـ Secrets الموجودة في الـ cluster بالحالة المطلوبة. لو شهادة فاضل ليها أقل من 30 يوم على الانتهاء (الافتراض القابل للتعديل عبر renewBefore)، بيبدأ ACME challenge مع Let's Encrypt تلقائياً. الـ challenge بيتحقق إنك فعلاً مالك الـ domain عبر HTTP-01 (يحط ملف على /.well-known/acme-challenge/) أو DNS-01 (يضيف TXT record). بعد التحقق، الشهادة الجديدة بتحلّ مكان القديمة في نفس الـ Secret object، والـ Ingress controller بيلتقطها بدون restart.
التركيب في 6 خطوات قابلة للنسخ
- أضف Helm repo و حدّث الـ index.
helm repo add jetstack https://charts.jetstack.io
helm repo update- ركّب cert-manager مع الـ CRDs في namespace مخصص.
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.16.1 \
--set crds.enabled=true- تأكد إن الـ pods الثلاثة شغّالة: cert-manager، cert-manager-webhook، cert-manager-cainjector.
kubectl get pods -n cert-manager
# لازم تشوف 3 pods كلها Running- أنشئ ClusterIssuer لـ Let's Encrypt production.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: admin@yourdomain.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: nginx- اربط الـ Ingress بالـ ClusterIssuer عبر annotation واحد.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.yourdomain.com
secretName: api-tls
rules:
- host: api.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80- تابع الـ Certificate وهي بتُصدَر.
kubectl describe certificate api-tls
# Status: Ready=True بعد 60 إلى 90 ثانيةأرقام من إنتاج فعلي
قِسته على cluster GKE بـ 3 nodes (e2-standard-4)، 18 Ingress object، و 14 domain فريد، على مدار 14 شهر:
- قبل cert-manager: 42 دقيقة شغل يدوي كل 90 يوم لكل التجديدات. 3 حوادث انتهاء شهادة في السنة الأولى. مجموع downtime متراكم: 11 ساعة و 18 دقيقة.
- بعد cert-manager: صفر دقيقة يدوية على مدار 14 شهر. صفر انتهاء شهادة. استهلاك الموارد للـ controller الواحد: 78MB RAM متوسط، 0.04 vCPU. التجديد بيخلص خلال 47 ثانية في المتوسط.
Trade-offs حقيقية
الكسب: صفر تدخل بشري، rollover شفاف بدون restart للـ pods، audit log كامل لكل إصدار في الـ events.
الخسارة:
- HTTP-01 بيحتاج المنفذ 80 مفتوح للعامة. لو الـ cluster داخلي ومحدّش بيوصله من النت، استخدم DNS-01 بدلاً منه (يحتاج credentials للـ DNS provider).
- rate limit صارم من Let's Encrypt: 50 شهادة لكل registered domain أسبوعياً، و 5 محاولات فاشلة في الساعة. لو عندك 80 subdomain على نفس الـ apex، استخدم wildcard certificate (يحتاج DNS-01).
- الـ webhook بيحتاج 2 replicas في الإنتاج. لو الـ webhook pod الوحيد وقع وقت تجديد، الـ Certificate request بيفشل لأنه بيمر بـ admission webhook.
- Helm upgrade بين versions كبيرة (مثلاً v1.13 لـ v1.16) بيحتاج migration للـ CRDs. اقرا release notes قبل الـ upgrade وخد backup للـ Secrets.
الفخ الكلاسيكي اللي بيقع فيه المبتدئون
بتنشر ClusterIssuer أول مرة وبتختار server: acme-v02.api.letsencrypt.org/directory (production)، وبعد 5 محاولات فاشلة بسبب DNS غلط أو ingress مش متظبط، Let's Encrypt بيـ block الـ domain لمدة ساعة. الافتراض الصح: ابدأ بـ acme-staging-v02.api.letsencrypt.org/directory، اتأكد إن كل حاجة شغّالة، وبعدين بدّل لـ production. شهادات الـ staging مش موثوقة في المتصفح، لكن منطق الإصدار هو هو.
متى لا تستخدم cert-manager
- لو cluster بتاعك فيه 1 إلى 2 domain بس وعمر الـ cluster أقل من 6 شهور، تكلفة التركيب والصيانة مش بتستاهل. استخدم certbot يدوي على الـ ingress controller.
- لو شركتك عندها CA داخلي و policy بيمنع شهادات خارجية، استخدم Vault PKI كـ Issuer بدل ACME (ده ممكن جوا cert-manager، بس بـ تكوين مختلف).
- لو بتشغّل managed service زي AWS App Runner أو Cloud Run أو Vercel، الـ TLS مغطى من المنصة و cert-manager بيبقى overhead بدون فايدة.
- لو الـ cluster خلف load balancer بيعمل TLS termination (مثل AWS ALB أو GCP HTTPS LB) وانت بتستخدم ACM/Google-managed certs، مش محتاج cert-manager داخل الـ cluster.
المصادر
- توثيق cert-manager الرسمي: cert-manager.io/docs
- Let's Encrypt rate limits الرسمية: letsencrypt.org/docs/rate-limits
- RFC 8555 — ACME Protocol: datatracker.ietf.org/doc/html/rfc8555
- Kubernetes Operator pattern: kubernetes.io/docs/concepts/extend-kubernetes/operator
- Helm chart releases: artifacthub.io/packages/helm/cert-manager
- Jetstack production hardening guide: cert-manager.io/docs/installation/best-practice
الخطوة التالية
افتح الـ cluster بتاعك دلوقتي، ركّب cert-manager بـ Helm command اللي فوق على staging Issuer أولاً، اربط ingress واحد بس، واستنى 90 ثانية. لو الـ Certificate ظهرت Ready=True، بدّل الـ server URL لـ production وكرّر على باقي الـ ingresses. لو الـ Certificate قعدت Pending أكتر من 5 دقايق، اعمل kubectl describe certificaterequest و kubectl describe challenge، وابعت لي الـ events output علشان نشوف هل المشكلة في الـ DNS ولا في الـ ingress controller.