BLOG | NGINX

Habilitando DNS de autoatendimento e gerenciamento de certificados no Kubernetes

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Miniatura de Jason Schmidt
Jason Schmidt
Publicado em 01 de novembro de 2022

O objetivo final do desenvolvimento de aplicativos é, obviamente, expor aplicativos na Internet. Para um desenvolvedor, o Kubernetes simplifica esse processo até certo ponto ao fornecer o controlador Ingress como mecanismo de roteamento de solicitações para o aplicativo. Mas nem tudo é tão self-service quanto você provavelmente gostaria: você ainda precisa de um registro no Sistema de Nomes de Domínio (DNS) para mapear o nome de domínio do aplicativo para o endereço IP do controlador Ingress e um certificado TLS para proteger conexões usando HTTPS. Na maioria das organizações, você não é o proprietário do DNS ou do TLS e, portanto, precisa coordenar com o grupo operacional (ou grupos!) que o possui.

As coisas não são necessariamente mais fáceis para os operadores. Na maioria das organizações, a necessidade de atualizar registros DNS é rara o suficiente para que os procedimentos – tanto as regras de negócios quanto as etapas técnicas reais – tendam a ser esparsos ou inexistentes. Isso significa que quando você precisa adicionar um registro DNS, primeiro precisa encontrar a documentação, perguntar a um colega ou (na pior das hipóteses) descobrir. Você também precisa garantir que está em conformidade com todas as regras de segurança corporativa e certificar-se de que a entrada esteja marcada corretamente para os firewalls.

Felizmente, existe uma maneira de facilitar a vida tanto dos desenvolvedores quanto dos operadores. Nesta postagem, mostramos como os operadores podem configurar uma implantação do Kubernetes para permitir o autoatendimento para desenvolvedores atualizarem registros DNS e gerarem certificados TLS em um ambiente Kubernetes. Ao construir a infraestrutura com antecedência, você pode garantir que todos os requisitos comerciais e técnicos necessários sejam atendidos.

Visão geral e pré-requisitos

Com a solução implementada, tudo o que um desenvolvedor precisa fazer para expor um aplicativo à Internet é criar um controlador Ingress seguindo um modelo fornecido que inclui um nome de domínio totalmente qualificado (FQDN) dentro de um domínio gerenciado pela instalação do Kubernetes. O Kubernetes usa o modelo para alocar um endereço IP para o controlador Ingress, criar o registro DNS A para mapear o FQDN para o endereço IP e gerar certificados TLS para o FQDN e adicioná-los ao controlador Ingress. A limpeza é igualmente fácil: quando o Ingress é removido, os registros DNS são limpos.

A solução aproveita as seguintes tecnologias (fornecemos instruções de instalação e configuração abaixo):

Antes de configurar a solução, você precisa:

  • Uma instalação em nuvem do Kubernetes com um objeto de saída ( LoadBalancer ). A solução usa Linode, mas outros provedores de nuvem também funcionam.
  • Um nome de domínio hospedado com Cloudflare , que escolhemos porque é um dos provedores de DNS suportados pelo cert-manager e oferece suporte ao ExternalDNS ( em beta no momento da redação deste artigo). Recomendamos fortemente que o domínio não seja usado para produção ou qualquer outro propósito crítico.
  • Acesso à API do Cloudflare, que está incluída no nível gratuito.
  • Helm para instalar e implantar o Kubernetes.
  • kubectl como interface de linha de comando para Kubernetes.
  • Opcionalmente, K9s , uma interface de usuário tangível (TUI) bem construída que fornece uma maneira mais estruturada de interagir com o Kubernetes.

Também presumimos que você tenha um conhecimento básico do Kubernetes (como aplicar um manifesto, usar um gráfico Helm e emitir comandos kubectl para visualizar a saída e solucionar problemas). Entender os conceitos básicos do Let's Encrypt é útil, mas não obrigatório; para uma visão geral, consulte nosso blog . Você também não precisa saber como o cert-manager funciona, mas se estiver interessado em como ele (e os certificados em geral) funcionam com o NGINX Ingress Controller, veja minha postagem recente, Automatizando o gerenciamento de certificados em um ambiente Kubernetes .

Testamos a solução no macOS e no Linux. Não testamos no Windows Subsystem for Linux versão 2 (WSL2), mas não prevemos problemas.

Observação:  A solução foi concebida como uma prova de conceito de amostra e não para uso em produção. Em particular, ele não incorpora todas as melhores práticas de operação e segurança. Para obter informações sobre esses tópicos, consulte a documentação do cert-manager e do ExternalDNS .

Implementando a solução

Siga as etapas nestas seções para implantar a solução:

