Usar TLS com um controlador de entrada no AKS (Serviço de Kubernetes do Azure)

O protocolo TLS (segurança da camada de transporte) usa certificados para fornecer segurança para comunicação, criptografia, autenticação e integridade. Ao usar o TLS com um controlador de entrada no AKS, é possível proteger a comunicação entre seus aplicativos e aproveite os benefícios de um controlador de entrada.

É possível usar seus próprios certificados ao integrá-los ao driver CSI do Repositório de Segredos. Como alternativa, é possível usar o gerenciador de certificados, que gera e configura automaticamente certificados Let's Encrypt. Dois aplicativos são executados no cluster do AKS, cada um dos quais é acessível em um único endereço IP.

Importante

O complemento de roteamento de aplicativos é recomendado para entrada no AKS. Para obter mais informações, consulte Entrada do nginx gerenciada com o complemento de roteamento de aplicativo.

Importante

A Microsoft não gerencia nem dá suporte ao cert-manager e a quaisquer problemas decorrentes de seu uso. Para problemas com o cert-manager, consulte a documentação solução de problemas do cert-manager.

Há dois controladores de entrada de código aberto para Kubernetes com base no Nginx: um mantido pela comunidade do Kubernetes (kubernetes/ingress-nginx) e outro mantido pela NGINX, Inc. (nginxinc/kubernetes-ingress). Este artigo usa o controlador de entrada da comunidade do Kubernetes.

Antes de começar

  • Este artigo pressupõe que você tem um controlador de entrada e aplicativos configurados. Se precisar de um controlador de entrada ou de aplicativos de exemplo, confira Criar um controlador de entrada.

  • Este artigo usa o Helm 3 para instalar o controlador de entrada NGINX em uma versão suportada do Kubernetes. Use a versão mais recente do Helm e de ter acesso aos repositórios ingress-nginx e jetstack do Helm. As etapas descritas neste artigo podem não ser compatíveis com versões anteriores do gráfico do Helm, do controlador de entrada NGINX ou do Kubernetes.

  • Este artigo pressupõe que você tenha um cluster do AKS com um ACR (Registro de Contêiner do Azure) integrado. Para obter mais informações sobre como criar um cluster do AKS com um ACR integrado, confira Autenticar com o ACR do AKS.

  • Se você estiver usando a CLI do Azure, este artigo exigirá que você esteja executando a CLI do Azure versão 2.0.64 ou posterior. Execute az --version para encontrar a versão. Se você precisa instalar ou atualizar, consulte Instalar a CLI do Azure.

  • Se você estiver usando Azure PowerShell, este artigo exigirá que você esteja executando o Azure PowerShell versão 5.9.0 ou posterior. Execute Get-InstalledModule -Name Az para encontrar a versão. Se precisar instalar ou atualizar, consulte Instalar o Azure PowerShell.

Usar o TLS com seus próprios certificados com o driver CSI do Repositório de Segredos

Para usar o TLS com seus certificados e o driver CSI do Repositório de Segredos, você precisa de um cluster do AKS com o driver CSI do Repositório de Segredos configurado, além de uma instância do Azure Key Vault.

Para saber mais, confira Configurar o driver CSI do Repositório de Segredos para habilitar o controlador de entrada NGINX com TLS.

Usar o TLS com certificados Let's Encrypt

Para usar o TLS com certificados Let's Encrypt, implante o gerenciador de certificados, que gera e configura automaticamente certificados Let's Encrypt.

Importar as imagens do gerenciador de certificados usadas pelo gráfico do Helm em seu ACR

  • Use az acr import para importar as imagens a seguir para o ACR.

    REGISTRY_NAME=<REGISTRY_NAME>
    CERT_MANAGER_REGISTRY=quay.io
    CERT_MANAGER_TAG=v1.8.0
    CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller
    CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook
    CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector
    
    az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG
    az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG
    az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG
    

Observação

Você também pode importar gráficos do Helm para o ACR. Para obter mais informações, confira Enviar e extrair gráficos do Helm para um ACR.

Opções de configuração do controlador de entrada

Você pode configurar o controlador de entrada do NGINX usando um endereço IP público estático ou um endereço IP público dinâmico. Se você estiver usando um domínio personalizado, precisará adicionar um registro A à zona DNS. Se você não estiver usando um domínio personalizado, poderá configurar um FQDN (nome de domínio totalmente qualificado) para o endereço IP do controlador de entrada.

