Certificate management no cluster: cert-manager e ACME
1. Introdução ao Gerenciamento de Certificados em Kubernetes
Em ambientes cloud-native, o gerenciamento manual de certificados TLS/SSL é um pesadelo operacional. Certificados expiram, domínios mudam, e cada falha de renovação pode derrubar serviços inteiros. Em Kubernetes, onde dezenas de ingress podem expor serviços simultaneamente, a automação não é opcional — é requisito fundamental.
O cert-manager surgiu como a solução padrão para esse problema. Ele é um operador Kubernetes que automatiza a emissão, renovação e validação de certificados TLS. Integrado ao protocolo ACME (Automatic Certificate Management Environment), ele se comunica com autoridades certificadoras como Let's Encrypt e ZeroSSL para obter certificados válidos sem intervenção humana.
Os benefícios são claros: renovação automática antes do vencimento, validação de domínio simplificada (HTTP-01 ou DNS-01) e integração nativa com recursos Kubernetes como Ingress e Gateway API.
2. Instalação e Configuração do cert-manager no Cluster
A instalação via Helm é a abordagem mais recomendada por sua simplicidade e flexibilidade:
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=true
Para quem prefere manifests YAML diretos:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.0/cert-manager.yaml
Após a instalação, verifique se tudo está operacional:
kubectl get pods -n cert-manager
kubectl get crd | grep cert-manager
kubectl get validatingwebhookconfigurations
Os pods principais são: cert-manager (controlador), cert-manager-cainjector (injeção de CA) e cert-manager-webhook (validação de recursos). Os CRDs instalados incluem certificates.cert-manager.io, issuers.cert-manager.io, clusterissuers.cert-manager.io, orders.acme.cert-manager.io e challenges.acme.cert-manager.io.
3. Entendendo os Recursos Customizados (CRDs) do cert-manager
Issuer vs ClusterIssuer: O Issuer tem escopo de namespace — só pode emitir certificados dentro do namespace onde foi criado. O ClusterIssuer é global, acessível por qualquer namespace. Para ambientes multi-equipe, geralmente usa-se um ClusterIssuer centralizado.
Certificate: Define o domínio, duração (via duration e renewBefore) e o issuer referenciado. Exemplo:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: app-exemplo-tls
namespace: default
spec:
secretName: app-exemplo-tls
duration: 2160h # 90 dias
renewBefore: 360h # 15 dias antes
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- app.exemplo.com
Order e Challenge: Quando um Certificate é criado, o cert-manager gera uma Order (pedido ACME) e um Challenge (desafio de validação). O Challenge materializa a prova de posse do domínio — seja via HTTP-01 (arquivo temporário no servidor web) ou DNS-01 (registro TXT no DNS).
4. Integração com Provedores ACME (Let's Encrypt e ZeroSSL)
ClusterIssuer para Let's Encrypt (Staging vs Production)
Sempre teste com o ambiente de staging para evitar rate limits:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: admin@exemplo.com
privateKeySecretRef:
name: letsencrypt-staging-key
solvers:
- http01:
ingress:
class: nginx
Para produção, troque a URL do servidor:
server: https://acme-v02.api.letsencrypt.org/directory
ClusterIssuer para ZeroSSL
ZeroSSL é uma alternativa confiável ao Let's Encrypt:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: zerossl-prod
spec:
acme:
server: https://acme.zerossl.com/v2/DV90
email: admin@exemplo.com
privateKeySecretRef:
name: zerossl-prod-key
externalAccountBinding:
keyID: "seu-key-id"
keySecretRef:
name: zerossl-eab-secret
key: hmac-key
Diferenças HTTP-01 vs DNS-01
| Característica | HTTP-01 | DNS-01 |
|---|---|---|
| Valida | domínio específico | domínio + wildcards |
| Requer | Ingress acessível publicamente | acesso à API do DNS |
| Renovação | automática via Ingress | automática via provedor DNS |
| Wildcards | não suporta | suporta |
5. Desafio HTTP-01: Validação Automática via Ingress
O HTTP-01 funciona assim: o cert-manager cria um pod temporário que expõe um arquivo de validação no caminho /.well-known/acme-challenge/<token>. A CA tenta acessar esse arquivo para confirmar que você controla o domínio.
Exemplo prático — Ingress com certificado automático:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
acme.cert-manager.io/http01-edit-in-place: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.exemplo.com
secretName: app-exemplo-tls
rules:
- host: app.exemplo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
O cert-manager detecta a annotation cert-manager.io/cluster-issuer, verifica o tls no spec e automaticamente cria o Certificate e gerencia a renovação.
6. Desafio DNS-01: Validação com Provedores DNS
DNS-01 é obrigatório para certificados wildcard (*.exemplo.com) e útil para ambientes internos sem exposição pública.
Exemplo com AWS Route53 — primeiro crie o secret com credenciais IAM:
apiVersion: v1
kind: Secret
metadata:
name: route53-credentials
namespace: cert-manager
type: Opaque
stringData:
secret-access-key: "sua-chave-secreta"
Depois configure o ClusterIssuer:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@exemplo.com
privateKeySecretRef:
name: letsencrypt-dns-key
solvers:
- dns01:
route53:
region: us-east-1
hostedZoneID: Z123456789
accessKeyID: AKIAIOSFODNN7EXAMPLE
secretAccessKeySecretRef:
name: route53-credentials
key: secret-access-key
Agora um certificado wildcard:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-exemplo
namespace: default
spec:
secretName: wildcard-exemplo-tls
dnsNames:
- "*.exemplo.com"
issuerRef:
name: letsencrypt-dns
kind: ClusterIssuer
7. Estratégias de Renovação, Monitoramento e Troubleshooting
Renovação automática
O cert-manager verifica certificados periodicamente. Por padrão, tenta renovar 30 dias antes do vencimento (configurável via renewBefore). Se falhar, faz novas tentativas com backoff exponencial.
Monitoramento com Prometheus
O cert-manager expõe métricas no formato Prometheus. Exemplo de consulta útil:
# Certificados que expiram em menos de 30 dias
certmanager_certificate_expiration_timestamp_seconds < (time() + 2592000)
Instale o ServiceMonitor para coleta automática:
kubectl apply -f https://raw.githubusercontent.com/cert-manager/cert-manager/master/deploy/charts/cert-manager/templates/servicemonitor.yaml
Troubleshooting comum
- Rate limits do Let's Encrypt: Use staging para testes. Em produção, limite-se a 50 certificados por domínio por semana.
- DNS propagation lento: Para DNS-01, aumente o tempo de espera com
--set dns01.dnsPropagationTimeout=120sno Helm. - Erro de validação HTTP-01: Verifique se o Ingress está acessível publicamente e se não há firewall bloqueando a porta 80.
Comandos úteis para debug:
kubectl describe certificate app-exemplo-tls
kubectl describe order -n default
kubectl logs -n cert-manager deployment/cert-manager
8. Boas Práticas e Integração no Pipeline DevOps
GitOps com cert-manager
Mantenha os manifests de Certificate e ClusterIssuer versionados no Git. Ferramentas como ArgoCD ou Flux sincronizam automaticamente:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: certificates
spec:
source:
repoURL: https://github.com/equipe/certificates.git
path: ./production
destination:
server: https://kubernetes.default.svc
Integração com External DNS e Ingress Controllers
External DNS + cert-manager formam um combo poderoso: o External DNS cria registros DNS automaticamente, e o cert-manager emite certificados para esses domínios. O Ingress Controller (NGINX, Traefik, HAProxy) termina o TLS e roteia o tráfego.
Estratégias de rollback e backup
- Backup: Exporte secrets com certificados usando
kubectl get secret -n default app-exemplo-tls -o yaml > backup.yamle armazene em cofre seguro. - Rollback: Mantenha versões anteriores dos CRDs no Git. Em caso de falha, reverta o commit e aplique novamente.
- DR: Para clusters multi-região, replique os ClusterIssuer e mantenha os mesmos provedores ACME em todas as regiões.
Referências
- Documentação oficial do cert-manager — Guia completo de instalação, configuração e troubleshooting do cert-manager.
- Let's Encrypt - ACME Protocol — Explicação detalhada do protocolo ACME e como funciona a validação de domínio.
- ZeroSSL ACME Integration — Documentação oficial da ZeroSSL para integração ACME com cert-manager.
- Kubernetes Ingress and cert-manager tutorial — Tutorial oficial da Kubernetes sobre gerenciamento de TLS com cert-manager.
- cert-manager Prometheus Metrics — Referência completa das métricas expostas pelo cert-manager para monitoramento.
- Route53 DNS-01 Solver Configuration — Guia específico para configurar validação DNS-01 com AWS Route53.
- GitOps com cert-manager e ArgoCD — Tutorial de integração entre cert-manager e ArgoCD para GitOps.