Como usar vários certificados SSL no balanceamento de carga HTTP(S) com Ingress

Visão geral

O balanceador de carga HTTP(S) encerra as conexões SSL/TLS do cliente e, em seguida, equilibra as solicitações entre os pods. Ao configurar um balanceador de carga HTTP(S) por meio da entrada, é possível defini-lo para apresentar até dez certificados TLS ao cliente.

O balanceador de carga usa a indicação de nome do servidor (SNI, na sigla em inglês) para determinar qual certificado precisa ser apresentado ao cliente com base no nome de domínio no handshake de TLS. Se o cliente não usar a SNI ou se o cliente usar um nome de domínio que não corresponda ao Nome comum (CN, na sigla em inglês) em um dos certificados, o balanceador de carga usará o primeiro certificado listado em Entrada. O diagrama a seguir descreve o tráfego de envio do balanceador de carga para diferentes back-ends, dependendo do nome de domínio usado na solicitação:

Diagrama de vários certificados SSL com o sistema da entrada

Para especificar certificados para uma Entrada, use um dos três métodos:

  • Secrets do Kubernetes.

  • Certificados pré-compartilhados enviados anteriormente ao seu projeto do Google Cloud Platform.

  • Certificados SSL gerenciados pelo Google. Certificados gerenciados são compatíveis com um único domínio sem caracteres curinga. Consulte a página de certificados gerenciados para mais informações sobre como usá-los.

É possível usar mais de um método na mesma Entrada. Isso permite migrações sem tempo de inatividade entre os métodos.

Versão mínima do GKE

Você precisa ter a versão 1.10.2 ou posterior do GKE para usar certificados pré-compartilhados ou especificar vários certificados em uma Entrada.

Visão geral

Veja abaixo uma visão geral das etapas deste tópico:

  1. Crie uma implantação.

  2. Crie um serviço.

  3. Crie dois arquivos de certificado e dois arquivos de chaves.

  4. Crie uma Entrada que use as chaves secretas ou os certificados pré-compartilhados. Como resultado da criação da Entrada, o GKE irá criar e configurar um balanceador de carga HTTP(S).

  5. Teste o balanceador de carga HTTP(S).

Antes de começar

Prepare-se para a tarefa tomando as seguintes medidas:

  • Verifique se você ativou a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Verifique se o SDK do Cloud está instalado.
  • Defina o ID do projeto padrão:
    gcloud config set project [PROJECT_ID]
  • Se você estiver trabalhando com clusters zonais, defina a zona de computação padrão:
    gcloud config set compute/zone [COMPUTE_ZONE]
  • Se você estiver trabalhando com clusters regionais, defina a região de computação padrão:
    gcloud config set compute/region [COMPUTE_REGION]
  • Atualize a gcloud para a versão mais recente:
    gcloud components update

Como criar uma implantação

Veja aqui um manifesto de uma implantação:

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: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50001"
      - name: hello-again
        image: "gcr.io/google-samples/node-hello:1.0"
        env:
        - name: "PORT"
          value: "50002"

A implantação tem três pods e cada pod tem dois contêineres. Um contêiner executa hello-app e escuta a porta TCP 50001. O outro contêiner executa node-hello e escuta a porta TCP 50002.

Copie o manifesto para um arquivo denominado my-mc-deployment.yaml e crie a implantação:

kubectl apply -f my-mc-deployment.yaml

Como criar um serviço

Veja aqui um manifesto de um serviço.

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

O campo selector no manifesto de serviço informa que qualquer pod que tenha os rótulos app: products e department: sales é um membro deste serviço. Assim, os pods da implantação que você criou na etapa anterior são membros do serviço.

O campo ports do manifesto de Service é uma matriz de objetos ServicePort (em inglês). Quando um cliente envia uma solicitação ao serviço em my-first-port, a solicitação é encaminhada para um dos pods de membro na porta 50001. Quando um cliente envia uma solicitação ao serviço em my-second-port, a solicitação é encaminhada para um dos pods de membro na porta 50002.

Copie o manifesto para um arquivo chamado my-mc-service.yaml e crie o serviço:

kubectl apply -f my-mc-service.yaml

Como criar certificados e chaves

Para fazer os exercícios desta página, você precisa de dois certificados, cada um com uma chave correspondente. Cada certificado precisa ter um Nome comum (CN, na sigla em inglês) que seja igual a um nome de domínio que você tem. Se você já tiver dois arquivos de certificado com os valores apropriados para o Nome comum, avance para a próxima seção.

Crie a primeira chave:

openssl genrsa -out test-ingress-1.key 2048

Crie a primeira solicitação de assinatura de certificado:

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

