Usar vários certificados SSL no balanceamento de carga HTTPS com o Ingress

Esta página mostra como configurar vários certificados SSL para recursos de entrada em clusters do Google Kubernetes Engine (GKE).

Vista geral

Se quiser aceitar pedidos HTTPS dos seus clientes, o Application Load Balancer tem de ter um certificado para poder provar a sua identidade aos seus clientes. O balanceador de carga também tem de ter uma chave privada para concluir o handshake HTTPS.

Quando o balanceador de carga aceita um pedido HTTPS de um cliente, o tráfego entre o cliente e o balanceador de carga é encriptado através do protocolo TLS. No entanto, o balanceador de carga termina a encriptação TLS e encaminha o pedido sem encriptação para a aplicação. Quando configura um balanceador de carga de aplicações através do Ingress, pode configurar o balanceador de carga para apresentar até 15 certificados TLS ao cliente.

O balanceador de carga usa a Indicação do nome do servidor (SNI) para determinar que certificado apresentar ao cliente, com base no nome do domínio na negociação TLS. Se o cliente não usar SNI ou se usar um nome de domínio que não corresponda ao nome comum (CN) num dos certificados, o balanceador de carga usa o primeiro certificado indicado no Ingress.

O diagrama seguinte mostra o balanceador de carga a enviar tráfego para diferentes back-ends, consoante o nome do domínio usado no pedido:

Vários certificados SSL com diagrama do sistema Ingress

Pode fornecer um Application Load Balancer com certificados SSL através dos seguintes métodos:

  • Certificados SSL geridos pela Google. Consulte a página de certificados geridos para ver informações sobre como os usar.

  • Trusted Cloud by S3NS Certificado SSL gerido por si. O certificado SSL usa um certificado pré-partilhado que carrega para o seu Trusted Cloud by S3NS projeto.

  • Kubernetes Secrets. O segredo contém um certificado e uma chave que cria. Adicione o nome do segredo ao campo tls do manifesto do Ingress.

Pode usar mais do que um método no mesmo Ingress. Isto permite migrações sem tempo de inatividade entre métodos.

O panorama geral

Segue-se uma vista geral dos passos descritos neste documento:

  1. Crie uma implementação.

  2. Crie um serviço.

  3. Crie dois ficheiros de certificado e dois ficheiros de chave ou dois objetos ManagedCertificate. Tem de configurar estes certificados no mesmo projeto e no mesmo espaço de nomes onde o equilibrador de carga está implementado.

  4. Crie um Ingress que use segredos ou certificados partilhados previamente. Quando cria o Ingress, o GKE cria e configura um Application Load Balancer.

  5. Teste o balanceador de carga de aplicações.

Antes de começar

Antes de começar, certifique-se de que realizou as seguintes tarefas:

  • Ative a API Google Kubernetes Engine.
  • Ative a API Google Kubernetes Engine
  • Se quiser usar a CLI gcloud para esta tarefa, instale-a e, em seguida, inicialize-a. Se instalou anteriormente a CLI gcloud, execute gcloud components update para obter a versão mais recente.
  • Tem de ser proprietário de dois nomes de domínio. Os nomes de domínio não podem ter mais de 63 carateres.
  • Certifique-se de que tem um cluster do Autopilot ou Standard existente. Para criar um novo cluster, consulte o artigo Crie um cluster do Autopilot.

Limitações

  • Os certificados geridos pela Google só são suportados com o GKE Ingress através do Application Load Balancer externo. Os certificados geridos pela Google não suportam controladores Ingress de terceiros.

  • Para balanceadores de carga de aplicações internos, tem de desativar o HTTP no manifesto de entrada. Isto não é necessário para o balanceador de carga externo.

  • Não deve alterar nem atualizar manualmente a configuração do Application Load Balancer. Isto significa que não pode editar nenhum dos componentes do equilibrador de carga, incluindo proxies de destino, mapas de URLs e serviços de back-end. Quaisquer alterações que fizer são substituídas pelo GKE.

