Utilizzo di più certificati SSL nel bilanciamento del carico HTTPS con Ingress


Questa pagina mostra come configurare più certificati SSL per le risorse Ingress nei cluster Google Kubernetes Engine (GKE).

Panoramica

Se vuoi accettare richieste HTTPS dai tuoi client, il bilanciatore del carico delle applicazioni deve avere un certificato in modo da poter verificare la sua identità con i client. Il bilanciatore del carico deve anche avere una chiave privata per completare l'handshake HTTPS.

Quando il bilanciatore del carico accetta una richiesta HTTPS da parte di un client, il traffico tra il client e il bilanciatore del carico viene criptato tramite TLS. Tuttavia, il bilanciatore del carico termina la crittografia TLS e inoltra la richiesta senza crittografia all'applicazione. Quando configuri un bilanciatore del carico delle applicazioni tramite Ingress, puoi configurare il bilanciatore del carico in modo che presenti fino a dieci certificati TLS al client.

Il bilanciatore del carico utilizza SNI (Server Name Indication) per determinare il certificato da presentare al client, in base al nome di dominio nell'handshake TLS. Se il client non utilizza SNI o se il client utilizza un nome di dominio che non corrisponde al nome comune (CN) in uno dei certificati, il bilanciatore del carico utilizza il primo certificato elencato nella risorsa Ingress.

Il seguente diagramma mostra il bilanciatore del carico che invia il traffico a backend diversi, a seconda del nome di dominio utilizzato nella richiesta:

Diagramma di sistema per più certificati SSL con Ingress

Puoi fornire a un bilanciatore del carico delle applicazioni con certificati SSL utilizzando i seguenti metodi:

  • Certificato Google Cloud SSL che gestisci autonomamente. Il certificato SSL utilizza un certificato precondiviso che carichi nel tuo progetto Google Cloud.

  • Secret di Kubernetes. Il secret contiene un certificato e una chiave creati da te. Devi aggiungere il nome del secret al campo tls del manifest Ingress.

Puoi utilizzare più di un metodo nella stessa risorsa Ingress. Ciò consente senza tempi di inattività per migrazioni tra i metodi.

Panoramica globale

Ecco una panoramica dei passaggi descritti in questo documento:

  1. Crea un deployment.

  2. Creare un servizio.

  3. Crea due file di certificato e due file chiave o due oggetti ManagedCertificate. Devi configurare questi certificati nello stesso progetto e nello stesso spazio dei nomi in cui viene eseguito il deployment del bilanciatore del carico.

  4. Crea una risorsa Ingress che utilizza secret o certificati precondivise. Quando crei la risorsa Ingress, GKE crea e configura un bilanciatore del carico delle applicazioni.

  5. Testa il bilanciatore del carico delle applicazioni.

Prima di iniziare

Prima di iniziare, assicurati di aver eseguito le seguenti attività:

  • Abilita l'API Google Kubernetes Engine.
  • Abilita l'API Google Kubernetes Engine
  • Se vuoi utilizzare Google Cloud CLI per questa attività, installa e initialize gcloud CLI. Se hai già installato gcloud CLI, scarica la versione più recente eseguendo gcloud components update.
  • Devi possedere due nomi di dominio. I nomi di dominio non devono contenere più di 63 caratteri.

Limitazioni

  • I certificati gestiti da Google sono supportati solo con GKE Ingress che utilizza il bilanciatore del carico delle applicazioni esterno. I certificati gestiti da Google non supportano i controller Ingress di terze parti.
  • Per gli Application Load Balancer interni, devi disabilitare HTTP nel manifest Ingress. Ciò non è necessario per il bilanciatore del carico esterno.
  • Non devi modificare o aggiornare manualmente la configurazione del bilanciatore del carico delle applicazioni. Ciò significa che non devi modificare nessuno dei componenti del bilanciatore del carico, inclusi proxy di destinazione, mappe URL e servizi di backend. Tutte le modifiche che apporti vengono sovrascritte da GKE.

