Utiliser plusieurs certificats SSL dans l'équilibrage de charge HTTPS avec un objet Ingress


Cette page explique comment configurer plusieurs certificats SSL pour des ressources Ingress situées dans des clusters Google Kubernetes Engine (GKE).

Présentation

Si vous souhaitez accepter les requêtes HTTPS de vos clients, l'équilibreur de charge d'application doit disposer d'un certificat pour justifier son identité auprès de vos clients. L'équilibreur de charge doit également disposer d'une clé privée pour mener à bien la négociation HTTPS.

Lorsque l'équilibreur de charge accepte une requête HTTPS d'un client, le trafic entre le client et l'équilibreur de charge est chiffré via TLS. Cependant, l'équilibreur de charge interrompt ce chiffrement TLS et transfère la requête sans chiffrement à l'application. Lorsque vous configurez un équilibreur de charge d'application via Ingress, vous pouvez le configurer pour qu'il présente au maximum dix certificats TLS au client.

L'équilibreur de charge utilise l'indication du nom du serveur SNI (Server Name Indication) pour déterminer le certificat à présenter au client, en fonction du nom de domaine figurant dans le handshake TLS. Si le client n'utilise pas SNI ou utilise un nom de domaine qui ne correspond pas au nom commun (CN) de l'un des certificats, l'équilibreur de charge utilise le premier certificat répertorié dans l'objet Entrée.

Le diagramme suivant représente l'envoi de trafic vers différents backends par l'équilibreur de charge, en fonction du nom de domaine utilisé dans la requête :

Certificats SSL multidomaines avec diagramme du système Entrée

Vous pouvez fournir un équilibreur de charge d'application avec des certificats SSL en optant pour l'une des solutions suivantes :

  • Certificat SSL Google Cloud que vous gérez vous-même. Le certificat SSL utilise un certificat prépartagé que vous importez dans votre projet Google Cloud.

  • Secrets Kubernetes. Le secret contient un certificat et une clé que vous créez vous-même. Ajoutez le nom du secret au champ tls de votre fichier manifeste Ingress.

Vous pouvez utiliser plusieurs méthodes dans la même entrée. Cela évite les temps d'arrêt entre les méthodes lors de la migration.

L'essentiel

Voici une vue d'ensemble des étapes abordées dans ce document :

  1. Créez un déploiement.

  2. Créez un service.

  3. Créez deux fichiers de certificat et deux fichiers de clé ou deux objets ManagedCertificate. Vous devez configurer ces certificats dans le même projet et dans le même espace de noms que ceux dans lequel l'équilibreur de charge est déployé.

  4. Créez une entrée qui utilise des Secrets ou des certificats prépartagés. Lorsque vous créez l'objet Ingress, GKE crée et configure un équilibreur de charge d'application.

  5. Testez l'équilibreur de charge d'application.

Avant de commencer

Avant de commencer, effectuez les tâches suivantes :

  • Activez l'API Google Kubernetes Engine.
  • Activer l'API Google Kubernetes Engine
  • Si vous souhaitez utiliser Google Cloud CLI pour cette tâche, installez puis initialisez gcloud CLI. Si vous avez déjà installé gcloud CLI, assurez-vous de disposer de la dernière version en exécutant la commande gcloud components update.
  • Vous devez posséder deux noms de domaine. Ceux-ci ne doivent pas dépasser 63 caractères.

Limites

  • Les certificats gérés par Google ne sont compatibles avec GKE Ingress qu'en utilisant l'équilibreur de charge d'application externe. Les certificats gérés par Google ne sont pas compatibles avec les contrôleurs Ingress tiers.
  • Pour les équilibreurs de charge d'application internes, vous devez désactiver HTTP dans le fichier manifeste Ingress. Cette opération n'est pas nécessaire dans le cas d'un équilibreur de charge externe.
  • Vous ne devez pas modifier ni mettre à jour manuellement la configuration de l'équilibreur de charge d'application. Cela signifie que vous ne devez modifier aucun des composants de l'équilibreur de charge. Cela s'applique entre autres aux proxys cibles, aux mappages d'URL et aux services de backend. Toutes les modifications que vous apportez sont remplacées par GKE.