em que [FIRST_DOMAIN_NAME] é um nome de domínio que você tem ou um nome de domínio falso.

Por exemplo, suponha que você queira que o balanceador de carga atenda a solicitações de your-store.example. Nesse caso, sua solicitação de assinatura de certificado ficaria assim:

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

Crie o primeiro certificado:

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

Crie a segunda chave:

openssl genrsa -out test-ingress-2.key 2048

Crie a segunda solicitação de assinatura de certificado:

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

em que [SECOND_DOMAIN] é o outro nome de domínio que você tem ou um nome de domínio falso.

Por exemplo, suponha que você queira que o balanceador de carga atenda a solicitações de your-experimental-store.example. Nesse caso, sua solicitação de assinatura de certificado ficaria assim:

openssl req -new -key test-ingress-2.key -out test-ingress-2.csr \
    -subj "/CN=your-experimental-store.example"

Crie o segundo certificado:

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

Para ver mais informações sobre como criar seus próprios certificados e chaves, consulte Como receber uma chave particular e um certificado assinado.

Agora você tem dois arquivos de certificado e dois arquivos de chaves. As demais etapas nessa tarefa usam esses marcadores para se referir a seus domínios, arquivos de certificado e arquivos de chave:

  • [FIRST_CERT_FILE] é o caminho para o primeiro arquivo de certificado.

  • [FIRST_KEY_FILE] é o caminho para o arquivo de chave que acompanha o primeiro certificado.

  • [SECOND_CERT_FILE] é o caminho para o segundo arquivo de certificado.

  • [SECOND_KEY_FILE] é o caminho para o arquivo de chave que acompanha o segundo certificado.

  • [FIRST_DOMAIN] é um nome de domínio que você tem ou um nome de domínio falso.

  • [SECOND_DOMAIN] é um segundo nome de domínio que você tem ou um segundo nome de domínio falso.

Como especificar certificados para uma Entrada

A próxima etapa é criar um objeto Entrada. No seu manifesto Entrada, é possível usar um dos dois métodos para fornecer certificados ao balanceador de carga:

  • Chaves secretas
  • Certificados pré-compartilhados

Escolha um dos dois métodos selecionando as guias SECRETS ou PRE-SHARED CERTS:

Chaves secretas

Como criar chaves secretas

Crie uma chave secreta que contenha seu primeiro certificado e chave:

kubectl create secret tls my-first-secret \
  --cert [FIRST_CERT_FILE] --key [FIRST_KEY_FILE]

Crie uma chave secreta que contenha seu segundo certificado e chave:

kubectl create secret tls my-second-secret \
  --cert [SECOND_CERT_FILE] --key [SECOND_KEY_FILE]

Como criar uma Entrada