Creazione di un deployment

  1. Salva il seguente manifest come 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"
    

    Questo manifest descrive un deployment con tre pod. Ogni pod ha due container. Un container esegue hello-app:1.0 e rimane in ascolto sulla porta TCP 50001. L'altro container esegue hello-app:2.0 e rimane in ascolto sulla porta TCP 50002.

  2. Applica il manifest al tuo cluster:

    kubectl apply -f my-mc-deployment.yaml
    

Crea un servizio

  1. Salva il seguente manifest come 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
    

    Questo file manifest descrive un servizio con i seguenti campi:

    • selector: specifica che tutti i pod con etichetta app: products e etichetta department: sales sono membri di questo servizio.
    • ports: specifica che quando un client invia una richiesta al servizio il giorno my-first-port, GKE la inoltra a uno dei pod membri sulla porta 50001. Quando un client invia una richiesta al servizio su my-second-port, GKE la inoltra a uno dei pod membri sulla porta 50002.
  2. Applica il manifest al tuo cluster:

    kubectl apply -f my-mc-service.yaml
    

Crea certificati e chiavi

Per eseguire gli esercizi in questa pagina, sono necessari due certificati, ciascuno con una chiave corrispondente. Ogni certificato deve avere un nome comune (CN) uguale al nome di dominio che possiedi.

Puoi creare questi certificati manualmente o utilizzare i certificati gestiti da Google.

Se hai già due file di certificato con i valori appropriati per Common Name, puoi passare alla prossima sezione.

Certificati gestiti dall'utente

  1. Crea la tua prima chiave:

    openssl genrsa -out test-ingress-1.key 2048
    
  2. Crea la tua prima richiesta di firma del certificato:

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

    Sostituisci FIRST_DOMAIN con un nome di dominio di tua proprietà, ad esempio example.com.

  3. Crea il tuo primo certificato:

    openssl x509 -req -days 365 -in test-ingress-1.csr -signkey test-ingress-1.key \
        -out test-ingress-1.crt
    
  4. Crea la tua seconda chiave:

    openssl genrsa -out test-ingress-2.key 2048
    
  5. Crea la tua seconda richiesta di firma del certificato:

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

    Sostituisci SECOND_DOMAIN con un altro nome di dominio di tua proprietà, ad esempio examplepetstore.com.

  6. Crea il tuo secondo certificato:

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

Per ulteriori informazioni su certificati e chiavi, consulta la panoramica dei certificati SSL.

Ora hai due file di certificato e due file della chiave.

Le attività rimanenti utilizzano i seguenti segnaposto per fare riferimento a domini, certificati e chiavi:

  • FIRST_CERT_FILE: il percorso del primo file di certificato.
  • FIRST_KEY_FILE: il percorso del file della chiave associato al primo certificato.
  • FIRST_DOMAIN: un nome di dominio di tua proprietà.
  • FIRST_SECRET_NAME: il nome del secret che contiene il primo certificato e la chiave.
  • SECOND_CERT_FILE: il percorso del secondo file di certificato.
  • SECOND_KEY_FILE: il percorso del file della chiave associato al secondo certificato.
  • SECOND_DOMAIN: un secondo nome di dominio di tua proprietà.
  • SECOND_SECRET_NAME: il nome del secret che contiene il secondo certificato e la chiave.

Certificati gestiti da Google

Per creare certificati gestiti da Google, devi aggiungere oggetti ManagedCertificate allo spazio dei nomi del tuo Ingress. Puoi utilizzare il seguente modello per definire i certificati per i tuoi domini:

  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

Sostituisci quanto segue:

  • FIRST_CERT_NAME: il nome del tuo primo oggetto ManagedCertificate.
  • FIRST_DOMAIN: il primo dominio di tua proprietà.
  • SECOND_CERT_NAME: il nome del secondo oggetto ManagedCertificate.
  • SECOND_DOMAIN: il secondo dominio di tua proprietà.

I nomi degli oggetti ManagedCertificate sono diversi dai nomi dei certificati effettivi che creano. Devi conoscere solo i nomi degli oggetti ManagedCertificate per utilizzarli nella tua risorsa Ingress.