Crie uma implementação

  1. Guarde o seguinte manifesto como my-mc-deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-mc-deployment
    spec:
      selector:
        matchLabels:
          app: products
          department: sales
      replicas: 3
      template:
        metadata:
          labels:
            app: products
            department: sales
        spec:
          containers:
          - name: hello
            image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0"
            env:
            - name: "PORT"
              value: "50001"
          - name: hello-again
            image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
            env:
            - name: "PORT"
              value: "50002"
    

    Este manifesto descreve uma implementação com três pods. Cada pod tem dois contentores. Um contentor executa o hello-app:1.0 e ouve na porta TCP 50001. O outro contentor executa o hello-app:2.0 e ouve na porta TCP 50002.

  2. Aplique o manifesto ao cluster:

    kubectl apply -f my-mc-deployment.yaml
    

Crie um serviço

  1. Guarde o seguinte manifesto como my-mc-service.yaml:

    apiVersion: v1
    kind: Service
    metadata:
      name: my-mc-service
    spec:
      type: NodePort
      selector:
        app: products
        department: sales
      ports:
      - name: my-first-port
        protocol: TCP
        port: 60001
        targetPort: 50001
      - name: my-second-port
        protocol: TCP
        port: 60002
        targetPort: 50002
    

    Este manifesto descreve um serviço com os seguintes campos:

    • selector: especifica que qualquer Pod que tenha a etiqueta app: products e a etiqueta department: sales é membro deste serviço.
    • ports: especifica que, quando um cliente envia um pedido ao serviço em my-first-port, o GKE encaminha o pedido para um dos pods membros na porta 50001. Quando um cliente envia um pedido para o Serviço em my-second-port, o GKE encaminha o pedido para um dos pods membros na porta 50002.
  2. Aplique o manifesto ao cluster:

    kubectl apply -f my-mc-service.yaml
    

Crie certificados e chaves

Para fazer os exercícios nesta página, precisa de dois certificados, cada um com uma chave correspondente. Cada certificado tem de ter um nome comum (CN) igual a um nome de domínio que lhe pertence.

Pode criar esses certificados manualmente ou usar certificados geridos pela Google.

Se já tiver dois ficheiros de certificado com os valores adequados para o nome comum, pode avançar para a secção seguinte.

Certificados geridos pelo utilizador

  1. Crie a sua primeira chave:

    openssl genrsa -out test-ingress-1.key 2048
    
  2. Crie o seu primeiro pedido de assinatura de certificado:

    openssl req -new -key test-ingress-1.key -out test-ingress-1.csr \
        -subj "/CN=FIRST_DOMAIN"
    

    Substitua FIRST_DOMAIN por um nome de domínio que lhe pertença, como example.com.

  3. Crie o seu primeiro certificado:

    openssl x509 -req -days 365 -in test-ingress-1.csr -signkey test-ingress-1.key \
        -out test-ingress-1.crt
    
  4. Crie a sua segunda chave:

    openssl genrsa -out test-ingress-2.key 2048
    
  5. Crie o segundo pedido de assinatura de certificado:

    openssl req -new -key test-ingress-2.key -out test-ingress-2.csr \
        -subj "/CN=SECOND_DOMAIN"
    

    Substitua-o por outro nome de domínio que lhe pertença, como examplepetstore.com.SECOND_DOMAIN

  6. Crie o seu segundo certificado:

    openssl x509 -req -days 365 -in test-ingress-2.csr -signkey test-ingress-2.key \
        -out test-ingress-2.crt
    

Para mais informações acerca de certificados e chaves, consulte a vista geral dos certificados SSL.

Agora, tem dois ficheiros de certificado e dois ficheiros de chave.

