Implementazione di riferimento del bilanciamento del carico di livello 7 di NGINX

Google Distributed Cloud (GDC) con air gap fornisce un bilanciatore del carico gestito integrato di livello 4 (L4), ma molte applicazioni aziendali richiedono funzionalità avanzate di livello 7 (L7), come il routing basato sull'host, la gestione TLS centralizzata e la suddivisione del traffico complessa. In passato, questo obiettivo veniva raggiunto utilizzando l'API Ingress, che ora è considerata in fase di blocco delle funzionalità nella community di Kubernetes.

Questa architettura di riferimento fornisce una soluzione di bilanciamento del carico di livello 7 autogestita. Eseguendo il deployment del popolare controller open source NGINX Gateway Fabric su un cluster GDC Standard, i clienti possono instradare senza problemi il traffico L7 verso ambienti ibridi. Questa architettura utilizza la terminazione TLS (HTTPRoute) per instradare il traffico in base all'indicazione del nome del server (SNI) sia ai pod containerizzati integrati sia alle applicazioni ospitate su macchine virtuali esterne.

Architettura

Diagramma dell'architettura per il bilanciamento del carico di livello 7 di NGINX su GDC con air gap.

I componenti chiave della soluzione includono:

  • Client: un'entità che avvia richieste HTTPS per interagire con le applicazioni.
  • Cluster GDC Standard: GDC fornisce un modo integrato per creare cluster Kubernetes Vanilla. In questa soluzione, il cluster ospiterà il bilanciatore del carico L7 e i relativi controller, insieme ai workload e al servizio headless per le VM esterne
  • Bilanciatore del carico L4 di GDC: il bilanciatore del carico L4 integrato funge da punto di ingresso e distribuisce il traffico TCP/443 direttamente ai pod Kubernetes che eseguono i controller gateway.
  • Controller gateway: operatori NGINX in esecuzione nel cluster Standard. Monitorano le risorse dell'API Gateway (come Gateway e HTTPRoute) e aggiornano dinamicamente i proxy sottostanti. Per la soluzione verrà utilizzato Nginx Gateway Fabric.
  • Gateway (con HTTPRoute): risorse Kubernetes standardizzate che definiscono la porta di ascolto fisica (443) e le regole di instradamento dell'host basate su SNI con terminazione TLS.
  • Workload containerizzato (pod): un deployment Kubernetes standard esposto internamente con un Service Kubernetes standard.
  • Workload basato su VM (esterno): un workload ospitato su una VM esterna nella rete del progetto, esposto al proxy con un Service Kubernetes headless e un endpoint personalizzato contenente l'IP diretto della VM.
  • Harbor Registry: un Container Registry privato utilizzato per archiviare ed erogare le immagini del proxy e dell'applicazione nell'ambiente con air gap.

Nel cluster Standard, crei quattro spazi dei nomi:

  • Lo spazio dei nomi nginx-gateway che ospita le risorse Nginx Gateway Fabric:

    Le risorse dello spazio dei nomi nginx-gateway.

  • Lo spazio dei nomi load-balancer che ospita le risorse Gateway:

    Le risorse dello spazio dei nomi del bilanciatore del carico.

  • Lo spazio dei nomi vm-app ospita l'IP VM esterno vm-app, un servizio headless, un EndpointSlice che punta all'IP esterno e un HTTPRoute per Gateway:

    Le risorse dello spazio dei nomi vm-app.

  • Lo spazio dei nomi hello-app ospita Deployment, Service, HTTPRoute e Gateway per il workload del container demo:

    Le risorse dello spazio dei nomi hello-app.

Prima di iniziare

Prima di eseguire il deployment di questa soluzione, assicurati di soddisfare i seguenti prerequisiti:

  • Software necessario: helm, docker, kubectl
  • Accesso tramite interfaccia a riga di comando e configurazione locale: scarica l'interfaccia a riga di comando gdcloud dalla console GDC e configura l'ambiente localmente.

    export USER_NAME="USER_NAME"
    export PROJECT_ID="PROJECT_ID"
    export ZONE="ZONE"
    export ORG_NAME="ORG_NAME"
    export GDC_URL="GDC_URL"
    
    gdcloud components install gdcloud-k8s-auth-plugin
    
    gdcloud config set core/organization_console_url \
      https://console.$ORG_NAME.$ZONE.$GDC_URL
    gdcloud config set core/zone $ZONE
    gdcloud config set core/project ${PROJECT_ID}
    
    gdcloud auth login # use --login-config-cert option in case of TLS error
    
  • Configurazione del progetto: crea un progetto nel tuo ambiente GDC con air gap per contenere le risorse.

    gdcloud projects create $PROJECT_ID
    
  • Ruoli IAM: concedi al tuo utente i ruoli Cluster Admin e Standard Cluster Admin per gestire le risorse Kubernetes e il ruolo Harbor Instance Admin per eseguire il push delle immagini.

    # Grant standard cluster and cluster admin roles
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=cluster-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=standard-cluster-admin
    
    # Grant Harbor instance admin role
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=harbor-instance-admin
    

crea un cluster standard

Questa sezione ti guida nella procedura di configurazione di un cluster Kubernetes standard all'interno del tuo ambiente GDC con air gap. Un cluster standard fornisce una base flessibile e solida per il deployment di vari workload, tra cui il controller gateway Nginx e le tue applicazioni personalizzate. I passaggi seguenti garantiranno che il cluster sia configurato correttamente e accessibile per i deployment successivi.

  1. Identifica i tipi di immagini delle macchine virtuali disponibili eseguendo:

    gdcloud compute machine-types list
    
  2. Seleziona un tipo di macchina appropriato per i nodi worker del cluster. Per questo tutorial, è consigliato un tipo di macchina con almeno 4 vCPU.

    export MACHINE_TYPE="MACHINE_TYPE"
    
  3. Recupera il kubeconfig del server API di gestione e imposta un alias:

    export CLUSTER_NAME="CLUSTER_NAME"
    
    KUBECONFIG=kubeconfig-admin.yaml gdcloud clusters \
      get-credentials ${ORG_NAME}-admin
    
    alias km="kubectl --kubeconfig kubeconfig-admin.yaml"
    
  4. Crea un cluster standard con 2 nodi worker:

    km create -f - <<EOF
    apiVersion: cluster.gdc.goog/v1
    kind: Cluster
    metadata:
      name: ${CLUSTER_NAME}
      namespace: ${PROJECT_ID}
    spec:
      nodePools:
      - machineTypeName: ${MACHINE_TYPE}
        nodeCount: 2
        name: ${CLUSTER_NAME}-node-pool
    EOF
    

    Per maggiori dettagli sulle opzioni disponibili, consulta la documentazione.

    La creazione di un cluster standard può richiedere fino a 60 minuti. Per controllare lo stato, utilizza il seguente comando:

    km get clusters/${CLUSTER_NAME} \
      -n ${PROJECT_ID} \
      --watch
    

    Una volta che il cluster è pronto, l'output dovrebbe mostrare lo stato In esecuzione, come questo:

    NAME         STATE     K8S VERSION
    my-cluster   Running   1.30.12-gke.300
    
  5. Quando il cluster è pronto, recupera le relative credenziali:

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \
      get-credentials ${CLUSTER_NAME} \
      --standard \
      --project ${PROJECT_ID} \
      --zone ${ZONE}
    
  6. Crea un alias per mantenere i comandi kubectl più concisi nel resto di questa guida. Questo alias verrà utilizzato per interagire con il cluster standard:

    alias kk="kubectl --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml"
    
  7. Crea gli spazi dei nomi per il controller, l'app containerizzata demo "hello-app" e l'app demo basata su VM:

    kk create namespace load-balancer
    kk create namespace hello-app
    kk create namespace vm-app
    

Crea e integra il registro Harbor

Harbor è un registry di immagini container con supporto integrato in GDC con air gap. Questa sezione illustra i passaggi per integrare un registro Harbor con il tuo cluster standard, inclusa la configurazione di credenziali e secret per consentire il pull e il push sicuri delle immagini.

  1. Crea un'istanza Harbor nel tuo progetto.
  2. Crea un progetto Harbor nella tua istanza Harbor.
  3. Imposta le variabili di ambiente:

    export HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME"
    export HARBOR_INSTANCE_URL="HARBOR_INSTANCE_URL"
    export HARBOR_PROJECT="HARBOR_INSTANCE_PROJECT"
    export IMAGE_PULL_SECRET_NAME="harbor-secret"
    
  4. Accedi all'istanza Harbor utilizzando un account robot:

    docker --config=./docker login ${HARBOR_INSTANCE_URL}
    
  5. Crea i secret nel cluster standard:

    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n load-balancer
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n hello-app
    

Esegui il deployment dell'app containerizzata demo

Questa sezione descrive in dettaglio il deployment di un'applicazione containerizzata demo (hello-app) all'interno del tuo cluster Kubernetes GDC con air gap. Creerai le risorse di deployment e servizio Kubernetes necessarie per eseguire hello-app ed esporlo internamente al cluster, preparandolo per l'accesso tramite il bilanciatore del carico L7.

  1. Carica un'immagine di esempio per l'app containerizzata demo in Harbor:

    docker pull gcr.io/google-samples/hello-app:1.0 \
      --platform linux/amd64
    docker tag gcr.io/google-samples/hello-app:1.0 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    
  2. Esegui il deployment del seguente manifest nel cluster Standard:

    cat << EOF > hello-app.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: hello-app
      template:
        metadata:
          labels:
            app: hello-app
        spec:
          containers:
          - name: hello-server
            image: ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
            ports:
            - containerPort: 8080
          imagePullSecrets:
          - name: ${IMAGE_PULL_SECRET_NAME}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      type: ClusterIP
      selector:
        app: hello-app
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
    EOF
    
    kk apply -f hello-app.yaml
    

Poi verifica che il deployment e il servizio siano presenti:

kk get svc,deploy -n hello-app

Esegui il deployment dell'app demo in una VM

Questa sezione descrive in dettaglio il deployment di un'applicazione demo all'interno di una macchina virtuale (VM) esterna al cluster Kubernetes. Configurando un server HTTP su una VM, simulerai un'applicazione esterna che il bilanciatore del carico può esporre, dimostrando la sua capacità di gestire il traffico verso le risorse sia all'interno che all'esterno del cluster.

Innanzitutto, crea una VM per l'app demo

  1. Apri la console GDC nel browser web.
  2. Seleziona lo stesso progetto in cui hai creato il cluster Kubernetes standard.
  3. Apri il menu, quindi fai clic su Macchine virtuali.
  4. Fai clic su Crea istanza.
  5. Assegna alla VM il nome vm-workload. Un'immagine con 2 vCPU è sufficiente per l'esempio.
  6. Per l'immagine disco di avvio, seleziona una distribuzione Ubuntu 22.04, che include Python preinstallato.
  7. Fai clic su Crea.
  8. Attendi qualche minuto finché la VM non è pronta.
  9. Stabilisci una connessione SSH alla VM:
    1. Nella console GDC, fai clic sulla VM.
    2. Fai clic su Connetti con SSH.

Dopo aver eseguito la connessione alla console SSH, esegui questo comando:

mkdir ~/simple-server
cd ~/simple-server
echo 'Welcome to my VM!' > index.html
python3 -m http.server --bind 0.0.0.0 8080 &

Per instradare il traffico a una VM, crea un servizio headless (senza selettori). Questo indirizzo verrà mappato manualmente all'indirizzo IP interno della VM utilizzando una risorsa EndpointSlice.

kk apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: vm-app-svc
  namespace: vm-app
spec:
  ports:
  - protocol: TCP
    port: 443
    targetPort: 443
EOF

Ottieni l'indirizzo IP della VM vm-workload eseguendo questo comando:

gdcloud compute instances list --project ${PROJECT_ID} \
  | grep workload-vm | awk '{print $3}'

L'output sarà l'indirizzo IP della VM necessario per configurare la risorsa EndpointSlice.

Crea la risorsa EndpointSlice che si connetterà al servizio senza selettore VM-app e indirizza l'IP della VM a cui deve essere instradato il traffico.

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: vm-app-endpoints
  namespace: vm-app
  labels:
    kubernetes.io/service-name: vm-app-svc
addressType: IPv4
ports:
  - port: 8080
endpoints:
  - addresses:
    - "VM_IP"
    conditions:
      ready: true

Crea certificati autofirmati

Questa sezione ti guida nella procedura di generazione di certificati TLS autofirmati per le tue applicazioni. Questa guida utilizza certificati autofirmati per comodità, ma negli ambienti di produzione devi utilizzare certificati di livello di produzione, come descritto in (Facoltativo) Utilizza certificati pronti per la produzione. Questi certificati sono fondamentali per abilitare la terminazione HTTPS nel gateway Nginx, garantendo una comunicazione criptata tra i client e il bilanciatore del carico per i workload containerizzati e basati su VM.

  1. Crea un certificato per l'app containerizzata:

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-containerized.key \
      -out tls-containerized.crt \
      -subj "/CN=k8s-app.example.com" \
      -days 365
    
    kk create secret tls tls-containerized \
      --namespace load-balancer \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
    kk create secret tls tls-containerized \
      --namespace hello-app \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
  2. Crea un certificato per l'app VM:

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-vm.key \
      -out tls-vm.crt \
      -subj "/CN=vm-app.example.com" \
      -days 365
    
    kk create secret tls tls-vm \
      --namespace load-balancer \
      --key tls-vm.key \
      --cert tls-vm.crt
    
    kk create secret tls tls-vm \
      --namespace vm-app \
      --key tls-vm.key \
      --cert tls-vm.crt
    

Esegui il deployment di NGINX

Questa sezione descrive i passaggi per eseguire il deployment di Nginx Gateway Controller, tra cui l'installazione delle definizioni di risorse personalizzate (CRD) dell'API Gateway, la configurazione di Nginx Gateway Fabric utilizzando Helm e la verifica dell'installazione all'interno del cluster standard. In questo modo, l'infrastruttura viene preparata per il routing avanzato di livello 7.

Installa i CRD dell'API Gateway

L'API Gateway richiede l'installazione delle definizioni di risorse personalizzate (CRD) nel cluster prima di eseguire il deployment del controller. Utilizzeremo le definizioni di risorse personalizzate (CRD) sperimentali ufficiali del progetto API Gateway (per questa guida viene utilizzata la versione 1.2.0).

  1. Installa le CRD sperimentali:

    kk apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml
    
  2. Verifica che i CRD siano installati correttamente eseguendo kk get crd gateways.gateway.networking.k8s.io.

Installa NGINX Gateway Fabric

Esegui il deployment del controller NGINX Gateway Fabric utilizzando Helm. Questo controller monitorerà le risorse dell'API Gateway e configurerà NGINX per gestire il traffico.

  1. Imposta il tag dell'immagine NGINX:

    helm template nfg oci://ghcr.io/nginx/charts/nginx-gateway-fabric | grep "image:" # get the tag of the nginx-gateway-fabric (in following case 2.4.2)
    
    export NGINX_TAG="2.4.2"
    
  2. Esegui il pull delle immagini NGINX Gateway Fabric e NGINX, quindi eseguine il push nel tuo registry Harbor:

    docker pull ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG}
    docker tag ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG} \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    
    docker pull nginx:1.27.3
    docker tag nginx:1.27.3 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    
  3. Cuga lo spazio dei nomi nginx-gateway e aggiungi il secret di pull dell'immagine Harbor:

    kk create namespace nginx-gateway
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n nginx-gateway
    
  4. Esegui il deployment di NGINX Gateway Fabric con Helm, puntando alle immagini nel tuo registry Harbor:

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml helm upgrade --install ngf \
      oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
      --create-namespace -n nginx-gateway \
      --set nginxGateway.image.tag="${NGINX_TAG}" \
      --set nginxGateway.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric" \
      --set nginx.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx" \
      --set nginxGateway.serviceAccount.imagePullSecret="${IMAGE_PULL_SECRET_NAME}" \
      --set nginx.imagePullSecret="${IMAGE_PULL_SECRET_NAME}"
    

    Il deployment di Kubernetes esegue il pull delle immagini da Harbor in modo sicuro utilizzando il secret fornito (${IMAGE_PULL_SECRET_NAME}), che contiene le credenziali dell'account robot di Harbor.

  5. Verifica che le risorse GatewayClass siano accettate:

    kk get gatewayclass
    

    Dovresti vedere nginx elencato con ACCEPTED = True.

Crea l'istanza Gateway

Definisci l'istanza del bilanciatore del carico logico in ascolto sulla porta 443. Lo configureremo per la modalità Terminate, il che significa che il gateway eseguirà la terminazione TLS e decripterà il traffico prima di trasmetterlo.

Crea e applica gateway.yaml:

cat << EOF > gateway.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: load-balancer
spec:
  gatewayClassName: nginx
  listeners:
  - name: https-k8s-workload
    hostname: "k8s-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-containerized 
  - name: https-vm-workload
    hostname: "vm-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-vm 
EOF

kk apply -f gateway.yaml

Verifica che il deployment del gateway sia andato a buon fine controllando se PROGRAMMED è True:

kk get gateway my-gateway --n load-balancer

Verifica che sia stato eseguito il deployment di un bilanciatore del carico L4 GDC gestito come servizio insieme al gateway

kk get services -n load-balancer

Verifica che il servizio Nginx sia stato creato e configurato. L'output dovrebbe essere simile a questo:

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)         AGE
my-gateway-nginx   LoadBalancer   10.252.19.148   10.200.32.43   443:30649/TCP   45h

Definisci la logica di routing L7 (HTTPRoute)

Associa HTTPRoute al tuo gateway per definire come deve essere distribuito il traffico in base al nome host richiesto (SNI).

Crea e applica routing.yaml:

cat << EOF > routing.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: k8s-http-route
  namespace: hello-app
spec:
  parentRefs:
  - name: my-gateway 
    namespace: load-balancer
  hostnames:
  - "k8s-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: hello-app 
      namespace: hello-app
      port: 80          
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: vm-http-route
  namespace: vm-app
spec:
  parentRefs:
  - name: my-gateway
    namespace: load-balancer
  hostnames:
  - "vm-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: vm-app-svc  
      namespace: vm-app
      port: 443       
EOF

kk apply -f routing.yaml   

Recupera l'IP del bilanciatore del carico

Esegui il comando per ottenere l'IP del bilanciatore del carico Nginx

kk get services/my-gateway-nginx \
  -n load-balancer \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Queste informazioni saranno necessarie per verificare l'accesso alle app. Questo verrà chiamato LOAD_BALANCER_IP.

Crea una VM client

Segui i passaggi per creare una VM client

  1. Apri la console GDC nel browser web.
  2. Apri il menu, quindi fai clic su Macchine virtuali.
  3. Fai clic su Crea istanza.
  4. Crea una VM denominata client, seleziona un tipo di macchina di piccole dimensioni e seleziona Rocky Linux o Ubuntu, che hanno curl preinstallato.
  5. Fai clic su Crea.
  6. Attendi qualche minuto finché la VM non è pronta.
  7. Dopo che la VM è pronta, stabilisci una connessione SSH alla VM:
    1. Nella console GDC, fai clic sulla VM.
    2. Fai clic su Connetti con SSH.

Verifica l'accesso verificato e il routing

Per testare il routing, esegui i comandi curl dalla VM client. Puoi connetterti a entrambe le applicazioni utilizzando i relativi nomi host definiti con l'indirizzo IP del bilanciatore del carico.

Se passi il flag --resolve in curl, puoi forzare la risoluzione dei nomi di dominio all'indirizzo IP del bilanciatore del carico L4 di GDC con air gap. Tieni presente che passiamo il flag -k per considerare attendibili i certificati autofirmati.

Testa l'app containerizzata di Kubernetes:

curl -k --resolve k8s-app.example.com:443:$LOAD_BALANCER_IP https://k8s-app.example.com -v

Testa l'app della VM esterna:

curl -k --resolve vm-app.example.com:443:$LOAD_BALANCER_IP https://vm-app.example.com -v

Se configurato correttamente, il controller del gateway fungerà perfettamente da terminatore TLS e trasmetterà il traffico alla destinazione.

(Facoltativo) Utilizza certificati pronti per la produzione

Questa sezione spiega come utilizzare il servizio CA di GDC air-gapped per creare un'autorità di certificazione (CA) radice privata, emettere certificati firmati per i tuoi workload e aggiornare in modo sicuro il cluster standard GDC air-gapped e le VM client.

Questa sezione descrive come utilizzare il servizio CA GDC con air gap per creare un'autorità di certificazione radice (CA) privata ed emettere certificati validi per le tue applicazioni. Installando questa CA radice sulla VM client, puoi verificare che la terminazione TLS funzioni perfettamente con i certificati attendibili, senza dover ignorare gli avvisi SSL (ad esempio, utilizzando curl -k).

Concedi le autorizzazioni necessarie e ottieni le credenziali