Créer un déploiement

  1. Enregistrez le manifeste suivant sous le nom 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"
    

    Ce fichier manifeste décrit un déploiement avec trois pods. Chaque pod possède deux conteneurs. Un conteneur exécute hello-app:1.0 et écoute sur le port TCP 50001. L'autre conteneur exécute hello-app:2.0 et écoute sur le port TCP 50002.

  2. Appliquez le fichier manifeste à votre cluster :

    kubectl apply -f my-mc-deployment.yaml
    

Créer un service

  1. Enregistrez le manifeste suivant sous le nom 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
    

    Ce fichier manifeste décrit un service par le biais des champs suivants :

    • selector : spécifie que tous les pods comportant les libellés app: products et department: sales sont membres de ce service.
    • ports : indique que lorsqu'un client envoie une requête au service sur le port my-first-port, GKE transfère la requête à l'un des pods membres sur le port 50001. Lorsqu'un client envoie une requête au service sur le port my-second-port, GKE la transfère à l'un des pods membres sur le port 50002.
  2. Appliquez le fichier manifeste à votre cluster :

    kubectl apply -f my-mc-service.yaml
    

Créer des certificats et des clés

Pour faire les exercices de cette page, vous avez besoin de deux certificats, chacun avec une clé correspondante. Chaque certificat doit avoir un nom commun (CN) correspondant à un nom de domaine que vous possédez.

Vous pouvez créer ces certificats manuellement ou utiliser des certificats gérés par Google.

Si vous avez déjà deux fichiers de certificat avec les valeurs appropriées pour le nom commun, vous pouvez passer à la section suivante.

Certificats gérés par l'utilisateur

  1. Créez votre première clé :

    openssl genrsa -out test-ingress-1.key 2048
    
  2. Créez votre première requête de signature de certificat :

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

    Remplacez FIRST_DOMAIN par un nom de domaine que vous possédez, tel que example.com.

  3. Créez votre premier certificat :

    openssl x509 -req -days 365 -in test-ingress-1.csr -signkey test-ingress-1.key \
        -out test-ingress-1.crt
    
  4. Créez votre deuxième clé :

    openssl genrsa -out test-ingress-2.key 2048
    
  5. Créez votre deuxième requête de signature de certificat :

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

    Remplacez SECOND_DOMAIN par un autre nom de domaine que vous possédez, tel que examplepetstore.com.

  6. Créez votre deuxième certificat :

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

Pour en savoir plus sur les certificats et les clés, consultez la présentation des certificats SSL.

Vous possédez maintenant deux fichiers de certificat et deux fichiers de clé.

Les tâches restantes utilisent les espaces réservés suivants pour désigner vos domaines, certificats et clés :

  • FIRST_CERT_FILE : chemin d'accès à votre premier fichier de certificat.
  • FIRST_KEY_FILE : chemin d'accès au fichier de clé qui accompagne votre premier certificat.
  • FIRST_DOMAIN : un nom de domaine que vous possédez.
  • FIRST_SECRET_NAME : nom du secret contenant votre premier certificat et votre première clé.
  • SECOND_CERT_FILE : chemin d'accès à votre deuxième fichier de certificat.
  • SECOND_KEY_FILE : chemin d'accès au fichier de clé qui accompagne votre deuxième certificat.
  • SECOND_DOMAIN : un deuxième nom de domaine que vous possédez.
  • SECOND_SECRET_NAME : nom du secret contenant votre deuxième certificat et votre deuxième clé.

Certificats gérés par Google

Pour créer des certificats gérés par Google, vous devez ajouter des objets ManagedCertificate à l'espace de noms de votre objet Ingress. Vous pouvez vous servir du modèle suivant pour définir des certificats pour vos domaines :

  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

Remplacez les éléments suivants :

  • FIRST_CERT_NAME : nom de votre premier objet ManagedCertificate.
  • FIRST_DOMAIN : premier domaine que vous possédez.
  • SECOND_CERT_NAME : nom du deuxième objet ManagedCertificate.
  • SECOND_DOMAIN : deuxième domaine que vous possédez.

