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

En esta página, se muestra cómo usar varios certificados SSL para Ingress con balanceo de cargas interno y externo.

Descripción general

Si deseas aceptar solicitudes HTTP de tus clientes, el balanceador de cargas de HTTP(S) interno o externo debe tener un certificado para demostrar su identidad a los clientes. También debe tener una clave privada para completar el protocolo de enlace HTTPS.

Cuando el balanceador de cargas acepta una solicitud HTTP(S) de un cliente, el tráfico entre el cliente y el balanceador de cargas se encripta mediante TLS. Sin embargo, el balanceador de cargas finaliza la encriptación TLS y reenvía la solicitud sin encriptación a la aplicación. Cuando configuras un balanceador de cargas de 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) 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 que se usa en la solicitud:

Varios certificados SSL con el diagrama del sistema Ingress

Puedes proporcionar un balanceador de cargas de HTTPS con certificados SSL mediante uno de estos tres métodos:

  • Certificados SSL administrados por Google. Consulta la página de certificados administrados para obtener información sobre cómo usarlos.

  • Certificado SSL de Google Cloud que administras tú mismo. Se usa un certificado ya compartido subido a tu proyecto de Google Cloud con anterioridad.

  • Secretos de Kubernetes El secreto contiene un certificado y una clave que tú mismo creas. Para usar un secreto, agrega su nombre en el campo tls del manifiesto de Ingress.

Puedes usar más de un método en el mismo Ingress. Esto permite migraciones entre métodos sin tiempo de inactividad.

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.

Requisitos previos

Para realizar los ejercicios de esta página, debes tener dos nombres de dominio. Puedes usar Google Domains o algún otro registrador.

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 o dos objetos ManagedCertificate. Asegúrate de configurar estos certificados en el mismo proyecto y en el mismo espacio de nombres en el que se implementa el balanceador de cargas.

  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

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

Establece la configuración de gcloud predeterminada mediante uno de los siguientes métodos:

  • Usa gcloud init si deseas ver una explicación sobre cómo configurar parámetros predeterminados.
  • Usa gcloud config para establecer el ID, la zona y la región del proyecto de manera individual.

Usa gcloud init

Si recibes el error One of [--zone, --region] must be supplied: Please specify location, completa esta sección.

  1. Ejecuta gcloud init y sigue las instrucciones:

    gcloud init

    Si usas SSH en un servidor remoto, usa la marca --console-only para evitar que el comando abra un navegador:

    gcloud init --console-only
  2. Sigue las instrucciones a fin de autorizar a gcloud para que use tu cuenta de Google Cloud.
  3. Crea una configuración nueva o selecciona una existente.
  4. Elige un proyecto de Google Cloud.
  5. Elige una zona predeterminada de Compute Engine para clústeres zonales o una región para clústeres regionales o de Autopilot.

Usa gcloud config

  • 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 de Autopilot o regionales, configura 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: "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"

La implementación tiene tres pods, y cada pod tiene dos contenedores. Un contenedor ejecuta hello-app:1.0 y escucha en el puerto TCP 50001. El otro contenedor ejecuta hello-app:2.0 y escucha en el puerto TCP 50002.

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

kubectl apply -f my-mc-deployment.yaml

Crea un objeto Service

A continuación, se detalla un manifiesto para Service:

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 Service dice que cualquier pod con 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 Service.

El campo ports del manifiesto del Service es un arreglo de objetos ServicePort. Cuando un cliente envía una solicitud al servicio en my-first-port, la solicitud se reenvía a uno de los pods miembro 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 miembro en el puerto 50002.

Copia el manifiesto en 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. Puedes crearlos de forma manual o usar certificados administrados por Google. Si ya tienes dos archivos de certificado con los valores adecuados para el nombre común, puedes pasar a la siguiente sección.

