Let's Encrypt com cert-manager: HTTP-01 vs DNS-01
Objective
O Let's Encrypt emite certificados publicamente confiáveis de graça, pelo protocolo ACME, depois que você prova que controla o domínio. O cert-manager automatiza essa prova com um de dois tipos de desafio: HTTP-01 (servir um token em http://<domínio>/.well-known/acme-challenge/...) ou DNS-01 (publicar um token num registro TXT). Eles têm requisitos diferentes, e escolher o errado é o principal motivo de certificados ficarem em READY False. Este conceito cobre um ClusterIssuer ACME, os dois desafios, staging vs produção, rate limits, e as validades mais curtas que o Let's Encrypt está adotando.
Use Cases
- HTTPS público para uma API e uma página de login num nó com IP público.
- Certificados para um cluster que não é acessível pela internet (rede do escritório, só VPN).
- Certificados wildcard (
*.example.com). - Entender um desafio preso em
pending.
Deep Dive
Um ClusterIssuer ACME
plaintextapiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: {name: letsencrypt-staging} spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: [email protected] privateKeySecretRef: {name: letsencrypt-staging-account} solvers: - http01: ingress: {ingressClassName: public}
Comece pelo staging. Os certificados dele não são confiáveis nos navegadores, mas os rate limits são generosos, então um erro de configuração não bloqueia você. Troque o server para https://acme-v02.api.letsencrypt.org/directory (e use um nome de issuer e uma Secret de conta separados) quando os certificados de staging estiverem sendo emitidos com sucesso.
Depois anote um Ingress exatamente como com qualquer issuer: cert-manager.io/cluster-issuer: letsencrypt-prod.
HTTP-01
O cert-manager cria um Ingress (ou HTTPRoute) temporário e um Pod solver que serve o token. Os servidores de validação do Let's Encrypt, a partir da internet pública, buscam:
plaintexthttp://api.example.com/.well-known/acme-challenge/<token>
Requisitos:
- DNS público
A/AAAAdo hostname apontando para o nó ou o seu load balancer. - Porta 80 acessível pela internet (a validação sempre começa na porta 80; redirects para a 443 são seguidos).
- O Ingress do solver precisa ser servido pelo controller indicado em
ingressClassName.
Limites: sem wildcards, uma validação por hostname, e simplesmente não funciona para um cluster que a internet não alcança. Se um firewall só libera a 443, o HTTP-01 falha.
DNS-01
O cert-manager cria um registro TXT _acme-challenge.example.com pela API do seu provedor de DNS, o Let's Encrypt consulta o DNS público, e o cert-manager remove o registro depois.
plaintextsolvers: - dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token # no namespace do cert-manager, para um ClusterIssuer key: api-token selector: dnsZones: [example.com]
O cert-manager suporta Cloudflare, Route 53, Google Cloud DNS, Azure DNS, DigitalOcean, RFC 2136 (BIND e companhia) e outros via webhooks.
Vantagens:
- Funciona para clusters sem nenhum acesso de entrada pela internet, porque só o DNS está envolvido. É a resposta usual para serviços internos que ainda querem certificados publicamente confiáveis (o hostname precisa existir numa zona pública, mas pode resolver para um IP privado).
- Wildcards (
*.example.com) só são possíveis com DNS-01.
Custos:
- Um token de API com permissão para editar o DNS fica dentro do cluster. Restrinja-o à zona em questão e, onde o provedor permitir, a registros
TXT. - Atraso de propagação: o cert-manager verifica se o registro está visível antes de pedir a validação. DNS split-horizon (um servidor interno respondendo pela mesma zona) pode fazer essa verificação falhar; aponte as verificações do cert-manager para resolvers públicos com
--dns01-recursive-nameservers=1.1.1.1:53,8.8.8.8:53e--dns01-recursive-nameservers-only.
Escolhendo
| Situação | Desafio |
|---|---|
| Nó público, porta 80 aberta, hostnames individuais | HTTP-01 |
| Cluster interno ou só por VPN | DNS-01 |
| Certificado wildcard | DNS-01 |
| Provedor de DNS sem API | HTTP-01, ou uma delegação CNAME do _acme-challenge para uma zona que você consegue automatizar |
Um issuer pode ter vários solvers com selectors (por exemplo HTTP-01 por padrão e DNS-01 para dnsZones: [internal.example.com]).
Depurando um certificado pendente
A cadeia de objetos é Certificate -> CertificateRequest -> Order -> Challenge. O Challenge tem a mensagem útil:
plaintextkubectl get certificate,certificaterequest,order,challenge -A kubectl describe challenge <nome>
Motivos típicos: connection refused ou timeout na porta 80 (HTTP-01 inacessível), 404 (o Ingress do solver não é servido pelo controller, classe errada), DNS record not yet propagated (verificação do DNS-01), rateLimited (veja abaixo).
Rate limits e validades
O Let's Encrypt de produção limita certificados por domínio registrado por semana e certificados duplicados, entre outros. Depurar contra a produção é o jeito mais rápido de bater nesses limites; é para isso que existe o staging.
As validades estão ficando mais curtas, o que torna a automação obrigatória em vez de conveniente:
- Desde 13 de maio de 2026, o perfil ACME opcional
tlsserveremite certificados de 45 dias. - A partir de 10 de fevereiro de 2027 o perfil padrão
classicpassa a 64 dias, e a partir de 16 de fevereiro de 2028 a 45 dias.
O cert-manager renova aos dois terços da validade por padrão, então se adapta sozinho; o que não pode existir é qualquer passo manual ou monitoramento que assuma 90 dias.
Trade-offs
- HTTP-01 vs DNS-01. O HTTP-01 não precisa de credencial no cluster, mas exige porta 80 de entrada e acesso público. O DNS-01 funciona em qualquer lugar e suporta wildcards, mas guarda no cluster uma credencial capaz de editar o DNS.
- Wildcard vs certificados por host. Um wildcard simplifica a configuração; a chave dele é compartilhada por todo serviço que o usa, então um vazamento afeta todos.
- Certificados públicos vs uma CA privada. Certificados públicos não precisam de distribuição de confiança; uma CA privada funciona sem nenhuma dependência externa ou rate limit.