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.

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

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

  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.

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

El campo ports del manifiesto del servicio 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. 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"

En el ejemplo anterior, first-domain es un nombre de dominio de tu propiedad o uno falso.

Por ejemplo, supongamos que deseas que el balanceador de cargas entregue solicitudes desde el dominio your-store.example. 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=your-store.example"

Crea el 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 la segunda solicitud de firma de certificado:

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

En el ejemplo anterior, second-domain es otro nombre de dominio de tu propiedad o uno falso.

Por ejemplo, supongamos que deseas que el balanceador de cargas entregue solicitudes desde el dominio your-experimental-store.example. 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=your-experimental-store.example"

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 al archivo del primer certificado.
  • first-key-file es la ruta de acceso al archivo de claves que acompaña al primer certificado.
  • first-domain es un nombre de dominio de tu propiedad o uno falso.
  • first-secret-name es el nombre del secreto que contiene el primer certificado y la primera clave.
  • second-cert-file es la ruta de acceso al archivo del segundo certificado.
  • second-key-file es la ruta al archivo de claves que acompaña al segundo certificado.
  • second-domain es un segundo nombre de dominio de tu propiedad o uno falso.
  • second-secret-name es el nombre del secreto que contiene el segundo certificado y la segunda clave.

Especifica certificados para el 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

Selecciona la pestaña SECRETS o PRE-SHARED CERTS para elegir uno de los métodos:

Secretos

Crea secretos

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

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/v1beta1
kind: Ingress
metadata:
  name: my-mc-ingress
spec:
  tls:
  - secretName: first-secret-name
  - secretName: second-secret-name
  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 en un archivo llamado my-mc-ingress.yaml. Reemplaza first-domain y second-domain por nombres de dominio de tu propiedad o falsos.

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.

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

gcloud compute ssl-certificates create test-ingress-1 \
--certificate first-cert-file --private-key first-key-file

En el ejemplo anterior, se ilustra lo siguiente:

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

gcloud compute ssl-certificates create test-ingress-2 \
--certificate second-cert-file --private-key second-key-file

En el ejemplo anterior, se ilustra lo siguiente:

  • second-cert-file es el segundo archivo de certificado.
  • second-key-file es el segundo archivo de claves.

Visualiza los recursos de certificado:

gcloud compute ssl-certificates list

En el resultado se 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: networking.k8s.io/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 en un archivo llamado my-psc-ingress.yaml. Reemplaza first-domain y second-domain por 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

En el resultado se muestra que el Ingress está asociado con certificados ya compartidos llamados test-ingress-1 y test-ingress-2. En el resultado también se 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 -v https://first-domain

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

...
*   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
...
&lt;
Hello, world!
Version: 2.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 your-experimental-store.example, la salida es similar 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!

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

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'

Próximos pasos