Usar gateways de saída do Cloud Service Mesh em clusters do GKE: tutorial

Este tutorial mostra como usar gateways de saída do Cloud Service Mesh e outros Google Cloud controlos para proteger o tráfego de saída (saída) de cargas de trabalho implementadas num cluster do Google Kubernetes Engine. Este tutorial destina-se a complementar o artigo Práticas recomendadas para usar gateways de saída da malha de serviços na nuvem em clusters do GKE.

O público-alvo deste tutorial inclui engenheiros de rede, plataforma e segurança que administram clusters do Google Kubernetes Engine usados por uma ou mais equipas de entrega de software. Os controlos descritos aqui são especialmente úteis para organizações que têm de demonstrar a conformidade com os regulamentos, por exemplo, o RGPD e a PCI.

Objetivos

  • Configure a infraestrutura para executar o Cloud Service Mesh:
  • Instale o Cloud Service Mesh.
  • Instale proxies de gateway de saída em execução num node pool dedicado.
  • Configure regras de encaminhamento multi-inquilino para tráfego externo através do gateway de saída:
    • As aplicações no espaço de nomes team-x podem estabelecer ligação a example.com
    • As aplicações no espaço de nomes team-y podem estabelecer ligação a httpbin.org
  • Use o recurso Sidecar para restringir o âmbito da configuração de saída do proxy sidecar para cada espaço de nomes.
  • Configure políticas de autorização para aplicar regras de saída.
  • Configure o gateway de saída para atualizar pedidos HTTP simples para TLS (originação de TLS).
  • Configure o gateway de saída para transmitir tráfego TLS.
  • Configure políticas de rede do Kubernetes como um controlo de saída adicional.
  • Configure o acesso direto às APIs Google através do acesso privado Google e das autorizações da gestão de identidade e de acesso (IAM).

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Quando terminar este tutorial, pode evitar custos contínuos eliminando os recursos que criou. Para mais informações, consulte o artigo Limpar.

