Usa varios certificados SSL en el balanceo de cargas HTTP(S) con Ingress

Descripción general

El balanceador de cargas HTTP(S) finaliza las conexiones SSL y TLS del cliente y, luego, balancea las solicitudes en tus Pods. Cuando configuras un balanceador de cargas HTTP(S) a través de [Ingress], puedes configurarlo para que presente hasta diez certificados TLS al cliente.

El balanceador de cargas usa la indicación de nombre del servidor (SNI, por sus siglas en inglés) para determinar qué certificado presentar al cliente, según el nombre de dominio en el protocolo de enlace TLS. Si el cliente no usa SNI o usa un nombre de dominio que no coincide con el nombre común (CN) en uno de los certificados, el balanceador de cargas usa el primer certificado que se encuentra en el Ingress. En el siguiente diagrama, se muestra un balanceador de cargas que envía tráfico a backends diferentes, según el nombre de dominio usado en la solicitud:

Varios certificados SSL con el diagrama del sistema Ingress

Puedes especificar certificados para un Ingress mediante uno de los siguientes métodos:

  • Secretos de Kubernetes

  • Certificados ya compartidos que subiste con anterioridad a tu proyecto de Google Cloud Platform

No puedes usar ambos métodos al mismo tiempo. Debes usar el mismo método para especificar todos los certificados.

Versión mínima de GKE

Debes tener una versión de GKE 1.10.2 o posterior para usar certificados ya compartidos o especificar varios certificados en un Ingress.

Panorama general

A continuación, hay una descripción general de los pasos en este tema:

  1. Crea una implementación

  2. Crea un servicio

  3. Crea dos archivos de certificado y dos archivos de claves.

  4. Crea un Ingress que use Secretos o certificados ya compartidos. Como resultado de la creación de un Ingress, GKE crea y configura un balanceador de cargas HTTP(S).

  5. Prueba el balanceador de cargas HTTP(S).

Antes de comenzar

Sigue estos pasos a fin de prepararte para esta tarea:

  • Asegúrate de que habilitaste la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Asegúrate de que instalaste el SDK de Cloud.
  • Establece tu ID del proyecto predeterminado:
    gcloud config set project [PROJECT_ID]
  • Si trabajas con clústeres zonales, establece tu zona de procesamiento predeterminada:
    gcloud config set compute/zone [COMPUTE_ZONE]
  • Si trabajas con clústeres regionales, establece tu región de procesamiento predeterminada:
    gcloud config set compute/region [COMPUTE_REGION]
  • Actualiza gcloud a la versión más reciente:
    gcloud components update

Crea una implementación

A continuación, se muestra un manifiesto para una implementación:

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"

La implementación tiene tres Pods y cada Pod tiene dos contenedores. Un contenedor ejecuta hello-app y escucha en el puerto TCP 50001. El otro contenedor ejecuta node-hello y escucha en el puerto TCP 50002.

Copia el manifiesto a un archivo llamado my-mc-deployment.yaml y crea la implementación:

kubectl apply -f my-mc-deployment.yaml

Crea un servicio

A continuación, se detalla un manifiesto para un servicio.

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

El campo selector en el manifiesto de servicio indica que cualquier Pod que tenga las etiquetas app: products y department: sales es miembro de este servicio. Por lo tanto, los Pods de la implementación que creaste en el paso anterior son miembros del servicio.

El campo ports del manifiesto de servicio es un arreglo de objetos de ServicePort. Cuando un cliente envía una solicitud al servicio en my-first-port, la solicitud se reenvía a uno de los Pods miembros en el puerto 50001. Cuando un cliente envía una solicitud al servicio en my-second-port, la solicitud se reenvía a uno de los Pods miembros en el puerto 50002.

Copia el manifiesto a un archivo llamado my-mc-service.yaml y crea el servicio:

kubectl apply -f my-mc-service.yaml

Crea certificados y claves

Para hacer los ejercicios en esta página, necesitas dos certificados, cada uno con una clave correspondiente. Cada certificado debe tener un nombre común (CN, por sus siglas en inglés) que sea igual a un nombre de dominio de tu propiedad. Si ya tienes dos archivos de certificado con los valores adecuados para el nombre común, puedes pasar a la siguiente sección.

Crea tu primera clave:

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

Crea tu primera solicitud de firma de certificado:

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

en la que [FIRST_DOMAIN_NAME] es un nombre de dominio de tu propiedad o un nombre de dominio falso.

Por ejemplo, supongamos que deseas que el balanceador de cargas entregue las solicitudes de your-store.example. Tu solicitud de firma de certificado se vería de la siguiente manera:

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

Crea tu primer certificado:

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

Crea tu segunda clave:

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

Crea tu segunda solicitud de firma de certificado:

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

en la que [SECOND_DOMAIN] es otro nombre de dominio de tu propiedad o un nombre de dominio falso.

Por ejemplo, supongamos que deseas que el balanceador de cargas entregue las solicitudes de your-experimental-store.example. Tu solicitud de firma de certificado se vería de la siguiente manera:

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

Crea tu segundo certificado:

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

Para obtener más información sobre la creación de tus certificados y claves, consulta Obtén una clave privada y un certificado firmado.