Veja aqui um manifesto de uma Entrada.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-mc-ingress
spec:
  tls:
  - secretName: my-first-secret
  - secretName: my-second-secret
  rules:
  - host: [FIRST_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-first-port
  - host: [SECOND_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-second-port

Copie o manifesto para um arquivo chamado my-mc-ingress.yaml. Substitua [FIRST_DOMAIN] e [SECOND_DOMAIN] por nomes de domínio que você tem ou por nomes de domínio falsos.

Crie a Entrada:

kubectl apply -f my-mc-ingress.yaml

Quando você cria uma Entrada, o controlador de entrada do GKE cria um balanceador de carga HTTP(S). Aguarde um minuto para que o GKE atribua um endereço IP externo ao balanceador de carga.

Descreva sua Entrada:

kubectl describe ingress my-mc-ingress

A saída mostra que duas chaves secretas estão associadas à Entrada. A saída também mostra o endereço IP externo do balanceador de carga.

Name: my-mc-ingress
Address: 203.0.113.1
...
TLS:
  my-first-secret terminates
  my-second-secret terminates
Rules:
  Host              Path  Backends
  ----              ----  --------
  your-store.example
                     my-mc-service:my-first-port (<none>)
  your-experimental-store.example
                     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

Certificados pré-compartilhados

Como usar certificados pré-compartilhados

Crie um recurso de certificado no seu projeto do Google Cloud Platform:

gcloud compute ssl-certificates create test-ingress-1 \
--certificate [FIRST_CERT_FILE] --private-key [FIRST_KEY_FILE]

em que:

Crie um segundo recurso de certificado no seu projeto do Google Cloud Platform:

gcloud compute ssl-certificates create test-ingress-2 \
--certificate [SECOND_CERT_FILE] --private-key [SECOND_KEY_FILE]

em que:

  • [SECOND_CERT_FILE] é o segundo arquivo de certificado.

  • [SECOND_KEY_FILE] é o segundo arquivo de chave.

Veja seus recursos de certificado:

gcloud compute ssl-certificates list

A saída mostra que você tem recursos de certificado chamados test-ingres-1 e test-ingress-2:

NAME                CREATION_TIMESTAMP
test-ingress-1      2018-11-03T12:08:47.751-07:00
test-ingress-2      2018-11-03T12:09:25.359-07:00

Veja aqui um manifesto de uma Entrada que lista recursos de certificado pré-compartilhados em uma anotação:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-psc-ingress
  annotations:
    ingress.gcp.kubernetes.io/pre-shared-cert: "test-ingress-1,test-ingress-2"
spec:
  rules:
  - host: [FIRST_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-first-port
  - host: [SECOND_DOMAIN]
    http:
      paths:
      - backend:
          serviceName: my-mc-service
          servicePort: my-second-port

Copie o manifesto para um arquivo chamado my-psc-ingress.yaml. Substitua [FIRST_DOMAIN] e [SECOND_DOMAIN] pelos seus nomes de domínio ou por nomes de domínio falsos.

Crie a Entrada:

kubectl apply -f my-psc-ingress.yaml

Aguarde um minuto para que o GKE atribua um endereço IP externo ao balanceador de carga.

Descreva sua Entrada:

kubectl describe ingress my-psc-ingress

A saída mostra que a Entrada está associada a certificados pré-compartilhados denominados test-ingress-1 e test-ingress-2. A saída também mostra o endereço IP externo do balanceador de carga:

Name:             my-psc-ingress
Address:          203.0.113.2
...
Rules:
  Host              Path  Backends
  ----              ----  --------
  your-store.example
                     my-mc-service:my-first-port (<none>)
  your-experimental-store.example
                     my-mc-service:my-second-port (<none>)
Annotations:
  ...
  ingress.gcp.kubernetes.io/pre-shared-cert:    test-ingress-1,test-ingress-2
  ...
  ingress.kubernetes.io/ssl-cert:               test-ingress-1,test-ingress-2
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

Como testar o balanceador de carga

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

Nesta etapa, você precisa ter dois nomes de domínio que precisam resolver o endereço IP externo do balanceador de carga HTTP(S).

Envie uma solicitação ao balanceador de carga usando seu primeiro nome de domínio:

curl -v https://[FIRST_DOMAIN]

A saída mostra que o primeiro certificado foi usado no handshake de TLS. Se o primeiro domínio for your-store.example, a saída será semelhante a esta:

...
*   Trying 203.0.113.1...
...
* Connected to your-store.example (203.0.113.1) port 443 (#0)
...
* TLSv1.2 (IN), TLS handshake, Certificate (11):
...
* Server certificate:
*  subject: CN=your-store.example
...
> Host: your-store.example
...
<
Hello, world!
Version: 2.0.0
...

Envie uma solicitação ao balanceador de carga usando o segundo nome de domínio:

curl -v https://[SECOND_DOMAIN]

A saída mostra que o segundo certificado foi usado no handshake de TLS. Se o segundo domínio for your-experimental-store.example, a saída será semelhante a esta:

...
*   Trying 203.0.113.1...
...
* Connected to your-experimental-store.example (203.0.113.1) port 443 (#0)
...
* Server certificate:
*  subject: CN=your-experimental-store.example
...
> Host: your-experimental-store.example
...
Hello Kubernetes!

O campo hosts de um objeto Entrada

No IngressSpec há um campo tls que é uma matriz de objetos IngressTLS (ambos links em inglês). 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, na sigla em inglês) do certificado na chave secreta. Se o Nome comum corresponder ao nome de domínio em uma solicitação do cliente, o balanceador de carga apresentará o certificado correspondente ao cliente.

Qual certificado é apresentado?

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

  • Se as chaves secretas e os certificados pré-compartilhados estiverem listados na Entrada, o balanceador de carga ignorará as chaves secretas e usará a lista de certificados pré-compartilhados.

  • Se nenhum certificado tiver um Nome comum que corresponda ao nome de domínio na solicitação do cliente, o balanceador de carga apresentará o certificado principal.

  • Para as chaves secretas listadas no bloco tls, o certificado principal fica na primeira chave secreta da lista.

  • Para certificados pré-compartilhados listados na anotação, o certificado principal é o primeiro certificado na lista.

Solução de problemas

A especificação de chaves secretas inválidas ou inexistentes resulta em um erro de evento do Kubernetes. Veja os eventos do Kubernetes para verificar se há uma Entrada como esta:

kubectl describe ingress

Esta saída é semelhante a:

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'

A seguir

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Documentação do Kubernetes Engine