Antes de começar

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

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    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. Crie um diretório de trabalho para usar enquanto segue o tutorial:

    mkdir -p ~/WORKING_DIRECTORY
    cd ~/WORKING_DIRECTORY
    
  5. Crie um script de shell para inicializar o seu ambiente para o tutorial. Substitua e edite as variáveis de acordo com o seu projeto e preferências. Execute este script com o comando source para reinicializar o seu ambiente se a sessão da shell expirar:

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

    gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
    
  7. Torne o script executável e execute-o com o comando source para inicializar o seu ambiente. Se lhe for pedido que ative a opção compute.googleapis.com, selecione Y:

    chmod +x ./init-egress-tutorial.sh
    source ./init-egress-tutorial.sh
    
  8. Configurar a infraestrutura

    Crie uma rede de VPC e uma sub-rede

    1. Criar uma nova rede de VPC:

      gcloud compute networks create vpc-network \
          --subnet-mode custom
      
    2. Crie uma sub-rede para o cluster ser executado com intervalos de endereços IP secundários pré-atribuídos para pods e serviços. O acesso privado à Google está ativado para que as aplicações com apenas endereços IP internos possam alcançar as APIs e os serviços 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
      

    Configure o Cloud NAT

    O Cloud NAT permite que as cargas de trabalho sem endereços IP externos se liguem a destinos na Internet e recebam respostas de entrada desses destinos.

    1. Crie um Cloud Router:

      gcloud compute routers create nat-router \
          --network vpc-network
      
    2. Adicione uma configuração NAT ao router:

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

    Crie contas de serviço para cada conjunto de nós do GKE

    Crie duas contas de serviço para utilização pelos dois conjuntos de nós do GKE. É atribuída uma conta de serviço separada a cada conjunto de nós para que possa aplicar regras de firewall de VPC a nós específicos.

    1. Crie uma conta de serviço para utilização pelos nós no node pool predefinido:

      gcloud iam service-accounts create sa-application-nodes \
          --description="SA for application nodes" \
          --display-name="sa-application-nodes"
      
    2. Crie uma conta de serviço para utilização pelos nós no node pool do gateway:

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

    Conceda autorizações às contas de serviço

    Adicione um conjunto mínimo de funções de IAM às contas de serviço da aplicação e da gateway. Estas funções são necessárias para o registo, a monitorização e a obtenção de imagens de contentores privados do 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
    

    Criar as regras de firewall

    Nos passos seguintes, aplica uma regra de firewall à rede VPC para que, por predefinição, todo o tráfego de saída seja recusado. É necessária uma conetividade específica para o cluster funcionar e para os nós de gateway poderem alcançar destinos fora da VPC. Um conjunto mínimo de regras de firewall específicas substitui a regra de recusa de tudo predefinida para permitir a conetividade necessária.

    1. Crie uma regra de firewall predefinida (prioridade baixa) para negar toda a saída da rede 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. Crie uma regra para permitir que apenas os nós com a conta do serviço de gateway acedam à Internet:

      gcloud compute firewall-rules create gateway-allow-egress-web \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp:80,tcp:443 \
          --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --network vpc-network \
          --priority 1000 \
          --description "Allow the nodes running the egress gateways to connect to the web"
      
    3. Permita que os nós alcancem o plano de controlo do Kubernetes:

      gcloud compute firewall-rules create allow-egress-to-api-server \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp:443,tcp:10250 \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 10.5.0.0/28 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow nodes to reach the Kubernetes API server."
      
    4. Opcional: esta regra de firewall não é necessária se usar o Managed Cloud Service Mesh.

      O Cloud Service Mesh usa webhooks quando injeta proxies sidecar em cargas de trabalho. Permita que o servidor da API GKE chame os webhooks expostos pelo plano de controlo da malha de serviços em execução nos nós:

      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. Permita a conetividade de saída entre os nós e os pods em execução no cluster. O GKE cria automaticamente uma regra de entrada correspondente. Não é necessária nenhuma regra para a conetividade do serviço, porque a cadeia de encaminhamento iptables converte sempre os endereços IP do serviço em endereços IP do pod.

      gcloud compute firewall-rules create allow-egress-nodes-and-pods \
          --action ALLOW \
          --direction EGRESS \
          --rules all \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 10.0.0.0/24,10.1.0.0/16 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow egress to other Nodes and Pods"
      
    6. Permita o acesso aos conjuntos reservados de endereços IP usados pelo acesso privado Google para publicar APIs Google, pelo Container Registry e por outros serviços:

      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. Permita que o serviço de verificação de saúde Google Cloud aceda aos pods em execução no cluster. Consulte as verificações de estado: para mais informações.

      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"
      

    Configurar o acesso privado às Google Cloud APIs

    O acesso privado à Google permite que as VMs e os pods que só têm endereços IP internos acedam às APIs e aos serviços Google. Embora as APIs e os serviços Google sejam fornecidos a partir de IPs externos, o tráfego dos nós nunca sai da rede Google quando usa o acesso privado à Google.

    Ative a API Cloud DNS:

    gcloud services enable dns.googleapis.com
    

    Crie uma zona de DNS privada e registos CNAME e A para que os nós e as cargas de trabalho possam ligar-se às APIs e aos serviços Google através do acesso privado à Google e do nome do anfitrião 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
    

    Configurar o acesso privado ao Container Registry

    Crie uma zona DNS privada, um registo CNAME e um registo A para que os nós possam estabelecer ligação ao Container Registry através do acesso privado da Google e do nome de anfitrião 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
    

    Crie um cluster privado do GKE

    1. Encontre o endereço IP externo do Cloud Shell para que o possa adicionar à lista de redes autorizadas a aceder ao servidor da API do cluster:

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

      Após um período de inatividade, o endereço IP externo da sua VM do Cloud Shell pode mudar. Se isso acontecer, tem de atualizar a lista de redes autorizadas do cluster. Adicione o seguinte comando ao script de inicialização:

      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. Ative a API Google Kubernetes Engine:

      gcloud services enable container.googleapis.com
      
    3. Crie um cluster privado do GKE:

      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}
      

      A criação do cluster demora alguns minutos. O cluster tem nós privados com endereços IP internos. Os pods e os serviços são atribuídos a IPs dos intervalos secundários com nomes que definiu quando criou a sub-rede da VPC.

      A Cloud Service Mesh com um plano de controlo no cluster requer que os nós do cluster usem um tipo de máquina com, pelo menos, 4 vCPUs.

      A Google recomenda que o cluster esteja subscrito no canal de lançamento "regular" para garantir que os nós estão a executar uma versão do Kubernetes suportada pelo Cloud Service Mesh.

      Para mais informações sobre os pré-requisitos para executar o Cloud Service Mesh com um plano de controlo no cluster, consulte os pré-requisitos no cluster.

      Para mais informações sobre os requisitos e as limitações da execução do Cloud Service Mesh gerido, consulte as funcionalidades suportadas do Cloud Service Mesh gerido.

      A federação de identidade da carga de trabalho para o GKE está ativada no cluster. O Cloud Service Mesh requer a Workload Identity Federation para o GKE e é a forma recomendada de aceder às APIs Google a partir de cargas de trabalho do GKE.

    4. Crie um node pool denominado gateway. É neste conjunto de nós que o gateway de saída é implementado. O dedicated=gateway:NoSchedule taint é adicionado a todos os nós no conjunto de nós do 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"
      

      As restrições e as tolerâncias do Kubernetes ajudam a garantir que apenas os pods do gateway de saída são executados em nós no conjunto de nós do gateway.

    5. Transfira as credenciais para poder estabelecer ligação ao cluster com o kubectl:

      gcloud container clusters get-credentials cluster1
      
    6. Verifique se os nós de gateway têm a rejeição correta:

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

      O resultado é semelhante ao seguinte:

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

    Instalar e configurar o Cloud Service Mesh

    Siga um dos guias de instalação do Cloud Service Mesh:

    Depois de instalar o Cloud Service Mesh, pare e regresse a este tutorial sem instalar gateways de entrada ou saída.

    Instale um gateway de saída

    1. Crie um espaço de nomes do Kubernetes para o gateway de saída:

      kubectl create namespace istio-egress
      
    2. Ative o espaço de nomes para injeção. Os passos dependem da sua implementação do plano de controlo.

      Gerido (TD)

      Aplique a etiqueta de injeção predefinida ao espaço de nomes:

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

      Gerido (Istiod)

      Recomendado: execute o seguinte comando para aplicar a etiqueta de injeção predefinida ao espaço de nomes:

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

      Se for um utilizador existente com o plano de controlo do Istiod gerido: recomendamos que use a injeção predefinida, mas a injeção baseada em revisões é suportada. Siga as instruções abaixo:

      1. Execute o seguinte comando para localizar os canais de lançamento disponíveis:

        kubectl -n istio-system get controlplanerevision
        

        O resultado é semelhante ao seguinte:

        NAME                AGE
        asm-managed-rapid   6d7h
        

        Na saída, o valor na coluna NAME é a etiqueta de revisão que corresponde ao canal de lançamento disponível para a versão do Cloud Service Mesh.

      2. Aplique a etiqueta de revisão ao espaço de nomes:

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

      No cluster

      Recomendado: execute o seguinte comando para aplicar a etiqueta de injeção predefinida ao espaço de nomes:

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

      Recomendamos que use a injeção predefinida, mas a injeção baseada em revisões é suportada: siga estas instruções:

      1. Use o seguinte comando para localizar a etiqueta de revisão em istiod:

        kubectl get deploy -n istio-system -l app=istiod -o \
           jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
        
      2. Aplique a etiqueta de revisão ao espaço de nomes. No comando seguinte, REVISION_LABEL é o valor da etiqueta de revisão istiod que anotou no passo anterior.

        kubectl label namespace istio-egress \
            istio-injection- istio.io/rev=REVISION_LABEL --overwrite
        
    3. Crie um manifesto do operador para o gateway de saída:

      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. Transfira a ferramenta istioctl. Tem de usar a versão 1.16.2-asm.2 ou mais recente, mesmo que esteja a usar a versão 1.15 ou inferior do Cloud Service Mesh. Consulte o artigo Transferir a versão correta do istioctl.

    5. Depois de extrair o arquivo transferido, defina uma variável de ambiente para guardar o caminho para a ferramenta istioctl e adicione-o ao script de inicialização:

      ISTIOCTL=$(find "$(pwd -P)" -name istioctl)
      echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
      
    6. Crie o manifesto de instalação do gateway de saída com o manifesto do operador e istioctl:

      ${ISTIOCTL} manifest generate \
          --filename egressgateway-operator.yaml \
          --output egressgateway \
          --cluster-specific
      
    7. Instale o gateway de saída:

      kubectl apply --recursive --filename egressgateway/
      
    8. Verifique se o gateway de saída está a ser executado em nós no conjunto de nós gateway:

      kubectl get pods -n istio-egress -o wide
      
    9. Os pods do gateway de saída têm affinity para nós no conjunto de nós gateway e uma tolerância que lhes permite serem executados nos nós do gateway contaminados. Examine a afinidade de nós e as tolerâncias para os pods do gateway de saída:

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

      O resultado é semelhante ao seguinte:

      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]
      

    Ative o registo de acesso do Envoy

    Os passos necessários para ativar os registos de acesso do Envoy dependem do tipo de Cloud Service Mesh, gerido ou no cluster:

    Preparar a malha e uma aplicação de teste

    1. Certifique-se de que o TLS mútuo STRICT está ativado. Aplique uma política PeerAuthentication predefinida para a malha no espaço de nomes 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
      

      Pode substituir esta configuração criando PeerAuthentication recursos em espaços de nomes específicos.

    2. Crie espaços de nomes para usar na implementação de cargas de trabalho de teste. Os passos posteriores neste tutorial explicam como configurar diferentes regras de encaminhamento de saída para cada espaço de nomes.

      kubectl create namespace team-x
      kubectl create namespace team-y
      
    3. Etiquete os espaços de nomes para que possam ser selecionados pelas políticas de rede do Kubernetes:

      kubectl label namespace team-x team=x
      kubectl label namespace team-y team=y
      
    4. Para que o Cloud Service Mesh injete automaticamente sidecars de proxy, tem de definir a etiqueta de revisão do plano de controlo nos espaços de nomes da carga de trabalho:

      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. Crie um ficheiro YAML para usar na criação de implementações de teste:

      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. Implemente a aplicação de teste no espaço de nomes team-x:

      kubectl -n team-x create -f ./test.yaml
      
    7. Verifique se a aplicação de teste está implementada num nó no conjunto predefinido e se é injetado um contentor sidecar de proxy. Repita o seguinte comando até que o estado do pod seja Running:

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

      O resultado é semelhante ao seguinte:

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

      2 de 2 contentores estão Running. Um contentor é a aplicação de teste e o outro é o sidecar do proxy.

      O pod está a ser executado num nó no conjunto de nós predefinido.

    8. Verifique se não é possível fazer um pedido HTTP do contentor de teste para um site externo:

      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
      

      É gerada uma mensagem de erro do proxy sidecar porque a regra de firewall global-deny-egress-all nega a ligação a montante.

    Usar o recurso Sidecar para restringir o âmbito da configuração do proxy sidecar

    Pode usar o recurso Sidecar para restringir o âmbito do ouvinte de saída configurado para proxies sidecar. Para reduzir o inchaço da configuração e a utilização de memória, é uma boa prática aplicar um recurso Sidecar predefinido para cada espaço de nomes.

    O proxy que o Cloud Service Mesh executa no sidecar é o Envoy. Na terminologia do Envoy, um cluster é um grupo logicamente semelhante de pontos finais a montante usado como destinos para o equilíbrio de carga.

    1. Inspecione os clusters de saída configurados no proxy sidecar do Envoy para o pod de teste executando o 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
      

      Existem aproximadamente 11 clusters do Envoy na lista, incluindo alguns para o gateway de saída.

    2. Restrinja a configuração do proxy a rotas de saída que foram explicitamente definidas com entradas de serviço nos espaços de nomes de saída e team-x. Aplique um recurso Sidecar ao espaço de nomes 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
      

      A definição do modo de política de tráfego de saída para REGISTRY_ONLY restringe a configuração do proxy para incluir apenas os anfitriões externos que foram adicionados explicitamente ao registo de serviços da malha através da definição de entradas de serviço.

      A definição de egress.hosts especifica que o proxy sidecar só seleciona rotas do espaço de nomes de saída que são disponibilizadas através do atributo exportTo. A parte "team-x/*" inclui todas as rotas que foram configuradas localmente no espaço de nomes team-x.

    3. Veja os clusters de saída configurados no proxy sidecar do Envoy e compare-os com a lista de clusters que foram configurados antes de aplicar o recurso Sidecar:

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

      São apresentados clusters para o gateway de saída e um para o próprio pod de teste.

    Configurar o Cloud Service Mesh para encaminhar o tráfego através do gateway de saída

    1. Configure um Gateway para tráfego HTTP na porta 80. O Gateway seleciona o proxy de gateway de saída que implementou no namespace de saída. A configuração Gateway é aplicada ao espaço de nomes de saída e processa o tráfego de qualquer anfitrião.

      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. Crie um DestinationRule para o gateway de saída com TLS mútuo para autenticação e encriptação. Use uma única regra de destino partilhada para todos os anfitriões externos.

      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. Crie um ServiceEntry no espaço de nomes de saída para registar explicitamente o example.com no registo de serviços da malha para o espaço de nomes team-x:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: example-com-ext
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: example.com
      spec:
        hosts:
        - example.com
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'team-x'
        - 'istio-egress'
      EOF
      
    4. Crie um VirtualService para encaminhar o tráfego para example.com através do gateway de saída. Existem duas condições de correspondência: a primeira condição direciona o tráfego para o gateway de saída e a segunda direciona o tráfego do gateway de saída para o anfitrião de destino. A propriedade exportTo controla que espaços de nomes podem usar o serviço virtual.

      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. Execute istioctl analyze para verificar se existem erros de configuração:

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

      O resultado é semelhante ao seguinte:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Envie vários pedidos através do gateway de saída para o site externo:

      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
      

      Vê códigos de estado 200 para todas as quatro respostas.

    7. Verifique se os pedidos foram encaminhados através do gateway de saída, verificando os registos de acesso do proxy. Primeiro, verifique o registo de acesso do sidecar do proxy implementado com a aplicação de teste:

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

      Para cada pedido que enviar, é apresentada uma entrada de registo semelhante à seguinte:

      [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. Verifique também o registo de acesso do gateway de saída:

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

      Para cada pedido que enviar, vê uma entrada do registo de acesso do gateway de saída semelhante à seguinte:

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

    Configure um encaminhamento diferente para um segundo espaço de nomes

    Configure o encaminhamento para um segundo anfitrião externo para saber como a conetividade externa diferente pode ser configurada para diferentes equipas.

    1. Crie um recurso Sidecar para o espaço de nomes 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. Implemente a aplicação de teste no espaço de nomes team-y:

      kubectl -n team-y create -f ./test.yaml
      
    3. Registe um segundo anfitrião externo e exporte-o para o espaço de nomes team-x e team-y:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: httpbin-org-ext
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: httpbin.org
      spec:
        hosts:
        - httpbin.org
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
        - 'team-y'
      EOF
      
    4. Crie um serviço virtual para encaminhar o tráfego para httpbin.org através do gateway de saída:

      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. Execute istioctl analyze para verificar se existem erros de configuração:

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

      Você vê:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Faça um pedido a httpbin.org a partir da app de teste 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
      

      Ver uma resposta 200 OK.

    7. Faça também um pedido a httpbin.org a partir da app de teste 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
      

      Ver uma resposta 200 OK.

    8. Tentar fazer um pedido a example.com a partir do espaço de nomes 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
      

      O pedido falha porque não existe uma rota de saída configurada para o anfitrião example.com.

    Usar a política de autorização para fornecer controlo adicional sobre o tráfego

    Neste tutorial, as políticas de autorização para o gateway de saída são criadas no espaço de nomes istio-egress. Pode configurar o RBAC do Kubernetes para que apenas os administradores de rede possam aceder ao espaço de nomes istio-egress.

    1. Crie um AuthorizationPolicy para que as aplicações no espaço de nomes team-x possam estabelecer ligação a example.com, mas não a outros anfitriões externos quando enviam pedidos através da porta 80. A porta targetPort correspondente nos pods do gateway de saída é 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. Verifique se pode fazer um pedido a example.com a partir da aplicação de teste no espaço de nomes 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
      

      Ver uma resposta 200 OK.

    3. Tente fazer um pedido a httpbin.org a partir da aplicação de teste no espaço de nomes 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
      

      O pedido falha com uma mensagem RBAC: access denied e um código de estado 403 Forbidden. Pode ter de aguardar alguns segundos porque existe, muitas vezes, um pequeno atraso antes de a política de autorização entrar em vigor.

    4. As políticas de autorização oferecem um controlo avançado sobre o tráfego que é permitido ou recusado. Aplique a seguinte política de autorização para permitir que a app de teste no espaço de nomes team-y faça pedidos a httpbin.org através de um caminho de URL específico quando envia pedidos através da porta 80. A porta targetPort correspondente nos pods do gateway de saída é 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. Tente estabelecer ligação a httpbin.org a partir da app de teste no espaço de nomes 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
      

      O pedido falha com uma mensagem RBAC: acesso negado e um código de estado 403 Proibido.

    6. Agora, faça um pedido a httpbin.org/status/418 a partir da mesma 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
      

      O pedido é bem-sucedido porque o caminho corresponde ao padrão na política de autorização. O resultado é semelhante ao seguinte:

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

    Originação de TLS no gateway de saída

    Pode configurar gateways de saída para upgrade (originar) pedidos HTTP simples para TLS ou TLS mútuo. Permitir que as aplicações façam pedidos HTTP simples tem várias vantagens quando usado com o TLS mútuo do Istio e a origem do TLS. Para mais informações, consulte o guia de práticas recomendadas.

    Originação de TLS no gateway de saída

    1. Create a DestinationRule. The DestinationRule especifica que o gateway origina uma ligação TLS a example.com.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: example-com-originate-tls
        namespace: istio-egress
      spec:
        host: example.com
        subsets:
          - name: example-com-originate-TLS
            trafficPolicy:
              portLevelSettings:
              - port:
                  number: 443
                tls:
                  mode: SIMPLE
                  sni: example.com
      EOF
      
    2. Atualize o serviço virtual para example.com de modo que os pedidos à porta 80 no gateway sejam upgraded para TLS na porta 443 quando forem enviados para o anfitrião de destino:

      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. Faça vários pedidos a example.com a partir da app de teste no espaço de nomes 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
      

      Tal como antes, os pedidos são bem-sucedidos com 200 OK respostas.

    4. Verifique o registo do gateway de saída para confirmar se o gateway encaminhou os pedidos para o anfitrião de destino ao originar ligações TLS:

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

      O resultado é semelhante ao seguinte:

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

      O sidecar do proxy enviou o pedido para o gateway através da porta 80 e o TLS foi originado na porta 443 para enviar o pedido para o anfitrião de destino.

    Encaminhamento de ligações HTTPS/TLS

    As suas aplicações existentes podem já estar a usar ligações TLS quando comunicam com serviços externos. Pode configurar o gateway de saída para transmitir ligações TLS sem as desencriptar.

    tls pass through

    1. Modifique a configuração para que o gateway de saída use a passagem direta de TLS para ligações à porta 443:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: egress-gateway
        namespace: istio-egress
      spec:
        selector:
          istio: egressgateway
        servers:
        - port:
            number: 80
            name: https
            protocol: HTTPS
          hosts:
            - '*'
          tls:
            mode: ISTIO_MUTUAL
        - port:
            number: 443
            name: tls
            protocol: TLS
          hosts:
          - '*'
          tls:
            mode: PASSTHROUGH
      EOF
      
    2. Atualize o DestinationRule que aponta para o gateway de saída para adicionar um segundo subconjunto para a porta 443 no gateway. Este novo subconjunto não usa TLS mútuo. O TLS mútuo do Istio não é suportado para a transferência de ligações TLS. As ligações na porta 80 continuam a usar 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. Atualize o serviço virtual para example.com de modo que o tráfego TLS na porta 443 seja transmitido através do 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. Atualize o serviço virtual para httpbin.org de modo que o tráfego TLS na porta 443 seja transmitido através do 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. Adicione uma política de autorização que aceite qualquer tipo de tráfego enviado para a porta 443 do serviço de gateway de saída. A porta targetPort correspondente nos pods do gateway é 8443.

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: egress-all-443
        namespace: istio-egress
      spec:
        action: ALLOW
        rules:
          - when:
            - key: destination.port
              values: ["8443"]
      EOF
      
    6. Execute istioctl analyze para verificar se existem erros de configuração:

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

      Você vê:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    7. Faça um pedido HTTP simples a example.com a partir da aplicação de teste no team-xnamespace:

      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
      

      O pedido é bem-sucedido com uma resposta 200 OK.

    8. Agora, faça vários pedidos TLS (HTTPS) a partir da aplicação de teste no espaço de nomes 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
      

      Vê 200 respostas.

    9. Veja novamente o registo do gateway de saída:

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

      São apresentadas entradas do registo semelhantes às seguintes:

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

      O pedido HTTPS foi tratado como tráfego TCP e transmitido através do gateway para o anfitrião de destino, pelo que não são incluídas informações HTTP no registo.

    Usar a NetworkPolicy do Kubernetes como um controlo adicional

    Existem muitos cenários em que uma aplicação pode ignorar um proxy sidecar. Pode usar o Kubernetes NetworkPolicy para especificar adicionalmente as ligações que as cargas de trabalho podem estabelecer. Depois de aplicar uma única política de rede, todas as ligações que não sejam especificamente permitidas são recusadas.

    Este tutorial considera apenas ligações de saída e seletores de saída para políticas de rede. Se controlar a entrada com políticas de rede nos seus próprios clusters, tem de criar políticas de entrada que correspondam às suas políticas de saída. Por exemplo, se permitir a saída de cargas de trabalho do espaço de nomes team-x para o espaço de nomes team-y, também tem de permitir a entrada no espaço de nomes team-y a partir do espaço de nomes team-x.

    1. Permita que as cargas de trabalho e os proxies implementados no espaço de nomes team-x estabeleçam ligação a istiod e à gateway de saída:

      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. Permita que as cargas de trabalho e os proxies consultem o 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. Permita que as cargas de trabalho e os proxies se liguem aos IPs que fornecem APIs e serviços Google, incluindo a autoridade de certificação do Cloud Service Mesh:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-google-apis
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - ipBlock:
              cidr: 199.36.153.4/30
          - ipBlock:
              cidr: 199.36.153.8/30
      EOF
      
    4. Permita que as cargas de trabalho e os proxies se liguem ao servidor de metadados do GKE:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-metadata-server
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to: # For GKE data plane v2
          - ipBlock:
              cidr: 169.254.169.254/32
        - to: # For GKE data plane v1
          - ipBlock:
              cidr: 127.0.0.1/32 # Prior to 1.21.0-gke.1000
          - ipBlock:
              cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later
          ports:
          - protocol: TCP
            port: 987
          - protocol: TCP
            port: 988
      EOF
      
    5. Opcional: permita que as cargas de trabalho e os proxies no espaço de nomes team-x estabeleçam ligações entre si:

      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. Opcional: permita que as cargas de trabalho e os proxies no espaço de nomes team-x estabeleçam ligações a cargas de trabalho implementadas por uma equipa diferente:

      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. As associações entre proxies sidecar persistem. As ligações existentes não são fechadas quando aplica uma nova política de rede. Reinicie as cargas de trabalho no espaço de nomes team-x para garantir que as ligações existentes são fechadas:

      kubectl -n team-x rollout restart deployment
      
    8. Verifique se ainda pode fazer um pedido HTTP para example.com a partir da aplicação de teste no espaço de nomes 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
      

      O pedido é bem-sucedido com uma resposta 200 OK.

    Aceder diretamente às APIs Google através do acesso privado Google e das autorizações da IAM

    As APIs e os serviços da Google são expostos através de endereços IP externos. Quando os pods com endereços IP de alias nativos da VPC estabelecem ligações às APIs Google através do acesso privado à Google, o tráfego nunca sai da rede da Google.

    Quando configurou a infraestrutura para este tutorial, ativou o acesso privado Google para a sub-rede usada pelos pods do GKE. Para permitir o acesso aos endereços IP usados pelo acesso privado à Google, criou uma rota, uma regra de firewall da VPC e uma zona DNS privada. Esta configuração permite que os pods alcancem as APIs Google diretamente sem enviar tráfego através do gateway de saída. Pode controlar que APIs estão disponíveis para contas de serviço do Kubernetes específicas (e, por conseguinte, espaços de nomes) através da Workload Identity Federation para o GKE e do IAM. A autorização do Istio não tem efeito porque o gateway de saída não está a processar as ligações às APIs Google.

    Antes de os pods poderem chamar as APIs Google, tem de usar o IAM para conceder autorizações. O cluster que está a usar para este tutorial está configurado para usar a Workload Identity Federation para o GKE, o que permite que uma conta de serviço do Kubernetes atue como uma conta de serviço Google.

    1. Crie uma conta de serviço Google para a sua aplicação usar:

      gcloud iam service-accounts create sa-test-app-team-x
      
    2. Permita que a conta de serviço do Kubernetes se faça passar pela conta de serviço da 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. Anote a conta de serviço do Kubernetes para a app de teste no espaço de nomes team-x com o endereço de email da conta de serviço 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. O pod da aplicação de teste tem de conseguir aceder ao servidor de metadados da Google (executado como um DaemonSet) para obter credenciais temporárias para chamar as APIs Google. Crie uma entrada de serviço para o servidor de metadados do GKE:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: metadata-google-internal
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: metadata.google.internal
      spec:
        hosts:
        - metadata.google.internal
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    5. Crie também uma entrada de serviço para private.googleapis.com e storage.googleapis.com:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: private-googleapis-com
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: googleapis.com
      spec:
        hosts:
        - private.googleapis.com
        - storage.googleapis.com
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    6. Verifique se a conta de serviço do Kubernetes está configurada corretamente para agir como a conta de serviço 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
      

      Vê a conta de serviço Google apresentada como a identidade ativa e única.

    7. Crie um ficheiro de teste num contentor do Cloud Storage:

      echo "Hello, World!" > /tmp/hello
      gcloud storage buckets create gs://${PROJECT_ID}-bucket
      gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
      
    8. Conceda autorização à conta de serviço para listar e ver ficheiros no contentor:

      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. Verifique se a aplicação de teste consegue aceder ao contentor de teste:

      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
      

      Você vê:

      Hello, World!
      

    Limpar

    Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

    Para evitar incorrer em custos na sua Google Cloud conta pelos recursos usados neste tutorial, conclua os passos nas secções seguintes:

    Elimine o projeto

    A forma mais fácil de eliminar a faturação é eliminar o projeto que criou para o tutorial.

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

      Go to Manage resources

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

    O que se segue?