Criar um endereço IP público estático ou dinâmico

Usar um endereço IP público estático

Você pode configurar seu controlador de entrada com um endereço IP público estático. O endereço IP público estático permanecerá, se você excluir seu controlador de entrada. O endereço IP não permanecerá, se você excluir o cluster do AKS.

Ao atualizar o controlador de entrada, você deve passar um parâmetro para a versão do Helm, para garantir que o serviço do controlador de entrada esteja ciente do balanceador de carga que será alocado a ele. Para que os certificados HTTPS funcionem corretamente, você usará um rótulo DNS para configurar um FQDN para o endereço IP do controlador de entrada.

  1. Obtenha o nome do grupo de recursos do cluster do AKS com o comando az aks show.

    az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv
    
  2. Crie um endereço IP público com o método de alocação estático usando o comando az network public-ip create. O exemplo a seguir cria um endereço IP público denominado myAKSPublicIP no grupo de recursos do cluster AKS obtido na etapa anterior.

    az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv
    

Observação

Como alternativa, você pode criar um endereço IP em um grupo de recursos diferente que você gerencia separadamente do cluster AKS. Se você criar um endereço IP em um grupo de recursos diferente, confirme o seguinte:

  • A identidade do cluster usada pelo cluster do AKS tem permissões delegadas para o outro grupo de recursos, como Colaborador de Rede.
  • Adicione o parâmetro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>". Substitua <RESOURCE_GROUP> pelo nome do grupo de recursos em que reside o endereço IP.
  1. Adicione o parâmetro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>". O rótulo DNS pode ser definido quando o controlador de entrada é implantado pela primeira vez ou mais tarde.

  2. Adicione o parâmetro --set controller.service.loadBalancerIP="<STATIC_IP>". Especifique seu próprio endereço IP público que foi criado na etapa anterior.

    DNS_LABEL="<DNS_LABEL>"
    NAMESPACE="ingress-basic"
    STATIC_IP=<STATIC_IP>
    
    helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
      --namespace $NAMESPACE \
      --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL \
      --set controller.service.loadBalancerIP=$STATIC_IP \
      --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz
    

Confira mais informações em Usar um endereço IP público estático e um rótulo DNS com o balanceador de carga AKS.

Usar um endereço IP público dinâmico

Um endereço IP público do Azure é criado para seu controlador de entrada após a criação. O endereço IP público é estático por todo o período de vida do seu controlador de entrada. O endereço IP público estático não permanecerá, se você excluir seu controlador de entrada. Se você criar um novo controlador de entrada, ele receberá um novo endereço IP público. Seu resultado deve ser semelhante ao exemplo de saída a seguir.

  • Use o comando kubectl get service para obter o endereço IP público do controlador de entrada.

    # Get the public IP address for your ingress controller
    
    kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller
    
    # Sample output
    
    NAME                                     TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE   SELECTOR
    nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.74.133   EXTERNAL_IP     80:32486/TCP,443:30953/TCP   44s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx
    

Adiciona um registro A a uma zona DNS.

Se você estiver usando um domínio personalizado, precisará adicionar um registro A à zona DNS. Se você não estiver usando um domínio personalizado, poderá configurar o endereço IP público com um FQDN.

  • Adicione um registro A à zona DNS com o endereço IP externo do serviço NGINX usando az network dns record-set a add-record.

    az network dns record-set a add-record \
        --resource-group myResourceGroup \
        --zone-name MY_CUSTOM_DOMAIN \
        --record-set-name "*" \
        --ipv4-address MY_EXTERNAL_IP
    

Configurar um FQDN para seu controlador de entrada

Uma opção é configurar um FQDN para o endereço IP do controlador de entrada em vez de um domínio personalizado definindo um rótulo DNS. O FQDN deve seguir este formulário: <CUSTOM DNS LABEL>.<AZURE REGION NAME>.cloudapp.azure.com.

Importante

Seu rótulo DNS deve ser exclusivo no local do Azure.

Você pode configurar seu FQDN usando um dos seguintes métodos:

  • Defina o rótulo DNS usando a CLI do Azure ou o Azure PowerShell.
  • Defina o rótulo DNS usando as configurações do gráfico do Helm.

Para obter mais informações, confira Rótulos de nome DNS do endereço IP público.

Definir o rótulo DNS usando a CLI do Azure ou o Azure PowerShell

Substitua <DNS_LABEL> pelo rótulo DNS exclusivo.