Baixar software
  1. Baixe seu token de API do Cloudflare .
  2. Clone o repositório do NGINX Ingress Controller:

    $ git clone https://github.com/nginxinc/kubernetes-ingress.git Clonando em 'kubernetes-ingress'... remoto: Enumerando objetos: 45176, concluído. remoto: Contando objetos: 100% (373/373), concluído. remoto: Comprimindo objetos: 100% (274/274), concluído. remoto: Total 45176 (delta 173), reutilizado 219 (delta 79), pacote-reutilizado 44803 Recebendo objetos: 100% (45176/45176), 60,45 MiB | 26,81 MiB/s, concluído.
    Resolução de deltas: 100% (26592/26592), concluído.
  3. Verifique se você consegue se conectar ao cluster do Kubernetes.

    $ kubectl cluster-info O plano de controle do Kubernetes está sendo executado em https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443 O KubeDNS está sendo executado em https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy Para depurar e diagnosticar melhor os problemas do cluster, use 'kubectl cluster-info dump'.

Implantar o NGINX Ingress Controller

  1. Usando o Helm, implante o NGINX Ingress Controller. Observe que estamos adicionando três opções de configuração não padronizadas :

    • controller.enableCustomResources – Instrui o Helm a instalar as definições de recursos personalizados (CRDs) usadas para criar os recursos personalizados NGINX VirtualServer e VirtualServerRoute .
    • controller.enableCertManager – Configura o NGINX Ingress Controller para se comunicar com os componentes do cert-manager .
    • controller.enableExternalDNS – Configura o Ingress Controller para se comunicar com componentes ExternalDNS.
    $ helm install nginx-kic nginx-stable/nginx-ingress --namespace nginx-ingress --set controller.enableCustomResources=true --create-namespace --set controller.enableCertManager=true --set controller.enableExternalDNS=true NOME: nginx-kic ÚLTIMA IMPLANTAÇÃO: Dia Seg DD hh : mm : ss AAAA NAMESPACE: nginx-ingress STATUS: implantado REVISÃO: 1 CONJUNTO DE TESTES: Nenhuma NOTAS:
    O NGINX Ingress Controller foi instalado.
  2. Verifique se o NGINX Ingress Controller está em execução e anote o valor no campo EXTERNAL-IP – é o endereço IP do NGINX Ingress Controller (aqui, www.xxx.yyy.zzz ). A saída é distribuída em duas linhas para maior legibilidade.

    $ kubectl get services --namespace nginx-ingress NOME TIPO CLUSTER-IP ... nginx-kic-nginx-ingress LoadBalancer 10.128.152.88 ... ... IDADE DA(S) PORTA(S) IP EXTERNA(S) ... www.xxx.yyy.zzz 80:32457/TCP,443:31971/TCP 3h8m

Implantar cert-manager

Na solução, o cert-manager usa o tipo de desafio DNS-01 ao obter um certificado TLS, o que exige que o token da API do Cloudflare seja fornecido durante a criação do recurso ClusterIssuer . Na solução, o token da API é fornecido como um Kubernetes Secret .

  1. Usando o Helm, implante o cert-manager :

    $ 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: Dia Seg DD hh : mm : ss AAAA NAMESPACE: cert-manager STATUS: implantado REVISÃO: 1 CONJUNTO DE TESTES: Nenhum NOTAS: cert-manager v1.9.1 foi implantado com sucesso!
  2. Implante o token da API do Cloudflare como um segredo do Kubernetes, substituindo-o por <seu-token-API>:

    $ kubectl apply -f - <<EOFapiVersão: v1
    tipo: Metadados secretos: nome: Namespace Cloudflare-api-token-secret: tipo cert-manager: Opaco
    stringData:
    api-token: "<seu-token-API>"
    Fim do prazo de validade
    secret/Cloudflare-api-token-secret criado
  3. Crie um objeto ClusterIssuer, especificando Cloudflare-api-token-secret (definido na etapa anterior) como o local para recuperar o token. Se desejar, você pode substituir example-issuer no campo metadata.name (e example-issuer-account-key no campo spec.acme.privateKeySecretRef.name ) por um nome diferente.

    $ kubectl apply -f - <<EOFapiVersão: cert-manager.io/v1
    tipo: Metadados do ClusterIssuer: nome: example-issuer namespace: cert-manager especificação: acme: e-mail: example@example.com servidor: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: nome: example-issuer-account-key solucionadores: - dns01:
              Cloudflare: apiTokenSecretRef: nome: Chave Cloudflare-api-token-secret: api-token EOF clusterissuer.cert-manager.io/example-issuer criado
  4. Verifique se o ClusterIssuer está implantado e pronto (o valor no campo READY é True ).

    $ kubectl get clusterissuer NOME PRONTO IDADE exemplo-emissor Verdadeiro 3h9m

Implantar ExternalDNS