As restantes tarefas usam os seguintes marcadores de posição para fazer referência aos seus domínios, certificados e chaves:

  • FIRST_CERT_FILE: o caminho para o ficheiro do seu primeiro certificado.
  • FIRST_KEY_FILE: o caminho para o ficheiro de chave que acompanha o seu primeiro certificado.
  • FIRST_DOMAIN: um nome de domínio do qual é proprietário.
  • FIRST_SECRET_NAME: o nome do segredo que contém o seu primeiro certificado e chave.
  • SECOND_CERT_FILE: o caminho para o seu segundo ficheiro de certificado.
  • SECOND_KEY_FILE: o caminho para o ficheiro de chave que corresponde ao seu segundo certificado.
  • SECOND_DOMAIN: um segundo nome de domínio que lhe pertence.
  • SECOND_SECRET_NAME: o nome do segredo que contém o seu segundo certificado e chave.

Certificados geridos pela Google

Para criar certificados geridos pela Google, tem de adicionar ManagedCertificate objetos ao espaço de nomes do seu Ingress. Pode usar o seguinte modelo para definir certificados para os seus domínios:

  apiVersion: networking.gke.io/v1
  kind: ManagedCertificate
  metadata:
    name: FIRST_CERT_NAME
  spec:
    domains:
      - FIRST_DOMAIN
  ---
  apiVersion: networking.gke.io/v1
  kind: ManagedCertificate
  metadata:
    name: SECOND_CERT_NAME
  spec:
    domains:
      - SECOND_DOMAIN

Substitua o seguinte:

  • FIRST_CERT_NAME: o nome do seu primeiro objeto ManagedCertificate.
  • FIRST_DOMAIN: o primeiro domínio que detém.
  • SECOND_CERT_NAME: o nome do segundo objeto ManagedCertificate.
  • SECOND_DOMAIN: o segundo domínio que detém.

Os nomes dos objetos ManagedCertificate são diferentes dos nomes dos certificados reais que criam. Só precisa de saber os nomes dos objetos ManagedCertificate para os usar no seu Ingress.

Especifique certificados para o seu Ingress

O passo seguinte é criar um objeto Ingress. No manifesto do Ingress, pode usar um dos seguintes métodos para fornecer certificados para o equilibrador de carga:

  • Secrets
  • Certificados pré-partilhados
  • Certificados geridos pela Google

Secrets

  1. Crie um Secret que contenha o seu primeiro certificado e chave:

    kubectl create secret tls FIRST_SECRET_NAME \
        --cert=FIRST_CERT_FILE \
        --key=FIRST_KEY_FILE
    
  2. Crie um Secret que contenha o seu segundo certificado e chave:

    kubectl create secret tls SECOND_SECRET_NAME \
        --cert=SECOND_CERT_FILE \
        --key=SECOND_KEY_FILE
    

Crie um Ingress

  1. Guarde o seguinte manifesto como my-mc-ingress.yaml:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-mc-ingress
    spec:
      tls:
      - secretName: FIRST_SECRET_NAME
      - secretName: SECOND_SECRET_NAME
      rules:
      - host: FIRST_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60001
      - host: SECOND_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60002
    

    Substitua FIRST_DOMAIN e SECOND_DOMAIN por nomes de domínio que lhe pertencem, por exemplo, example.com e examplepetstore.com.

  2. Aplique o manifesto ao cluster:

    kubectl apply -f my-mc-ingress.yaml
    
  3. Descreva a sua entrada no Ingress:

    kubectl describe ingress my-mc-ingress
    

    O resultado é semelhante ao seguinte:

    Name: my-mc-ingress
    Address: 203.0.113.1
    ...
    TLS:
      FIRST_SECRET_NAME terminates
      SECOND_SECRET_NAME terminates
    Rules:
      Host              Path  Backends
      ----              ----  --------
      FIRST_DOMAIN
                          my-mc-service:my-first-port (<none>)
      SECOND_DOMAIN
                          my-mc-service:my-second-port (<none>)
    Annotations:
    ...
    Events:
      Type    Reason  Age   From                     Message
      ----    ------  ----  ----                     -------
      Normal  ADD     3m    loadbalancer-controller  default/my-mc-ingress
      Normal  CREATE  2m    loadbalancer-controller  ip: 203.0.113.1
    

    O resultado mostra que existem dois segredos associados ao Ingress. O resultado também mostra o endereço IP externo do balanceador de carga. Se o endereço IP externo não estiver definido, aguarde alguns minutos e experimente o comando novamente.

