Traefik + CertManager: Gerenciando certificados TLS no Kubernetes

Neste artigo, eu apresento um simples setup utilizando o Cert Manager e Traefik para gerenciar certificados via Let’s Encrypt em clusters Kubernetes.

Motivação

Atualmente, eu tenho um pequeno cluster Kubernetes utilizando o K3S, que é uma versão simplificada e que possui API compatível com o Kubernetes clássico. Eu estava precisando gerenciar alguns certificados TLS e resolvi experimentar uma nova ferramenta, o Cert Manager.

Conceitos Básicos

A instalação do Cert Manager é bem simples e não entrarei em detalhes, você pode instalá-lo com um simples kubectl apply ou então com o Helm, consulte as instruções na documentação. Nós vamos precisar configurar apenas 3 componentes principais.

Issuer

O Issuer é bastante simples. No caso do Let’s Encrypt, você precisa apenas de informar um email e a URL do servidor. No meu caso, também estou informando qual o meu sistema de Ingress, no caso é Traefik.

# cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-issuer
spec:
  acme:
    email: [email protected]
    privateKeySecretRef:
      name: prod-issuer-account-key
    server: https://acme-v02.api.letsencrypt.org/directory
    solvers:
      - http01:
          ingress:
            class: traefik

Para aplicá-lo, basta executar: kubectl apply -f cluster-issuer.yaml

Certificate

Para cada grupo de domínios é necessário registrar uma configuração de Certificate. Essa configuração também pode ser feita apenas com anotações, mas desta forma é mais fácil de gerenciar e reaproveitar entre Deployments. No exemplo abaixo estou declarando o domínio example.com, que após gerado será salvo no Secret chamado example-com-tls. Repare que é necessário informar também o nome do Issuer que criamos anteriormente: letsencrypt-issuer.

# cert-example-com.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: cert-example-com
  namespace: 
spec:
  dnsNames:
    - "example.com"
  secretName: example-com-tls
  issuerRef:
    name: letsencrypt-issuer
    kind: ClusterIssuer

Para aplicar, basta executar o comando kubectl apply -f cert-example-com.yaml.

Pronto, a partir desse momento, o Cert Manager já tem os dados necessários para criar os certificados usando o Let’s Encrypt.

Basta executar o comando kubectl get certificates para listar os certificados e verificar o status de cada:

$ kubectl get certificates
NAME                READY   SECRET            AGE
cert-example-com    True    example-com-tls   10s

Caso ele esteja com o valor True na coluna READY, o nosso certificado foi gerado e está pronto para ser utilizado.

Caso retorne algum erro, você pode verificar os detalhes do processo utilizando o comando: kubectl describe <cetificate-name>.

Utilização

Não é necessário utilizar um Ingress para consumir o certificado, você pode simplesmente montar um volume em um container e consumí-lo via aplicação.

No meu caso, estou utilizando o Traefik com Ingress Controller. Ele é responsável por mapear e rotear o tráfego dos domínios utilizados no cluster. O consumo via Traefik é bastante simples, como mostrado no exemplo abaixo:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: example-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  tls:
    secretName: example-com-tls # Informe o secret com certificado aqui.
  entryPoints:
    - web
    - websecure
  routes:
    - match: HostRegexp(`example.com`)
      kind: Rule
      services:
        - name: my-service
          port: 8080

E pronto, todo o meu tráfego que é requisitado no domínio example.com será direcionado para o serviço my-service na porta 8080, utilizado um certificado auto gerenciado via Cert Manager.

Dica Extra

Para facilitar ainda mais o trabalho com o Traefik, você pode criar um Middleware para redirecionar todo as requisições HTTP para HTTPS, e também redirecionar requests utilizando o subdomínio www para o domínio raiz.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: strip-www-https
  namespace: default
spec:
  redirectRegex:
    regex: ^https?://(?:www\.)?(.+)
    replacement: https://${1}
    permanent: true

comments powered by Disqus