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


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

Il pubblico di destinazione di questo tutorial include rete, piattaforma e tecnici della sicurezza che amministrano i cluster di Google Kubernetes Engine utilizzati da uno o 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 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 del proxy sidecar configurazione in uscita per ogni spazio dei nomi.
  • Configura i criteri di autorizzazione per applicare le regole in uscita.
  • Configura il gateway in uscita per eseguire l'upgrade delle richieste HTTP semplici a TLS (TLS origine).
  • Configura il gateway in uscita in modo che trasmetta il traffico TLS.
  • Configura i criteri di rete di Kubernetes come controllo in uscita aggiuntivo.
  • Configura l'accesso diretto alle API di Google utilizzando Accesso privato Google e Identity and Access Management (IAM) autorizzazioni aggiuntive.

Costi

In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi basata sull'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud potrebbero essere idonei per una prova gratuita.

Al termine di questo tutorial, puoi evitare costi ricorrenti eliminando le risorse che hai creato. Per ulteriori informazioni, consulta la sezione 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. Make sure 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 durante l'esecuzione del 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 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 per inizializzare il tuo ambiente. Seleziona Y se ti viene richiesto di abilitare compute.googleapis.com:

    chmod +x ./init-egress-tutorial.sh
    source ./init-egress-tutorial.sh
    

Configurazione dell'infrastruttura

Crea una rete e una subnet VPC

  1. Crea una nuova rete VPC:

    gcloud compute networks create vpc-network \
        --subnet-mode custom
    
  2. Crea una subnet per l'esecuzione del cluster con un server secondario preassegnato di indirizzi IP per pod e servizi. Accesso privato Google corrente abilitata in modo che le applicazioni con solo indirizzi IP interni possano raggiungere API e servizi 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 la connessione a carichi di lavoro senza indirizzi IP esterni destinazioni su internet e ricevono risposte in entrata 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 account di servizio per ogni pool di nodi GKE

Crea due account di servizio da utilizzare per i due pool di nodi GKE. Un account di servizio separato è assegnato a ogni pool di nodi, e applicare regole firewall VPC a nodi specifici.

  1. Crea un account di servizio da utilizzare dai 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 dai nodi nel pool di nodi del gateway:

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

Concedi le autorizzazioni agli account di servizio

Aggiungi un insieme minimo di ruoli IAM all'applicazione e al gateway account di servizio. Questi ruoli sono necessari per il logging, il monitoraggio e il recupero di 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

crea le regole firewall

Nei passaggi seguenti, applichi una regola firewall alla rete VPC in modo che, per impostazione predefinita, tutto il traffico in uscita venga negato. È necessaria una connettività specifica per il funzionamento del cluster e per consentire ai nodi gateway di raggiungere destinazioni al di fuori della VPC. Un insieme minimo di regole firewall specifiche esegue l'override regola predefinita di negazione di tutto 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 i nodi con il servizio gateway per connetterti 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 piano di controllo 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 inietta i proxy sidecar nei carichi di lavoro. Consenti al server API GKE di chiamare i webhook esposti dal piano di controllo di Service Mesh 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 i nodi e i pod in esecuzione sul cluster. GKE crea automaticamente con la regola in entrata corrispondente. Nessuna regola richiesta per la connettività al servizio poiché la catena di routing iptables converte sempre gli indirizzi IP del servizio in gli indirizzi IP dei 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 agli insiemi riservati di indirizzi IP utilizzati da Accesso privato Google 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à di Google Cloud di accedere ai pod in esecuzione nel cluster. Vedi i controlli di integrità: per ulteriori informazioni.

    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 abilita VM e pod che hanno solo IP interno per accedere alle API e ai servizi Google. Anche se le API e i servizi Google vengono pubblicati da indirizzi IP esterni, il traffico dai nodi non esce mai dalla rete di Google quando utilizzi l'accesso privato Google.

Abilita l'API Cloud DNS:

gcloud services enable dns.googleapis.com