Ahora tienes dos archivos de certificado y dos archivos de claves. En los pasos restantes en esta tarea, se usan estos marcadores de posición para referirse a tus dominios, archivos de certificado y archivos de claves:

  • [FIRST_CERT_FILE] es la ruta a tu primer archivo de certificado.

  • [FIRST_KEY_FILE] es la ruta al archivo de claves que acompaña a tu primer certificado.

  • [SECOND_CERT_FILE] es la ruta a tu segundo archivo de certificado.

  • [SECOND_KEY_FILE] es la ruta al archivo de claves que acompaña a tu segundo certificado.

  • [FIRST_DOMAIN] es un nombre de dominio de tu propiedad o un nombre de dominio falso.

  • [SECOND_DOMAIN] es un segundo nombre de dominio de tu propiedad o un segundo nombre de dominio falso.

Especifica certificados para tu Ingress

El paso siguiente es crear un objeto Ingress. En tu manifiesto de Ingress, puedes usar uno de los dos métodos a fin de proporcionar certificados para el balanceador de cargas:

  • Secretos
  • Certificados ya compartidos

Puedes elegir uno de los dos métodos si seleccionas la pestaña SECRETS o la pestaña PRE-SHARED CERTS:

Secretos

Crea Secretos

Crea un Secreto que contenga tu primer certificado y tu primera clave:

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

Crea un Secreto que contenga tu segundo certificado y tu segunda clave:

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

Crea un Ingress

A continuación, se detalla un manifiesto para un Ingress.

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

Copia el manifiesto a un archivo llamado my-mc-ingress.yaml. Reemplaza [FIRST_DOMAIN] y [SECOND_DOMAIN] con nombres de dominio de tu propiedad o nombres de dominio falsos.

Crea el Ingress:

kubectl apply -f my-mc-ingress.yaml

Cuando creas un Ingress, el controlador de entrada de GKE crea un balanceador de cargas HTTP(S). Espera un minuto para que GKE asigne una dirección IP externa al balanceador de cargas.

Describe tu Ingress:

kubectl describe ingress my-mc-ingress

El resultado muestra que dos Secretos están asociados con el Ingress. El resultado también muestra la dirección IP externa del balanceador de cargas.

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 ya compartidos

Usa certificados ya compartidos

Crea un recurso de certificado en tu proyecto de Google Cloud Platform:

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

donde:

Crea un segundo recurso de certificado en tu proyecto de Google Cloud Platform:

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

donde:

  • [SECOND_CERT_FILE] es tu segundo archivo de certificado.

  • [SECOND_KEY_FILE] es tu segundo archivo de claves.

Observa tus recursos de certificado:

gcloud compute ssl-certificates list

El resultado muestra que tienes recursos de certificado llamados test-ingres-1 y 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

A continuación, se presenta un manifiesto para un Ingress que enumera recursos de certificados ya compartidos en una anotación:

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

Copia el manifiesto a un archivo llamado my-psc-ingress.yaml. Reemplaza [FIRST_DOMAIN] y [SECOND_DOMAIN] con tus nombres de dominio o nombres de dominio falsos.

Crea el Ingress:

kubectl apply -f my-psc-ingress.yaml

Espera un minuto para que GKE asigne una dirección IP externa al balanceador de cargas.

Describe tu Ingress:

kubectl describe ingress my-psc-ingress

El resultado muestra que el Ingress está asociado con certificados ya compartidos llamados test-ingress-1 y test-ingress-2. El resultado también muestra la dirección IP externa del balanceador de cargas:

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

Prueba el balanceador de cargas

Espera unos cinco minutos para que GKE termine de configurar el balanceador de cargas.

Para realizar este paso, debes tener dos nombres de dominio y ambos nombres deben resolver la dirección IP externa del balanceador de cargas HTTP(S).

Envía una solicitud al balanceador de cargas mediante tu primer nombre de dominio:

curl -kv https://[FIRST_DOMAIN]

El resultado muestra que tu primer certificado se usó en el protocolo de enlace TLS. Si tu primer dominio es your-store.example, el resultado es similar a lo siguiente:

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

Envía una solicitud al balanceador de cargas mediante tu segundo nombre de dominio:

curl -kv https://[SECOND_DOMAIN]

El resultado muestra que tu segundo certificado se usó en el protocolo de enlace TLS. Si tu segundo dominio es your-experimental-store.example, el resultado es similar a lo siguiente:

...
*   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!

El campo hosts de un objeto Ingress

Un IngressSpec tiene un campo tls que es un arreglo de objetos de IngressTLS. Cada objeto IngressTLS tiene un campo hosts y un campo SecretName. En GKE, el campo hosts no se usa. GKE lee el nombre común (CN) del certificado en el Secreto. Si el nombre común coincide con el nombre de dominio en una solicitud del cliente, entonces el balanceador de cargas presenta al cliente el certificado coincidente.

¿Qué certificado se presenta?

El balanceador de cargas elige un certificado de acuerdo con las siguientes reglas:

  • Si los Secretos y los certificados ya compartidos se enumeran en el Ingress, el balanceador de cargas ignora los Secretos y usa la lista de certificados ya compartidos.

  • Si ningún certificado tiene un nombre común (CN) que coincida con el nombre de dominio en la solicitud del cliente, el balanceador de cargas presenta el certificado principal.

  • Para los Secretos enumerados en el bloque de tls, el certificado principal es el primer Secreto en la lista.

  • Para los certificados ya compartidos que se enumeran en la anotación, el certificado principal es el primer certificado en la lista.

Solución de problemas

Especificar los Secretos no válidos o que no existen genera un error de evento de Kubernetes. Puedes verificar los eventos de Kubernetes para un Ingress de la siguiente manera:

kubectl describe ingress

El resultado es similar al siguiente ejemplo:

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'

Pasos siguientes

¿Te sirvió esta página? Envíanos tu opinión:

Enviar comentarios sobre…