Certificados administrados por el usuario

  1. Crea tu primera clave:

    openssl genrsa -out test-ingress-1.key 2048
    
  2. 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"
    

    Reemplaza FIRST_DOMAIN por un nombre de dominio de tu propiedad.

    Por ejemplo, supongamos que deseas que el balanceador de cargas entregue solicitudes desde el dominio example.com. La solicitud de firma de certificado debería verse así:

    openssl req -new -key test-ingress-1.key -out test-ingress-1.csr \
        -subj "/CN=example.com"
    
  3. Crea el primer certificado:

    openssl x509 -req -days 365 -in test-ingress-1.csr -signkey test-ingress-1.key \
        -out test-ingress-1.crt
    
  4. Crea tu segunda clave:

    openssl genrsa -out test-ingress-2.key 2048
    
  5. 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"
    

    Reemplaza SECOND_DOMAIN por otro nombre de dominio de tu propiedad.

    Por ejemplo, supongamos que deseas que el balanceador de cargas entregue solicitudes desde el dominio examplepetstore.com. La solicitud de firma de certificado debería verse así:

    openssl req -new -key test-ingress-2.key -out test-ingress-2.csr \
        -subj "/CN=examplepetstore.com"
    
  6. Crea el 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 los certificados y las claves, consulta la Descripción general de certificados SSL.

Ahora tienes dos archivos de certificado y dos archivos de claves.

En las tareas restantes, se usan los siguientes marcadores de posición para hacer referencia a tus dominios, certificados y claves:

  • FIRST_CERT_FILE es la ruta de acceso a tu primer archivo de certificado.
  • FIRST_KEY_FILE es la ruta al archivo de claves que acompaña a tu primer certificado.
  • FIRST_DOMAIN es un nombre de dominio de tu propiedad.
  • FIRST_SECRET_NAME: El nombre del Secret que contiene tu primer certificado y clave.
  • 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.
  • SECOND_DOMAIN es un segundo nombre de dominio de tu propiedad.
  • SECOND_SECRET_NAME: El nombre del Secret que contiene tu segundo certificado y clave.

Certificados administrados por Google

Para crear certificados administrados por Google, debes agregar objetos ManagedCertificate al espacio de nombres de tu Ingress. Puedes usar la siguiente plantilla para definir certificados en tus dominios:

  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

Reemplaza lo siguiente:

  • FIRST_CERT_NAME: Es el nombre de tu primer objeto ManagedCertificate.
  • FIRST_DOMAIN: Es el primer dominio que posees.
  • SECOND_CERT_NAME: Es el nombre del segundo objeto ManagedCertificate.
  • SECOND_DOMAIN: Es el segundo dominio que posees.

Especifica certificados para el Ingress

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

  • Secrets
  • Certificados ya compartidos
  • Certificados administrados por Google

Selecciona una de las pestañas para elegir uno de los métodos:

Secrets

Crea secretos

  1. Crea un secreto que contenga el primer certificado y la primera clave:

    kubectl create secret tls FIRST_SECRET_NAME \
        --cert FIRST_CERT_FILE --key FIRST_KEY_FILE
    
  2. Crea un secreto que contenga el segundo certificado y la segunda clave:

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

Crea un Ingress

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

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:
              name: my-first-port
  - host: SECOND_DOMAIN
    http:
      paths:
      - pathType: ImplementationSpecific
        backend:
          service:
            name: my-mc-service
            port:
              name: my-second-port
  1. Copia el manifiesto en un archivo llamado my-mc-ingress.yaml. Reemplaza FIRST_DOMAIN y SECOND_DOMAIN por nombres de dominio de tu propiedad, como example.com y examplepetstore.com.

  2. Crea el Ingress:

    kubectl apply -f my-mc-ingress.yaml
    

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

  3. 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:
      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
    

Certificados ya compartidos

Crea certificados ya compartidos

  1. Crea un recurso de certificado en tu proyecto de Google Cloud:

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

    Reemplaza lo siguiente:

    • FIRST_CERT_NAME es el nombre de tu primer certificado.
    • FIRST_CERT_FILE: Es el primer archivo de certificado.
    • FIRST_KEY_FILE: Es el primer archivo de claves.
  2. Crea un segundo recurso de certificado en tu proyecto de Google Cloud:

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

    Reemplaza lo siguiente:

    • SECOND_CERT_NAME es el nombre de tu segundo certificado.
    • SECOND_CERT_FILE: El segundo archivo de certificado.
    • SECOND_KEY_FILE: Es el segundo archivo de claves.
  3. Observa tus recursos de certificado:

    gcloud compute ssl-certificates list
    

    En el resultado se muestra que tienes recursos de certificado llamados FIRST_CERT_NAME y SECOND_CERT_NAME:

    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
    

