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

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Questa pagina mostra come utilizzare più certificati SSL per Ingress con bilanciamento del carico interno ed esterno.

Panoramica

Se vuoi accettare richieste HTTPS dai tuoi client, il bilanciatore del carico HTTP(S) interno o esterno deve avere un certificato in modo che possa dimostrare la propria identità ai tuoi 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 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 HTTP(S) tramite Ingress, puoi configurarlo in modo che mostri fino a dieci 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 la funzione 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 in Ingress. Il seguente diagramma illustra il bilanciatore del carico che invia il traffico a backend diversi, a seconda del nome di dominio utilizzato nella richiesta:

più certificati SSL con diagramma di sistema di Ingress

Puoi fornire un bilanciatore del carico HTTPS con certificati SSL utilizzando uno dei tre metodi:

  • Certificati SSL gestiti da Google. Consulta la pagina dei certificati gestiti per informazioni su come utilizzarli.

  • Il certificato SSL Google Cloud che gestisci autonomamente. Utilizza un certificato pre-condiviso precedentemente caricato nel tuo progetto Google Cloud.

  • Secret di Kubernetes. Il secret contiene un certificato e una chiave che crei personalmente. Per utilizzare un secret, aggiungine il nome nel campo tls del manifest Ingress.

Puoi utilizzare più di un metodo nella stessa risorsa Ingress. Questo consente migrazioni senza tempo di inattività tra i metodi.

Versione minima di GKE

Per utilizzare i certificati precondivisi o per specificare più certificati in una risorsa Ingress, devi avere GKE versione 1.10.2 o successiva.

Prerequisiti

Per eseguire gli esercizi in questa pagina, devi possedere due nomi di dominio. Puoi utilizzare Google Domains o un altro registrar.

Panoramica globale

Ecco una panoramica dei passaggi da seguire in questo argomento:

  1. Crea un deployment.

  2. Creare un Service.

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

  4. Creare una risorsa Ingress che utilizzi secret o certificati precondivise. Alla creazione di Ingress, GKE crea e configura un bilanciatore del carico HTTP(S).

  5. Testare il bilanciatore del carico HTTP(S).

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 poi inizializza l'interfaccia a riga di comando gcloud.

Creazione di un deployment

Di seguito è riportato un manifest per un deployment:

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"

Il deployment ha tre pod e 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.

Copia il manifest in un file denominato my-mc-deployment.yaml e crea il deployment:

kubectl apply -f my-mc-deployment.yaml

Crea un Service

Ecco un manifest per un servizio:

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

Il campo selector nel manifest del servizio indica qualsiasi pod con l'etichetta app: products e l'etichetta department: sales è membro di questo servizio. Quindi i pod del deployment che hai creato nel passaggio precedente sono membri del servizio.

Il campo ports del manifest del servizio è un array di oggetti ServicePort. Quando un client invia una richiesta al servizio su my-first-port, la richiesta viene inoltrata a uno dei pod membri sulla porta 50001. Quando un client invia una richiesta al servizio su my-second-port, la richiesta viene inoltrata a uno dei pod membri sulla porta 50002.

Copia il manifest in un file denominato my-mc-service.yaml e crea il servizio:

kubectl apply -f my-mc-service.yaml

Creazione di certificati e chiavi

Per eseguire gli esercizi in questa pagina, hai bisogno di due certificati, ciascuno 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 i certificati gestiti da Google. Se hai già due file di certificato con i valori appropriati per Common Name, puoi andare direttamente 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à.

    Supponi, ad esempio, che vuoi che il bilanciatore del carico gestisca le richieste provenienti dal dominio example.com. La richiesta di firma del certificato sarà simile a questa:

    openssl req -new -key test-ingress-1.key -out test-ingress-1.csr \
        -subj "/CN=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à.

    Supponi, ad esempio, che vuoi che il bilanciatore del carico gestisca le richieste provenienti dal dominio examplepetstore.com. La richiesta di firma del certificato sarà simile a questa:

    openssl req -new -key test-ingress-2.key -out test-ingress-2.csr \
        -subj "/CN=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 sui certificati e sulle chiavi, consulta la Panoramica dei certificati SSL.

Ora hai due file di certificato e due file 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 che contiene la prima chiave e il primo certificato.
  • 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 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 della tua risorsa 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à.

Specificare i certificati per la risorsa Ingress

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

  • Secret
  • Certificati precondivisi
  • Certificati gestiti da Google

Scegli uno dei metodi selezionando una delle schede:

Secret

Creazione dei secret

  1. Crea un Secret che contenga il primo certificato e la 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
    

Creare una risorsa Ingress