Crea una zona DNS privata, un record CNAME e un 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 l'hostname 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 e un record CNAME e un record A in modo che i nodi possano connettersi a Container Registry utilizzando l'accesso privato Google e 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 tuo 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 gli IP degli intervalli secondari denominati che hai definito durante la creazione della subnet VPC.

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

    Google consiglia di sottoscrivere un abbonamento al cluster "regular" rilasciare per garantire che i nodi eseguano una versione Kubernetes supportate 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 Cloud Service Mesh per la gestione funzionalità supportate da Cloud Service Mesh gestito.

    Workload Identity Federation for GKE è attivata sul cluster. Cloud Service Mesh richiede la federazione delle identità per i carichi di lavoro per GKE e è il metodo consigliato per accedere alle API di Google da GKE carichi di lavoro con scale out impegnativi.

  4. Crea un pool di nodi denominato gateway. Questo pool di nodi è il punto in cui il traffico in uscita del gateway VPN ad alta disponibilità. L'incompatibilitàdedicated=gateway:NoSchedule viene aggiunta a ogni nodo del 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 le tolleranze di Kubernetes contribuiscono a garantire che solo i pod del gateway in uscita vengano eseguiti sui nodi del pool di nodi del gateway.

  5. Scarica le credenziali in modo da poterti connettere al cluster con kubectl:

    gcloud container clusters get-credentials cluster1
    
  6. Verifica che i nodi del gateway abbiano l'incompatibilità corretta:

    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 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 in uscita:

    kubectl create namespace istio-egress
    
  2. Attiva lo spazio dei nomi per l'iniezione. I passaggi dipendono dall'implementazione del piano di controllo.

    Gestito (TD)

    Applica l'etichetta di inserimento predefinita allo spazio dei nomi:

    kubectl label namespace istio-egress \
        istio.io/rev- istio-injection=enabled --overwrite
    

    Gestito (Istiod)

    Consigliato: esegui questo comando per applicare l'etichetta di inserimento predefinita allo spazio dei nomi:

      kubectl label namespace istio-egress \
          istio.io/rev- istio-injection=enabled --overwrite
    

    Se sei un utente esistente con il piano di controllo Managed Istiod: Ti consigliamo di usare l'inserimento predefinito, ma l'inserimento basato sulle revisioni supportati. Segui queste istruzioni:

    1. Esegui questo comando per individuare i canali di rilascio disponibili:

      kubectl -n istio-system get controlplanerevision
      

      L'output è simile al seguente:

      NAME                AGE
      asm-managed-rapid   6d7h
      

      Nell'output, il valore nella colonna NAME è l'etichetta di revisione corrispondente al canale di rilascio disponibile per la versione di Cloud Service Mesh.

    2. Applica l'etichetta di revisione allo spazio dei nomi:

      kubectl label namespace istio-egress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      

    Nel cluster

    Consigliato: esegui questo comando per applicare l'etichetta di inserimento predefinita allo spazio dei nomi:

      kubectl label namespace istio-egress \
          istio.io/rev- istio-injection=enabled --overwrite
    

    Consigliamo di utilizzare l'inserimento predefinito, ma l'inserimento basato sulle revisioni è supportato: Segui queste istruzioni:

    1. Usa questo comando per individuare l'etichetta di revisione su istiod:

      kubectl get deploy -n istio-system -l app=istiod -o \
         jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
      
    2. Applica l'etichetta di revisione allo spazio dei nomi. Nel comando seguente, REVISION_LABEL è il valore della revisione istiod che hai annotato nel passaggio precedente.

      kubectl label namespace istio-egress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      
  3. 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
    
  4. Scarica lo strumento istioctl. Devi utilizzare la versione 1.16.2-asm.2 o successiva anche se utilizzi Cloud Service Mesh 1.15 o versioni precedenti. Consulta: Download della versione istioctl corretta.

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

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

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

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

    kubectl get pods -n istio-egress -o wide
    
  9. I pod del gateway in uscita hanno affinity per i nodi del 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]
    

Attivare 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:

Gestito

Segui le istruzioni per abilitare i log di accesso in Cloud Service Mesh gestito.

All'interno del cluster

Segui le istruzioni per abilita i log degli accessi in Cloud Service Mesh nel cluster.

Preparazione della rete mesh e di un'applicazione di test

  1. Assicurati che il protocollo TLS reciproco STRICT sia abilitato. Applica un criterio PeerAuthentication predefinito 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 PeerAuthentication in spazi dei nomi specifici.

  2. Crea spazi dei nomi da utilizzare per il deployment dei carichi di lavoro di test. Passaggi successivi in questo tutorial spiega come configurare diverse regole di routing in uscita 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 possa inserire automaticamente i file collaterali proxy, devi Imposta l'etichetta di revisione del piano di controllo sugli spazi dei nomi dei carichi di lavoro:

    kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite
    kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwrite
    
  5. Crea un file YAML da utilizzare per eseguire i 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 dispiattata su un nodo nel pool predefinito e che sia stato inserito un contenitore sidecar proxy. Ripeti quanto segue 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 container su 2 sono Running. Un contenitore è l'applicazione di test e l'altro è il sidecar proxy.

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

  8. Verifica che non sia possibile effettuare una richiesta HTTP dal contenitore 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 del firewallglobal-deny-egress-all nega la connessione a monte.

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

