Kubernetes üzerinde bir servisi TLS ile yayına açmak tek seferlik bir iş gibi durur ama değildir. Sertifika birkaç ay sonra biter, yenilemeyi hatırlayan kişi izinlidir, alert kuyruğunda kaybolur, sabah 07:00'de tarayıcılar kırmızı uyarı basar. cert-manager bu döngüyü cluster içine taşıyan, Jetstack tarafından geliştirilen ve CNCF bünyesinde yol alan bir kontrolör. Certificate diye bir kaynağı izler, sertifika üretmek için dış bir otoriteyle konuşur, sonucu Secret olarak yazar ve süresi dolmadan yeniler.
Kaynak modeli: Certificate ve Issuer
cert-manager kurulunca cluster'a bir dizi CRD gelir. En çok dokunacağınız ikisi Certificate ve Issuer. Issuer bir sertifika otoritesinin tanımıdır; Certificate ise "bu alan adı için bu issuer'dan sertifika iste, şu Secret'a koy" diyen somut taleptir. Issuer namespaced bir kaynaktır, bulunduğu namespace ile sınırlıdır. ClusterIssuer ise tüm namespace'lerden referans verilebilen küresel versiyonudur.
ACME issuer kullanıldığında arka planda CertificateRequest, Order ve Challenge kaynakları oluşur, doğrulama tamamlanınca hepsi temizlenir ve sertifika kubernetes.io/tls tipinde bir Secret'a yazılır. Yani elinizde her zaman bir Kubernetes kaynağı olarak durum bilgisi durur, dışarıdan bir state dosyası yoktur.
Desteklenen issuer tipleri: ACME (Let’s Encrypt ve uyumlu sunucular), CA, selfSigned, HashiCorp Vault, Venafi. Kendi iç CA'nız varsa CA issuer, root sertifikası üretmek için selfSigned issuer kullanılır; bunlar birbirine zincirlenebilir.
Kurulum
Helm chart'ı ya da düz manifest ile kurulur. Helm tarafı:
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true Alternatif olarak GitHub releases sayfasındaki statik manifest uygulanabilir: kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/vX.Y.Z/cert-manager.yaml. Buradaki sürümü releases sayfasından güncel v1.x olarak seçin. CRD kurulum yöntemi chart sürümleri arasında değişikliğe uğradı; eski installCRDs bayrağı yerine yeni sürümlerde crds.enabled kullanılıyor. Kurulumdan önce resmi dokümantasyondaki güncel komutu almak en sağlamı.
Kurulum bitince cert-manager namespace'inde üç Deployment görürsünüz: controller, webhook ve cainjector. Webhook eksik ya da sağlıksızsa Certificate kaynağı bile yaratılamaz, hata mesajı kafa karıştırıcı olabilir.
ClusterIssuer tanımı
Let’s Encrypt için tipik bir üretim ClusterIssuer şöyle:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: operasyon@ornek.com
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
ingressClassName: nginx ACME hesabı ilk kez bu issuer kullanıldığında açılır; account key'i belirtilen Secret'ta tutulur. Production sunucusu yerine https://acme-staging-v02.api.letsencrypt.org/directory adresini veren bir ikinci ClusterIssuer tanımlamak akıllıca olur. Staging otoritesi tarayıcılarca güvenilmez sertifikalar üretir ama rate limit'leri gevşektir; akışı kurcalarken production kotasını yakmamış olursunuz.
Certificate kaynağı
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: app-tls
spec:
secretName: app-tls
dnsNames:
- app.ornek.com
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer secretName ile Certificate'ın namespace'inde bir Secret oluşur; Ingress ya da herhangi bir pod bu Secret'ı referans eder. kubectl get certificate çıktısında READY kolonu True olduğunda iş tamamdır.
Ingress anotasyonu ile tetikleme
Certificate yazmak istemiyorsanız ingress-shim devreye girer. Ingress kaynağına anotasyon koyduğunuzda cert-manager sizin yerine Certificate üretir:
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.ornek.com
secretName: app-tls Bu yol küçük ekiplerde en az sürtünmeli olanıdır. Aynı davranışın Issuer ile versiyonu cert-manager.io/issuer anotasyonudur; sertifikanın yazılacağı Secret adı ingress'in tls.secretName alanından gelir, ingress-shim Certificate kaynağını bu isimle yaratır.
HTTP-01 mi DNS-01 mi
HTTP-01 doğrulamasında Let’s Encrypt sunucusu /.well-known/acme-challenge/ yoluna gelen isteklere bakar; cert-manager bunun için geçici bir solver pod ve ingress parçası ayağa kaldırır. Bunun çalışması için 80 portuna cluster'a dışarıdan erişilebilir olması gerekir. Kurumsal ortamlarda bu çoğu zaman engellidir.
DNS-01 ise alan adının TXT kaydı üzerinden doğrular. Wildcard sertifika istiyorsanız tek yol budur, çünkü ACME wildcard'ları yalnız DNS-01 ile verir. DNS-01 için onlarca DNS sağlayıcısı desteği mevcut; her sağlayıcının yapılandırma şeması ve token yönetimi kendine göre olduğu için o kısmı dokümantasyondaki güncel örnekle yazın.
Yenileme döngüsü
cert-manager sertifikaları bitişten önce kendiliğinden yeniler. Varsayılan yenileme penceresi sertifika ömrüne göre hesaplanır; renewBefore alanı ile bu süre özelleştirilebilir. Yenilenen sertifika aynı Secret'a yazılır, ingress-nginx kontrolcüsü Secret değişimini izlediği için kendini yeniden yükler. Secret'ı dosya olarak mount eden podlar için durum farklıdır; kubelet senkronu ile yeni içerik görünür ama podun bunu yeniden yüklemesi uygulamaya kalmıştır.
Kırıldığında nereye bakılır
İlk durak kubectl describe certificate app-tls. Events bölümü çoğu sorunu söyler: issuer bulunamadı, doğrulama zaman aşımına uğradı, rate limit aşıldı. Bir alt seviye olarak kubectl get order ve kubectl get challenge ile ACME tarafının hangi aşamada takıldığı görülür. HTTP-01 takıldıysa solver podun loglarına bakın; DNS-01'de TXT kaydının gerçekten yayılıp yayılmadığını dışarıdan bir dig sorgusuyla kontrol edin.
Serbest haltaları da bilin: yanlış issuerRef, staging issuer ile production DNS adı, 80 portuna kapalı firewall, Certificate ile Secret'ın farklı namespace'lerde olması. Bunlar günlük hayatta karşılaşılan vakaların büyük kısmını oluşturur. Gerisi kontrolörün işi; siz anotasyonu yazıp olayı izliyorsunuz.