Utilizzo dei gateway in uscita di Cloud Service Mesh su cluster GKE: tutorial


Questo tutorial mostra come utilizzare i gateway di uscita Cloud Service Mesh e altri controlli Google Cloud per proteggere il traffico in uscita dai carichi di lavoro di cui è stato eseguito il deployment in un cluster Google Kubernetes Engine. Il tutorial è inteso come complemento alle best practice per l'utilizzo dei gateway in uscita di Cloud Service Mesh su cluster GKE.

Il pubblico di destinazione di questo tutorial include tecnici di rete, piattaforma e sicurezza che amministrano i cluster Google Kubernetes Engine utilizzati da uno o più team di distribuzione del software. I controlli descritti qui sono particolarmente utili per le organizzazioni che devono dimostrare la conformità alle normative, ad esempio GDPR e PCI.

Obiettivi

  • Configura l'infrastruttura per l'esecuzione di Cloud Service Mesh:
  • Installa Cloud Service Mesh.
  • Installa i proxy del gateway in uscita in esecuzione su un pool di nodi dedicato.
  • Configura le regole di routing multi-tenant per il traffico esterno tramite il gateway in uscita:
    • Le applicazioni nello spazio dei nomi team-x possono connettersi a example.com
    • Le applicazioni nello spazio dei nomi team-y possono connettersi a httpbin.org
  • Utilizza la risorsa Sidecar per limitare l'ambito della configurazione di uscita del proxy sidecar per ogni spazio dei nomi.
  • Configura i criteri di autorizzazione per applicare le regole di uscita.
  • Configura il gateway di uscita per eseguire l'upgrade delle richieste HTTP semplici a TLS (origine TLS).
  • Configura il gateway in uscita per il pass-through del traffico TLS.
  • Configura i criteri di rete Kubernetes come controllo in uscita aggiuntivo.
  • Configura l'accesso diretto alle API di Google utilizzando le autorizzazioni diaccesso privato Googles e Identity and Access Management (IAM).

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il calcolatore prezzi.

I nuovi utenti di Google Cloud potrebbero avere diritto a una prova senza costi.

Al termine di questo tutorial, puoi evitare costi continui eliminando le risorse che hai creato. Per ulteriori informazioni, vedi Pulizia.