# Public IP address of your ingress controller
IP="MY_EXTERNAL_IP"

# Name to associate with public IP address
DNSLABEL="<DNS_LABEL>"

# Get the resource-id of the public IP
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)

# Update public IP address with DNS name
az network public-ip update --ids $PUBLICIPID --dns-name $DNSLABEL

# Display the FQDN
az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv

Definir o rótulo DNS usando as configurações do gráfico do Helm

Você pode transmitir uma configuração de anotação para a configuração de gráfico do Helm usando o parâmetro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name". O parâmetro pode ser definido quando o controlador de entrada é implantado pela primeira vez ou mais tarde.

O exemplo a seguir mostra como atualizar essa configuração após a implantação do controlador. Substitua <DNS_LABEL> pelo rótulo DNS exclusivo.

DNSLABEL="<DNS_LABEL>"
NAMESPACE="ingress-basic"

helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNSLABEL \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz

Instalar o cert-manager

O controlador de entrada NGINX dá suporte para terminação TLS. Há várias maneiras de recuperar e configurar certificados para HTTPS. Este artigo usa o cert-manager, que fornece a geração automática do certificado Lets Encrypt e funcionalidade de gerenciamento.

Para instalar o controlador cert-manager, use os comando a seguir.

# Set variable for ACR location to use for pulling images
ACR_URL=<REGISTRY_URL>

# Label the ingress-basic namespace to disable resource validation
kubectl label namespace ingress-basic cert-manager.io/disable-validation=true

# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update your local Helm chart repository cache
helm repo update

# Install the cert-manager Helm chart
helm install cert-manager jetstack/cert-manager \
  --namespace ingress-basic \
  --version=$CERT_MANAGER_TAG \
  --set installCRDs=true \
  --set nodeSelector."kubernetes\.io/os"=linux \
  --set image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CONTROLLER \
  --set image.tag=$CERT_MANAGER_TAG \
  --set webhook.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_WEBHOOK \
  --set webhook.image.tag=$CERT_MANAGER_TAG \
  --set cainjector.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CAINJECTOR \
  --set cainjector.image.tag=$CERT_MANAGER_TAG

Para obter mais informações sobre a configuração docert-manager, consulte o projeto cert-manager.

Criar o emissor de cluster de CA

Antes da emissão de certificados, o cert-manager requer um dos seguintes emissores:

  • Um Emissor, que funciona em um só namespace.
  • Um recurso ClusterIssuer, que funciona em todos os namespaces.

Para obter mais informações, consulte a documentação do emissor do cert-manager.

  1. Crie um emissor de cluster, como cluster-issuer.yaml, usando o manifesto a seguir. Substitua MY_EMAIL_ADDRESS por um endereço válido da sua organização.

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email: MY_EMAIL_ADDRESS
        privateKeySecretRef:
          name: letsencrypt
        solvers:
        - http01:
            ingress:
              class: nginx
              podTemplate:
                spec:
                  nodeSelector:
                    "kubernetes.io/os": linux
    
  2. Aplique o emissor usando o comando kubectl apply.

    kubectl apply -f cluster-issuer.yaml --namespace ingress-basic
    

Atualizar suas rotas de entrada

Você precisa atualizar suas rotas de entrada para lidar com o tráfego para o FQDN ou o domínio personalizado.

No seguinte exemplo, o tráfego é roteado como tal:

  • O tráfego para o endereço hello-world-ingress.MY_CUSTOM_DOMAIN é roteado para o serviço aks-helloworld-one.
  • O tráfego para hello-world-ingress.MY_CUSTOM_DOMAIN/hello-world-two é roteado para o serviço aks-helloworld-two.
  • O tráfego para o endereço hello-world-ingress.MY_CUSTOM_DOMAIN/static é roteado para o serviço chamado aks-helloworld-one para ativos estáticos.

Observação

Se você tiver configurado um FQDN para o endereço IP do controlador de entrada em vez de um domínio personalizado, use o FQDN em vez de hello-world-ingress.MY_CUSTOM_DOMAIN.

