Anthos Service Mesh 1.10 ha raggiunto la fine del ciclo di vita e non è più supportato. Vedi Eseguire l'upgrade dalle versioni precedenti.

Visualizza la documentazione più recente o seleziona un'altra versione disponibile:

Utilizzo dei gateway in uscita di Anthos Service Mesh sui cluster GKE: Tutorial

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

Questo tutorial mostra come utilizzare i gateway in uscita Anthos Service Mesh e altri controlli di Google Cloud per proteggere il traffico in uscita (egress) dai carichi di lavoro di cui è stato eseguito il deployment su un cluster Google Kubernetes Engine. Il tutorial è inteso come complemento alla guida alle best practice.

Il pubblico di destinazione di questo tutorial è composto da tecnici di rete, piattaforma e sicurezza che amministrano i cluster di 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 Anthos Service Mesh:
  • Installa Anthos Service Mesh con gateway in uscita su un pool di nodi dedicato.
  • Configura le regole di routing multi-tenant per il traffico esterno attraverso 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 del traffico in uscita del proxy sidecar 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 (origine TLS).
  • Configura il gateway in uscita in modo che trasferisca il traffico TLS.
  • Configura i criteri di rete di Kubernetes come controllo aggiuntivo del traffico in uscita.
  • Configurare l'accesso diretto alle API di Google utilizzando le autorizzazioni di accesso privato Google e Identity and Access Management (IAM).

Costi

Questo tutorial utilizza 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 possono beneficiare di una prova gratuita.

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

Prima di iniziare

  1. Nella pagina del selettore dei progetti in Google Cloud Console, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  2. Assicurati che la fatturazione sia attivata per il tuo progetto Cloud. Scopri come verificare se la fatturazione è abilitata su un progetto.

  3. In Google Cloud Console, attiva Cloud Shell.

    Attiva 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 progetto e alle 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. Rendi eseguibile lo script ed eseguilo con il comando source per inizializzare l'ambiente:

    chmod +x ./init-egress-tutorial.sh
    source ./init-egress-tutorial.sh
    
  7. Imposta i ruoli di gestione di Identity and Access Management (IAM) richiesti. Se sei il proprietario del progetto, hai tutte le autorizzazioni necessarie per completare l'installazione. Se non sei un proprietario del progetto, chiedi all'amministratore di concederti i seguenti ruoli IAM. Nel comando seguente, modifica PROJECT_EMAIL_ADDRESS nell'account che utilizzi per accedere a Google Cloud.

    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member user:PROJECT_EMAIL_ADDRESS \
        --role=roles/editor \
        --role=roles/compute.admin \
        --role=roles/container.admin \
        --role=roles/resourcemanager.projectIamAdmin \
        --role=roles/iam.serviceAccountAdmin \
        --role=roles/iam.serviceAccountKeyAdmin \
        --role=roles/gkehub.admin \
        --role=roles/serviceusage.serviceUsageAdmin
    
  8. Abilita le API necessarie per il tutorial:

    gcloud services enable \
        dns.googleapis.com \
        container.googleapis.com \
        compute.googleapis.com \
        monitoring.googleapis.com \
        logging.googleapis.com \
        cloudtrace.googleapis.com \
        meshca.googleapis.com \
        meshtelemetry.googleapis.com \
        meshconfig.googleapis.com \
        iamcredentials.googleapis.com \
        gkeconnect.googleapis.com \
        gkehub.googleapis.com \
        cloudresourcemanager.googleapis.com \
        stackdriver.googleapis.com
    

    L'abilitazione delle API può richiedere un minuto o più. Quando le API sono abilitate, viene visualizzato un output simile al seguente:

    Operation "operations/acf.601db672-88e6-4f98-8ceb-aa3b5725533c" finished
    successfully.
    

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 soli indirizzi IP interni possano raggiungere le API e i 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 ai carichi di lavoro senza indirizzi IP esterni di connettersi alle destinazioni su Internet e ricevere risposte in entrata da tali 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 ciascun pool di nodi GKE

Creare due account di servizio da utilizzare per i due pool di nodi GKE. A ogni pool di nodi viene assegnato un account di servizio separato per poter applicare le 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 che deve essere utilizzato 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 agli account di servizio dell'applicazione e del gateway. Questi ruoli sono richiesti per il logging, il monitoraggio e il pull 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