Assim como o cert-manager, o projeto ExternalDNS requer um token de API do Cloudflare para gerenciar o DNS. O mesmo token pode ser usado para ambos os projetos, mas isso não é obrigatório.

  1. Crie os CRDs do ExternalDNS para o NGINX Ingress Controller para permitir a integração entre os projetos.

    $ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yaml customresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org criado
  2. Crie o serviço DNS externo ( external-dns ). Como o manifesto é bastante longo, aqui o dividimos em duas partes. A primeira parte configura contas, funções e permissões:

    • Cria um objeto ServiceAccount chamado external-dns para gerenciar todas as operações de gravação e atualização para gerenciar o DNS.
    • Cria um objeto ClusterRole (também chamado external-dns ) que define as permissões necessárias.
    • Vincula o ClusterRole ao ServiceAccount.
    $ kubectl apply -f - <<EOFapiVersão: v1
    tipo: Metadados da conta de serviço: nome: external-dns --- apiVersion: rbac.authorization.k8s.io/v1 tipo: Metadados do ClusterRole: nome: external-dns regras: - apiGroups: [""] recursos: ["services","endpoints","pods"] verbos: ["get","watch","list"] - apiGroups: ["extensions","networking.k8s.io"] recursos: ["ingresses"] verbos: ["get","watch","list"] - apiGroups: ["externaldns.nginx.org"] recursos: ["dnsendpoints"] verbos: ["get","watch","list"] - apiGroups: ["externaldns.nginx.org"] recursos: ["dnsendpoints/status"] verbos: ["update"] - apiGroups: [""] recursos: ["nodes"] verbos: ["list","watch"] --- apiVersion: rbac.authorization.k8s.io/v1 tipo: ClusterRoleBinding metadados: nome: external-dns-viewer roleRef: apiGroup: rbac.authorization.k8s.io tipo: Nome do ClusterRole: external-dns assuntos: - tipo: Nome da conta de serviço: namespace external-dns: EOF padrão serviceaccount/external-dns criado clusterrole.rbac.authorization.k8s.io/external-dns criado clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer criado

    A segunda parte do manifesto cria a implantação do ExternalDNS:

    • Cria um filtro de domínio, que limita o escopo de possíveis danos causados pelo ExternalDNS ao gerenciar domínios. Por exemplo, você pode especificar os nomes de domínio dos ambientes de preparação para evitar alterações nos ambientes de produção. Neste exemplo, definimos domain-filter como example.com .
    • Define a variável de ambiente CF_API_TOKEN para seu token de API do Cloudflare. Para <seu-token-API>, substitua o token real ou um Segredo contendo o token. No último caso, você também precisa projetar o Secret no contêiner usando uma variável de ambiente.
    • Define a variável de ambiente FREE_TIER como "true" (apropriado, a menos que você tenha uma assinatura paga do Cloudflare).
    $  kubectl apply -f - <<EOF 
    ---
    apiVersão: apps/v1
    tipo: Metadados de implantação: nome: external-dns especificação: estratégia: tipo: Recriar seletor: matchLabels: aplicativo: external-dns modelo: metadados: rótulos: aplicativo: external-dns especificação: serviceAccountName: external-dns contêineres: - nome: external-dns imagem: k8s.gcr.io/external-dns/external-dns:v0.12.0 argumentos: - --source=service - --source=ingress - --source=crd - --crd-source-apiversion=externaldns.nginx.org/v1 - --crd-source-kind=DNSEndpoint - --domain-filter=example.com - --provider=Cloudflare env: - nome: CF_API_TOKEN
    valor: "<seu-token-API>"
              - nome: Valor FREE_TIER: "true" EOF serviceaccount/external-dns criado clusterrole.rbac.authorization.k8s.io/external-dns criado clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer criado deployment.apps/external-dns criado

Implantar o aplicativo de exemplo

Use o aplicativo de exemplo padrão do NGINX Ingress Controller chamado Cafe para fins de teste.

  1. Implante o aplicativo Cafe.

    $ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yaml deployment.apps/coffee criado service/coffee-svc criado deployment.apps/tea criado service/tea-svc criado
  2. Implante o NGINX Ingress Controller para o aplicativo Cafe. Observe as seguintes configurações:

    • tipo: VirtualServer – Estamos usando o recurso personalizado NGINX VirtualServer, não o recurso padrão do Kubernetes Ingress.
    • spec.host – Substitua cafe.example.com pelo nome do host que você está implantando. O host deve estar dentro do domínio que está sendo gerenciado com ExternalDNS.
    • spec.tls.cert-manager.cluster-issuer – Se você estiver usando os valores especificados nesta postagem, este é example-issuer . Se necessário, substitua o nome escolhido na Etapa 3 de Implantar cert‑manager .
    • spec.externalDNS.enable – O valor true informa ao ExternalDNS para criar um registro DNS A.

    Observe que o tempo que leva para essa etapa ser concluída depende muito do provedor de DNS, pois o Kubernetes está interagindo com a API de DNS do provedor.

    $ kubectl apply -f - <<EOFapiVersão: k8s.nginx.org/v1
    tipo: Metadados do VirtualServer: nome: cafe especificação: host: cafe.example.com tls: segredo: cafe-secret gerenciador de certificados: cluster-issuer: example-issuer externalDNS: enable: true upstreams: - nome: tea serviço: tea-svc porta: 80 - nome: serviço de café: coffee-svc porto: 80 rotas: - caminho: /tea ação: senha: chá - caminho: /coffee ação: senha: café EOF virtualserver.k8s.nginx.org/cafe criado