Specifica i certificati per la tua risorsa Ingress

Il passaggio successivo consiste nella creazione di un oggetto Ingress. Nel manifest Ingress, puoi utilizzare uno dei seguenti metodi per fornire certificati per il bilanciatore del carico:

  • Secret
  • Certificati precondivise
  • Certificati gestiti da Google

Secret

  1. Crea un secret che contenga il tuo primo certificato e la tua prima chiave:

    kubectl create secret tls FIRST_SECRET_NAME \
        --cert=FIRST_CERT_FILE \
        --key=FIRST_KEY_FILE
    
  2. Crea un secret che contenga il secondo certificato e la chiave:

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

Crea una risorsa Ingress

  1. Salva il seguente manifest come 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
    

    Sostituisci FIRST_DOMAIN e SECOND_DOMAIN con i nomi di dominio di tua proprietà, ad esempio example.com e examplepetstore.com.

  2. Applica il manifest al tuo cluster:

    kubectl apply -f my-mc-ingress.yaml
    
  3. Descrivi il tuo Ingress:

    kubectl describe ingress my-mc-ingress
    

    L'output è simile al seguente:

    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
    

    L'output mostra che due secret sono associati alla risorsa Ingress. L'output mostra anche l'indirizzo IP esterno del bilanciatore del carico. Se l'indirizzo IP esterno non è impostato, attendi qualche minuto e riprova a eseguire il comando.

Certificati precondivise

  1. Crea un certificato:

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

    Sostituisci quanto segue:

    • FIRST_CERT_NAME: il nome del tuo primo certificato.
    • FIRST_CERT_FILE: il file del primo certificato.
    • FIRST_KEY_FILE: il tuo primo file di chiave.
  2. Crea un secondo certificato:

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

    Sostituisci quanto segue:

    • SECOND_CERT_NAME: il nome del secondo certificato.
    • SECOND_CERT_FILE: il secondo file di certificato.
    • SECOND_KEY_FILE: il secondo file di chiave.
  3. Visualizza le risorse del certificato:

    gcloud compute ssl-certificates list
    

    L'output è simile al seguente:

    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 una risorsa Ingress

  1. Salva il seguente manifest come 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
    

    Sostituisci FIRST_DOMAIN e SECOND_DOMAIN con i tuoi nomi di dominio.

    Questo manifest descrive una risorsa Ingress che elenca le risorse di certificato precondivise in un'annotazione.

  2. Applica il manifest al tuo cluster:

    kubectl apply -f my-psc-ingress.yaml
    
  3. Descrivi il tuo Ingress:

    kubectl describe ingress my-psc-ingress
    

    L'output è simile al seguente:

    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
    

    L'output mostra che la risorsa Ingress è associata a certificati precondivisi denominati FIRST_CERT_NAME e SECOND_CERT_NAME. L'output mostra anche l'indirizzo IP esterno del bilanciatore del carico. Se l'indirizzo IP esterno non è impostato, attendi qualche minuto e riprova a eseguire il comando.

Certificati gestiti da Google

Crea una risorsa Ingress

  1. Salva il seguente manifest come 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
    

    Sostituisci FIRST_DOMAIN e SECOND_DOMAIN con i tuoi nomi di dominio.

    Questo manifest descrive una risorsa Ingress che elenca le risorse di certificato precondivise in un'annotazione.

  2. Applica il manifest al tuo cluster:

    kubectl apply -f my-gmc-ingress.yaml
    
  3. Descrivi il tuo Ingress:

    kubectl describe ingress my-gmc-ingress
    

    L'output è simile al seguente:

    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
    

    L'output mostra che la risorsa Ingress è associata a certificati gestiti denominati FIRST_CERT_NAME e SECOND_CERT_NAME. GKE compila automaticamente le annotazioni ingress.gcp.kubernetes.io/pre-shared-cert e ingress.kubernetes.io/ssl-cert con i certificati gestiti da Google che hai creato utilizzando gli oggetti ManagedCertificate. L'output mostra anche l'indirizzo IP esterno del bilanciatore del carico. Se l'indirizzo IP esterno non è impostato, attendi qualche minuto e prova di nuovo a eseguire il comando.

