Certificados SSL/TLS válidos são um requisito fundamental do cenário de aplicativos modernos. Infelizmente, gerenciar renovações de certificados (ou cert) geralmente é uma reflexão tardia ao implantar um aplicativo. Os certificados têm uma vida útil limitada, variando de aproximadamente 13 meses para certificados da DigiCert a 90 dias para certificados da Let's Encrypt . Para manter o acesso seguro, esses certificados precisam ser renovados/reemitidos antes de expirarem. Dada a carga de trabalho substancial da maioria das equipes de operações, a renovação de certificados às vezes não é realizada, resultando em confusão à medida que os certificados se aproximam — ou pior, passam — da data de expiração.
Não precisa ser assim. Com algum planejamento e preparação, o gerenciamento de certificados pode ser automatizado e simplificado. Aqui, veremos uma solução para o Kubernetes usando três tecnologias:
Neste blog, você aprenderá a simplificar o gerenciamento de certificados fornecendo certificados exclusivos, renovados e atualizados automaticamente para seus endpoints.
Antes de entrarmos em detalhes técnicos, precisamos definir alguma terminologia. O termo “certificado TLS” se refere a dois componentes necessários para habilitar conexões HTTPS em nosso controlador Ingress:
Tanto o certificado quanto a chave privada são emitidos pela Let's Encrypt . Para uma explicação completa de como os certificados TLS funcionam, consulte a postagem da DigiCert Como funcionam os certificados TLS/SSL .
No Kubernetes, esses dois componentes são armazenados como Secrets . Cargas de trabalho do Kubernetes – como o NGINX Ingress Controller e o cert-manager – podem gravar e ler esses segredos, que também podem ser gerenciados por usuários que têm acesso à instalação do Kubernetes.
O projeto cert-manager é um controlador de certificado que funciona com Kubernetes e OpenShift. Quando implantado no Kubernetes, o cert-manager emitirá automaticamente os certificados exigidos pelos controladores do Ingress e garantirá que eles sejam válidos e atualizados. Além disso, ele rastreará as datas de expiração dos certificados e tentará renová-los em um intervalo de tempo configurado. Embora trabalhe com vários emissores públicos e privados, mostraremos sua integração com o Let's Encrypt.
Ao usar o Let’s Encrypt, todo o gerenciamento de certificados é feito automaticamente. Embora isso ofereça muita conveniência, também apresenta um problema: Como o serviço garante que você é o proprietário do nome de domínio totalmente qualificado (FQDN) em questão?
Esse problema é resolvido usando um desafio , que exige que você responda a uma solicitação de verificação que somente alguém com acesso aos registros DNS do domínio específico pode fornecer. Os desafios assumem uma de duas formas:
HTTP-01 é a maneira mais simples de gerar um certificado, pois não requer acesso direto ao provedor de DNS. Esse tipo de desafio é sempre conduzido pela Porta 80 (HTTP). Observe que ao usar desafios HTTP-01, o cert-manager utilizará o controlador Ingress para servir o token de desafio.
Um controlador de entrada é um serviço especializado para Kubernetes que traz tráfego de fora do cluster, equilibra a carga para Pods internos (um grupo de um ou mais contêineres) e gerencia o tráfego de saída. Além disso, o controlador Ingress é controlado pela API do Kubernetes e monitorará e atualizará a configuração de balanceamento de carga conforme os Pods são adicionados, removidos ou falham.
Para saber mais sobre os controladores Ingress, leia os seguintes blogs:
Nos exemplos abaixo, usaremos o NGINX Ingress Controller desenvolvido e mantido pela F5 NGINX.
Esses exemplos pressupõem que você tenha uma instalação funcional do Kubernetes que pode ser testada e que a instalação pode atribuir um endereço IP externo (objeto Kubernetes LoadBalancer). Além disso, ele pressupõe que você pode receber tráfego na Porta 80 e na Porta 443 (se estiver usando o desafio HTTP-01) ou somente na Porta 443 (se estiver usando o desafio DNS-01). Esses exemplos são ilustrados usando Mac OS X, mas também podem ser usados no Linux ou WSL.
Você também precisará de um provedor de DNS e um FQDN para os quais possa ajustar o registro A. Se você estiver usando o desafio HTTP-01, você só precisa adicionar um registro A (ou ter um adicionado para você). Se estiver usando o desafio DNS-01, você precisará de acesso à API para um provedor de DNS ou um provedor de webhook compatível .
A maneira mais fácil é implantar via Helm . Esta implantação permite que você use o Kubernetes Ingress e o NGINX Virtual Server CRD.
$ helm repo add nginx-stable https://helm.nginx.com/stable "nginx-stable" foi adicionado aos seus repositórios
$ helm repo update Aguarde enquanto pegamos as últimas novidades dos seus repositórios de gráficos...
...Recebemos com sucesso uma atualização do repositório de gráficos "nginx-stable"
Atualização concluída. ⎈Feliz Helming!⎈
$ helm install nginx-kic nginx-stable/nginx-ingress \ --namespace nginx-ingress --set controller.enableCustomResources=true \
--create-namespace --set controller.enableCertManager=true
NOME: nginx-kic
ÚLTIMA IMPLANTAÇÃO: Qui Set 1 15:58:15 2022
NAMESPACE: nginx-ingress
STATUS: implantado
REVISÃO: 1
SUÍTE DE TESTES: Nenhum
NOTAS:
O NGINX Ingress Controller foi instalado.
$ kubectl get deployments --namespace nginx-ingress NOME PRONTO ATUALIZADO DISPONÍVEL IDADE
nginx-kic-nginx-ingress 1/1 1 1 23s
$ kubectl get services --namespace nginx-ingress
NOME TIPO CLUSTER-IP EXTERNO-IP PORTA(S) IDADE
nginx-kic-nginx-ingress Balanceador de carga 10.128.60.190 www.xxx.yyy.zzz 80:31526/TCP,443:32058/TCP 30s
O processo aqui dependerá do seu provedor de DNS. Esse nome DNS precisará ser resolvido pelos servidores Let's Encrypt, o que pode exigir que você espere o registro se propagar antes que ele funcione. Para mais informações sobre isso, consulte o artigo do SiteGround O que é propagação de DNS e por que demora tanto?
Depois de resolver o FQDN escolhido, você estará pronto para passar para a próxima etapa.
$ host cert.example.com cert.example.com tem o endereço www.xxx.yyy.zzz
O próximo passo é implantar a versão mais recente do cert-manager. Novamente, usaremos o Helm para nossa implantação.
$ helm repo add jetstack https://charts.jetstack.io "jetstack" foi adicionado aos seus repositórios
$ helm repo update Aguarde enquanto pegamos as últimas novidades dos seus repositórios de gráficos...
...Recebemos com sucesso uma atualização do repositório de gráficos "nginx-stable"
...Recebemos com sucesso uma atualização do repositório de gráficos "jetstack"
Atualização concluída. ⎈Feliz Helming!⎈
$ helm install cert-manager jetstack/cert-manager \ --namespace cert-manager --create-namespace \ --version v1.9.1 --set installCRDs=true NOME: cert-manager ÚLTIMA IMPLANTAÇÃO: Qui Set 1 16:01:52 2022 NAMESPACE: cert-manager STATUS: implantado REVISÃO: 1 CONJUNTO DE TESTES: Nenhum NOTAS: cert-manager v1.9.1 foi implantado com sucesso!
Para começar a emitir certificados, você precisará configurar um recurso ClusterIssuer ou Issuer (por exemplo, criando um emissor 'letsencrypt-staging').
Mais informações sobre os diferentes tipos de emissores e como configurá-los podem ser encontradas em nossa documentação:
https://cert-manager.io/docs/configuration/
Para obter informações sobre como configurar o cert-manager para provisionar automaticamente certificados para recursos do Ingress, consulte a documentação do `ingress-shim`:
https://cert-manager.io/docs/usage/ingress/
$ kubectl get deployments --namespace cert-manager NOME PRONTO ATUALIZADO DISPONÍVEL IDADE
cert-manager 1/1 1 1 4m30s
cert-manager-cainjector 1/1 1 1 4m30s
cert-manager-webhook 1/1 1 1 4m30s
Usaremos o exemplo do NGINX Cafe para fornecer nossa implantação de backend e serviços. Este é um exemplo comum usado na documentação fornecida pelo NGINX. Não implementaremos o Ingress como parte disso.
$ git clone https://github.com/nginxinc/kubernetes-ingress.git Clonando em 'kubernetes-ingress'...
remoto: Enumerando objetos: 44979, feito.
remoto: Contando objetos: 100% (172/172), concluído.
remoto: Comprimindo objetos: 100% (108/108), concluído.
remoto: Total 44979 (delta 87), reutilizado 120 (delta 63), pacote-reutilizado 44807
Recebendo objetos: 100% (44979/44979), 60,27 MiB | 27,33 MiB/s, concluído.
Resolução de deltas: 100% (26508/26508), concluído.
$ cd ./kubernetes-ingress/examples/ingress-resources/complete-example
$ kubectl apply -f ./cafe.yaml
implantação.apps/café criado
serviço/café-svc criado
implantação.apps/tea criado
serviço/chá-svc criado
kubectl
get. Você quer garantir que os Pods estejam aparecendo como PRONTOS
e os Serviços estejam aparecendo como em execução
. O exemplo abaixo mostra uma amostra representativa do que você está procurando. Observe que o serviço kubernetes
é um serviço de sistema executado no mesmo namespace (padrão) do exemplo do NGINX Cafe.$ kubectl get deployments,services --namespace default NOME PRONTO ATUALIZADO DISPONÍVEL IDADE
deployment.apps/coffee 2/2 2 2 69s
deployment.apps/tea 3/3 3 3 68s
NOME TIPO IP DO CLUSTER IP EXTERNO PORTA(S) IDADE
service/coffee-svc ClusterIP 10.128.154.225 <nenhum> 80/TCP 68s
service/kubernetes ClusterIP 10.128.0.1 <nenhum> 443/TCP 29m
serviço/tea-svc ClusterIP 10.128.96.145 <nenhum> 80/TCP 68s
Dentro do cert-manager, o ClusterIssuer pode ser usado para emitir certificados. Este é um objeto com escopo de cluster que pode ser referenciado por qualquer namespace e usado por qualquer solicitação de certificado com a autoridade emissora de certificado definida. Neste exemplo, qualquer solicitação de certificado para certificados Let's Encrypt pode ser manipulada por este ClusterIssuer.
Implante o ClusterIssuer para o tipo de desafio que você selecionou. Embora esteja fora do escopo desta postagem, há opções de configuração avançadas que permitem especificar vários resolvedores (escolhidos com base nos campos do seletor) no seu ClusterIssuer.
O protocolo Automated Certificate Management Environment (ACME) é usado para determinar se você possui um nome de domínio e, portanto, pode receber um certificado Let’s Encrypt. Para este desafio, estes são os parâmetros que precisam ser passados:
Este exemplo mostra como configurar um ClusterIssuer para usar o desafio HTTP-01 para provar a propriedade do domínio e receber um certificado.
$ cat << EOF | kubectl apply -f apiVersão: cert-manager.io/v1
tipo: ClusterIssuer
metadados:
nome: prod-issuer
spec:
acme:
e-mail: example@example.com
servidor: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
nome: prod-issuer-account-key
solucionadores:
- http01:
ingress:
classe: nginx
EOF
clusterissuer.cert-manager.io/prod-issuer criado
$ kubectl get clusterissuer NOME PRONTO IDADE
prod-issuer Verdadeiro 34s
Este exemplo mostra como configurar um ClusterIssuer para usar o desafio DNS-01 para autenticar a propriedade do seu domínio. Dependendo do seu provedor de DNS, você provavelmente precisará usar um Kubernetes Secret para armazenar seu token. Este exemplo usa o Cloudflare . Observe o uso do namespace. O aplicativo cert-manager, que é implantado no namespace cert-manager, precisa ter acesso ao Secret .
Para este exemplo, você precisará de um token da API do Cloudflare , que pode ser criado na sua conta. Isso precisará ser colocado na linha abaixo. Se você não estiver usando o Cloudflare, precisará seguir a documentação do seu provedor .
$ cat << EOF | kubectl apply -f apiVersion: v1
tipo: Segredo
metadados:
nome: cloudflare-api-token-secret
namespace: cert-manager
tipo: Opaco
stringData:
api-token: <API Token>
EOF
$ cat << EOF | kubectl apply -f apiVersão: cert-manager.io/v1
tipo: ClusterIssuer
metadados:
nome: prod-issuer
especificação:
acme:
e-mail: example@example.com
servidor: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
nome: prod-issuer-account-key
solucionadores:
- dns01:
cloudflare:
apiTokenSecretRef:
nome: cloudflare-api-token-secret
chave: api-token
EOF
$ kubectl get clusterissuer NOME PRONTO IDADE
prod-issuer Verdadeiro 31m
Este é o ponto em que estamos construindo – a implantação do recurso Ingress para nosso aplicativo. Isso roteará o tráfego para o aplicativo NGINX Cafe que implantamos anteriormente.
Se estiver usando o recurso Ingress padrão do Kubernetes, você usará o seguinte YAML de implantação para configurar o Ingress e solicitar um certificado.
apiVersion: networking.k8s.io/v1 tipo: Ingress
metadados:
nome: cafe-ingress
anotações:
cert-manager.io/cluster-issuer: prod-issuer
acme.cert-manager.io/http01-edit-in-place: "true"
especificação:
ingressClassName: nginx
tls:
- hosts:
cert.example.com
secretName: cafe-secret
regras:
- host: cert.example.com
http:
paths:
path: /tea
Tipo de caminho: Prefixo
backend:
serviço:
nome: tea-svc
porta:
número: 80
- caminho: /café
pathType: Prefixo
backend:
serviço:
nome: coffee-svc
porta:
número: 80
Vale a pena rever algumas partes importantes do manifesto:
metadata.annotations
, onde definimos acme.cert-manager.io/http01-edit-in-place
como “true”. Este valor é obrigatório e ajusta a maneira como o desafio é atendido. Para mais informações, consulte o documento Anotações Suportadas . Isso também pode ser resolvido usando uma configuração mestre/servo .spec.ingressClassName
se refere ao controlador NGINX Ingress que instalamos e usaremos.spec.tls.secret
do Kubernetes Secret armazena a chave de certificado que é retornada quando o certificado é emitido pelo Let's Encrypt. cert.example.com
é especificado para spec.tls.hosts
e spec.rules.host
. Este é o nome do host para o qual nosso ClusterIssuer emitiu o certificado.spec.rules.http
define os caminhos e os serviços de backend que atenderão às solicitações nesses caminhos. Por exemplo, o tráfego para /tea
será direcionado para a porta 80 no tea-svc
.spec.rules.host
e spec.tls.hosts
, mas você deve revisar todos os parâmetros na configuração. $ kubectl apply -f ./cafe-virtual-server.yaml virtualserver.k8s.nginx.org/cafe criado
$ kubectl obter certificados NOME PRONTO SEGREDO IDADE
certificate.cert-manager.io/cafe-secret True cafe-secret 37m
Se estiver usando os CRDs do NGINX, você precisará usar o seguinte YAML de implantação para configurar seu Ingress.
apiVersion: k8s.nginx.org/v1
tipo: VirtualServer
metadados:
nome: cafe
spec:
host: cert.example.com
tls:
segredo: cafe-secret
cert-manager:
cluster-issuer: prod-issuer
upstreams:
- nome: tea
serviço: tea-svc
porta: 80
- nome: café
serviço: café-svc
porta: 80
rotas:
- caminho: /chá
ação:
senha: chá
- caminho: /café
ação:
senha: café
Mais uma vez, vale a pena rever algumas partes importantes do manifesto:
spec.tls.secret
do Kubernetes Secret armazena a chave de certificado que é retornada quando o certificado é emitido pelo Let's Encrypt. cert.example.com
é especificado para spec.host
. Este é o nome do host para o qual nosso ClusterIssuer emitiu o certificado.spec.upstreams
apontam para nossos serviços de backend, incluindo as portas.spec.routes
define a rota e a ação a ser tomada quando essas rotas são atingidas.spec.host
, mas você deve revisar todos os parâmetros na configuração. $ kubectl apply -f ./cafe-virtual-server.yaml virtualserver.k8s.nginx.org/cafe criado
$ kubectl get VirtualServers NOME ESTADO HOST IP PORTAS IDADE
cafe Válido cert.example.com www.xxx.yyy.zzz [80.443] 51m
Você pode visualizar o certificado por meio da API do Kubernetes. Isso mostrará detalhes sobre o certificado, incluindo seu tamanho e a chave privada associada.
$ kubectl describe secret cafe-secret Nome: cafe-secret
Espaço para nome: default
Etiquetas: <nenhum>
Anotações: cert-manager.io/nomes-alt: cert.exemplo.com
cert-manager.io/certificate-name: café-secreto
cert-manager.io/nome-comum: cert.exemplo.com
cert-manager.io/ip-sans:
cert-manager.io/issuer-group:
cert-manager.io/emissor-tipo: ClusterIssuer cert-manager.io/issuer-name : prod-issuer cert-manager.io/uri-sans :Tipo: kubernetes.io/tls Dados ==== tls.crt: 5607 bytes tls.key: 1675 bytes
Se você quiser ver o certificado e a chave reais, pode fazê-lo executando o seguinte comando. (Observação: Isso ilustra uma fraqueza dos segredos do Kubernetes. Ou seja, eles podem ser lidos por qualquer pessoa com as permissões de acesso necessárias.)
$ kubectl obter segredo cafe-secret -o yaml
Teste os certificados. Você pode usar qualquer método que desejar aqui. O exemplo abaixo usa cURL . O sucesso é indicado por um bloco similar ao que é mostrado antes, que inclui o nome do servidor, endereço interno do servidor, data, o URI (rota) escolhido (café ou chá) e o ID da solicitação. Falhas tomarão a forma de códigos de erro HTTP, provavelmente 400 ou 301.
$ curl https://cert.example.com/tea
Endereço do servidor: 10.2.0.6:8080
Nome do servidor: tea-5c457db9-l4pvq
Data: 02/Set/2022:15:21:06 +0000
URI: /tea
ID da solicitação: d736db9f696423c6212ffc70cd7ebecf
$ curl https://cert.example.com/coffee
Endereço do servidor: 10.2.2.6:8080
Nome do servidor: coffee-7c86d7d67c-kjddk
Data: 02/Set/2022:15:21:10 +0000
URI: /coffee
ID da solicitação: 4ea3aa1c87d2f1d80a706dde91f31d54
No início, prometemos que essa abordagem eliminaria a necessidade de gerenciar renovações de certificados. No entanto, ainda precisamos explicar como fazer isso. Porquê?Porque esta é uma parte central e integrada do cert-manager. Neste processo automático, quando o cert-manager percebe que um certificado não está presente, expirou, está a 15 dias do vencimento ou se o usuário solicita um novo certificado via CLI, um novo certificado é solicitado automaticamente . Não fica muito mais fácil do que isso.
Se você for assinante do NGINX Plus, a única diferença para você envolverá a instalação do NGINX Ingress Controller. Consulte a seção Instalação do Helm da documentação do NGINX para obter instruções sobre como modificar o comando Helm fornecido acima para fazer isso.
Isso depende muito do seu caso de uso.
O método de desafio HTTP-01 requer que a porta 80 esteja aberta para a Internet e que o registro DNS A tenha sido configurado corretamente para o endereço IP do controlador Ingress. Essa abordagem não requer acesso ao provedor de DNS além da criação do registro A.
O método de desafio DNS-01 pode ser usado quando você não pode expor a Porta 80 à Internet e requer apenas que o gerenciador de certificados tenha acesso de saída ao provedor de DNS. No entanto, esse método exige que você tenha acesso à API do seu provedor de DNS, embora o nível de acesso necessário varie de acordo com o provedor específico.
Como o Kubernetes é tão complexo, é difícil fornecer informações específicas para solução de problemas. Caso você tenha algum problema, gostaríamos de convidá-lo a nos perguntar no NGINX Community Slack (assinantes do NGINX Plus podem usar suas opções normais de suporte).
Comece solicitando sua avaliação gratuita de 30 dias do NGINX Ingress Controller com NGINX App Protect WAF e DoS e baixe o NGINX Service Mesh sempre gratuito.
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."