Crea un Ingress de GKE

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

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:
              name: my-first-port
  - host: SECOND_DOMAIN
    http:
      paths:
      - pathType: ImplementationSpecific
        backend:
          service:
            name: my-mc-service
            port:
              name: my-second-port
  1. Copia el manifiesto en un archivo llamado my-psc-ingress.yaml. Reemplaza FIRST_DOMAIN y SECOND_DOMAIN por tus nombres de dominio.

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

  3. Describe tu Ingress:

    kubectl describe ingress my-psc-ingress
    

    En el resultado se muestra que el Ingress está asociado con certificados ya compartidos llamados FIRST_CERT_NAME y SECOND_CERT_NAME. 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
      ----              ----  --------
      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
    

Certificados administrados por Google

Crea un Ingress de GKE

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

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:
              name: my-first-port
  - host: SECOND_DOMAIN
    http:
      paths:
      - pathType: ImplementationSpecific
        backend:
          service:
            name: my-mc-service
            port:
              name: my-second-port
  1. Copia el manifiesto en un archivo llamado my-gmc-ingress.yaml. Reemplaza FIRST_DOMAIN y SECOND_DOMAIN por tus nombres de dominio.

  2. Crea el Ingress:

    kubectl apply -f my-gmc-ingress.yaml
    

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

  3. Describe tu Ingress:

    kubectl describe ingress my-gmc-ingress
    

    En el resultado, se muestra que el Ingress está asociado con certificados administrados llamados FIRST_CERT_NAME y SECOND_CERT_NAME. GKE completa automáticamente las anotaciones ingress.gcp.kubernetes.io/pre-shared-cert y ingress.kubernetes.io/ssl-cert para apuntar a los certificados administrados por Google que creaste mediante los objetos ManagedCertificate. En el resultado, también se muestra la dirección IP externa del balanceador de cargas:

    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
    

Prueba el balanceador de cargas

Espera unos cinco minutos para que GKE termine de configurar el balanceador de cargas. En el caso de los certificados administrados por Google, es posible que lleve mucho más tiempo en completar la configuración, ya que el sistema necesita aprovisionar los certificados y verificar la configuración de DNS para los dominios determinados.

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 -v https://FIRST_DOMAIN

El resultado muestra que el primer certificado se usó en el protocolo de enlace TLS. Si el primer dominio es example.com, el resultado es similar a este:

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

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

curl -v https://SECOND_DOMAIN

La salida muestra que el segundo certificado se usó en el protocolo de enlace TLS. Si el segundo dominio es examplepetstore.com, la salida es similar a esta:

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

El campo hosts de un objeto Ingress

Un IngressSpec tiene un campo tls que es un arreglo de objetos 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 aparecen en el Ingress, los certificados ya compartidos tienen prioridad sobre los Secretos. En otras palabras, los Secretos siguen incluidos, pero los certificados ya compartidos se presentan primero.

  • 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 tls, el certificado principal se encuentra en el primer secreto de la lista.

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

Prácticas recomendadas para la rotación de certificados

Si deseas rotar el contenido de tu certificado (Secreto o ya compartido), sigue estas prácticas recomendadas:

  • Crea un nuevo Secreto o certificado ya compartido con un nombre diferente que contenga los datos del certificado nuevo. Conecta este recurso (junto con el existente) a tu Ingress siguiente las instrucciones anteriores. Una vez que los cambios sean de tu agrado, puedes quitar el certificado anterior del Ingress.
  • Si no te molesta interrumpir el tráfico, puedes quitar el recurso anterior del Ingress, aprovisionar un recurso nuevo con el mismo nombre, pero de contenido diferente y, luego, volver a conectarlo al Ingress.

Para evitar llevar a cabo la administración de la rotación de certificados, consulta la función de SSL administrada por Google.

Soluciona 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