Les noms des objets ManagedCertificate sont différents de ceux des certificats réels qu'ils créent. Il vous suffit de connaître le nom des objets ManagedCertificate pour les utiliser dans votre objet Ingress.

Spécifier des certificats pour votre objet Ingress

L'étape suivante consiste à créer un objet Entrée. Dans le fichier manifeste d'entrée, vous pouvez utiliser l'une des méthodes suivantes pour fournir des certificats à l'équilibreur de charge :

  • Secrets
  • Certificats prépartagés
  • Certificats gérés par Google

Secrets

  1. Créez un Secret contenant votre premier certificat et votre première clé :

    kubectl create secret tls FIRST_SECRET_NAME \
        --cert=FIRST_CERT_FILE \
        --key=FIRST_KEY_FILE
    
  2. Créez un Secret contenant votre deuxième certificat et votre deuxième clé :

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

Créer un objet Ingress

  1. Enregistrez le manifeste suivant sous le nom 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
    

    Remplacez FIRST_DOMAIN et SECOND_DOMAIN par des noms de domaine que vous possédez, par exemple example.com et examplepetstore.com.

  2. Appliquez le fichier manifeste à votre cluster :

    kubectl apply -f my-mc-ingress.yaml
    
  3. Décrivez votre entrée :

    kubectl describe ingress my-mc-ingress
    

    Le résultat ressemble à ce qui suit :

    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
    

    Le résultat montre que deux Secrets sont associés à l'entrée. La sortie affiche également l'adresse IP externe de l'équilibreur de charge. Si l'adresse IP externe n'est pas définie, attendez quelques minutes, puis relancez la commande.

Certificats prépartagés

  1. Créez un certificat :

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

    Remplacez les éléments suivants :

    • FIRST_CERT_NAME : nom de votre premier certificat.
    • FIRST_CERT_FILE : votre premier fichier de certificat.
    • FIRST_KEY_FILE : votre premier fichier de clé.
  2. Créez un deuxième certificat :

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

    Remplacez les éléments suivants :

    • SECOND_CERT_NAME : nom de votre deuxième certificat.
    • SECOND_CERT_FILE : votre deuxième fichier de certificat.
    • SECOND_KEY_FILE : votre deuxième fichier de clé.
  3. Affichez vos ressources de certificat :

    gcloud compute ssl-certificates list
    

    Le résultat ressemble à ce qui suit :

    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
    

Créer un objet Ingress

  1. Enregistrez le manifeste suivant sous le nom 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
    

    Remplacez FIRST_DOMAIN et SECOND_DOMAIN par vos noms de domaine.

    Ce fichier manifeste décrit un objet Ingress qui liste les ressources de certificat prépartagées dans une annotation.

  2. Appliquez le fichier manifeste à votre cluster :

    kubectl apply -f my-psc-ingress.yaml
    
  3. Décrivez votre entrée :

    kubectl describe ingress my-psc-ingress
    

    Le résultat ressemble à ce qui suit :

    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
    

    La sortie montre que l'Ingress est associé à des certificats prépartagés nommés FIRST_CERT_NAME et SECOND_CERT_NAME. La sortie affiche également l'adresse IP externe de l'équilibreur de charge. Si l'adresse IP externe n'est pas définie, attendez quelques minutes, puis relancez la commande.

Certificats gérés par Google

Créer un objet Ingress

  1. Enregistrez le manifeste suivant sous le nom 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
    

    Remplacez FIRST_DOMAIN et SECOND_DOMAIN par vos noms de domaine.

    Ce fichier manifeste décrit un objet Ingress qui liste les ressources de certificat prépartagées dans une annotation.

  2. Appliquez le fichier manifeste à votre cluster :

    kubectl apply -f my-gmc-ingress.yaml
    
  3. Décrivez votre entrée :

    kubectl describe ingress my-gmc-ingress
    

    Le résultat ressemble à ce qui suit :

    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
    

    La sortie montre que l'Ingress est associé à des certificats gérés nommés FIRST_CERT_NAME et SECOND_CERT_NAME. GKE renseigne automatiquement les annotations ingress.gcp.kubernetes.io/pre-shared-cert et ingress.kubernetes.io/ssl-cert avec les certificats gérés par Google que vous avez créés à l'aide des objets ManagedCertificate. La sortie affiche également l'adresse IP externe de l'équilibreur de charge. Si l'adresse IP externe n'est pas définie, attendez quelques minutes, puis relancez la commande.