Por exemplo, se o FQDN for demo-aks-ingress.eastus.cloudapp.azure.com, substitua hello-world-ingress.MY_CUSTOM_DOMAIN por demo-aks-ingress.eastus.cloudapp.azure.com em hello-world-ingress.yaml.

  1. Crie ou atualize o arquivo hello-world-ingress.yaml usando o arquivo YAML de exemplo a seguir. Atualize o spec.tls.hosts e spec.rules.host para o nome DNS que você criou na etapa anterior.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-world-ingress
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /$2
        nginx.ingress.kubernetes.io/use-regex: "true"
        cert-manager.io/cluster-issuer: letsencrypt
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - hello-world-ingress.MY_CUSTOM_DOMAIN
        secretName: tls-secret
      rules:
      - host: hello-world-ingress.MY_CUSTOM_DOMAIN
        http:
          paths:
          - path: /hello-world-one(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
          - path: /hello-world-two(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-two
                port:
                  number: 80
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-world-ingress-static
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "false"
        nginx.ingress.kubernetes.io/rewrite-target: /static/$2
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - hello-world-ingress.MY_CUSTOM_DOMAIN
        secretName: tls-secret
      rules:
      - host: hello-world-ingress.MY_CUSTOM_DOMAIN
        http:
          paths:
          - path: /static(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
    
  2. Atualize o recurso de entrada usando o comando kubectl apply.

    kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic
    

Verifique se foi criado um objeto de certificado

Em seguida, um recurso de certificado deve ser criado. O recurso de certificado define o certificado X.509 desejado. Saiba mais em Certificados do Gerenciador de Certificados.

O cert-manager cria automaticamente um objeto de certificado para você usando o ingress-shim, que é implantado automaticamente com o cert-manager desde a v0.2.2. Para obter mais informações, consulte a Documentação do ingress-shim.

Para verificar se o certificado foi criado com êxito, use o comando kubectl get certificate --namespace ingress-basic e verifique se READY é True. Pode demorar alguns minutos para a saída chegar.

kubectl get certificate --namespace ingress-basic

A saída a seguir mostra o status do certificado.

NAME         READY   SECRET       AGE
tls-secret   True    tls-secret   11m

Testar a configuração de entrada

Abra um navegador da Web para hello-world-ingress.MY_CUSTOM_DOMAIN ou para o FQDN do controlador de entrada do Kubernetes. Verifique se o seguinte é verdadeiro:

  • Você é redirecionado para usar HTTPS.
  • O certificado é confiável.
  • O aplicativo de demonstração é mostrado no navegador da Web.
  • Adicione /hello-world-two ao final do domínio e verifique se o segundo aplicativo de demonstração com o título personalizado é mostrado.

Limpar os recursos

Este artigo usou o Helm para instalar os componentes de ingresso, os certificados e os aplicativos de exemplo. Quando você implanta um gráfico do Helm, vários recursos do Kubernetes são criados. Esses recursos incluem pods, implantações e serviços. Para limpar esses recursos, você poderá excluir o namespace inteiro de exemplo ou os recursos individuais.

Excluir o namespace de exemplo e todos os recursos

Excluir o namespace de exemplo também exclui todos os recursos no namespace.

  • Exclua o namespace de exemplo inteiro usando o comando kubectl delete e especificando o nome do namespace.

    kubectl delete namespace ingress-basic
    

Excluir recursos individualmente

Como alternativa, você pode excluir o recurso individualmente.

  1. Remova os recursos do emissor do cluster.

    kubectl delete -f cluster-issuer.yaml --namespace ingress-basic
    
  2. Liste as versões do Helm com o comando helm list. Procure por gráficos chamados nginx e cert-manager conforme mostrado na saída de exemplo a seguir.

    $ helm list --namespace ingress-basic
    
    NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
    cert-manager            ingress-basic   1               2020-01-15 10:23:36.515514 -0600 CST    deployed        cert-manager-v0.13.0    v0.13.0
    nginx                   ingress-basic   1               2020-01-15 10:09:45.982693 -0600 CST    deployed        nginx-ingress-1.29.1    0.27.0
    
  3. Desinstale as versões com o comando helm uninstall. O exemplo a seguir desinstala a entrada NGINX e as implantações do cert-manager.

    $ helm uninstall cert-manager nginx --namespace ingress-basic
    
    release "cert-manager" uninstalled
    release "nginx" uninstalled
    
  4. Remova os dois aplicativos de exemplo.

    kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
    kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic
    
  5. Remova a rota de entrada que direcionava o tráfego para os aplicativos de exemplo.

    kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic
    
  6. Exclua o namespace. Use o comando kubectl delete e especifique o nome do namespace.

    kubectl delete namespace ingress-basic
    

Próximas etapas

Este artigo incluído alguns componentes externos no AKS. Para saber mais sobre esses componentes, consulte as seguintes páginas do projeto:

Também é possível: