Egress-Gateways von Cloud Service Mesh in GKE-Clustern verwenden: Anleitung


In dieser Anleitung wird gezeigt, wie Sie mit Cloud Service Mesh-Ausgangsgateways und anderen Google Cloud -Steuerelementen ausgehenden Traffic von Arbeitslasten schützen, die auf einem Google Kubernetes Engine-Cluster bereitgestellt werden. Die Anleitung dient als begleitende Ergänzung zu den Best Practices für die Verwendung von Cloud Service Mesh-Ausgangsgateways für GKE-Cluster.

Sie ist für Entwickler von Netzwerk-, Plattform- und Sicherheitsfunktionen gedacht, die Google Kubernetes Engine-Cluster verwalten, die von einem oder mehreren Teams für das Software-Deployment genutzt werden. Die hier erläuterten Kontrollen sind insbesondere für Organisationen hilfreich, die die Einhaltung von Vorschriften – z. B. die DSGVO und PCI – nachweisen müssen.

Lernziele

  • Sie richten die Infrastruktur zum Ausführen von Cloud Service Mesh ein:
  • Cloud Service Mesh installieren.
  • Installieren Sie Ausgangsgateway-Proxys, die auf einem dedizierten Knotenpool ausgeführt werden.
  • Sie konfigurieren mandantenfähige Routingregeln für externen Traffic über das Ausgangsgateway:
    • Anwendungen im Namespace team-x sollen eine Verbindung zu example.com herstellen können.
    • Anwendungen im Namespace team-y sollen eine Verbindung zu httpbin.org herstellen können.
  • Sie beschränken mit der Sidecar-Ressource den Geltungsbereich der Sidecar-Proxykonfiguration für ausgehenden Traffic für jeden Namespace.
  • Sie konfigurieren Autorisierungsrichtlinien, um Regeln für ausgehenden Traffic in Kraft zu setzen.
  • Sie konfigurieren das Ausgangsgateway, um einfache HTTP-Anfragen in TLS (TLS-Ursprung) zu ändern.
  • Sie konfigurieren das Ausgangsgateway für die Weiterleitung von TLS-Traffic.
  • Sie richten Kubernetes-Netzwerkrichtlinien als zusätzliche Kontrolle für ausgehenden Traffic ein.
  • Sie konfigurieren den direkten Zugriff auf Google APIs mithilfe des privaten Google-Zugriffs und mit Berechtigungen der Identitäts- und Zugriffsverwaltung (IAM).

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen.

Neuen Google Cloud Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.

Nach Abschluss dieser Anleitung können Sie weitere Kosten durch Löschen von erstellten Ressourcen vermeiden. Weitere Informationen finden Sie unter Bereinigen.