Validar a solução

  1. Verifique o registro DNS A – em particular se no bloco ANSWER SECTION o FQDN (aqui, cafe.example.com ) está mapeado para o endereço IP correto ( www.xxx.yyy.zzz ).

    $ dig cafe.example.com ; <<>> DiG 9.10.6 <<>> cafe.example.com ;; opções globais: +cmd ;; Resposta obtida: ;; ->>HEADER<<- opcode: CONSULTA, status: SEM ERRO, id: 22633 ;; sinalizadores: qr rd ra; CONSULTA: 1, RESPOSTA: 1, AUTORIDADE: 0, ADICIONAL: 1;; OPTAR PSEUDOSECÇÃO: ; EDS: versão: 0, sinalizadores:; udp: 4096 ;; SEÇÃO DE PERGUNTAS: ;cafe.example.com.		EM UMA SEÇÃO DE RESPOSTAS: cafe.example.com.	279 IN A www.xxx.yyy.zzz ;; Tempo de consulta: 1 mseg ;; SERVIDOR: 2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359#53(2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359) ;; QUANDO: Dia Seg DD hh : mm : ss TZ AAAA ;; MSG TAMANHO rcvd: 67
  2. Verifique se o certificado é válido (o valor no campo READY é True ).

    $ kubectl obter certificados NOME PRONTO SEGREDO IDADE cafe-secret Verdadeiro cafe-secret 8m51s
  3. Verifique se você consegue acessar o aplicativo.

    $ curl https://cafe.example.com/coffee Endereço do servidor: 10.2.2.4:8080 Nome do servidor: coffee-7c86d7d67c-lsfs6 Data: DD/Seg/AAAA:hh:mm:ss +TZ-offset URI: /café ID da solicitação: 91077575f19e6e735a91b9d06e9684cd $ curl https://cafe.example.com/tea Endereço do servidor: 10.2.2.5:8080 Nome do servidor: tea-5c457db9-ztpns Data: DD/Seg/AAAA:hh:mm:ss +TZ-offset URI: /tea ID da solicitação: 2164c245a495d22c11e900aa0103b00f

O que acontece quando um desenvolvedor implanta o NGINX Ingress Controller

Muita coisa acontece nos bastidores quando a solução é implementada. O diagrama mostra o que acontece quando um desenvolvedor implanta o NGINX Ingress Controller com um recurso personalizado do NGINX VirtualServer. Observe que alguns detalhes operacionais são omitidos.

  1. O desenvolvedor implanta um recurso VirtualServer usando o NGINX CRD
  2. O Kubernetes cria o VirtualServer usando o NGINX Ingress Controller
  3. O NGINX Ingress Controller chama o ExternalDNS para criar um registro DNS A
  4. ExternalDNS cria o registro A no DNS
  5. O NGINX Ingress Controller chama o cert-manager para solicitar um certificado TLS
  6. cert-manager adiciona um registro DNS para uso durante o desafio DNS-01
  7. cert-manager contata Let’s Encrypt para completar o desafio
  8. Let’s Encrypt valida o desafio contra DNS
  9. Let’s Encrypt emite o certificado TLS
  10. cert-manager fornece o certificado TLS para o NGINX Ingress Controller
  11. O NGINX Ingress Controller roteia solicitações externas protegidas por TLS para os pods do aplicativo

solucao-problemas

Dada a complexidade do Kubernetes e dos componentes que estamos usando, é difícil fornecer um guia de solução de problemas abrangente. Dito isso, há algumas sugestões básicas para ajudar você a determinar o problema.

  • Use os comandos kubectl get e kubectl describe para validar a configuração de objetos implantados.
  • Use o kubectl registros <componente> comando para visualizar arquivos de log para os vários componentes implantados.
  • Use o K9s para inspecionar a instalação; o software destaca os problemas em amarelo ou vermelho (dependendo da gravidade) e fornece uma interface para acessar logs e detalhes sobre objetos.

Se você ainda estiver tendo problemas, entre em contato conosco no Slack da Comunidade NGINX e peça ajuda! Temos uma comunidade vibrante e estamos sempre felizes em resolver problemas.

Para experimentar o NGINX Ingress Controller baseado no NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso .


"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."