Puoi utilizzare lo Risorsa collaterale per limitare l'ambito del listener in uscita configurato per il sidecar proxy. Per ridurre le dimensioni eccessive della configurazione e l'utilizzo della memoria, è buona norma applica una risorsa Sidecar predefinita per ogni spazio dei nomi.

Il proxy che Cloud Service Mesh esegue nel file collaterale è Envoy. Nella Terminologia di Envoy, un cluster è un gruppo logicamente simile di endpoint upstream 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 ai route di uscita che sono stati definiti esplicitamente con voci di servizio nei namespace 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 del traffico in uscita su REGISTRY_ONLY limita le configurazione proxy per includere solo gli host esterni che sono stati esplicitamente aggiunto al registro dei servizi del mesh definendo le voci di servizio.

    L'impostazione egress.hosts specifica che il proxy sidecar seleziona solo i percorsi dello spazio dei nomi di uscita resi disponibili utilizzando l'attributo exportTo. La parte "team-x/*" include tutti i percorsi che sono stati configurati localmente nello spazio dei nomi team-x.

  3. Visualizzare i cluster in uscita configurati nel proxy sidecar di Envoy e e confrontarle con l'elenco dei cluster configurati prima dell'applicazione la risorsa Sidecar:

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

    Vedrai i cluster per la porta di uscita e uno per il pod di test stesso.

Configurare Cloud Service Mesh per instradare il traffico tramite il gateway in uscita

  1. Configura un Gateway per il traffico HTTP sulla porta 80. Gateway seleziona il proxy del gateway di uscita di cui hai eseguito il deployment nello spazio dei nomi di uscita. La configurazione Gateway viene applicata al nome di spazio 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 reciproco per l'autenticazione e la crittografia. Utilizza un'unica regola di destinazione condivisa per tutti per 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 registry 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 instradare il traffico verso example.com tramite il gateway di uscita. Esistono due condizioni di corrispondenza: la prima condizione indirizza il traffico verso il gateway in uscita e il secondo indirizza il traffico dalla gateway in uscita all'host di destinazione. La proprietà exportTo controlla gli spazi dei nomi che possono usare 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 in 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
    

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

  7. Verifica che le richieste siano state indirizzate attraverso il gateway in uscita da controllare i log di accesso proxy. Innanzitutto, controlla il log di accesso del sidecar proxy 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 inviata, 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 del gateway in 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 inviata, viene visualizzata una voce di log di accesso al gateway in uscita simile al 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 è possibile configurare diverse connettività esterne 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 in team-x e lo spazio dei nomi 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. Creare un servizio virtuale per instradare il traffico a httpbin.org tramite la gateway in 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. Effettua una richiesta a httpbin.org dall'app di prova 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. Effettua anche una richiesta ad 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. Tentativo 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 è configurato alcun percorso in uscita per l'example.com host.

Utilizzo del criterio di autorizzazione per fornire ulteriore controllo 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 gli amministratori di rete possono accedere allo spazio dei nomi istio-egress.

  1. Crea un AuthorizationPolicy in modo che le applicazioni in team-x dello spazio dei nomi può connettersi a example.com ma non ad altri host esterni quando che invia richieste utilizzando la porta 80. Il valore targetPort corrispondente nella per i pod del gateway in 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 nel 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 restituito un messaggio RBAC: access denied e un errore 403 Codice di stato vietato. Potresti dover attendere qualche secondo perché spesso si verifica un breve ritardo prima che il criterio di autorizzazione venga applicato.

  4. I criteri di autorizzazione offrono un controllo dettagliato sul traffico che viene consentito o non consentito. Applica il seguente criterio di autorizzazione per consentire test dell'app nello spazio dei nomi team-y per effettuare richieste a httpbin.org utilizzando a un determinato percorso dell'URL durante l'invio di richieste utilizzando la porta 80. 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 restituito un RBAC: messaggio di accesso negato e un errore 403 Codice di stato vietato.

  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 nella criterio di autorizzazione. L'output è simile al seguente:

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

Originazione TLS al gateway in uscita

Puoi configurare i gateway in uscita in modo che upgrade (originino) richieste HTTP non protette in TLS o TLS reciproco. Consentire alle applicazioni di effettuare richieste HTTP semplici offre diversi vantaggi quando viene utilizzato con TLS reciprocamente Istio e originazione TLS. Per maggiori informazioni, consulta la guida alle best practice.

