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 le richieste HTTPS dai tuoi client, il bilanciatore del carico delle applicazioni deve avere un certificato per poter dimostrare la sua identità ai tuoi client. Il bilanciatore del carico deve avere anche una chiave privata per completare l'handshake HTTPS.

Quando il bilanciatore del carico accetta una richiesta HTTPS da un client, il traffico tra il client e il bilanciatore del carico viene criptato utilizzando 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 15 certificati TLS al client.

Il bilanciatore del carico utilizza l'indicazione del nome del server (SNI) per determinare quale certificato presentare al client, in base al nome di dominio nell'handshake TLS. Se il client non utilizza SNI o se 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 in 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 di più certificati SSL con Ingress

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

  • Certificati SSL gestiti da Google. Per informazioni su come utilizzarli, consulta la pagina dei certificati gestiti.

  • Google Cloud Certificato SSL che gestisci personalmente. 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 che crei tu. Aggiungi il nome del secret al campo tls del manifest Ingress.

Puoi utilizzare più di un metodo nello stesso Ingress. Ciò consente migrazioni senza tempi di inattività tra i metodi.

Panoramica globale

Ecco una panoramica dei passaggi descritti in questo documento:

  1. Crea un deployment.

  2. Crea un servizio.

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

  4. Crea un Ingress che utilizzi secret o certificati precondivisi. Quando crei 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 operazioni:

  • Attiva l'API Google Kubernetes Engine.
  • Attiva l'API Google Kubernetes Engine
  • Se vuoi utilizzare Google Cloud CLI per questa attività, installala e poi inizializza gcloud CLI. Se hai già installato gcloud CLI, scarica l'ultima versione eseguendo il comando gcloud components update. Le versioni precedenti di gcloud CLI potrebbero non supportare l'esecuzione dei comandi in questo documento.
  • Devi essere proprietario di due nomi di dominio. I nomi di dominio non devono superare i 63 caratteri.
  • Assicurati di avere un cluster Autopilot o Standard esistente. Per creare un nuovo cluster, consulta Creare un cluster Autopilot.

Limitazioni

  • I certificati gestiti da Google sono supportati solo con GKE Ingress utilizzando il bilanciatore del carico delle applicazioni esterno. I certificati gestiti da Google non supportano i controller Ingress di terze parti.

  • Per i bilanciatori del carico delle applicazioni interni, devi disattivare HTTP nel manifest Ingress. 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 apportate 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 cluster:

    kubectl apply -f my-mc-deployment.yaml 

Creare 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 manifest descrive un servizio con i seguenti campi:

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

    kubectl apply -f my-mc-service.yaml 

Crea certificati e chiavi

Per svolgere gli esercizi in questa pagina, hai bisogno di due certificati, ognuno con una chiave corrispondente. Ogni certificato deve avere un nome comune (CN) uguale a un nome di dominio di tua proprietà.

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

Se hai già due file di certificato con i valori appropriati per il nome comune, puoi passare alla sezione successiva.

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

    openssl genrsa -out test-ingress-2.key 2048 
  5. Crea la 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 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 di chiave.

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

  • FIRST_CERT_FILE: il percorso del primo file del 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 contenente il primo certificato e la prima chiave.
  • SECOND_CERT_FILE: il percorso del secondo file del 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 contenente il secondo certificato e la seconda 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 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. Per utilizzarli in Ingress, ti basta conoscere i nomi degli oggetti ManagedCertificate.

Specificare i certificati per Ingress

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

  • Secret
  • Certificati precondivisi
  • Certificati gestiti da Google

Secret

  1. Crea un secret che contenga il primo certificato e la 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 seconda 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 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 all'ingresso. 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 precondivisi

  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 primo certificato.
    • FIRST_CERT_FILE: il tuo primo file del certificato.
    • FIRST_KEY_FILE: il primo file della 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 del certificato.
    • SECOND_KEY_FILE: il secondo file della 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 un Ingress che elenca le risorse dei certificati precondivisi in un'annotazione.

  2. Applica il manifest al 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 l'ingresso è associato 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 un Ingress che elenca le risorse dei certificati precondivisi in un'annotazione.

  2. Applica il manifest al 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 l'ingresso è associato 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 riprova a eseguire il comando.

testa il bilanciatore del carico

Attendi circa cinque minuti affinché GKE completi la configurazione del bilanciatore del carico.

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

Per testare il bilanciatore del carico, devi essere proprietario di 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 primo nome di dominio:

    curl -v https://FIRST_DOMAIN 

    Potresti dover 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 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

Un IngressSpec ha un campo tls che è 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) 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 in Ingress sono elencati sia i secret che i certificati precondivisi, i certificati precondivisi hanno la priorità sui secret. In altre parole, i segreti sono ancora 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 del 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 ingress.gcp.kubernetes.io/pre-shared-cert, l'ordine in cui elenchi i certificati determina il certificato principale. Il certificato principale, presentato quando nessun altro certificato corrisponde alla richiesta del client, è il primo certificato elencato nell'annotazione.

  • Quando utilizzi i certificati gestiti da Google, tutti i certificati elencati nell'annotazione networking.gke.io/managed-certificates vengono ordinati automaticamente in ordine alfabetico per nome. Il certificato principale è il primo in questo elenco alfabetico. Per impostare un certificato specifico come principale, devi denominare gli oggetti ManagedCertificate di conseguenza per controllare l'ordine di ordinamento. Ad esempio, per impostare my-default-cert come principale rispetto a another-cert, puoi chiamarli 0-my-default-cert e 1-another-cert.

Best practice per la rotazione dei certificati

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

  • Crea un nuovo secret o un nuovo certificato precondiviso con un nome diverso che contenga i nuovi dati del certificato. Allega questa risorsa (insieme a quella esistente) all'ingresso seguendo le istruzioni fornite in precedenza. Una volta soddisfatto delle modifiche, puoi rimuovere il vecchio certificato da Ingress.
  • Se non ti preoccupa interrompere il traffico, puoi rimuovere la vecchia risorsa da Ingress, eseguire il provisioning di una nuova risorsa con lo stesso nome ma contenuti diversi e poi ricollegarla a Ingress.

Per evitare di gestire autonomamente la rotazione dei certificati, consulta la sezione Utilizzare certificati SSL gestiti da Google.

Risoluzione dei problemi

La specifica di secret non validi o inesistenti genera 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