Di seguito è riportato un manifest per una risorsa 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:
              number: 60001
  - host: SECOND_DOMAIN
    http:
      paths:
      - pathType: ImplementationSpecific
        backend:
          service:
            name: my-mc-service
            port:
              number: 60002
  1. Copia il file manifest in un file denominato my-mc-ingress.yaml. Sostituisci FIRST_DOMAIN e SECOND_DOMAIN con i nomi di dominio di tua proprietà, ad esempio example.com e examplepetstore.com.

  2. Crea la risorsa Ingress:

    kubectl apply -f my-mc-ingress.yaml
    

    Quando crei una risorsa Ingress, il controller Ingress di GKE crea un bilanciatore del carico HTTP(S). Attendi un minuto che GKE assegni un indirizzo IP esterno al bilanciatore del carico.

  3. Descrivi la tua risorsa Ingress:

    kubectl describe ingress my-mc-ingress
    

    L'output mostra che due Secret sono associati alla risorsa Ingress. L'output mostra anche l'indirizzo IP esterno del bilanciatore del carico.

    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
    

Concerti precondivisi

Creazione di certificati precondivisi

  1. Crea una risorsa del certificato nel tuo progetto Google Cloud:

    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 tuo primo file della chiave.
  2. Crea una seconda risorsa del certificato nel tuo progetto Google Cloud:

    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. Visualizzare le risorse del certificato:

    gcloud compute ssl-certificates list
    

    L'output mostra che hai risorse dei certificati denominate FIRST_CERT_NAME e 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
    

Creazione di Ingress GKE

Di seguito è riportato un manifest per una risorsa Ingress che elenca le risorse del certificato precondivise in un'annotazione:

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
  1. Copia il file manifest in un file denominato my-psc-ingress.yaml. Sostituisci FIRST_DOMAIN e SECOND_DOMAIN con i nomi di dominio.

  2. Crea la risorsa Ingress:

    kubectl apply -f my-psc-ingress.yaml
    

    Attendi un minuto che GKE assegni un indirizzo IP esterno al bilanciatore del carico.

  3. Descrivi la tua risorsa Ingress:

    kubectl describe ingress my-psc-ingress
    

    L'output mostra che la risorsa Ingress è associata ai certificati precondivisi denominati FIRST_CERT_NAME e SECOND_CERT_NAME. L'output mostra anche l'indirizzo IP esterno del bilanciatore del carico:

    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
    

Certificati gestiti da Google

Creazione di Ingress GKE

Di seguito è riportato un manifest per una risorsa Ingress che elenca le risorse del certificato precondivise in un'annotazione:

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
  1. Copia il file manifest in un file denominato my-gmc-ingress.yaml. Sostituisci FIRST_DOMAIN e SECOND_DOMAIN con i nomi di dominio.

  2. Crea la risorsa Ingress:

    kubectl apply -f my-gmc-ingress.yaml
    

    Attendi un minuto che GKE assegni un indirizzo IP esterno al bilanciatore del carico.

  3. Descrivi la tua risorsa Ingress:

    kubectl describe ingress my-gmc-ingress
    

    L'output mostra che la risorsa Ingress è associata ai 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 in modo che puntino ai certificati gestiti da Google creati utilizzando gli oggetti ManagedCertificate. L'output mostra anche l'indirizzo IP esterno del bilanciatore del carico:

    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
    

Test del bilanciatore del carico

Attendi circa cinque minuti che GKE completi la configurazione del bilanciatore del carico. Nel caso di 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 determinati domini.

Per eseguire questo passaggio, devi possedere due nomi di dominio ed entrambi devono risolvere l'indirizzo IP esterno del bilanciatore del carico HTTP(S).

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

curl -v https://FIRST_DOMAIN

L'output mostra che il primo certificato è stato utilizzato nell'handshake TLS. Se il tuo primo dominio è example.com, l'output è simile al seguente:

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

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

curl -v https://SECOND_DOMAIN

L'output mostra che il secondo certificato è stato utilizzato nell'handshake TLS. Se il tuo secondo dominio è examplepetstore.com, l'output è simile al seguente:

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

Il campo hosts di un oggetto Ingress

Un IngressSpec ha un campo tls che è un array di oggetti IngressTLS. Ogni oggetto IngressTLS include 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 sia i secret sia i certificati precondivisi sono elencati in Ingress, i certificati precondivisati 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) corrispondente 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 nell'elenco.

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

Best practice per la rotazione dei certificati

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

  • Crea un nuovo certificato Secret o pre-condiviso con un nome diverso contenente i dati del nuovo certificato. Associa questa risorsa (insieme a quella esistente) alla risorsa Ingress seguendo le istruzioni fornite in precedenza. Una volta apportate le modifiche necessarie, puoi rimuovere il vecchio certificato dalla risorsa Ingress.
  • Se non vuoi interrompere il traffico, puoi rimuovere la vecchia risorsa dalla risorsa Ingress, eseguire il provisioning di una nuova risorsa con lo stesso nome ma contenuti diversi e quindi ricollegarla alla risorsa Ingress.

Per evitare di gestire autonomamente la rotazione dei certificati, consulta la funzionalità SSL gestito da Google.

Risolvere i problemi

Se viene specificato un Secret non valido o inesistente, viene visualizzato un errore di evento di Kubernetes. Puoi controllare gli eventi Kubernetes per una risorsa Ingress come segue:

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