Creazione delle regole firewall in corso...

Nei passaggi seguenti, applichi una regola firewall alla rete VPC in modo che, per impostazione predefinita, venga rifiutato tutto il traffico in uscita. Affinché il cluster funzioni e i nodi gateway possano raggiungere le destinazioni al di fuori del VPC, è necessaria una connettività specifica. Un numero minimo di regole firewall specifiche sostituisce la regola predefinita di negazione generale per consentire la connettività necessaria.

  1. Crea una regola firewall predefinita (con priorità bassa) per rifiutare 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 la connessione a Internet solo per i nodi in possesso dell'account di servizio gateway:

    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 \
        --destination-ranges 10.5.0.0/28 \
        --network vpc-network \
        --priority 1000 \
        --description "Allow nodes to reach the Kubernetes API server."
    
  4. Anthos Service Mesh utilizza i webhook durante l'inserimento di proxy sidecar nei carichi di lavoro. Consenti al server API GKE di chiamare i webhook esposti dal piano di controllo del mesh di servizi in esecuzione sui nodi:

    gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \
        --action ALLOW \
        --direction INGRESS \
        --rules tcp:15017 \
        --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 pod e servizi in esecuzione nel cluster. Tieni presente che GKE crea automaticamente una regola in entrata corrispondente.

    gcloud compute firewall-rules create allow-egress-pods-and-services \
        --action ALLOW \
        --direction EGRESS \
        --rules all \
        --destination-ranges 10.1.0.0/16,10.2.0.0/20 \
        --network vpc-network \
        --priority 1000 \
        --description "Allow pods and services on nodes to reach each other"
    
  6. Un servizio chiamato Calico fornisce funzionalità API NetworkPolicy per GKE. Consenti la connettività per Calico all'interno della subnet:

    gcloud compute firewall-rules create allow-egress-calico \
        --action ALLOW \
        --direction EGRESS \
        --rules tcp:5473 \
        --destination-ranges 10.0.0.0/24 \
        --network vpc-network \
        --priority 1000 \
        --description "Allow Calico Typha within the subnet"
    
  7. Affinché GKE possa leggere le metriche dei nodi, è necessaria la porta di sola lettura kubelet. Consenti l'accesso alla subnet:

    gcloud compute firewall-rules create allow-egress-kubelet-readonly \
        --action ALLOW \
        --direction EGRESS \
        --rules tcp:10255 \
        --destination-ranges 10.0.0.0/24 \
        --network vpc-network \
        --priority 1000 \
        --description "Allow access to the kubelet read-only port within the subnet"
    
  8. Consenti l'accesso ai set riservati di indirizzi IP utilizzati dall'accesso privato Google per la gestione delle API di Google, Container Registry e altri servizi:

    gcloud compute firewall-rules create allow-egress-gcp-apis \
        --action ALLOW \
        --direction EGRESS \
        --rules tcp \
        --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)"
    
  9. Consenti al servizio di controllo di integrità di Google Cloud di accedere ai pod in esecuzione nel cluster:

    gcloud compute firewall-rules create allow-ingress-gcp-health-checker \
        --action ALLOW \
        --direction INGRESS \
        --rules tcp:80,tcp:443 \
        --source-ranges 130.211.0.0/22,35.191.0.0/16,35.191.0.0/16,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 gestiti da IP esterni, il traffico proveniente dai nodi non lascia mai la rete Google quando si utilizza l'accesso privato Google.

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 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. Individua l'indirizzo IP esterno di Cloud Shell in modo da poterlo aggiungere all'elenco delle reti a cui è consentito di accedere al server API del 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 tal caso, devi aggiornare l'elenco di 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. Crea un cluster GKE privato:

    gcloud container clusters create cluster1 \
        --enable-ip-alias \
        --enable-private-nodes \
        --release-channel "regular" \
        --no-enable-basic-auth \
        --no-issue-client-certificate \
        --enable-master-authorized-networks \
        --master-authorized-networks ${SHELL_IP//\"}/32 \
        --master-ipv4-cidr 10.5.0.0/28 \
        --enable-network-policy \
        --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
        --machine-type "e2-standard-4" \
        --num-nodes "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 dispone di nodi privati con indirizzi IP interni. Ai pod e ai servizi vengono assegnati IP dagli intervalli secondari denominati che hai definito durante la creazione della subnet VPC.

    Anthos Service Mesh richiede che i nodi cluster utilizzino un tipo di macchina con almeno 4 vCPU. Google consiglia di iscrivere il cluster al canale di rilascio "standard" per garantire che i nodi stiano eseguendo una versione di Kubernetes supportata da Anthos Service Mesh. Per ulteriori informazioni, consulta le guide all'installazione di Anthos Service Mesh.

    Workload Identity è abilitato sul cluster. Anthos Service Mesh richiede Workload Identity ed è il modo consigliato per accedere alle API di Google dai carichi di lavoro GKE.

  3. Crea un pool di nodi denominato gateway. È in questo pool di nodi che viene eseguito il deployment del gateway in uscita. L'incompatibilità dedicated=gateway:NoSchedule viene aggiunta a ogni nodo nel pool di nodi 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 aiutano a garantire che solo i pod del gateway in uscita vengano eseguiti sui nodi nel pool del nodo gateway.

  4. Scarica le credenziali per connetterti al cluster con kubectl:

    gcloud container clusters get-credentials cluster1
    
  5. Verifica che i nodi 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 Anthos Service Mesh

Questo tutorial utilizza funzionalità facoltative di Anthos Service Mesh. Per scoprire di più sull'installazione di Anthos Service Mesh con uno script, consulta la guida all'installazione nella documentazione.

  1. Crea gli spazi dei nomi per i piani di controllo e i gateway in uscita del mesh di servizi in cui eseguire il deployment:

    kubectl create ns istio-system
    kubectl create ns istio-egress
    
  2. Assegna un'etichetta agli spazi dei nomi istio-egress, istio-system e kube-system:

    kubectl label ns istio-egress istio=egress istio-injection=disabled
    kubectl label ns istio-system istio=system
    kubectl label ns kube-system kube-system=true
    

    che verranno utilizzate in un secondo momento per applicare Kubernetes NetworkPolicy. L'etichetta istio-injection=disabled impedisce avvisi non corretti durante l'esecuzione di istioctlanalisi.

  3. Crea un file manifest per personalizzare l'installazione di Anthos Service Mesh utilizzando l'APIIstio OperatorAPI:

    cat << 'EOF' > ./asm-custom-install.yaml
    apiVersion: install.istio.io/v1alpha1
    kind: IstioOperator
    metadata:
      name: "egress-gateway"
    spec:
      meshConfig:
        accessLogFile: "/dev/stdout"
      components:
        egressGateways:
          - name: "istio-egressgateway"
            enabled: true
            namespace: "istio-egress"
            label:
              istio: "egress"
            k8s:
              tolerations:
              - key: "dedicated"
                operator: "Equal"
                value: "gateway"
              nodeSelector:
                cloud.google.com/gke-nodepool: "gateway"
    EOF
    

    Questo file viene fornito come argomento per lo script di installazione e specifica la seguente configurazione:

    • Un deployment del gateway in uscita in esecuzione nello spazio dei nomi istio-egress con una tolleranza e un nodeSelector in modo che venga eseguito solo sui nodi gateway.
    • Accesso al logging in "stdout" per tutti i proxy sidecar.
  4. Scarica lo script di installazione:

    curl -O https://storage.googleapis.com/csm-artifacts/asm/install_asm
    
  5. Rendi lo script eseguibile:

    chmod +x install_asm
    
  6. Installa Anthos Service Mesh eseguendo lo script:

    ./install_asm \
        --mode install \
        --project_id ${PROJECT_ID} \
        --cluster_name cluster1 \
        --cluster_location ${ZONE} \
        --custom_overlay ./asm-custom-install.yaml \
        --output_dir ./ \
        --enable_all
    
  7. Al termine dello script, imposta una variabile di ambiente in modo che conservi il percorso verso lo strumento istioctl e aggiungila allo script di inizializzazione:

    ISTIOCTL=$(find "$(pwd -P)" -name istioctl)
    echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
    

Verifica dell'installazione di Anthos Service Mesh

  1. Controlla che i componenti del piano di controllo di Anthos Service Mesh siano in esecuzione nello spazio dei nomi istio-system:

    kubectl get pod -n istio-system
    

    Vedrai istio-ingressgateway e istiod-asm pod in esecuzione.

  2. Verifica che i pod del gateway in uscita siano in esecuzione nello spazio dei nomi istio-egress e sui nodi nel pool di nodi gateway:

    kubectl get pods -n istio-egress -o wide
    
  3. I pod del gateway in uscita hanno una nodeSelector per selezionare nodi nel pool di nodi gateway e una tolleranza che ne consente l'esecuzione sui nodi del gateway incompatibili. Esamina il nodeSelector e le tolleranze per i pod del gateway in uscita:

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

    L'output è simile al seguente:

    name                                   nodeSelector                                 tolerations
    istio-egressgateway-74687946f5-dg9mp   map[cloud.google.com/gke-nodepool:gateway]   map[key:dedicated operator:Equal value:gateway]
    

Preparazione del mesh e di un'applicazione di test in corso...

  1. Assicurati che la crittografia STRICT TLS sia abilitata. 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 ignorare questa configurazione creando risorse PeerAuthentication in spazi dei nomi specifici.

  2. Creare spazi dei nomi da utilizzare per il deployment dei carichi di lavoro di test. I passaggi successivi di questo tutorial spiegano come configurare diverse regole di routing per il traffico 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 dai criteri di rete di Kubernetes:

    kubectl label namespace team-x team=x
    kubectl label namespace team-y team=y
    
  4. Affinché Anthos Service Mesh possa inserire automaticamente i file collaterali proxy, devi impostare un'etichetta di revisione negli spazi dei nomi del carico di lavoro. L'etichetta di revisione deve corrispondere alla revisione del piano di controllo di Anthos Service Mesh di cui è stato eseguito il deployment nel cluster. Cerca l'etichetta di revisione sul pod istiod e archiviala in una variabile di ambiente:

    REVISION_LABEL=$(kubectl get pod -n istio-system -l app=istiod \
      -o jsonpath='{.items[0].metadata.labels.istio\.io/rev}')
    
  5. Imposta l'etichetta di revisione negli spazi dei nomi team-x e team-y:

    kubectl label ns team-x istio.io/rev=${REVISION_LABEL}
    kubectl label ns team-y istio.io/rev=${REVISION_LABEL}
    
  6. 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
    
  7. Esegui il deployment dell'applicazione di test nello spazio dei nomi team-x:

    kubectl -n team-x create -f ./test.yaml
    
  8. Verifica che venga eseguito il deployment dell'applicazione di test in un nodo nel pool predefinito e che sia stato inserito un container collaterale proxy. Ripeti il seguente comando finché lo stato del pod non sarà 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
    

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

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

  9. 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 a monte.

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

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

Il proxy eseguito da Anthos Service Mesh nel file collaterale è Envoy. In Terminologia Envoy, un cluster è un gruppo logicamente simile di endpoint a monte 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
    

    L'elenco contiene circa 20 cluster Envoy, inclusi diversi gateway per il gateway in uscita.

  2. Limita la configurazione proxy alle route in uscita che sono state definite in modo esplicito con le voci di servizio negli spazi dei nomi istio-egress 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 la configurazione del proxy in modo da includere solo gli host esterni che sono stati aggiunti esplicitamente al registro dei servizi del mesh, definendo le voci del servizio.

    La parte "istio-egress/*" specifica che il proxy sidecar seleziona le route dallo spazio dei nomi istio-egress che sono rese disponibili utilizzando l'attributo exportTo. La parte "team-x/*" include le route 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 di applicare la risorsa Sidecar:

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

    L'output include solo alcuni cluster per il gateway in uscita e uno per il pod di test stesso.

Configurazione di Anthos Service Mesh per instradare il traffico attraverso il gateway in uscita

  1. Configura un Gateway per il traffico HTTP sulla porta 80. Il Gateway seleziona il proxy istio-egressgateway di cui il programma di installazione ha eseguito il deployment nello spazio dei nomi istio-egress. La configurazione Gateway viene applicata allo spazio dei nomi istio-egress 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: egress
      servers:
      - port:
          number: 80
          name: https
          protocol: HTTPS
        hosts:
          - '*'
        tls:
          mode: ISTIO_MUTUAL
    EOF
    
  2. Crea un DestinationRule per il gateway in uscita con TLS reciproco per autenticazione e crittografia. Utilizza una sola 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:
          loadBalancer:
            simple: ROUND_ROBIN
          tls:
            mode: ISTIO_MUTUAL
    EOF
    
  3. Crea un ServiceEntry nello spazio dei nomi istio-egress per registrare esplicitamente example.com nel registro di servizio 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
    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 attraverso il gateway in uscita. Esistono due condizioni di corrispondenza: la prima indirizza il traffico al gateway in uscita e la seconda indirizza il traffico dal gateway in 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
    

    L'output è simile al seguente:

    ✔ No validation issues found when analyzing namespace: istio-egress.
    
  6. Invia diverse richieste attraverso 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
    

    Vedrai 200 codici di stato per tutte e quattro le risposte.

  7. Verifica che le richieste siano state indirizzate attraverso il gateway in uscita controllando i log di accesso al proxy. Controlla innanzitutto nel log di accesso il 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 dell'accesso al gateway in uscita:

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

    Per ogni richiesta inviata, viene visualizzata una voce di log per l'accesso al gateway in 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 -
    

Configura il routing diverso per un secondo spazio dei nomi

Configura il routing per un secondo host esterno per scoprire come si può configurare la connettività esterna 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 nello spazio 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
    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 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
    

    Le voci della tabella sono:

    ✔ No validation issues found when analyzing namespace: istio-egress.
    
  6. Fai 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
    

    Vedi una risposta 200 OK.

  7. Invia anche 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
    

    Vedi una risposta 200 OK.

  8. Prova a 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 è stata configurata alcuna route in uscita per l'host example.com.

Utilizzo del criterio di autorizzazione per fornire maggiore controllo sul traffico

In questo tutorial, i criteri di autorizzazione per il gateway in uscita vengono creati nello istio-egressspazio dei nomi. 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 invia richieste con la porta 80. Il valore 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-x-to-example-com
      namespace: istio-egress
    spec:
      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
    

    Vedi una risposta 200 OK.

  3. Prova a effettuare 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 riesce con un messaggio RBAC: access denied e un codice di stato 403 Forbidden. Potrebbe essere necessario attendere qualche secondo perché spesso si verifica un leggero ritardo prima che le norme di autorizzazione entrino in vigore.

  4. I criteri di autorizzazione forniscono un controllo avanzato sul traffico consentito o negato. Applica il criterio di autorizzazione seguente per consentire all'app di test nello spazio dei nomi team-y di effettuare richieste a httpbin.org utilizzando un particolare percorso URL quando invia le richieste utilizzando la porta 80. La corrispondente targetPort 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:
      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 con un messaggio RBAC: Access negato e un codice di stato 403 Forbidden.

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

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

originazione TLS sul gateway in uscita

Puoi configurare i gateway in uscita in modo da "eseguire l'upgrade" (originari) delle richieste HTTP semplici a TLS. Consentire alle applicazioni di effettuare richieste HTTP semplici presenta diversi vantaggi quando viene utilizzato con la configurazione TLS e TLS originaria di Istio. Per ulteriori informazioni, consulta la guida alle best practice.

originazione TLS sul gateway in uscita

  1. Creare un DestinationRule. The DestinationRule specifica che il gateway ha origine 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:
            loadBalancer:
              simple: ROUND_ROBIN
            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 vengano "aggiornate" 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 varie 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 200 OK risposte.

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

    kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egress \
        -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 proxy ha inviato la richiesta al gateway utilizzando la porta 80 e TLS originati sulla porta 443 per inviare la richiesta all'host di destinazione.

Passthrough di connessioni HTTPS/TLS

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

passaggio di tls

  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: egress
      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 il DestinationRule che punta al gateway in uscita per aggiungere un secondo sottoinsieme per la porta 443 sul gateway. Questo nuovo sottoinsieme non utilizza TLS reciproco. TLS reciproca di Istio non è supportato per il passthrough di connessioni TLS. Le connessioni sulla porta 80 utilizzano comunque 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:
          loadBalancer:
            simple: ROUND_ROBIN
          portLevelSettings:
          - port:
              number: 80
            tls:
              mode: ISTIO_MUTUAL
      - name: target-egress-gateway-TLS-passthrough
    EOF
    
  3. Aggiorna il servizio virtuale example.com in modo che il traffico TLS sulla porta 443 passi attraverso 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 passato attraverso 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. Il valore 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:
      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
    

    Le voci della tabella sono:

    ✔ No validation issues found when analyzing namespace: istio-egress.
    
  7. Esegui una richiesta HTTP semplice a example.com dall'applicazione di test 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 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
    

    Vedi 200 risposte.

  9. Esamina nuovamente il log del gateway in uscita:

    kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egress \
        -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 attraverso il gateway all'host di destinazione, quindi non sono incluse informazioni HTTP nel log.

Utilizzo di NetworkPolicy di Kubernetes come controllo aggiuntivo

Esistono molti scenari in cui un'applicazione può ignorare un proxy sidecar. Puoi utilizzare Kubernetes NetworkPolicy per specificare quali connessioni sono consentite per i carichi di lavoro delle operazioni. Dopo aver applicato un unico criterio di rete, tutte le connessioni non specificamente consentite vengono rifiutate.

Questo tutorial considera solo le connessioni in uscita e i selettori di traffico in uscita per i criteri di rete. Se controlli i criteri di rete in entrata nei tuoi cluster, devi creare criteri in entrata che corrispondano ai tuoi criteri in uscita. Ad esempio, se si consente il traffico in uscita da carichi di lavoro nello spazio dei nomi team-x allo spazio dei nomi team-y, è necessario consentire il traffico in entrata anche nello spazio dei nomi team-y dello 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 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:
              istio: system
          podSelector:
            matchLabels:
              istio: istiod
        - namespaceSelector:
            matchLabels:
              istio: egress
          podSelector:
            matchLabels:
              istio: egress
    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:
              kube-system: "true"
        ports:
        - port: 53
          protocol: UDP
        - port: 53
          protocol: TCP
    EOF
    
  3. Consenti a carichi di lavoro e proxy di connettersi agli IP che gestiscono API e servizi Google, tra cui Mesh CA:

    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 ai carichi di lavoro e ai proxy di connettersi al server dei 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
        ports:
        - 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 i carichi di lavoro e i proxy nello spazio dei nomi team-x per effettuare connessioni ai carichi di lavoro di cui viene 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:
              team: 'y'
    EOF
    
  7. Le connessioni tra i proxy sidecar vengono mantenute. Le connessioni esistenti non vengono chiuse quando applichi un nuovo criterio di rete. Riavvia i carichi di lavoro nello spazio dei nomi team-x per assicurarti che le connessioni esistenti siano 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 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.

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

Le API e i servizi Google vengono esposti utilizzando indirizzi IP esterni. Quando i pod con indirizzi IP alias nativi VPC connettono le API Google utilizzando l'accesso privato Google, il traffico non lascia mai la rete Google.

Durante la configurazione dell'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 dall'accesso privato Google, hai creato una route, una regola firewall VPC e una zona DNS privato. Questa configurazione consente ai pod di raggiungere le API di Google direttamente senza inviare il traffico tramite il gateway in uscita. Puoi controllare quali API sono disponibili per account di servizio Kubernetes specifici (e quindi spazi dei nomi) utilizzando Workload Identity e IAM. L'autorizzazione Istio non ha effetto perché il gateway in 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, che consente a un account di servizio Kubernetes di agire come account di servizio Google.

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

    gcloud iam service-accounts create sa-test-app-team-x
    
  2. Consenti all'account di servizio Kubernetes di impersonare l'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 nello spazio dei nomi 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 al server di metadati Google (in esecuzione come DaemonSet) per ottenere credenziali temporanee per le chiamate alle API di Google. Crea una voce di servizio per il server metadati GKE:

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1beta1
    kind: ServiceEntry
    metadata:
      name: metadata-google-internal
      namespace: istio-egress
    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
    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 agire come 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 l'account di servizio Google elencato come unica e attiva.

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

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

    gsutil iam ch \
    serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com:objectViewer \
        gs://${PROJECT_ID}-bucket/
    
  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 \
    -- gsutil 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 descritti nelle sezioni seguenti.

Elimina il progetto

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

  1. In Google Cloud Console, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Passaggi successivi