Testa il bilanciatore del carico

Attendi circa cinque minuti per consentire a GKE di completare la configurazione del bilanciatore del carico.

Se hai utilizzato certificati gestiti da Google, il completamento della configurazione potrebbe richiedere molto più tempo, in quanto il sistema deve eseguire il provisioning dei certificati e verificare la configurazione DNS per determinati domini.

Per testare il bilanciatore del carico, devi possedere due nomi di dominio ed entrambi devono risolvere l'indirizzo IP esterno del bilanciatore del carico delle applicazioni esterno.

  1. Invia una richiesta al bilanciatore del carico utilizzando il tuo nome di dominio:

    curl -v https://FIRST_DOMAIN
    

    Potrebbe essere necessario utilizzare l'opzione curl -k per eseguire un trasferimento SSL non sicuro, in modo che curl accetti i certificati autofirmati.

    L'output è simile al seguente:

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

    Questo output mostra che il tuo primo certificato è stato utilizzato nell'handshake TLS.

  2. Invia una richiesta al bilanciatore del carico utilizzando il secondo nome di dominio:

    curl -v https://SECOND_DOMAIN
    

    L'output è simile al seguente:

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

    Questo output mostra che il secondo certificato è stato utilizzato nell'handshake TLS.

Il campo hosts di un oggetto Ingress

IngressSpec ha un campo tls, ovvero un array di oggetti IngressTLS. Ogni oggetto IngressTLS ha un campo hosts e un campo SecretName. In GKE, il campo hosts non viene utilizzato. GKE legge il nome comune (CN) a partire dal certificato nel secret. Se il nome comune corrisponde al nome di dominio in una richiesta client, il bilanciatore del carico presenta il certificato corrispondente al client.

Quale certificato viene presentato?

Il bilanciatore del carico sceglie un certificato in base a queste regole:

  • Se sia i secret che i certificati precondivise sono elencati nella risorsa Ingress, i certificati precondivisi hanno la priorità sui secret. In altre parole, i secret sono comunque inclusi, ma i certificati precondivisi vengono presentati per primi.

  • Se nessun certificato ha un nome comune (CN) che corrisponde al nome di dominio nella richiesta client, il bilanciatore del carico presenta il certificato principale.

  • Per i secret elencati nel blocco tls, il certificato principale si trova nel primo Secret dell'elenco.

  • Per i certificati precondivisi elencati nell'annotazione, il certificato principale è il primo certificato nell'elenco.

Best practice per la rotazione dei certificati

Se vuoi ruotare i contenuti del secret o del certificato precondiviso, ecco alcune best practice:

  • Crea un nuovo secret o un certificato precondiviso con un nome diverso che contenga i dati del nuovo certificato. Collega questa risorsa (insieme a quella esistente) a Ingress utilizzando le istruzioni fornite in precedenza. Se le modifiche ti soddisfano, puoi rimuovere il certificato precedente da Ingress.
  • Se non ti dispiace interrompere il traffico, puoi rimuovere la risorsa precedente da Ingress, eseguire il provisioning di una nuova risorsa con lo stesso nome ma contenuti diversi e quindi ricollegarla all'oggetto Ingress.
Per evitare di gestire autonomamente la rotazione dei certificati, consulta Utilizzare i certificati SSL gestiti da Google.

Risoluzione dei problemi

Se specifichi secret non validi o inesistenti, viene restituito un errore di evento Kubernetes. Puoi controllare gli eventi Kubernetes per un Ingress nel seguente modo:

kubectl describe ingress

L'output è simile al seguente:

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'

Passaggi successivi

  • Se hai un'applicazione in esecuzione su più cluster GKE in diverse regioni, configura un'impostazione Ingress multi-cluster per instradare il traffico a un cluster nella regione più vicina all'utente.