Certificados pré-partilhados

  1. Crie um certificado:

    gcloud compute ssl-certificates create FIRST_CERT_NAME \
        --certificate=FIRST_CERT_FILE \
        --private-key=FIRST_KEY_FILE
    

    Substitua o seguinte:

    • FIRST_CERT_NAME: o nome do seu primeiro certificado.
    • FIRST_CERT_FILE: o seu primeiro ficheiro de certificado.
    • FIRST_KEY_FILE: o seu primeiro ficheiro de chave.
  2. Crie um segundo certificado:

    gcloud compute ssl-certificates create SECOND_CERT_NAME \
        --certificate=SECOND_CERT_FILE \
        --private-key=SECOND_KEY_FILE
    

    Substitua o seguinte:

    • SECOND_CERT_NAME: o nome do seu segundo certificado.
    • SECOND_CERT_FILE: o segundo ficheiro de certificado.
    • SECOND_KEY_FILE: o seu segundo ficheiro de chave.
  3. Veja os recursos do certificado:

    gcloud compute ssl-certificates list
    

    O resultado é semelhante ao seguinte:

    NAME                   CREATION_TIMESTAMP
    FIRST_CERT_NAME      2018-11-03T12:08:47.751-07:00
    SECOND_CERT_NAME     2018-11-03T12:09:25.359-07:00
    

Crie um Ingress

  1. Guarde o seguinte manifesto como my-psc-ingress.yaml:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-psc-ingress
      annotations:
        ingress.gcp.kubernetes.io/pre-shared-cert: "FIRST_CERT_NAME,SECOND_CERT_NAME"
    spec:
      rules:
      - host: FIRST_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60001
      - host: SECOND_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60002
    

    Substitua FIRST_DOMAIN e SECOND_DOMAIN pelos seus nomes de domínios.

    Este manifesto descreve um Ingress que lista recursos de certificados pré-partilhados numa anotação.

  2. Aplique o manifesto ao cluster:

    kubectl apply -f my-psc-ingress.yaml
    
  3. Descreva a sua entrada no Ingress:

    kubectl describe ingress my-psc-ingress
    

    O resultado é semelhante ao seguinte:

    Name:             my-psc-ingress
    Address:          203.0.113.2
    ...
    Rules:
      Host              Path  Backends
      ----              ----  --------
      FIRST_DOMAIN
                          my-mc-service:my-first-port (<none>)
      SECOND_DOMAIN
                          my-mc-service:my-second-port (<none>)
    Annotations:
      ...
      ingress.gcp.kubernetes.io/pre-shared-cert:    FIRST_CERT_NAME,SECOND_CERT_NAME
      ...
      ingress.kubernetes.io/ssl-cert:               FIRST_CERT_NAME,SECOND_CERT_NAME
    Events:
      Type    Reason  Age   From                     Message
      ----    ------  ----  ----                     -------
      Normal  ADD     2m    loadbalancer-controller  default/my-psc-ingress
      Normal  CREATE  1m    loadbalancer-controller  ip: 203.0.113.2
    

    O resultado mostra que o Ingress está associado a certificados partilhados previamente com os nomes FIRST_CERT_NAME e SECOND_CERT_NAME. O resultado também mostra o endereço IP externo do balanceador de carga. Se o endereço IP externo não estiver definido, aguarde alguns minutos e experimente o comando novamente.

Certificados geridos pela Google