Hinweise

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

    Go to project selector

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

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

    Activate Cloud Shell

  4. Erstellen Sie ein Arbeitsverzeichnis, das für die Anleitung verwendet werden soll:

    mkdir -p ~/WORKING_DIRECTORY
    cd ~/WORKING_DIRECTORY
    
  5. Erstellen Sie ein Shell-Skript, um Ihre Umgebung für die Anleitung zu initialisieren. Ersetzen und bearbeiten Sie die Variablen entsprechend Ihres Projekts und Ihrer Einstellungen. Führen Sie dieses Skript mit dem Befehl source aus, um Ihre Umgebung neu zu initialisieren, wenn Ihre Shell-Sitzung abgelaufen ist:

    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. compute.googleapis.com aktivieren:

    gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
    
  7. Machen Sie das Skript ausführbar und führen Sie es mit dem Befehl source aus, um die Umgebung zu initialisieren. Wählen Sie Y aus, wenn Sie aufgefordert werden, compute.googleapis.com zu aktivieren:

    chmod +x ./init-egress-tutorial.sh
    source ./init-egress-tutorial.sh
    
  8. Infrastruktur einrichten

    VPC-Netzwerk und Subnetz erstellen

    1. Erstellen Sie ein neues VPC-Netzwerk:

      gcloud compute networks create vpc-network \
          --subnet-mode custom
      
    2. Erstellen Sie ein Subnetz für den Cluster zur Ausführung mit vorab zugewiesenen sekundären IP-Adressbereichen für Pods und Dienste. Der private Google-Zugriff ist aktiviert, damit Anwendungen, die nur interne IP-Adressen haben, Google APIs und Google-Dienste erreichen können:

      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
      

    Cloud NAT konfigurieren

    Mit Cloud NAT können Arbeitslasten ohne externe IP-Adresse eine Verbindung zu Zielen im Internet herstellen und eingehende Antworten von diesen Zielen empfangen.

    1. Erstellen Sie einen Cloud Router:

      gcloud compute routers create nat-router \
          --network vpc-network
      
    2. Fügen Sie eine NAT-Konfiguration zum Router hinzu:

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

    Dienstkonten für jeden GKE-Knotenpool erstellen

    Erstellen Sie zwei Dienstkonten für die beiden GKE-Knotenpools. Jedem Knotenpool wird ein eigenes Dienstkonto zugewiesen, damit Sie VPC-Firewallregeln auf bestimmte Knoten anwenden können.

    1. Erstellen Sie ein Dienstkonto, das von Knoten im Standardknotenpool verwendet werden soll:

      gcloud iam service-accounts create sa-application-nodes \
          --description="SA for application nodes" \
          --display-name="sa-application-nodes"
      
    2. Erstellen Sie ein Dienstkonto, das von Knoten im Gatewayknotenpool verwendet werden soll:

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

    Berechtigungen für die Dienstkonten erteilen

    Fügen Sie den Anwendungs- und Gatewaydienstkonten einen Mindestsatz an IAM-Rollen hinzu. Diese Rollen werden benötigt, um private Container-Images aus Container Registry zu protokollieren, zu überwachen und abzurufen.

        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
    

    Firewallregeln erstellen

    In den folgenden Schritten wenden Sie eine Firewallregel auf das VPC-Netzwerk an, mit der standardmäßig der gesamte ausgehende Traffic abgelehnt wird. Für das Funktionieren des Clusters und für das Erreichen von Zielen außerhalb der VPC durch Gatewayknoten ist eine eigene Verbindung erforderlich. Ein Mindestsatz an speziellen Firewallregeln überschreibt die Standardregel zum Ablehnen des gesamten Traffics, um die erforderliche Verbindung zuzulassen.

    1. Erstellen Sie eine standardmäßige Firewallregel (mit niedriger Priorität), um den gesamten ausgehenden Traffic vom VPC-Netzwerk abzulehnen:

      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. Erstellen Sie eine Regel, die nur für die Knoten mit dem Gatewaydienstkonto Zugriff auf das Internet zulässt:

      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. Erlauben Sie Knoten das Erreichen der Kubernetes-Steuerungsebene:

      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. Optional: Diese Firewallregel ist nicht erforderlich, wenn Sie Managed Cloud Service Mesh verwenden.

      Cloud Service Mesh verwendet Webhooks, um Sidecar-Proxys in Arbeitslasten einzufügen. Erlauben Sie dem GKE API-Server, die Webhooks aufzurufen, die von der Service Mesh-Steuerungsebene bereitgestellt werden, die auf den Knoten ausgeführt wird:

      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. Erlauben Sie eine ausgehende Verbindung zwischen Knoten und Pods, die im Cluster ausgeführt werden. GKE erstellt automatisch eine entsprechende Regel für eingehenden Traffic. Für die Dienstverbindung ist keine Regel erforderlich, da die iptables-Routingkette Dienst-IP-Adressen immer in Pod-IP-Adressen konvertiert.

      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. Gewähren Sie Zugriff auf die reservierten IP-Adressen, die vom privaten Google-Zugriff zur Bereitstellung für Google APIs, Container Registry und andere Dienste verwendet werden:

      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. Gewähren Sie dem Systemdiagnosedienst Google Cloud Zugriff auf Pods, die im Cluster ausgeführt werden. Weitere Informationen finden Sie unter Systemdiagnosen.

      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"
      

    Privaten Zugriff auf Google Cloud APIs konfigurieren

    Mit dem privaten Google-Zugriff können VMs und Pods, die nur interne IP-Adressen haben, auf Google APIs und Google-Dienste zugreifen. Obwohl Google APIs und Google-Dienste von externen IP-Adressen bereitgestellt werden, verlässt der Traffic von den Knoten nie das Google-Netzwerk, wenn der private Google-Zugriff verwendet wird.

    Aktivieren Sie die Cloud DNS API:

    gcloud services enable dns.googleapis.com
    

    Erstellen Sie eine private DNS-Zone, einen CNAME- und A-Eintrag, damit Knoten und Arbeitslasten über den privater Google-Zugriff und den Hostnamen private.googleapis.com eine Verbindung zu Google APIs und Google-Diensten herstellen können:

    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
    

    Privaten Zugriff auf Container Registry konfigurieren

    Erstellen Sie eine private DNS-Zone, einen CNAME- und einen A-Eintrag, damit Knoten über den privater Google-Zugriff und den Hostnamen gcr.io eine Verbindung zu Container Registry herstellen können:

    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
    

    Privaten GKE-Cluster erstellen

    1. Ermitteln Sie die externe IP-Adresse von Cloud Shell, damit Sie sie der Liste der Netzwerke hinzufügen können, die Zugriff auf den API-Server Ihres Clusters haben sollen:

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

      Nach einer Inaktivitätsphase kann sich die externe IP-Adresse der Cloud Shell-VM ändern. In diesem Fall müssen Sie die Liste der autorisierten Netzwerke Ihres Clusters aktualisieren. Fügen Sie Ihrem Initialisierungsskript den folgenden Befehl hinzu:

      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. Aktivieren Sie die Google Kubernetes Engine API:

      gcloud services enable container.googleapis.com
      
    3. Erstellen Sie einen privaten GKE-Cluster:

      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}
      

      Es dauert einige Minuten, bis der Cluster erstellt ist. Der Cluster hat private Knoten mit internen IP-Adressen. Pods und Diensten werden IP-Adressen aus den benannten sekundären Bereichen zugewiesen, die Sie beim Erstellen des VPC-Subnetzes definiert haben.

      Cloud Service Mesh mit einer In-Cluster-Steuerungsebene erfordert, dass die Clusterknoten einen Maschinentyp mit mindestens 4 vCPUs verwenden.

      Google empfiehlt, dass der Cluster die Release-Version „Regulär“ abonniert. Damit ist gewährleistet, dass auf Knoten eine Kubernetes-Version ausgeführt wird, die von Cloud Service Mesh unterstützt wird.

      Weitere Informationen zu den Voraussetzungen für die Ausführung von Cloud Service Mesh mit einer clusterinternen Steuerungsebene finden Sie unter Voraussetzungen für die clusterinterne Steuerungsebene.

      Weitere Informationen zu den Anforderungen und Einschränkungen für die Ausführung von verwaltetem Cloud Service Mesh finden Sie unter Unterstützte Features für verwaltetes Cloud Service Mesh.

      Workload Identity Federation for GKE ist im Cluster aktiviert. Cloud Service Mesh erfordert die Identitätsföderation von Arbeitslasten für GKE und wird für den Zugriff auf Google APIs von GKE-Arbeitslasten empfohlen.

    4. Erstellen Sie einen Knotenpool namens gateway. In diesem Knotenpool wird das Ausgangsgateway bereitgestellt. Die Markierung dedicated=gateway:NoSchedule wird allen Knoten im Gatewayknotenpool hinzugefügt.

      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"
      

      Markierungen und Toleranzen von Kubernetes gewährleisten, dass nur Ausgangsgateway-Pods auf Knoten im Gatewayknotenpool ausgeführt werden.

    5. Laden Sie die Anmeldedaten herunter, mit denen Sie mit kubectl eine Verbindung zum Cluster herstellen können:

      gcloud container clusters get-credentials cluster1
      
    6. Prüfen Sie, ob die Gatewayknoten die richtige Markierung haben:

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

      Die Ausgabe sieht etwa so aus:

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

    Cloud Service Mesh installieren und einrichten

    Folgen Sie einer der Installationsanleitungen für Cloud Service Mesh:

    Nachdem Sie Cloud Service Mesh installiert haben, halten Sie an und kehren Sie zu diesem Tutorial zurück, ohne Ingress- oder Egress-Gateways zu installieren.

    Egress-Gateway installieren

    1. Erstellen Sie einen Kubernetes-Namespace für das Egress-Gateway:

      kubectl create namespace istio-egress
      
    2. Aktivieren Sie den Namespace für die Injection: Die Schritte hängen von Ihrer Implementierung der Steuerungsebene ab.

      Verwaltet (TD)

      So wenden Sie das Standard-Injektionslabel auf einen Namespace an:

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

      Verwaltet (Istiod)

      Empfohlen:Führen Sie den folgenden Befehl aus, um das Standard-Injektionslabel auf den Namespace anzuwenden:

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

      Wenn Sie ein vorhandener Nutzer mit der verwalteten Istiod-Steuerungsebene sind:Wir empfehlen die Verwendung der Standardeinfügung, aber die revisionsbasierte Einfügung wird unterstützt. Gehen Sie dazu so vor:

      1. Verwenden Sie folgenden Befehl, um die verfügbaren Release-Kanäle zu finden:

        kubectl -n istio-system get controlplanerevision
        

        Die Ausgabe sieht etwa so aus:

        NAME                AGE
        asm-managed-rapid   6d7h
        

        In der Ausgabe ist der Wert in der NAME-Spalte das Überarbeitungslabel, das dem verfügbaren Release-Kanal für die Cloud Service Mesh-Version entspricht.

      2. Wenden Sie das Überarbeitungslabel auf den Namespace an.

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

      Clusterintern

      Empfohlen:Führen Sie den folgenden Befehl aus, um das Standard-Injektionslabel auf den Namespace anzuwenden:

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

      Wir empfehlen die Verwendung der Standardinjektion, aber auch die revisionsbasierte Injektion wird unterstützt. Folgen Sie dieser Anleitung:

      1. Verwenden Sie den folgenden Befehl, um das Überarbeitungslabel für istiod zu finden:

        kubectl get deploy -n istio-system -l app=istiod -o \
           jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
        
      2. Wenden Sie das Überarbeitungslabel auf den Namespace an. Im folgenden Befehl ist REVISION_LABEL der Wert des Überarbeitungslabels istiod, den Sie im vorherigen Schritt notiert haben.

        kubectl label namespace istio-egress \
            istio-injection- istio.io/rev=REVISION_LABEL --overwrite
        
    3. Erstellen Sie ein Operatormanifest für das Egress-Gateway:

      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. Laden Sie das istioctl-Tool herunter. Sie müssen Version 1.16.2-asm.2 oder höher verwenden, auch wenn Sie Cloud Service Mesh-Version 1.15 oder niedriger verwenden. Weitere Informationen finden Sie unter Korrekte istioctl-Version herunterladen.

    5. Legen Sie nach dem Extrahieren des heruntergeladenen Archivs eine Umgebungsvariable fest, die den Pfad zum istioctl-Tool enthält, und fügen Sie diese dem Initialisierungsskript hinzu:

      ISTIOCTL=$(find "$(pwd -P)" -name istioctl)
      echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
      
    6. Erstellen Sie das Installationsmanifest für das Egress-Gateway mit dem Operatormanifest und istioctl:

      ${ISTIOCTL} manifest generate \
          --filename egressgateway-operator.yaml \
          --output egressgateway \
          --cluster-specific
      
    7. Installieren Sie das Egress-Gateway:

      kubectl apply --recursive --filename egressgateway/
      
    8. Prüfen Sie, ob das Ausgangsgateway auf Knoten im Knotenpool gateway ausgeführt wird:

      kubectl get pods -n istio-egress -o wide
      
    9. Die Ausgangsgateway-Pods haben affinity für Knoten im gateway-Knotenpool und eine Toleranz, mit der sie auf den markierten Gatewayknoten ausgeführt werden können. Prüfen Sie die Knotenaffinität und Toleranzen für die Pods des Ausgangsgateways:

      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")]'
      

      Die Ausgabe sieht etwa so aus:

      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]
      

    Envoy-Zugriffs-Logging aktivieren

    Die erforderlichen Schritte zum Aktivieren von Envoy-Zugriffslogs hängen von Ihrem Cloud Service Mesh-Typ ab (verwaltet oder im Cluster):

    Mesh-Netzwerk und Testanwendung vorbereiten

    1. Prüfen Sie, ob das strikte gegenseitige TLS-Protokoll aktiviert ist. Wenden Sie eine PeerAuthentication-Standardrichtlinie für das Mesh-Netzwerk im Namespace istio-system an:

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

      Sie können diese Konfiguration durch Erstellen von PeerAuthentication-Ressourcen in bestimmten Namespaces überschreiben.

    2. Erstellen Sie Namespaces zum Bereitstellen von Testarbeitslasten. In Schritten dieser Anleitung weiter unten wird erläutert, wie Sie für jeden Namespace unterschiedliche Routingregeln für ausgehenden Traffic konfigurieren.

      kubectl create namespace team-x
      kubectl create namespace team-y
      
    3. Kennzeichnen Sie die Namespaces so, dass sie von Kubernetes-Netzwerkrichtlinien ausgewählt werden können:

      kubectl label namespace team-x team=x
      kubectl label namespace team-y team=y
      
    4. Damit Cloud Service Mesh Proxy-Sidecars automatisch einfügt, legen Sie das Überarbeitungslabel der Steuerungsebene für die Namespaces der Arbeitslast fest:

      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. Erstellen Sie eine YAML-Datei, um Test-Deployments auszuführen:

      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. Stellen Sie die Testanwendung im Namespace team-x bereit:

      kubectl -n team-x create -f ./test.yaml
      
    7. Prüfen Sie, ob die Testanwendung in einem Knoten im Standardpool bereitgestellt und ein Proxy-Sidecar-Container eingefügt wurde. Wiederholen Sie den folgenden Befehl, bis der Status des Pods Running lautet:

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

      Die Ausgabe sieht in etwa so aus:

      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
      

      Für zwei von zwei Containern gilt der Status Running. Ein Container ist die Testanwendung und der andere der Proxy-Sidecar.

      Der Pod wird auf einem Knoten im Standardknotenpool ausgeführt.

    8. Prüfen Sie, ob es möglich ist, eine HTTP-Anfrage vom Testcontainer an eine externe Website zu stellen:

      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
      

      Es wird eine Fehlermeldung vom Sidecar-Proxy generiert, da die Firewallregel global-deny-egress-all die Upstream-Verbindung ablehnt.

    Mithilfe der Sidecar-Ressource den Geltungsbereich der Sidecar-Proxykonfiguration einschränken

    Mit der Sidecar-Ressource können Sie den Geltungsbereich des ausgehenden Listeners einschränken, der für Sidecar-Proxys konfiguriert ist. Um das Volumen der Konfiguration und die Speichernutzung zu reduzieren, wird empfohlen, für jeden Namespace eine Standardressource vom Typ Sidecar anzuwenden.

    Der Proxy, den Cloud Service Mesh im Sidecar ausführt, ist Envoy. In der Envoy-Terminologie ist ein cluster eine logisch ähnliche Gruppe von vorgelagerten Endpunkten, die als Ziel für das Load-Balancing verwendet werden.

    1. Prüfen Sie die im Envoy-Sidecar-Proxy für den Test-Pod konfigurierten Cluster für ausgehenden Traffic mit dem Befehl istioctl proxy-config:

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

      Die Liste enthält etwa 11 Envoy-Cluster, darunter einige für das Ausgangsgateway.

    2. Beschränken Sie die Proxykonfiguration auf ausgehende Routen, die explizit mit Diensteinträgen in den Namespaces „egress“ und team-x definiert wurden. Wenden Sie eine Sidecar-Ressource auf den Namespace team-x an:

      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
      

      Durch Festlegen von REGISTRY_ONLY als Richtlinienmodus für ausgehenden Traffic wird die Proxykonfiguration auf diejenigen externen Hosts beschränkt, die der Dienst-Registry des Mesh-Netzwerks explizit durch Definition der Diensteinträge hinzugefügt wurden.

      Wenn Sie egress.hosts festlegen, wählt der Sidecar-Proxy nur Routen aus dem Egress-Namespace aus, die mithilfe des Attributs exportTo verfügbar gemacht werden. Der Teil „team-x/*“ enthält alle Routen, die lokal im Namespace team-x konfiguriert wurden.

    3. Prüfen Sie die im Envoy-Sidecar-Proxy konfigurierten Cluster für ausgehenden Traffic und vergleichen Sie sie mit der Liste der Cluster, die konfiguriert werden, bevor Sie die Ressource Sidecar anwenden:

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

      Sie sehen Cluster für das Ausgangsgateway und einen Cluster für den Test-Pod selbst.

    Cloud Service Mesh für die Weiterleitung von Traffic über das Ausgangsgateway konfigurieren

    1. Konfigurieren Sie ein Gateway für HTTP-Traffic an Port 80. Das Gateway wählt den Ausgangsgateway-Proxy aus, den Sie für den Ausgangs-Namespace bereitgestellt haben. Die Gateway-Konfiguration wird auf den Egress-Namespace angewendet und verarbeitet den Traffic für jeden 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. Erstellen Sie eine DestinationRule für das Ausgangsgateway mit gegenseitigem TLS zur Authentifizierung und Verschlüsselung. Verwenden Sie eine einzige gemeinsame Zielregel für alle externen Hosts.

      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. Erstellen Sie im Ausgangs-Namespace einen ServiceEntry, um „example.com“ explizit in der Dienst-Registry des Mesh-Netzwerks für den Namespace team-x zu registrieren:

      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. Erstellen Sie einen VirtualService, um Traffic an „example.com“ über das Ausgangsgateway zu leiten. Es gibt zwei Abgleichbedingungen: Mit der ersten wird der Traffic an das Ausgangsgateway und mit der zweiten der Traffic vom Ausgangsgateway an den Zielhost weitergeleitet. Das Attribut exportTo legt fest, welche Namespaces den virtuellen Dienst verwenden können.

      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. Führen Sie istioctl analyze aus, um Konfigurationsfehler zu ermitteln:

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

      Die Ausgabe sieht in etwa so aus:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Senden Sie mehrere Anfragen über das Ausgangsgateway an die externe Website:

      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
      

      Für alle vier Antworten werden 200-Statuscodes angezeigt.

    7. Prüfen Sie in den Proxyzugriffslogs, ob die Anfragen über das Ausgangsgateway geleitet wurden. Prüfen Sie zuerst das Zugriffslog für den mit der Testanwendung bereitgestellten Proxy-Sidecar:

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

      Für jede von Ihnen gesendete Anfrage wird ein Logeintrag wie der folgende angezeigt:

      [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. Prüfen Sie außerdem das Zugriffslog für das Ausgangsgateway:

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

      Für jede von Ihnen gesendete Anfrage wird ein Zugriffslogeintrag für das Ausgangsgateway angezeigt, der in etwa so aussieht:

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

    Anderes Routing für einen zweiten Namespace konfigurieren

    Konfigurieren Sie das Routing für einen zweiten externen Host, um zu erfahren, wie verschiedene externe Verbindungen für unterschiedliche Teams konfiguriert werden können.

    1. Erstellen Sie eine Sidecar-Ressource für den Namespace 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. Stellen Sie die Testanwendung im Namespace team-y bereit:

      kubectl -n team-y create -f ./test.yaml
      
    3. Registrieren Sie einen zweiten externen Host und exportieren Sie ihn in die Namespaces team-x und 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. Erstellen Sie einen virtuellen Dienst, um Traffic zu „httpbin.org“ über das Ausgangsgateway zu leiten:

      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. Führen Sie istioctl analyze aus, um Konfigurationsfehler zu ermitteln:

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

      Es wird Folgendes angezeigt:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Stellen Sie aus der Testanwendung team-y eine Anfrage an „httpbin.org“:

      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
      

      Es wird eine 200 OK-Antwort angezeigt.

    7. Stellen Sie außerdem aus der Testanwendung team-x eine Anfrage an „httpbin.org“.

      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
      

      Es wird eine 200 OK-Antwort angezeigt.

    8. Versuchen Sie, eine Anfrage an „example.com“ aus dem Namespace team-y zu stellen:

      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
      

      Die Anfrage schlägt fehl, da keine ausgehende Route für den Host example.com konfiguriert ist.

    Autorisierungsrichtlinie für eine zusätzliche Kontrolle von Traffic verwenden

    In dieser Anleitung wurden im Namespace istio-egress Autorisierungsrichtlinien für das Ausgangsgateway erstellt. Sie können Kubernetes RBAC so konfigurieren, dass nur Netzwerkadministratoren Zugriff auf den Namespace istio-egress haben.

    1. Erstellen Sie eine AuthorizationPolicy, damit Anwendungen im Namespace team-x eine Verbindung zu „example.com“, aber nicht zu anderen externen Hosts herstellen können, wenn sie Anfragen über Port 80 stellen. Der entsprechende targetPort auf den Ausgangsgateway-Pods ist 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. Prüfen Sie, ob Sie aus der Testanwendung im Namespace team-x eine Anfrage an „example.com“ stellen können:

      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
      

      Es wird eine 200 OK-Antwort angezeigt.

    3. Stellen Sie aus der Testanwendung im Namespace team-x eine Anfrage an „httpbin.org“:

      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
      

      Die Anfrage schlägt mit der Meldung RBAC: access denied und dem Statuscode „403 Verboten“ fehl. Es kann einige Sekunden dauern, bis die Autorisierungsrichtlinie wirksam wird.

    4. Autorisierungsrichtlinien bieten eine umfassende Kontrolle darüber, welcher Traffic zugelassen oder abgelehnt wird. Wenden Sie die folgende Autorisierungsrichtlinie an, damit die Testanwendung im Namespace team-y Anfragen an „httpbin.org“ stellen kann. Dazu wird ein bestimmter URL-Pfad für das Stellen von Anfragen mithilfe von Port 80 verwendet. Der entsprechende targetPort auf den Ausgangsgateway-Pods ist 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. Versuchen Sie, aus der Testanwendung im Namespace team-y eine Verbindung zu „httpbin.org“ herzustellen:

      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
      

      Die Anfrage schlägt mit einer RBAC-Meldung über die Ablehnung des Zugriffs und mit dem Statuscode „403 Verboten“ fehl.

    6. Stellen Sie nun eine Anfrage an „httpbin.org/status/418“ von derselben Anwendung aus:

      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
      

      Die Anfrage ist erfolgreich, da der Pfad dem Muster in der Autorisierungsrichtlinie entspricht. Die Ausgabe sieht in etwa so aus:

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

    TLS-Ursprung am Ausgangsgateway

    Sie können Ausgangsgateways so konfigurieren, dass ursprüngliche einfache HTTP-Anfragen auf TLS oder gegenseitiges TLS upgrade werden. Wenn Anwendungen einfache HTTP-Anfragen stellen können, hat dies verschiedene Vorteile, wenn sie in Kombination mit gegenseitigem TLS und TLS-Ursprung von Istio verwendet werden. Weitere Informationen

    TLS-Ursprung am Ausgangsgateway

    1. Erstellen Sie eine DestinationRule. The DestinationRule um festzulegen, dass das Gateway eine TLS-Verbindung zu „example.com“ herstellt.

      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. Aktualisieren Sie den virtuellen Dienst für „example.com“ so, dass Anfragen an Port 80 auf dem Gateway auf TLS an Port 443 upgraded werden, wenn sie an den Zielhost gesendet werden:

      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. Stellen Sie aus der Testanwendung im Namespace team-x mehrere Anfragen an „example.com“:

      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
      

      Wie zuvor werden die Anfragen mit 200 OK-Antworten erfolgreich ausgeführt.

    4. Prüfen Sie anhand des Ausgangsgatewaylogs, ob die Anfragen vom Gateway durch Herstellen von TLS-Verbindungen an die Zielhosts weitergeleitet wurden:

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

      Die Ausgabe sieht in etwa so aus:

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

      Der Proxy-Sidecar-Server hat die Anfrage an das Gateway mithilfe von Port 80 gesendet und eine TLS-Verbindung an Port 443 hergestellt, um die Anfrage an den Zielhost zu senden.

    Weiterleitung von HTTPS-/TLS-Verbindungen

    Ihre vorhandenen Anwendungen nutzen möglicherweise bereits TLS-Verbindungen, wenn sie mit externen Diensten kommunizieren. Sie können das Ausgangsgateway so konfigurieren, dass TLS-Verbindungen weitergeleitet werden, ohne sie zu entschlüsseln.

    TLS-Weiterleitung

    1. Ändern Sie Ihre Konfiguration so, dass das Ausgangsgateway für die Verbindungen zu Port 443 die TLS-Weiterleitung nutzt:

      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. Aktualisieren Sie die DestinationRule, die auf das Ausgangsgateway verweist, um eine zweite Teilmenge für Port 443 auf dem Gateway hinzuzufügen. Diese neue Teilmenge verwendet kein gegenseitiges TLS. Die Kommunikation über gegenseitiges TLS von Istio wird für die Weiterleitung von TLS-Verbindungen nicht unterstützt. Verbindungen auf Port 80 verwenden weiterhin 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. Aktualisieren Sie den virtuellen Dienst für „example.com“ so, dass TLS-Traffic an Port 443 über das Gateway geleitet wird:

      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. Aktualisieren Sie den virtuellen Dienst für „httpbin.org“ so, dass TLS-Traffic an Port 443 über das Gateway geleitet wird:

      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. Fügen Sie eine Autorisierungsrichtlinie hinzu, die jede Art von Traffic zulässt, der an Port 443 des Ausgangsgatewaydienstes gesendet wird. Der entsprechende targetPort auf den Gateway-Pods ist 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. Führen Sie istioctl analyze aus, um Konfigurationsfehler zu ermitteln:

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

      Es wird Folgendes angezeigt:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    7. Stellen Sie aus der Testanwendung im Namespace team-x eine einfache HTTP-Anfrage an „example.com“:

      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
      

      Die Anfrage wird mit einer 200 OK-Antwort erfolgreich ausgeführt.

    8. Erstellen Sie nun mehrere TLS-Anfragen (HTTPS) aus der Testanwendung im Namespace 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
      

      Es werden Antworten vom Typ „200“ angezeigt.

    9. Prüfen Sie das Log für das Ausgangsgateway noch einmal:

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

      Die Logeinträge sehen in etwa so aus:

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

      Die HTTPS-Anfrage wurde als TCP-Traffic behandelt und über das Gateway an den Zielhost weitergeleitet. Deshalb sind keine HTTP-Informationen im Log enthalten.

    NetworkPolicy von Kubernetes als zusätzliche Kontrolle verwenden

    Es gibt viele Szenarien, in denen eine Anwendung einen Sidecar-Proxy umgehen kann. Mit der NetworkPolicy von Kubernetes können Sie zusätzlich festlegen, welche Verbindungen Arbeitslasten herstellen dürfen. Nach dem Anwenden einer Netzwerkrichtlinie werden alle nicht explizit zugelassenen Verbindungen abgelehnt.

    In dieser Anleitung werden nur ausgehende Verbindungen und ausgehende Selektoren für Netzwerkrichtlinien berücksichtigt. Wenn Sie eingehenden Traffic mit Netzwerkrichtlinien für Ihre Cluster steuern möchten, müssen Sie dafür Richtlinien erstellen, die Ihren Richtlinien für ausgehenden Traffic entsprechen. Wenn Sie beispielsweise ausgehenden Traffic von Arbeitslasten im Namespace team-x zum Namespace team-y zulassen, müssen Sie gleichzeitig eingehenden Traffic zum Namespace team-y vom Namespace team-x zulassen.

    1. Erlauben Sie, dass im Namespace team-x bereitgestellte Arbeitslasten und Proxys eine Verbindung zu istiod und zum Ausgangsgateway herstellen:

      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. Erlauben Sie Arbeitslasten und Proxys das Abfragen von 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. Erlauben Sie Arbeitslasten und Proxys, eine Verbindung zu den IP-Adressen für Google APIs und Google-Dienste herzustellen, einschließlich der Cloud Service Mesh-Zertifizierungsstelle:

      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. Erlauben Sie Arbeitslasten und Proxys, eine Verbindung zum GKE-Metadatenserver herzustellen:

      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. Optional: Erlauben Sie Arbeitslasten und Proxys im Namespace team-x Verbindungen untereinander herzustellen:

      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. Optional: Erlauben Sie Arbeitslasten und Proxys im Namespace team-x Verbindungen zu Arbeitslasten herzustellen, die von einem anderen Team bereitgestellt wurden:

      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. Verbindungen zwischen Sidecar-Proxys bleiben bestehen. Vorhandene Verbindungen werden nicht geschlossen, wenn Sie eine neue Netzwerkrichtlinie anwenden. Damit vorhandene Verbindungen geschlossen werden, starten Sie die Arbeitslasten im Namespace „team-x“ neu:

      kubectl -n team-x rollout restart deployment
      
    8. Prüfen Sie, ob Sie weiterhin eine HTTP-Anfrage an „example.com“ aus der Testanwendung im Namespace team-x stellen können:

      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
      

      Die Anfrage wird mit einer 200 OK-Antwort erfolgreich ausgeführt.

    Direkter Zugriff auf Google APIs über privaten Google-Zugriff und IAM-Berechtigungen

    Die Google APIs und Google-Dienste werden über externe IP-Adressen bereitgestellt. Wenn Pods mit VPC-nativen Alias-IP-Adressen Verbindungen zu Google APIs über den privaten Google-Zugriff herstellen, verlässt der Traffic nie das Google-Netzwerk.

    Beim Einrichten der Infrastruktur für diese Anleitung haben Sie den privaten Google-Zugriff für das von GKE-Pods verwendete Subnetz aktiviert. Um den Zugriff auf die IP-Adressen zu ermöglichen, die vom privaten Google-Zugriff verwendet werden, erstellen Sie eine Route, eine VPC-Firewallregel und eine private DNS-Zone. Mit dieser Konfiguration können Pods Google APIs direkt erreichen, ohne Traffic über das Ausgangsgateway zu senden. Sie können mit Workload Identity-Föderation für GKE und IAM festlegen, welche APIs für bestimmte Kubernetes-Dienstkonten (und damit für bestimmte Namespaces) verfügbar sind. Die Istio-Autorisierung ist nicht wirksam, da das Ausgangsgateway keine Verbindungen zu den Google APIs verarbeitet.

    Damit Pods Google APIs aufrufen können, müssen Sie mithilfe von IAM Berechtigungen gewähren. Der Cluster, den Sie für diese Anleitung verwenden, ist für die Verwendung der Workload Identity-Föderation für GKE konfiguriert. Dadurch kann ein Kubernetes-Dienstkonto als Google-Dienstkonto verwendet werden.

    1. Erstellen Sie ein Google-Dienstkonto für die Anwendung:

      gcloud iam service-accounts create sa-test-app-team-x
      
    2. Erlauben Sie dem Kubernetes-Dienstkonto, die Identität des Google-Dienstkontos zu übernehmen:

      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. Annotieren Sie das Kubernetes-Dienstkonto für die Testanwendung im Namespace team-x mit der E-Mail-Adresse des Google-Dienstkontos:

      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. Der Testanwendungs-Pod muss auf den Google-Metadatenserver (als DaemonSet ausgeführt) zugreifen können, um temporäre Anmeldedaten für den Aufruf von Google APIs abzurufen. Erstellen Sie einen Diensteintrag für den GKE-Metadatenserver:

      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. Erstellen Sie außerdem einen Diensteintrag für „private.googleapis.com“ und „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. Prüfen Sie, ob das Kubernetes-Dienstkonto ordnungsgemäß als Google-Dienstkonto konfiguriert ist:

      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
      

      Es wird ein Google-Dienstkonto als aktive und einzige Identität aufgeführt.

    7. Erstellen Sie eine Testdatei in einem Cloud Storage-Bucket:

      echo "Hello, World!" > /tmp/hello
      gcloud storage buckets create gs://${PROJECT_ID}-bucket
      gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
      
    8. Gewähren Sie dem Dienstkonto die Berechtigung zum Auflisten und Aufrufen von Dateien im 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. Prüfen Sie, ob die Testanwendung auf den Test-Bucket zugreifen kann:

      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
      

      und die Tabelle enthält folgende Informationen:

      Hello, World!
      

    Bereinigen

    Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, löschen Sie entweder das Projekt, das die Ressourcen enthält, oder Sie behalten das Projekt und löschen die einzelnen Ressourcen.

    Führen Sie die Schritte in den folgenden Abschnitten aus, um zu vermeiden, dass Ihrem Google Cloud Konto die in dieser Anleitung verwendeten Ressourcen in Rechnung gestellt werden:

    Projekt löschen

    Sie vermeiden weitere Kosten am einfachsten, wenn Sie das für die Anleitung erstellte Projekt löschen.

    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.

    Nächste Schritte