Originazione TLS al gateway in uscita

  1. Crea un DestinationRule. The DestinationRule che 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. Effettua diverse richieste a example.com dall'app di prova in team-x spazio dei nomi:

    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 prima, le richieste vanno a buon fine con risposte 200 OK.

  4. Controlla il log del gateway in uscita per verificare che il gateway abbia inoltrato le richieste all'host di destinazione tramite le connessioni TLS di origine:

    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 sidecar del proxy ha inviato la richiesta al gateway utilizzando la porta 80 e TLS sulla porta 443 per inviare la richiesta all'host di destinazione.

Passthrough delle connessioni HTTPS/TLS

Le applicazioni esistenti potrebbero già utilizzare le connessioni TLS quando comunicare con servizi esterni. Puoi configurare il gateway in uscita per passare le connessioni TLS senza decriptarle.

tls pass through

  1. Modifica la configurazione in modo che il gateway in uscita utilizzi il passthrough 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 rimanda al gateway in uscita per aggiungere un secondo sottoinsieme per la porta 443 sul gateway. Questo nuovo sottoinsieme non utilizza TLS mutuale. Il TLS mutuale di Istio non è supportato per il passthrough 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 Viene fatto passare attraverso il gateway l'errore 443:

    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 a la porta 443 del servizio gateway in uscita. Il valore di targetPort corrispondente attivato dei 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. Invia una semplice richiesta HTTP a example.com dall'applicazione di test in nello team-xspazio dei nomi:

    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 nel 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
    

    Vengono visualizzate 200 risposte.

  9. Esamina di nuovo il log del gateway in uscita:

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

    Vedrai 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 Kubernetes NetworkPolicy come controllo aggiuntivo

Esistono molti scenari in cui un'applicazione può bypassare un proxy sidecar. Puoi utilizzare Kubernetes NetworkPolicy per specificare inoltre quali connessioni possono essere effettuate dai carichi di lavoro. Dopo l'applicazione di un singolo criterio di rete, tutte le connessioni non consentite specificamente 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 i criteri di rete sui tuoi cluster, devi creare criteri di ingresso corrispondenti ai criteri 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 consentire anche 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 connettiti a istiod e al gateway in 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 ai carichi di lavoro e ai proxy di eseguire query sul 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 carichi di lavoro e ai proxy di connettersi agli IP che pubblicano 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 carichi di lavoro e proxy di connettersi a GKE server metadati:

    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 eseguire 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 eseguire connessioni a carichi di lavoro di cui è stato eseguito il deployment da un team diverso:

    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 conservate. Le connessioni esistenti sono non viene chiusa quando applichi un nuovo criterio di rete. Riavvia i carichi di lavoro in lo spazio dei nomi team-x per assicurarti che le connessioni esistenti siano chiuse:

    kubectl -n team-x rollout restart deployment
    
  8. Verifica di poter comunque effettuare una richiesta HTTP a example.com dal testa l'applicazione nello team-xspazio dei nomi:

    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.

Accedere direttamente alle API Google utilizzando le autorizzazioni di accesso privato Google e IAM

Le API e i servizi Google sono esposti utilizzando indirizzi IP esterni. Quando i pod con indirizzi IP di alias VPC nativi effettuano connessioni alle API di Google utilizzando Accesso privato Google, il traffico non esce mai dalla rete di Google.

Quando hai configurato l'infrastruttura per questo tutorial, hai abilitato Accesso privato Google per la subnet utilizzata da GKE dei pod. Per consentire l'accesso agli indirizzi IP utilizzati dall'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 account di servizio Kubernetes specifici (e quindi per i relativi spazi dei nomi) utilizzando la federazione delle identità per i carichi di lavoro per GKE e IAM. L'autorizzazione Istio non viene applicata 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 autorizzazioni aggiuntive. Il cluster che usi per questo tutorial è configurato per usare Federazione delle identità per i carichi di lavoro per GKE, che consente a un account di servizio Kubernetes di agire 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 all'account di servizio Kubernetes di rubare l'identità dell'account di servizio 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 l'account di servizio Kubernetes per l'app di test nella team-x con l'indirizzo email dell'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 ai metadati Google server (in esecuzione come DaemonSet) per ottenere credenziali temporanee per le chiamate API di Google. Crea una voce di servizio per GKE server metadati:

    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 l'account di servizio Kubernetes sia configurato correttamente per fungere da account di servizio 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
    

    Vedrai il service account Google elencato come unica identità attiva.

  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 a elencare e visualizzare i file nel del 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 usati in questo tutorial, completa i passaggi nelle seguenti sezioni:

Elimina il progetto

Il modo più semplice per eliminare la fatturazione è eliminare il progetto che hai 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