Tester l'équilibreur de charge

Attendez environ cinq minutes que GKE ait fini de configurer l'équilibreur de charge.

Si vous avez utilisé des certificats gérés par Google, l'exécution de la configuration peut prendre bien plus de temps, car le système doit provisionner les certificats et vérifier la configuration DNS pour des domaines donnés.

Pour tester l'équilibreur de charge, vous devez posséder deux noms de domaine et ceux-ci doivent tous deux résoudre l'adresse IP externe de l'équilibreur de charge d'application externe.

  1. Envoyez une requête à l'équilibreur de charge en utilisant votre premier nom de domaine :

    curl -v https://FIRST_DOMAIN
    

    Vous devrez peut-être utiliser l'option curl -k pour effectuer un transfert SSL non sécurisé, afin que curl accepte les certificats autosignés.

    Le résultat ressemble à ce qui suit :

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

    Cette sortie indique que votre premier certificat a été utilisé lors de l'établissement du handshake TLS.

  2. Envoyez une requête à l'équilibreur de charge en utilisant votre deuxième nom de domaine :

    curl -v https://SECOND_DOMAIN
    

    Le résultat ressemble à ce qui suit :

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

    Cette sortie indique que votre deuxième certificat a été utilisé lors de l'établissement du handshake TLS.

Le champ "hosts" d'un objet Entrée

Un objet IngressSpec possède un champ tls qui est un tableau d'objets IngressTLS. Chaque objet IngressTLS possède un champ hosts et un champ SecretName. Dans GKE, le champ hosts n'est pas utilisé. GKE lit le nom commun (CN) du certificat dans le Secret. Si le nom commun correspond au nom de domaine dans une requête de client, l'équilibreur de charge présente le certificat correspondant au client.

Quel certificat est présenté ?

L'équilibreur de charge choisit un certificat en fonction des règles suivantes :

  • Si les secrets et les certificats prépartagés sont répertoriés dans l'objet Ingress (entrée), les certificats prépartagés sont prioritaires sur les secrets. En d'autres termes, les secrets sont toujours inclus, mais les certificats prépartagés sont présentés en premier.

  • Si aucun certificat ne possède de nom commun (CN) correspondant au nom de domaine dans une requête de client, l'équilibreur de charge présente le certificat principal.

  • Pour les secrets répertoriés dans le bloc tls, le certificat principal figure dans le premier secret de la liste.

  • Pour les certificats prépartagés répertoriés dans l'annotation, le certificat principal est le premier certificat de la liste.

Bonnes pratiques concernant la rotation des certificats

Voici quelques bonnes pratiques à suivre si vous souhaitez faire tourner le contenu de votre certificat secret ou prépartagé :

  • Créez un certificat secret ou prépartagé avec un autre nom, contenant les nouvelles données de certificat. Associez cette ressource (ainsi que la ressource existante) à votre entrée (objet Ingress) en suivant les instructions fournies précédemment. Une fois que vous êtes satisfait des modifications, vous pouvez supprimer l'ancien certificat de l'entrée.
  • Si cela ne vous dérange pas de perturber le trafic, vous pouvez supprimer l'ancienne ressource de l'entrée, provisionner une nouvelle ressource avec le même nom, mais avec un contenu différent, puis la réassocier à l'entrée.
Pour éviter de devoir gérer vous-même la rotation des certificats, consultez la page Utiliser des certificats SSL gérés par Google.

Dépannage

Si vous renseignez des résultats de certificats Secrets incorrects ou inexistants, une erreur d'événement Kubernetes est renvoyée. Vous pouvez consulter les événements Kubernetes pour un objet Entrée en procédant comme suit :

kubectl describe ingress

Le résultat ressemble à ce qui suit :

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'

Étapes suivantes

  • Si une application s'exécute sur plusieurs clusters GKE dans différentes régions, configurez une entrée multicluster pour acheminer le trafic vers un cluster de la région la plus proche de l'utilisateur.