Prima di iniziare

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  4. Crea una directory di lavoro da utilizzare mentre segui il tutorial:

    mkdir -p ~/WORKING_DIRECTORY
    cd ~/WORKING_DIRECTORY
    
  5. Crea uno script shell per inizializzare l'ambiente per il tutorial. Sostituisci e modifica le variabili in base al tuo progetto e alle tue preferenze. Esegui questo script con il comando source per reinizializzare l'ambiente se la sessione della shell scade:

    cat << 'EOF' > ./init-egress-tutorial.sh
    #! /usr/bin/env bash
    PROJECT_ID=YOUR_PROJECT_ID
    REGION=REGION
    ZONE=ZONE
    
    gcloud config set project ${PROJECT_ID}
    gcloud config set compute/region ${REGION}
    gcloud config set compute/zone ${ZONE}
    
    EOF
    
  6. Attiva compute.googleapis.com:

    gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
    
  7. Rendi eseguibile lo script ed eseguilo con il comando source per inizializzare l'ambiente. Se richiesto, seleziona Y per attivare compute.googleapis.com:

    chmod +x ./init-egress-tutorial.sh
    source ./init-egress-tutorial.sh
    
  8. Configurazione dell'infrastruttura

    Crea una rete VPC e una subnet

    1. Crea una nuova rete VPC:

      gcloud compute networks create vpc-network \
          --subnet-mode custom
      
    2. Crea una subnet in cui eseguire il cluster con intervalli di indirizzi IP secondari preassegnati per pod e servizi. L'accesso privato Google è abilitato in modo che le applicazioni con solo indirizzi IP interni possano raggiungere i servizi e le API di Google:

      gcloud compute networks subnets create subnet-gke \
          --network vpc-network \
          --range 10.0.0.0/24 \
          --secondary-range pods=10.1.0.0/16,services=10.2.0.0/20 \
          --enable-private-ip-google-access
      

    Configurazione di Cloud NAT

    Cloud NAT consente ai carichi di lavoro senza indirizzi IP esterni di connettersi a destinazioni su internet e ricevere risposte in entrata da queste destinazioni.

    1. Crea un router Cloud:

      gcloud compute routers create nat-router \
          --network vpc-network
      
    2. Aggiungi una configurazione NAT al router:

      gcloud compute routers nats create nat-config \
          --router nat-router \
          --nat-all-subnet-ip-ranges \
          --auto-allocate-nat-external-ips
      

    Crea service account per ogni pool di nodi GKE

    Crea due service account da utilizzare nei due pool di nodi GKE. A ogni pool di nodi viene assegnato un account di servizio separato in modo da poter applicare regole firewall VPC a nodi specifici.

    1. Crea un account di servizio da utilizzare per i nodi nel pool di nodi predefinito:

      gcloud iam service-accounts create sa-application-nodes \
          --description="SA for application nodes" \
          --display-name="sa-application-nodes"
      
    2. Crea un account di servizio da utilizzare per i nodi nel pool di nodi gateway:

      gcloud iam service-accounts create sa-gateway-nodes \
          --description="SA for gateway nodes" \
          --display-name="sa-gateway-nodes"
      

    Concedi le autorizzazioni ai service account

    Aggiungi un insieme minimo di ruoli IAM ai service account dell'applicazione e del gateway. Questi ruoli sono necessari per la registrazione, il monitoraggio e il pull delle immagini container private da Container Registry.

        project_roles=(
            roles/logging.logWriter
            roles/monitoring.metricWriter
            roles/monitoring.viewer
            roles/storage.objectViewer
        )
        for role in "${project_roles[@]}"
        do
            gcloud projects add-iam-policy-binding ${PROJECT_ID} \
                --member="serviceAccount:sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
                --role="$role"
            gcloud projects add-iam-policy-binding ${PROJECT_ID} \
                --member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
                --role="$role"
        done
    

    Creazione delle regole firewall

    Nei passaggi successivi, applichi una regola firewall alla rete VPC in modo che, per impostazione predefinita, tutto il traffico in uscita venga negato. Per il funzionamento del cluster e per consentire ai nodi gateway di raggiungere destinazioni al di fuori del VPC è necessaria una connettività specifica. Un insieme minimo di regole firewall specifiche sostituisce la regola predefinita di negazione totale per consentire la connettività necessaria.

    1. Crea una regola firewall predefinita (a bassa priorità) per negare tutto il traffico in uscita dalla rete VPC:

      gcloud compute firewall-rules create global-deny-egress-all \
          --action DENY \
          --direction EGRESS \
          --rules all \
          --destination-ranges 0.0.0.0/0 \
          --network vpc-network \
          --priority 65535 \
          --description "Default rule to deny all egress from the network."
      
    2. Crea una regola per consentire solo ai nodi con l'account di servizio gateway di accedere a internet:

      gcloud compute firewall-rules create gateway-allow-egress-web \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp:80,tcp:443 \
          --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --network vpc-network \
          --priority 1000 \
          --description "Allow the nodes running the egress gateways to connect to the web"
      
    3. Consenti ai nodi di raggiungere il control plane Kubernetes:

      gcloud compute firewall-rules create allow-egress-to-api-server \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp:443,tcp:10250 \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 10.5.0.0/28 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow nodes to reach the Kubernetes API server."
      
    4. (Facoltativo) Questa regola firewall non è necessaria se utilizzi Managed Cloud Service Mesh.

      Cloud Service Mesh utilizza i webhook quando inserisce i proxy sidecar nei carichi di lavoro. Consenti al server API GKE di chiamare i webhook esposti dal control plane delmesh di servizih in esecuzione sui nodi:

      gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \
          --action ALLOW \
          --direction INGRESS \
          --rules tcp:15017 \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --source-ranges 10.5.0.0/28 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow the API server to call the webhooks exposed by istiod discovery"
      
    5. Consenti la connettività in uscita tra nodi e pod in esecuzione sul cluster. GKE crea automaticamente una regola in entrata corrispondente. Non è necessaria alcuna regola per la connettività del servizio perché la catena di routing iptables converte sempre gli indirizzi IP del servizio in indirizzi IP del pod.

      gcloud compute firewall-rules create allow-egress-nodes-and-pods \
          --action ALLOW \
          --direction EGRESS \
          --rules all \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 10.0.0.0/24,10.1.0.0/16 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow egress to other Nodes and Pods"
      
    6. Consenti l'accesso ai set riservati di indirizzi IP utilizzati da accesso privato Googles per la pubblicazione di API Google, Container Registry e altri servizi:

      gcloud compute firewall-rules create allow-egress-gcp-apis \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 199.36.153.8/30 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow access to the VIPs used by Google Cloud APIs (Private Google Access)"
      
    7. Consenti al servizio di controllo di integrità Google Cloud di accedere ai pod in esecuzione nel cluster. Per saperne di più, consulta Controlli di integrità.

      gcloud compute firewall-rules create allow-ingress-gcp-health-checker \
          --action ALLOW \
          --direction INGRESS \
          --rules tcp:80,tcp:443 \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --source-ranges 35.191.0.0/16,130.211.0.0/22,209.85.152.0/22,209.85.204.0/22 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow workloads to respond to Google Cloud health checks"
      

    Configurazione dell'accesso privato alle API Google Cloud

    L'accesso privato Google consente alle VM e ai pod che hanno solo indirizzi IP interni di accedere alle API e ai servizi Google. Anche se le API e i servizi Google vengono forniti da IP esterni, il traffico dai nodi non esce mai dalla rete Google quando viene utilizzato l'accesso privato Google.

    Abilita l'API Cloud DNS:

    gcloud services enable dns.googleapis.com
    

    Crea una zona DNS privata, un CNAME e record A in modo che i nodi e i carichi di lavoro possano connettersi alle API e ai servizi Google utilizzando l'accesso privato Google e il nome host private.googleapis.com:

    gcloud dns managed-zones create private-google-apis \
        --description "Private DNS zone for Google APIs" \
        --dns-name googleapis.com \
        --visibility private \
        --networks vpc-network
    
    gcloud dns record-sets transaction start --zone private-google-apis
    
    gcloud dns record-sets transaction add private.googleapis.com. \
        --name "*.googleapis.com" \
        --ttl 300 \
        --type CNAME \
        --zone private-google-apis
    
    gcloud dns record-sets transaction add "199.36.153.8" \
    "199.36.153.9" "199.36.153.10" "199.36.153.11" \
        --name private.googleapis.com \
        --ttl 300 \
        --type A \
        --zone private-google-apis
    
    gcloud dns record-sets transaction execute --zone private-google-apis
    

    Configurazione dell'accesso privato a Container Registry

    Crea una zona DNS privata, un record CNAME e un record A in modo che i nodi possano connettersi a Container Registry utilizzando l'accesso privato Google e il nome host gcr.io:

    gcloud dns managed-zones create private-gcr-io \
        --description "private zone for Container Registry" \
        --dns-name gcr.io \
        --visibility private \
        --networks vpc-network
    
    gcloud dns record-sets transaction start --zone private-gcr-io
    
    gcloud dns record-sets transaction add gcr.io. \
        --name "*.gcr.io" \
        --ttl 300 \
        --type CNAME \
        --zone private-gcr-io
    
    gcloud dns record-sets transaction add "199.36.153.8" "199.36.153.9" "199.36.153.10" "199.36.153.11" \
        --name gcr.io \
        --ttl 300 \
        --type A \
        --zone private-gcr-io
    
    gcloud dns record-sets transaction execute --zone private-gcr-io
    

    Crea un cluster GKE privato

    1. Trova l'indirizzo IP esterno di Cloud Shell in modo da poterlo aggiungere all'elenco delle reti autorizzate ad accedere al server API del tuo cluster:

      SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
      

      Dopo un periodo di inattività, l'indirizzo IP esterno della VM Cloud Shell può cambiare. In questo caso, devi aggiornare l'elenco delle reti autorizzate del cluster. Aggiungi il seguente comando allo script di inizializzazione:

      cat << 'EOF' >> ./init-egress-tutorial.sh
      SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
      gcloud container clusters update cluster1 \
          --enable-master-authorized-networks \
          --master-authorized-networks ${SHELL_IP//\"}/32
      EOF
      
    2. Attiva l'API Google Kubernetes Engine:

      gcloud services enable container.googleapis.com
      
    3. Crea un cluster GKE privato:

      gcloud container clusters create cluster1 \
          --enable-ip-alias \
          --enable-private-nodes \
          --release-channel "regular" \
          --enable-master-authorized-networks \
          --master-authorized-networks ${SHELL_IP//\"}/32 \
          --master-ipv4-cidr 10.5.0.0/28 \
          --enable-dataplane-v2 \
          --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
          --machine-type "e2-standard-4" \
          --network "vpc-network" \
          --subnetwork "subnet-gke" \
          --cluster-secondary-range-name "pods" \
          --services-secondary-range-name "services" \
          --workload-pool "${PROJECT_ID}.svc.id.goog" \
          --zone ${ZONE}
      

      La creazione del cluster richiede alcuni minuti. Il cluster ha nodi privati con indirizzi IP interni. A pod e servizi vengono assegnati IP dagli intervalli secondari denominati che hai definito durante la creazione della subnet VPC.

      Cloud Service Mesh con un control plane in-cluster richiede che i nodi del cluster utilizzino un tipo di macchina con almeno 4 vCPU.

      Google consiglia di iscrivere il cluster al canale di rilascio "regolare" per garantire che i nodi eseguano una versione di Kubernetes supportata da Cloud Service Mesh.

      Per ulteriori informazioni sui prerequisiti per l'esecuzione di Cloud Service Mesh con un control plane in-cluster, consulta i prerequisiti in-cluster.

      Per ulteriori informazioni sui requisiti e sulle limitazioni per l'esecuzione di Service Mesh gestito, consulta la pagina Funzionalità supportate di Service Mesh gestito.

      Workload Identity Federation for GKE è abilitata sul cluster. Cloud Service Mesh richiede Workload Identity Federation for GKE ed è il modo consigliato per accedere alle API di Google dai carichi di lavoro GKE.

    4. Crea un pool di nodi denominato gateway. In questo pool di nodi viene eseguito il deployment del gateway di uscita. L'dedicated=gateway:NoSchedule taint viene aggiunto a ogni nodo nel pool di nodi del gateway.

      gcloud container node-pools create "gateway" \
          --cluster "cluster1" \
          --machine-type "e2-standard-4" \
          --node-taints dedicated=gateway:NoSchedule \
          --service-account "sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
          --num-nodes "1"
      

      Le incompatibilità e tolleranze di Kubernetes contribuiscono a garantire che solo i pod del gateway di uscita vengano eseguiti sui nodi nel pool di nodi del gateway.

    5. Scarica le credenziali per poterti connettere al cluster con kubectl:

      gcloud container clusters get-credentials cluster1
      
    6. Verifica che i nodi gateway abbiano il taint corretto:

      kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \
      -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
      

      L'output è simile al seguente:

      name                                 taints
      gke-cluster1-gateway-9d65b410-cffs   map[effect:NoSchedule key:dedicated value:gateway]
      

    Installazione e configurazione di Cloud Service Mesh

    Segui una delle guide all'installazione di Cloud Service Mesh:

    Dopo aver installato Cloud Service Mesh, interrompi l'operazione e torna a questo tutorial senza installare gateway in entrata o in uscita.

    Installare un gateway in uscita

    1. Crea uno spazio dei nomi Kubernetes per il gateway di uscita:

      kubectl create namespace istio-egress
      
    2. Quando esegui il deployment del gateway di uscita, la configurazione verrà inserita automaticamente in base a un'etichetta che applichi al deployment o allo spazio dei nomi. Se il tag predefinito è configurato, etichetta lo spazio dei nomi con le etichette di inserimento predefinite , altrimenti utilizza l'etichetta di revisione per il control plane che hai installato. L'etichetta di revisione che aggiungi dipende anche dal fatto che tu abbia eseguito il deployment di Cloud Service Mesh gestito o installato il control plane in-cluster.

      Seleziona la scheda di seguito in base al tipo di installazione (gestita o in-cluster).

      Gestito

      Utilizza il seguente comando per individuare le revisioni del control plane disponibili:

      kubectl -n istio-system get controlplanerevision
      

      L'output è simile al seguente:

      NAME          RECONCILED   STALLED   AGE
      asm-managed   True         False     112m
      

      Prendi nota del valore nella colonna NAME per la revisione del control plane che vuoi utilizzare. In genere, il canale di rilascio di Cloud Service Mesh corrisponde al canale di rilascio del cluster Google Kubernetes Engine.

      In-cluster

      Per i control plane in-cluster, il servizio e il deployment istiod in genere hanno un'etichetta di revisione simile a istio.io/rev=, dove identifica la versione di Cloud Service Mesh. La revisione diventa parte del nome del servizio istiod, ad esempio: istiod-.istio-system

      Utilizza il seguente comando per individuare l'etichetta della revisione su istiod per il control plane in-cluster:

      kubectl get deploy -n istio-system -l app=istiod \
        -o=jsonpath='{.items[*].metadata.labels.istio\.io\/rev}''{"\n"}'
      
    3. (Facoltativo) Etichetta lo spazio dei nomi in modo che la configurazione del gateway venga inserita automaticamente. È sufficiente etichettare lo spazio dei nomi o il deployment. Ai fini di questo tutorial, etichettali entrambi per evitare avvisi dallo strumento istioctl analyze.

      kubectl label namespace istio-egress istio.io/rev=REVISION
      
    4. Crea un manifest dell'operatore per il gateway in uscita:

      cat << EOF > egressgateway-operator.yaml
      apiVersion: install.istio.io/v1alpha1
      kind: IstioOperator
      metadata:
        name: egressgateway-operator
        annotations:
          config.kubernetes.io/local-config: "true"
      spec:
        profile: empty
        revision: REVISION
        components:
          egressGateways:
          - name: istio-egressgateway
            namespace: istio-egress
            enabled: true
        values:
          gateways:
            istio-egressgateway:
              injectionTemplate: gateway
              tolerations:
                - key: "dedicated"
                  operator: "Equal"
                  value: "gateway"
              nodeSelector:
                cloud.google.com/gke-nodepool: "gateway"
      EOF
      
    5. Scarica lo strumento istioctl. Devi utilizzare la versione 1.16.2-asm.2 o successive anche se utilizzi Cloud Service Mesh versione 1.15 o precedenti. Consulta la sezione Download della versione corretta di istioctl.

    6. Dopo aver estratto l'archivio scaricato, imposta una variabile di ambiente per contenere il percorso dello strumento istioctl e aggiungilo allo script di inizializzazione:

      ISTIOCTL=$(find "$(pwd -P)" -name istioctl)
      echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
      
    7. Crea il manifest di installazione del gateway di uscita utilizzando il manifest dell'operatore e istioctl:

      ${ISTIOCTL} manifest generate \
          --filename egressgateway-operator.yaml \
          --output egressgateway \
          --cluster-specific
      
    8. Installa il gateway in uscita:

      kubectl apply --recursive --filename egressgateway/
      
    9. Verifica che il gateway di uscita sia in esecuzione sui nodi nel pool di nodi gateway:

      kubectl get pods -n istio-egress -o wide
      
    10. I pod del gateway di uscita hanno affinity per i nodi nel pool di nodi gateway e una tolleranza che consente loro di essere eseguiti sui nodi del gateway incompatibili. Esamina l'affinità e le tolleranze dei nodi per i pod del gateway in uscita:

      kubectl -n istio-egress get pod -l istio=egressgateway \
          -o=custom-columns='name:metadata.name,node-affinity:spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,tolerations:spec.tolerations[?(@.key=="dedicated")]'
      

      L'output è simile al seguente:

      name                                   node-affinity                                                                                   tolerations
      istio-egressgateway-754d9684d5-jjkdz   [map[matchExpressions:[map[key:cloud.google.com/gke-nodepool operator:In values:[gateway]]]]]   map[key:dedicated operator:Equal value:gateway]
      

    Abilita il logging degli accessi di Envoy

    I passaggi necessari per abilitare i log di accesso di Envoy dipendono dal tipo di Cloud Service Mesh, gestito o in-cluster:

    Preparazione della mesh e di un'applicazione di test

    1. Assicurati che la mutual TLS STRICT sia abilitata. Applica una policy PeerAuthentication predefinita per il mesh nello spazio dei nomi istio-system:

      cat <<EOF | kubectl apply -f -
      apiVersion: "security.istio.io/v1beta1"
      kind: "PeerAuthentication"
      metadata:
        name: "default"
        namespace: "istio-system"
      spec:
        mtls:
          mode: STRICT
      EOF
      

      Puoi eseguire l'override di questa configurazione creando risorse PeerAuthentication in spazi dei nomi specifici.

    2. Crea spazi dei nomi da utilizzare per il deployment dei carichi di lavoro di test. I passaggi successivi di questo tutorial spiegano come configurare regole di routing di uscita diverse per ogni spazio dei nomi.

      kubectl create namespace team-x
      kubectl create namespace team-y
      
    3. Etichetta gli spazi dei nomi in modo che possano essere selezionati dalle norme di rete Kubernetes:

      kubectl label namespace team-x team=x
      kubectl label namespace team-y team=y
      
    4. Affinché Cloud Service Mesh inserisca automaticamente i sidecar proxy, devi impostare l'etichetta di revisione del control plane negli spazi dei nomi dei workload:

      kubectl label ns team-x istio.io/rev=REVISION
      kubectl label ns team-y istio.io/rev=REVISION
      
    5. Crea un file YAML da utilizzare per eseguire deployment di test:

      cat << 'EOF' > ./test.yaml
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: test
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: test
        labels:
          app: test
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: test
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: test
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: test
        template:
          metadata:
            labels:
              app: test
          spec:
            serviceAccountName: test
            containers:
            - name: test
              image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
              command: ["/bin/sleep", "infinity"]
              imagePullPolicy: IfNotPresent
      EOF
      
    6. Esegui il deployment dell'applicazione di test nello spazio dei nomi team-x:

      kubectl -n team-x create -f ./test.yaml
      
    7. Verifica che l'applicazione di test sia sottoposta a deployment su un nodo nel pool predefinito e che venga inserito un contenitore secondario proxy. Ripeti il seguente comando finché lo stato del pod non è Running:

      kubectl -n team-x get po -l app=test -o wide
      

      L'output è simile al seguente:

      NAME                   READY   STATUS    RESTARTS   AGE   IP          NODE                                      NOMINATED NODE   READINESS GATES
      test-d5bdf6f4f-9nxfv   2/2     Running   0          19h   10.1.1.25   gke-cluster1-default-pool-f6c7a51f-wbzj
      

      2 contenitori su 2 sono Running. Un container è l'applicazione di test e l'altro è il proxy sidecar.

      Il pod è in esecuzione su un nodo nel pool di nodi predefinito.

    8. Verifica che non sia possibile effettuare una richiesta HTTP dal container di test a un sito esterno:

      kubectl -n team-x exec -it \
          $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \
          -c test -- curl -v http://example.com
      

      Viene generato un messaggio di errore dal proxy sidecar perché la regola firewall global-deny-egress-all nega la connessione upstream.

    Utilizzo della risorsa Sidecar per limitare l'ambito della configurazione del proxy sidecar

    Puoi utilizzare la risorsa Sidecar per limitare l'ambito del listener di uscita configurato per i proxy sidecar. Per ridurre il sovraccarico di configurazione e l'utilizzo della memoria, è buona norma applicare una risorsa Sidecar predefinita per ogni spazio dei nomi.

    Il proxy eseguito in sidecar da Cloud Service Mesh è Envoy. Nella terminologia di Envoy, un cluster è un gruppo di endpoint upstream logicamente simili utilizzati come destinazioni per il bilanciamento del carico.

    1. Controlla i cluster in uscita configurati nel proxy sidecar Envoy per il pod di test eseguendo il comando istioctl proxy-config:

      ${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}).team-x --direction outbound
      

      Nell'elenco sono presenti circa 11 cluster Envoy, inclusi alcuni per il gateway di uscita.

    2. Limita la configurazione del proxy alle route di uscita che sono state definite in modo esplicito con voci di servizio negli spazi dei nomi di uscita e team-x. Applica una risorsa Sidecar allo spazio dei nomi team-x:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Sidecar
      metadata:
        name: default
        namespace: team-x
      spec:
        outboundTrafficPolicy:
          mode: REGISTRY_ONLY
        egress:
        - hosts:
          - 'istio-egress/*'
          - 'team-x/*'
      EOF
      

      L'impostazione della modalità del criterio di traffico in uscita su REGISTRY_ONLY limita la configurazione del proxy in modo da includere solo gli host esterni che sono stati aggiunti esplicitamente al registro di servizio del mesh definendo le voci di servizio.

      L'impostazione di egress.hosts specifica che il proxy sidecar seleziona solo le route dallo spazio dei nomi di uscita rese disponibili utilizzando l'attributo exportTo. La parte "team-x/*" include tutte le route che sono state configurate localmente nello spazio dei nomi team-x.

    3. Visualizza i cluster in uscita configurati nel proxy sidecar Envoy e confrontali con l'elenco dei cluster configurati prima dell'applicazione della risorsa Sidecar:

      ${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}).team-x --direction outbound
      

      Vedi i cluster per il gateway di uscita e uno per il pod di test stesso.

    Configurazione di Cloud Service Mesh per il routing del traffico tramite il gateway di uscita

    1. Configura un Gateway per il traffico HTTP sulla porta 80. Gateway seleziona il proxy del gateway di uscita che hai eseguito il deployment nello spazio dei nomi di uscita. La configurazione Gateway viene applicata allo spazio dei nomi in uscita e gestisce il traffico per qualsiasi host.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: egress-gateway
        namespace: istio-egress
      spec:
        selector:
          istio: egressgateway
        servers:
        - port:
            number: 80
            name: https
            protocol: HTTPS
          hosts:
            - '*'
          tls:
            mode: ISTIO_MUTUAL
      EOF
      
    2. Crea un DestinationRule per il gateway di uscita con TLS reciproca per l'autenticazione e la crittografia. Utilizza una singola regola di destinazione condivisa per tutti gli host esterni.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: target-egress-gateway
        namespace: istio-egress
      spec:
        host: istio-egressgateway.istio-egress.svc.cluster.local
        subsets:
        - name: target-egress-gateway-mTLS
          trafficPolicy:
            tls:
              mode: ISTIO_MUTUAL
      EOF
      
    3. Crea un ServiceEntry nello spazio dei nomi di uscita per registrare esplicitamente example.com nel registro dei servizi del mesh per lo spazio dei nomi team-x:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: example-com-ext
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: example.com
      spec:
        hosts:
        - example.com
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'team-x'
        - 'istio-egress'
      EOF
      
    4. Crea un VirtualService per indirizzare il traffico a example.com tramite il gateway di uscita. Esistono due condizioni di corrispondenza: la prima indirizza il traffico al gateway di uscita e la seconda indirizza il traffico dal gateway di uscita all'host di destinazione. La proprietà exportTo controlla quali spazi dei nomi possono utilizzare il servizio virtuale.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: example-com-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - example.com
        gateways:
        - istio-egress/egress-gateway
        - mesh
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
            weight: 100
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: example.com
              port:
                number: 80
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    5. Esegui istioctl analyze per verificare la presenza di errori di configurazione:

      ${ISTIOCTL} analyze -n istio-egress --revision REVISION
      

      L'output è simile al seguente:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Invia diverse richieste tramite il gateway di uscita al sito esterno:

      for i in {1..4}
      do
          kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
              -o jsonpath={.items..metadata.name}) -c test -- \
          curl -s -o /dev/null -w "%{http_code}\n" http://example.com
      done
      

      Vengono visualizzati i codici di stato 200 per tutte e quattro le risposte.

    7. Verifica che le richieste siano state indirizzate tramite il gateway di uscita controllando i log di accesso al proxy. Controlla innanzitutto il log di accesso del proxy sidecar di cui è stato eseguito il deployment con l'applicazione di test:

      kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) istio-proxy
      

      Per ogni richiesta che invii, viene visualizzata una voce di log simile alla seguente:

      [2020-09-14T17:37:08.045Z] "HEAD / HTTP/1.1" 200 - "-" "-" 0 0 5 4 "-" "curl/7.67.0" "d57ea5ad-90e9-46d9-8b55-8e6e404a8f9b" "example.com" "10.1.4.12:8080" outbound|80||istio-egressgateway.istio-egress.svc.cluster.local 10.1.0.17:42140 93.184.216.34:80 10.1.0.17:60326 - -
      
    8. Controlla anche il log di accesso al gateway di uscita:

      kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \
          -o jsonpath="{.items[0].metadata.name}") istio-proxy
      

      Per ogni richiesta che invii, viene visualizzata una voce di log di accesso al gateway di uscita simile alla seguente:

      [2020-09-14T17:37:08.045Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 4 3 "10.1.0.17" "curl/7.67.0" "095711e6-64ef-4de0-983e-59158e3c55e7" "example.com" "93.184.216.34:80" outbound|80||example.com 10.1.4.12:37636 10.1.4.12:8080 10.1.0.17:44404 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
      

    Configurare un routing diverso per un secondo spazio dei nomi

    Configura il routing per un secondo host esterno per scoprire come configurare una connettività esterna diversa per team diversi.

    1. Crea una risorsa Sidecar per lo spazio dei nomi team-y:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Sidecar
      metadata:
        name: default
        namespace: team-y
      spec:
        outboundTrafficPolicy:
          mode: REGISTRY_ONLY
        egress:
        - hosts:
          - 'istio-egress/*'
          - 'team-y/*'
      EOF
      
    2. Esegui il deployment dell'applicazione di test nello spazio dei nomi team-y:

      kubectl -n team-y create -f ./test.yaml
      
    3. Registra un secondo host esterno ed esportalo negli spazi dei nomi team-x e team-y:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: httpbin-org-ext
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: httpbin.org
      spec:
        hosts:
        - httpbin.org
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
        - 'team-y'
      EOF
      
    4. Crea un servizio virtuale per indirizzare il traffico a httpbin.org tramite il gateway di uscita:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: httpbin-org-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - httpbin.org
        gateways:
        - istio-egress/egress-gateway
        - mesh
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
            weight: 100
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: httpbin.org
              port:
                number: 80
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
        - 'team-y'
      EOF
      
    5. Esegui istioctl analyze per verificare la presenza di errori di configurazione:

      ${ISTIOCTL} analyze -n istio-egress --revision REVISION
      

      Le voci della tabella sono:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Fai una richiesta a httpbin.org dall'app di test team-y:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test -o \
          jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
      

      Viene visualizzata una risposta 200 OK.

    7. Inoltre, effettua una richiesta a httpbin.org dall'app di test team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
      

      Viene visualizzata una risposta 200 OK.

    8. Tenta di effettuare una richiesta a example.com dallo spazio dei nomi team-y:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      La richiesta non va a buon fine perché non è configurata alcuna route in uscita per l'host example.com.

    Utilizzo dei criteri di autorizzazione per fornire un controllo aggiuntivo sul traffico

    In questo tutorial, i criteri di autorizzazione per il gateway in uscita vengono creati nello spazio dei nomi istio-egress. Puoi configurare Kubernetes RBAC in modo che solo gli amministratori di rete possano accedere allo spazio dei nomi istio-egress.

    1. Crea un AuthorizationPolicy in modo che le applicazioni nello spazio dei nomi team-x possano connettersi a example.com, ma non ad altri host esterni quando inviano richieste utilizzando la porta 80. Il targetPort corrispondente sui pod del gateway di uscita è 8080.

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: egress-team-x-to-example-com
        namespace: istio-egress
      spec:
        action: ALLOW
        rules:
          - from:
            - source:
                namespaces:
                - 'team-x'
            to:
            - operation:
                hosts:
                  - 'example.com'
            when:
            - key: destination.port
              values: ["8080"]
      EOF
      
    2. Verifica di poter effettuare una richiesta a example.com dall'applicazione di test nello spazio dei nomi team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      Viene visualizzata una risposta 200 OK.

    3. Prova a inviare una richiesta a httpbin.org dall'applicazione di test nello spazio dei nomi team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \
          http://httpbin.org
      

      La richiesta non va a buon fine e viene visualizzato un messaggio RBAC: access denied e un codice di stato 403 Forbidden. Potresti dover attendere qualche secondo perché spesso c'è un breve ritardo prima che la norma di autorizzazione diventi effettiva.

    4. I criteri di autorizzazione forniscono un controllo avanzato sul traffico consentito o negato. Applica il seguente criterio di autorizzazione per consentire all'app di test nello spazio dei nomi team-y di effettuare richieste a httpbin.org utilizzando un particolare percorso URL quando invii richieste utilizzando la porta 80. La targetPort corrispondente sui pod del gateway in uscita è 8080.

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: egress-team-y-to-httpbin-teapot
        namespace: istio-egress
      spec:
        action: ALLOW
        rules:
          - from:
            - source:
                namespaces:
                - 'team-y'
            to:
            - operation:
                hosts:
                - httpbin.org
                paths: ['/status/418']
            when:
            - key: destination.port
              values: ["8080"]
      EOF
      
    5. Prova a connetterti a httpbin.org dall'app di test nello spazio dei nomi team-y:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \
          http://httpbin.org
      

      La richiesta non va a buon fine e viene visualizzato il messaggio RBAC: accesso negato e il codice di stato 403 Forbidden.

    6. Ora invia una richiesta a httpbin.org/status/418 dalla stessa app:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl http://httpbin.org/status/418
      

      La richiesta ha esito positivo perché il percorso corrisponde al pattern nelle norme di autorizzazione. L'output è simile al seguente:

         -=[ teapot ]=-
            _...._
          .'  _ _ `.
         | ."` ^ `". _,
         \_;`"---"`|//
           |       ;/
           \_     _/
             `"""`
      

    Originazione TLS sul gateway in uscita

    Puoi configurare i gateway di uscita per upgrade (originare) richieste HTTP non criptate a TLS o TLS reciproco. Consentire alle applicazioni di effettuare richieste HTTP semplici presenta diversi vantaggi se utilizzato con l'autenticazione TLS reciproca e l'origine TLS di Istio. Per ulteriori informazioni, consulta la guida alle best practice.

    Originazione TLS nel gateway in uscita

    1. Crea un DestinationRule. The DestinationRule specifica che il gateway deve avviare una connessione TLS a example.com.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: example-com-originate-tls
        namespace: istio-egress
      spec:
        host: example.com
        subsets:
          - name: example-com-originate-TLS
            trafficPolicy:
              portLevelSettings:
              - port:
                  number: 443
                tls:
                  mode: SIMPLE
                  sni: example.com
      EOF
      
    2. Aggiorna il servizio virtuale per example.com in modo che le richieste alla porta 80 sul gateway siano upgraded a TLS sulla porta 443 quando vengono inviate all'host di destinazione:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: example-com-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - example.com
        gateways:
        - mesh
        - istio-egress/egress-gateway
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: example.com
              port:
                number: 443
              subset: example-com-originate-TLS
            weight: 100
      EOF
      
    3. Esegui diverse richieste a example.com dall'app di test nello spazio dei nomi team-x:

      for i in {1..4}
      do
          kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
              -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      done
      

      Come in precedenza, le richieste hanno esito positivo con risposte 200 OK.

    4. Controlla il log del gateway di uscita per verificare che il gateway abbia indirizzato le richieste all'host di destinazione creando connessioni TLS:

      kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \
          -o jsonpath="    {.items[0].metadata.name}") istio-proxy
      

      L'output è simile al seguente:

      [2020-09-24T17:58:02.548Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 6 5 "10.1.1.15" "curl/7.67.0" "83a77acb-d994-424d-83da-dd8eac902dc8" "example.com" "93.184.216.34:443" outbound|443|example-com-originate-TLS|example.com 10.1.4.31:49866 10.1.4.31:8080 10.1.1.15:37334 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
      

      Il proxy sidecar ha inviato la richiesta al gateway utilizzando la porta 80 e TLS ha avuto origine sulla porta 443 per inviare la richiesta all'host di destinazione.

    Pass-through delle connessioni HTTPS/TLS

    Le tue applicazioni esistenti potrebbero già utilizzare connessioni TLS quando comunicano con servizi esterni. Puoi configurare il gateway di uscita in modo che trasferisca le connessioni TLS senza decriptarle.

    tls pass through

    1. Modifica la configurazione in modo che il gateway di uscita utilizzi il pass-through TLS per le connessioni alla porta 443:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: egress-gateway
        namespace: istio-egress
      spec:
        selector:
          istio: egressgateway
        servers:
        - port:
            number: 80
            name: https
            protocol: HTTPS
          hosts:
            - '*'
          tls:
            mode: ISTIO_MUTUAL
        - port:
            number: 443
            name: tls
            protocol: TLS
          hosts:
          - '*'
          tls:
            mode: PASSTHROUGH
      EOF
      
    2. Aggiorna DestinationRule che punta al gateway di uscita per aggiungere un secondo sottoinsieme per la porta 443 sul gateway. Questo nuovo sottoinsieme non utilizza TLS reciproco. Istio mutual TLS non è supportato per il pass-through delle connessioni TLS. Le connessioni sulla porta 80 utilizzano ancora mTLS:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: target-egress-gateway
        namespace: istio-egress
      spec:
        host: istio-egressgateway.istio-egress.svc.cluster.local
        subsets:
        - name: target-egress-gateway-mTLS
          trafficPolicy:
            portLevelSettings:
            - port:
                number: 80
              tls:
                mode: ISTIO_MUTUAL
        - name: target-egress-gateway-TLS-passthrough
      EOF
      
    3. Aggiorna il servizio virtuale per example.com in modo che il traffico TLS sulla porta 443 venga trasmesso tramite il gateway:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: example-com-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - example.com
        gateways:
        - mesh
        - istio-egress/egress-gateway
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: example.com
              port:
                number: 443
              subset: example-com-originate-TLS
            weight: 100
        tls:
        - match:
          - gateways:
            - mesh
            port: 443
            sniHosts:
            - example.com
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-TLS-passthrough
              port:
                number: 443
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 443
            sniHosts:
            - example.com
          route:
          - destination:
              host: example.com
              port:
                number: 443
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    4. Aggiorna il servizio virtuale per httpbin.org in modo che il traffico TLS sulla porta 443 venga trasmesso tramite il gateway:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: httpbin-org-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - httpbin.org
        gateways:
        - istio-egress/egress-gateway
        - mesh
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
            weight: 100
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: httpbin.org
              port:
                number: 80
            weight: 100
        tls:
        - match:
          - gateways:
            - mesh
            port: 443
            sniHosts:
            - httpbin.org
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-TLS-passthrough
              port:
                number: 443
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 443
            sniHosts:
            - httpbin.org
          route:
          - destination:
              host: httpbin.org
              port:
                number: 443
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
        - 'team-y'
      EOF
      
    5. Aggiungi un criterio di autorizzazione che accetti qualsiasi tipo di traffico inviato alla porta 443 del servizio gateway in uscita. La porta targetPort corrispondente sui pod del gateway è 8443.

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: egress-all-443
        namespace: istio-egress
      spec:
        action: ALLOW
        rules:
          - when:
            - key: destination.port
              values: ["8443"]
      EOF
      
    6. Esegui istioctl analyze per verificare la presenza di errori di configurazione:

      ${ISTIOCTL} analyze -n istio-egress --revision REVISION
      

      Le voci della tabella sono:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    7. Fai una richiesta HTTP semplice a example.com dall'applicazione di test nello spazio dei nomi team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      La richiesta ha esito positivo con una risposta 200 OK.

    8. Ora effettua diverse richieste TLS (HTTPS) dall'applicazione di test nello spazio dei nomi team-x:

      for i in {1..4}
      do
          kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
              -o jsonpath={.items..metadata.name}) -c test -- curl -s -o /dev/null \
              -w "%{http_code}\n" \
              https://example.com
      done
      

      Visualizzi 200 risposte.

    9. Guarda di nuovo il log del gateway di uscita:

      kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \
          -o jsonpath="{.items[0].metadata.name}") istio-proxy
      

      Vengono visualizzate voci di log simili alle seguenti:

      [2020-09-24T18:04:38.608Z] "- - -" 0 - "-" "-" 1363 5539 10 - "-" "-" "-" "-" "93.184.216.34:443" outbound|443||example.com 10.1.4.31:51098 10.1.4.31:8443 10.1.1.15:57030 example.com -
      

      La richiesta HTTPS è stata trattata come traffico TCP e trasmessa tramite il gateway all'host di destinazione, pertanto nel log non sono incluse informazioni HTTP.

    Utilizzo di NetworkPolicy di Kubernetes come controllo aggiuntivo

    Esistono molti scenari in cui un'applicazione può bypassare un proxy sidecar. Puoi utilizzare NetworkPolicy di Kubernetes per specificare ulteriormente le connessioni che i carichi di lavoro sono autorizzati a effettuare. Dopo l'applicazione di una singola policy di rete, tutte le connessioni non specificamente consentite vengono negate.

    Questo tutorial prende in considerazione solo le connessioni in uscita e i selettori in uscita per i criteri di rete. Se controlli l'ingresso con le norme di rete sui tuoi cluster, devi creare norme di ingresso che corrispondano alle norme di uscita. Ad esempio, se consenti l'uscita dai carichi di lavoro nello spazio dei nomi team-x allo spazio dei nomi team-y, devi anche consentire l'ingresso nello spazio dei nomi team-y dallo spazio dei nomi team-x.

    1. Consenti ai carichi di lavoro e ai proxy di cui è stato eseguito il deployment nello spazio dei nomi team-x di connettersi a istiod e al gateway di uscita:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-control-plane
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": istio-system
            podSelector:
              matchLabels:
                istio: istiod
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": istio-egress
            podSelector:
              matchLabels:
                istio: egressgateway
      EOF
      
    2. Consenti a carichi di lavoro e proxy di eseguire query DNS:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-dns
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": kube-system
          ports:
          - port: 53
            protocol: UDP
          - port: 53
            protocol: TCP
      EOF
      
    3. Consenti ai workload e ai proxy di connettersi agli IP che forniscono API e servizi Google, inclusa l'autorità di certificazione Cloud Service Mesh:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-google-apis
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - ipBlock:
              cidr: 199.36.153.4/30
          - ipBlock:
              cidr: 199.36.153.8/30
      EOF
      
    4. Consenti a workload e proxy di connettersi al server metadati GKE:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-metadata-server
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to: # For GKE data plane v2
          - ipBlock:
              cidr: 169.254.169.254/32
        - to: # For GKE data plane v1
          - ipBlock:
              cidr: 127.0.0.1/32 # Prior to 1.21.0-gke.1000
          - ipBlock:
              cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later
          ports:
          - protocol: TCP
            port: 987
          - protocol: TCP
            port: 988
      EOF
      
    5. (Facoltativo) Consenti ai carichi di lavoro e ai proxy nello spazio dei nomi team-x di stabilire connessioni tra loro:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-same-namespace
        namespace: team-x
      spec:
        podSelector: {}
        ingress:
          - from:
            - podSelector: {}
        egress:
          - to:
            - podSelector: {}
      EOF
      
    6. (Facoltativo) Consenti ai carichi di lavoro e ai proxy nello spazio dei nomi team-x di stabilire connessioni ai carichi di lavoro di cui è stato eseguito il deployment da un altro team:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-team-y
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": team-y
      EOF
      
    7. Le connessioni tra i proxy sidecar vengono mantenute. Le connessioni esistenti non vengono chiuse quando applichi una nuova policy di rete. Riavvia i carichi di lavoro nello spazio dei nomi team-x per assicurarti che le connessioni esistenti vengano chiuse:

      kubectl -n team-x rollout restart deployment
      
    8. Verifica di poter ancora effettuare una richiesta HTTP a example.com dall'applicazione di test nello spazio dei nomi team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      La richiesta ha esito positivo con una risposta 200 OK.

    Accesso diretto alle API di Google utilizzando l'accesso privato Google e le autorizzazioni IAM

    Le API e i servizi di Google vengono esposti utilizzando indirizzi IP esterni. Quando i pod con indirizzi IP alias VPC nativi si connettono alle API di Google utilizzando l'accesso privato Google, il traffico non esce mai dalla rete di Google.

    Quando hai configurato l'infrastruttura per questo tutorial, hai abilitato l'accesso privato Google per la subnet utilizzata dai pod GKE. Per consentire l'accesso agli indirizzi IP utilizzati da Accesso privato Google, hai creato una route, una regola firewall VPC e una zona DNS privata. Questa configurazione consente ai pod di raggiungere direttamente le API di Google senza inviare traffico tramite il gateway di uscita. Puoi controllare quali API sono disponibili per service account Kubernetes (e quindi spazi dei nomi) specifici utilizzando Workload Identity Federation for GKE e IAM. L'autorizzazione Istio non ha effetto perché il gateway di uscita non gestisce le connessioni alle API di Google.

    Prima che i pod possano chiamare le API di Google, devi utilizzare IAM per concedere le autorizzazioni. Il cluster che utilizzi per questo tutorial è configurato per utilizzare Workload Identity Federation for GKE, che consente a un account di servizio Kubernetes di fungere da account di servizio Google.

    1. Crea un account di servizio Google da utilizzare per la tua applicazione:

      gcloud iam service-accounts create sa-test-app-team-x
      
    2. Consenti al account di servizio Kubernetes di rappresentare il service account Google:

      gcloud iam service-accounts add-iam-policy-binding \
        --role roles/iam.workloadIdentityUser \
        --member "serviceAccount:${PROJECT_ID}.svc.id.goog[team-x/test]" \
        sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
      
    3. Annota il account di servizio Kubernetes per l'app di test nello spazio dei nomi team-x con l'indirizzo email del account di servizio Google:

      cat <<EOF | kubectl apply -f -
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        annotations:
          iam.gke.io/gcp-service-account: sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
        name: test
        namespace: team-x
      EOF
      
    4. Il pod dell'applicazione di test deve essere in grado di accedere al server di metadati Google (in esecuzione come DaemonSet) per ottenere credenziali temporanee per chiamare le API di Google. Crea una voce di servizio per il server di metadati GKE:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: metadata-google-internal
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: metadata.google.internal
      spec:
        hosts:
        - metadata.google.internal
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    5. Crea anche una voce di servizio per private.googleapis.com e storage.googleapis.com:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: private-googleapis-com
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: googleapis.com
      spec:
        hosts:
        - private.googleapis.com
        - storage.googleapis.com
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    6. Verifica che il account di servizio Kubernetes sia configurato correttamente per fungere daaccount di serviziot Google:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- gcloud auth list
      

      Vedi il account di servizio Google elencato come identità attiva e unica.

    7. Crea un file di test in un bucket Cloud Storage:

      echo "Hello, World!" > /tmp/hello
      gcloud storage buckets create gs://${PROJECT_ID}-bucket
      gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
      
    8. Concedi all'account di servizio l'autorizzazione per elencare e visualizzare i file nel bucket:

      gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-bucket/ \
          --member=serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com \
          --role=roles/storage.objectViewer
      
    9. Verifica che l'applicazione di test possa accedere al bucket di test:

      kubectl -n team-x exec -it \
      $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \
      -c test \
      -- gcloud storage cat gs://${PROJECT_ID}-bucket/hello
      

      Le voci della tabella sono:

      Hello, World!
      

    Esegui la pulizia

    Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

    Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, completa i passaggi nelle sezioni seguenti:

    Elimina il progetto

    Il modo più semplice per eliminare la fatturazione è eliminare il progetto creato per il tutorial.

    1. In the Google Cloud console, go to the Manage resources page.

      Go to Manage resources

    2. In the project list, select the project that you want to delete, and then click Delete.
    3. In the dialog, type the project ID, and then click Shut down to delete the project.

    Passaggi successivi