Per gestire CA Service ed emettere certificati, l'utente deve disporre dei ruoli IAM appropriati nel progetto.

  1. Concedi i ruoli certificate-authority-service-admin e certificate-requester:

    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-authority-service-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-requester
    
  2. Recupera le credenziali del server API di gestione:

    gdcloud clusters get-credentials ${ORG_NAME}-admin
    

Crea la CA radice

Creerai un'autorità di certificazione nel server API di gestione all'interno dello spazio dei nomi del progetto.

  1. Applica la risorsa CertificateAuthority:

    km apply -f - <<EOF
    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateAuthority
    metadata:
      name: my-root-ca
      namespace: ${PROJECT_ID}
    spec:
      caProfile:
        commonName: "My Root CA"
        duration: 87600h # 10 years
        keyAlgorithm: RSA_2048
        maxChainLength: 1
      caType: ROOT
      keyLocation: HSM
      rotationPolicy:
        cronTime: 0 0 1 1 *
    EOF
    
    km -n ${PROJECT_ID} get \
    certificateauthority.pki.security.gdc.goog/my-root-ca -ojson \
    | jq -r '
    .status.conditions[] | select( .type as $id | "Ready" | index($id)) .status'
    

Emetti ed esegui il deployment dei certificati

Una volta che la CA è pronta, richiederai i certificati sia per l'app containerizzata sia per l'app basata su VM. Queste richieste vengono eseguite nel server API di gestione e le chiavi risultanti devono essere spostate nel cluster standard.

Crea richieste per entrambi i domini:

km apply -f - <<EOF
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-containerized-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "k8s-app.example.com"
      dnsNames:
      - "k8s-app.example.com"
  signedCertificateSecret: tls-containerized-signed
---
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-vm-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "vm-app.example.com"
      dnsNames:
      - "vm-app.example.com"
  signedCertificateSecret: tls-vm-signed
EOF

Attendi qualche istante affinché i certificati vengano emessi. Puoi verificare che siano pronti quando la condizione Ready è True:

km get certificaterequests -n ${PROJECT_ID}

Aggiorna il cluster standard

Se hai seguito le sezioni precedenti di questa guida, hai secret autofirmati nel tuo cluster standard. Devi eliminarli prima di creare le nuove versioni firmate:

kk delete secret tls-containerized -n load-balancer
kk delete secret tls-vm -n load-balancer

kk delete secret tls-containerized -n hello-app
kk delete secret tls-vm -n vm-app

Ora estrai i certificati firmati dal server API di gestione e crea i nuovi secret nel cluster standard.

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-containerized.key

kk create secret tls tls-containerized \
  --namespace load-balancer \
  --key tls-containerized.key \
  --cert tls-containerized.crt

kk create secret tls tls-containerized \
  --namespace hello-app \
  --key tls-containerized.key \
  --cert tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-vm.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-vm.key

kk create secret tls tls-vm \
  --namespace load-balancer \
  --key tls-vm.key \
  --cert tls-vm.crt

kk create secret tls tls-vm \
  --namespace vm-app \
  --key tls-vm.key \
  --cert tls-vm.crt

I nuovi secret verranno ottenuti automaticamente e aggiornati dai bilanciatori del carico.

Configura l'attendibilità del client

Per verificare la configurazione, devi indicare alla VM client di considerare attendibile la nuova CA radice.

Estrai il certificato CA radice in un file:

km get secret -n ${PROJECT_ID} my-root-ca-secret \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > my-root-ca.crt

Trasferisci il certificato alla VM client. Puoi copiare i contenuti di my-root-ca.crt e incollarli in un file sulla VM client.

Sulla VM client, aggiorna l'archivio di attendibilità.

Se la VM client è Ubuntu:

sudo cp my-root-ca.crt /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates

Se la VM client è Rocky Linux:

sudo cp my-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

Verifica l'accesso

Ora puoi accedere alle tue applicazioni utilizzando curl senza il flag -k. La connessione sarà completamente attendibile.

Testa l'app containerizzata di Kubernetes:

curl -v --resolve k8s-app.example.com:443:LOAD_BALANDER_IP https://k8s-app.example.com

Testa l'app VM:

curl -v --resolve vm.example.com:443:LOAD_BALANDER_IP https://vm-app.example.com

Se l'operazione va a buon fine, vedrai immediatamente l'output dell'applicazione senza avvisi relativi ai certificati SSL.