Crie um Ingress

  1. Guarde o seguinte manifesto como my-gmc-ingress.yaml:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-gmc-ingress
      annotations:
        networking.gke.io/managed-certificates: "FIRST_CERT_NAME,SECOND_CERT_NAME"
    spec:
      rules:
      - host: FIRST_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60001
      - host: SECOND_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60002
    

    Substitua FIRST_DOMAIN e SECOND_DOMAIN pelos seus nomes de domínios.

    Este manifesto descreve um Ingress que lista recursos de certificados pré-partilhados numa anotação.

  2. Aplique o manifesto ao cluster:

    kubectl apply -f my-gmc-ingress.yaml
    
  3. Descreva a sua entrada no Ingress:

    kubectl describe ingress my-gmc-ingress
    

    O resultado é semelhante ao seguinte:

    Name:             my-gmc-ingress
    Address:          203.0.113.2
    ...
    Rules:
      Host              Path  Backends
      ----              ----  --------
      FIRST_DOMAIN
                          my-mc-service:my-first-port (<none>)
      SECOND_DOMAIN
                          my-mc-service:my-second-port (<none>)
    Annotations:
      ...
      ingress.gcp.kubernetes.io/pre-shared-cert:    mcrt-a6e41ce4-2b39-4334-84ce-867ff543c424,mcrt-bbff4116-f014-4800-a43a-4095bffeb4f4
      ...
      ingress.kubernetes.io/ssl-cert:               mcrt-a6e41ce4-2b39-4334-84ce-867ff543c424,mcrt-bbff4116-f014-4800-a43a-4095bffeb4f4
      networking.gke.io/managed-certificates:       FIRST_CERT_NAME,SECOND_CERT_NAME
    Events:
      Type    Reason  Age   From                     Message
      ----    ------  ----  ----                     -------
      Normal  ADD     2m    loadbalancer-controller  default/my-gmc-ingress
      Normal  CREATE  1m    loadbalancer-controller  ip: 203.0.113.2
    

    O resultado mostra que o Ingress está associado a certificados geridos com os nomes FIRST_CERT_NAME e SECOND_CERT_NAME. O GKE preenche automaticamente as anotações ingress.gcp.kubernetes.io/pre-shared-cert e ingress.kubernetes.io/ssl-cert com os certificados geridos pela Google que criou através dos objetos ManagedCertificate. O resultado também mostra o endereço IP externo do equilibrador de carga. Se o endereço IP externo não estiver definido, aguarde alguns minutos e experimente o comando novamente.

Teste o balanceador de carga

Aguarde cerca de cinco minutos para que o GKE termine a configuração do balanceador de carga.

Se usou certificados geridos pela Google, a conclusão da configuração pode demorar consideravelmente mais tempo, uma vez que o sistema tem de aprovisionar os certificados e validar a configuração de DNS para os domínios indicados.

Para testar o equilibrador de carga, tem de ter dois nomes de domínio e ambos os nomes de domínio têm de resolver o endereço IP externo do equilibrador de carga de aplicações externo.

  1. Envie um pedido ao balanceador de carga através do seu primeiro nome de domínio:

    curl -v https://FIRST_DOMAIN
    

    Pode ter de usar a opção curl -k para fazer uma transferência SSL não segura, para que o curl aceite certificados autoassinados.

    O resultado é semelhante ao seguinte:

    ...
    *   Trying 203.0.113.1...
    ...
    * Connected to FIRST_DOMAIN (203.0.113.1) port 443 (#0)
    ...
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    ...
    * Server certificate:
    *  subject: CN=FIRST_DOMAIN
    ...
    > Host: FIRST_DOMAIN.com
    ...
    Hello, world!
    Version: 1.0.0
    ...
    

    Este resultado mostra que o seu primeiro certificado foi usado no handshake TLS.

  2. Envie um pedido ao balanceador de carga através do segundo nome de domínio:

    curl -v https://SECOND_DOMAIN
    

    O resultado é semelhante ao seguinte:

    ...
    *   Trying 203.0.113.1...
    ...
    * Connected to SECOND_DOMAIN (203.0.113.1) port 443 (#0)
    ...
    * Server certificate:
    *  subject: CN=SECOND_DOMAIN
    ...
    > Host: SECOND_DOMAIN
    ...
    Hello, world!
    Version: 2.0.0
    

    Este resultado mostra que o seu segundo certificado foi usado na negociação de TLS.

O campo hosts de um objeto Ingress

Um IngressSpec tem um campo tls que é uma matriz de objetos IngressTLS. Cada objeto IngressTLS tem um campo hosts e um campo SecretName. No GKE, o campo hosts não é usado. O GKE lê o nome comum (CN) do certificado no segredo. Se o nome comum corresponder ao nome de domínio num pedido do cliente, o equilibrador de carga apresenta o certificado correspondente ao cliente.

Que certificado é apresentado?

O balanceador de carga escolhe um certificado de acordo com estas regras:

  • Se os segredos e os certificados pré-partilhados estiverem listados no Ingress, os certificados pré-partilhados têm prioridade sobre os segredos. Por outras palavras, os segredos continuam a ser incluídos, mas os certificados pré-partilhados são apresentados primeiro.

  • Se nenhum certificado tiver um nome comum (CN) que corresponda ao nome do domínio no pedido do cliente, o equilibrador de carga apresenta o certificado principal.

  • Para os segredos listados no bloco tls, o certificado principal encontra-se no primeiro segredo da lista.

  • Para os certificados partilhados previamente indicados na anotação ingress.gcp.kubernetes.io/pre-shared-cert, a ordem pela qual indica os certificados determina o certificado principal. O certificado principal, que é apresentado quando nenhum outro certificado corresponde ao pedido do cliente, é o primeiro certificado apresentado na anotação.

  • Quando usa certificados geridos pela Google, todos os certificados listados na anotação networking.gke.io/managed-certificates são automaticamente ordenados alfabeticamente por nome. O certificado principal é o que aparece primeiro nesta lista alfabética. Para definir um certificado específico como o principal, tem de atribuir nomes aos objetos ManagedCertificate em conformidade para controlar a ordem de ordenação. Por exemplo, para tornar my-default-cert o principal em relação a another-cert, pode atribuir-lhes os nomes 0-my-default-cert e 1-another-cert.

Práticas recomendadas para a rotação de certificados

Se quiser rodar o conteúdo do seu segredo ou certificado pré-partilhado, seguem-se algumas práticas recomendadas:

  • Crie um novo Secret ou um certificado pré-partilhado com um nome diferente que contenha os novos dados do certificado. Anexe este recurso (juntamente com o existente) ao seu Ingress através das instruções fornecidas anteriormente. Quando estiver satisfeito com as alterações, pode remover o certificado antigo do Ingress.
  • Se não se importar de interromper o tráfego, pode remover o recurso antigo do Ingress, aprovisionar um novo recurso com o mesmo nome, mas conteúdos diferentes e, em seguida, voltar a anexá-lo ao Ingress.

Para evitar gerir a rotação de certificados, consulte o artigo Use certificados SSL geridos pela Google.

Resolução de problemas

A especificação de secrets inválidos ou inexistentes resulta num erro de evento do Kubernetes. Pode verificar os eventos do Kubernetes para um Ingress da seguinte forma:

kubectl describe ingress

O resultado é semelhante ao seguinte:

Name:             my-ingress
Namespace:        default
Address:          203.0.113.3
Default backend:  hello-server:8080 (10.8.0.3:8080)
TLS:
  my-faulty-Secret terminates
Rules:
  Host  Path  Backends
  ----  ----  --------
  *     *     my-service:443 (10.8.0.3:443)
Events:
   Error during sync: cannot get certs for Ingress default/my-ingress:
 Secret "my-faulty-ingress" has no 'tls.crt'

O que se segue?