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


Neste tutorial, mostramos como usar os gateways de saída do Cloud Service Mesh e outros controles do Google Cloud para proteger o tráfego de saída (saída) das cargas de trabalho implantadas em um cluster do Google Kubernetes Engine. O tutorial serve como complemento das Práticas recomendadas para usar gateways de saída do Cloud Service Mesh em clusters do GKE.

O público-alvo deste tutorial inclui engenheiros de rede, plataforma e segurança que administram os clusters do Google Kubernetes Engine usados por uma ou mais equipes de entrega de software. Os controles descritos aqui são especialmente úteis para organizações que precisam demonstrar conformidade com regulamentações, por exemplo, GDPR e 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 em um pool de nós dedicado.
  • Configure regras de roteamento de vários locatários para o tráfego externo por meio do gateway de saída:
    • Os aplicativos no namespace team-x podem se conectar a example.com
    • Os aplicativos no namespace team-y podem se conectar a httpbin.org
  • Use o recurso Sidecar para restringir o escopo da configuração de saída do proxy sidecar para cada namespace.
  • Configure políticas de autorização para aplicar regras de saída.
  • Configure o gateway de saída para fazer upgrade de solicitações HTTP simples para a TLS (origem de TLS).
  • Configure o gateway de saída para transmitir o tráfego TLS de passagem.
  • Configure as políticas de rede do Kubernetes como um controle de saída adicional.
  • Configure o acesso direto às APIs do Google usando permissões de Acesso privado do Google e de Gerenciamento de identidade e acesso (IAM).

Custos

Neste documento, você vai usar os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços.

Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir este tutorial, exclua os recursos criados para evitar custos contínuos. Para mais informações, consulte Como fazer a limpeza.

Antes de começar

  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. Crie um diretório de trabalho para usar e siga este tutorial:

    mkdir -p ~/WORKING_DIRECTORY
    cd ~/WORKING_DIRECTORY
    
  5. Crie um script de shell para inicializar seu ambiente para o tutorial. Substitua e edite as variáveis de acordo com o projeto e as preferências. Execute este script com o comando source para reinicializar o ambiente se a sessão de 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. Ativar compute.googleapis.com:

    gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
    
  7. Torne o script executável e o execute com o comando source para inicializar seu ambiente. Selecione Y se for necessário ativar compute.googleapis.com:

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

    Crie uma rede e uma sub-rede VPC

    1. Crie uma nova rede VPC:

      gcloud compute networks create vpc-network \
          --subnet-mode custom
      
    2. Crie uma sub-rede para o cluster executar em intervalos com endereços IP secundários pré-atribuídos para pods e serviços. O Acesso privado do Google é ativado para que os aplicativos apenas com endereços IP internos possam acessar as APIs e os serviços do 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
      

    Configurar o Cloud NAT

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

    1. Criar um Cloud Router

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

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

    Criar contas de serviço para cada pool de nós do GKE

    Crie duas contas de serviço para uso pelos dois pools de nós do GKE. Uma conta de serviço separada é atribuída a cada pool de nós para que você possa aplicar regras de firewall VPC a nós específicos.

    1. Crie uma conta de serviço para ser usada pelos nós no pool de nós padrão:

      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 ser usada pelos nós no pool de nós de gateway:

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

    Conceder permissões às contas de serviço

    Adicione um conjunto mínimo de papéis do IAM às contas de serviço do aplicativo e do gateway. Esses papéis são necessários para registrar, monitorar e extrair imagens de contêiner particular 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
    

    Como criar as regras de firewall

    Nas etapas a seguir, você aplica uma regra de firewall à rede VPC para que, por padrão, todo o tráfego de saída seja negado. É necessária uma conectividade específica para que o cluster funcione e os nós de gateway possam alcançar destinos fora da VPC. Um conjunto mínimo de regras de firewall específicas substitui a regra padrão de negação de tudo para permitir a conectividade necessária.

    1. Crie uma regra de firewall padrão (de baixa prioridade) para negar todas as saídas 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 de serviço de gateway cheguem à 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 cheguem ao plano de controle 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: essa regra de firewall não será necessária se você usar o Cloud Service Mesh gerenciado.

      O Cloud Service Mesh usa webhooks ao injetar proxies sidecar em cargas de trabalho. Permita que o servidor da API GKE chame os webhooks expostos pelo plano de controle da malha de serviço 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 conectividade de saída entre os nós e os pods em execução no cluster. O GKE cria automaticamente uma regra de entrada correspondente. Nenhuma regra é necessária para conectividade de serviço porque a cadeia de roteamento do iptables sempre converte endereços IP de serviço em endereços IP de 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 de endereços IP usados pelo Acesso privado do Google para disponibilizar APIs do Google, o Container Registry e 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 do verificador de integridade do Google Cloud acesse os pods em execução no cluster. Consulte verificações de integridade 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"
      

    Como configurar o acesso particular às APIs do Google Cloud

    O Acesso privado do Google permite que VMs e pods que tenham apenas endereços IP internos acessem APIs e serviços do Google. As APIs e os serviços do Google são exibidos do IPs externos, mas o tráfego dos nós nunca sai da rede do Google quando o Acesso privado do Google é usado.

    Ative a API Cloud DNS:

    gcloud services enable dns.googleapis.com
    

    Crie uma zona DNS particular, um CNAME e registros A para que os nós e as cargas de trabalho possam se conectar a APIs e serviços do Google usando o Acesso privado do Google e o nome do host private.googleapis.com:

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

    Como configurar o acesso particular ao Container Registry

    Crie uma zona DNS particular, um CNAME e registros A para que os nós possam se conectar ao Container Registry usando o Acesso privado do Google e o nome do host gcr.io:

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

    Criar um cluster do GKE particular

    1. Encontre o endereço IP externo do seu Cloud Shell para que você possa adicioná-lo à lista de redes que podem acessar o 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 VM do Cloud Shell pode mudar. Se isso acontecer, você precisará atualizar a lista de redes autorizadas do cluster. Adicione o seguinte comando ao seu 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. Criar um cluster do GKE particular

      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}
      

      O cluster leva alguns minutos para ser criado. O cluster tem nós particulares com endereços IP internos. Os pods e serviços recebem os IPs dos intervalos secundários nomeados que você definiu ao criar a sub-rede VPC.

      O Cloud Service Mesh com um plano de controle no cluster requer que os nós do cluster usem um tipo de máquina com pelo menos quatro vCPUs.

      O Google recomenda que o cluster seja inscrito no canal de lançamento "regular" para garantir que os nós estejam executando uma versão do Kubernetes compatível com o Cloud Service Mesh.

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

      Consulte mais informações sobre os requisitos e as limitações para executar o Cloud Service Mesh gerenciado em Recursos compatíveis do Cloud Service Mesh gerenciado.

      A federação de identidade da carga de trabalho do GKE está ativada no cluster. O Cloud Service Mesh requer a federação de identidade da carga de trabalho para o GKE e é a maneira recomendada de acessar as APIs do Google das cargas de trabalho do GKE.

    4. Crie um pool de nós chamado gateway. Esse pool de nós é onde o gateway de saída é implantado. O taint dedicated=gateway:NoSchedule é adicionado a cada nó no pool de nós de 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"
      

      Os taints e as tolerâncias do Kubernetes ajudam a garantir que somente os pods do gateway de saída sejam executados nos nós do pool.

    5. Faça o download de credenciais para se conectar ao cluster com a kubectl:

      gcloud container clusters get-credentials cluster1
      
    6. Verifique se os nós de gateway têm o taint correto:

      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 será assim:

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

    Como 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 retorne a este tutorial sem instalar gateways de entrada ou saída.

    Instalar um gateway de saída

    1. Crie um namespace do Kubernetes para o gateway de saída:

      kubectl create namespace istio-egress
      
    2. Ativar o namespace para injeção. As etapas dependem da sua implementação do plano de controle.

      Gerenciado (TD)

      Aplique o rótulo de injeção padrão ao namespace:

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

      Gerenciado (Istiod)

      Recomendado:execute o comando a seguir para aplicar o rótulo de injeção padrão ao namespace:

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

      Se você já usa o plano de controle gerenciado do Istiod:recomendamos usar a injeção padrão, mas a injeção baseada em revisão é compatível. Siga estas instruções:

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

        kubectl -n istio-system get controlplanerevision
        

        O resultado será assim:

        NAME                AGE
        asm-managed-rapid   6d7h
        

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

      2. Aplique o rótulo de revisão ao namespace:

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

      No cluster

      Recomendado:execute o comando a seguir para aplicar o rótulo de injeção padrão ao namespace:

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

      Recomendamos que você use a injeção padrão, mas a injeção baseada em revisão é compatível. Use as seguintes instruções:

      1. Use o seguinte comando para localizar o rótulo 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 o rótulo de revisão ao namespace. No comando a seguir, REVISION_LABEL é o valor do rótulo de revisão istiod que você anotou na etapa 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. Faça o download da ferramenta istioctl. É necessário usar a versão 1.16.2-asm.2 ou mais recente, mesmo que você esteja usando o Cloud Service Mesh versão 1.15 ou anterior. Consulte Como fazer o download da versão correta do istioctl.

    5. Depois de extrair o arquivo do download, defina uma variável de ambiente para manter o caminho para a ferramenta istioctl e adicioná-lo 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 usando 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á em execução nos nós no pool de nós gateway:

      kubectl get pods -n istio-egress -o wide
      
    9. Os pods do gateway de saída têm affinity para os nós no pool de nós gateway e uma tolerância que permite a execução nos nós do gateway com taint. Examine a afinidade e as tolerâncias dos nós 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 será assim:

      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]
      

    Ativar a geração de registros de acesso do Envoy

    As etapas necessárias para ativar os registros de acesso do Envoy dependem do seu tipo de Cloud Service Mesh, seja gerenciado ou no cluster:

    Como preparar a malha e um aplicativo de teste

    1. Verifique se a TLS mútuo do STRICT está ativada. Aplique uma política de PeerAuthentication padrão para a malha no namespace 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
      

      É possível modificar essa configuração criando recursos PeerAuthentication em namespaces específicos.

    2. Crie namespaces a serem usados para implantar cargas de trabalho de teste. As etapas posteriores neste tutorial explicam como configurar diferentes regras de roteamento de saída para cada namespace.

      kubectl create namespace team-x
      kubectl create namespace team-y
      
    3. Rotule os namespaces para que eles 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 proxies sidecar, defina o identificador da revisão do plano de controle nos namespaces 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 arquivo YAML a ser usado para fazer implantaçõ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. Implante o aplicativo de teste no namespace team-x:

      kubectl -n team-x create -f ./test.yaml
      
    7. Verifique se o aplicativo de teste está implantado em um nó no pool padrão e se um contêiner de arquivo secundário de proxy está injetado. Repita o comando a seguir até o status do pod ser Running:

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

      A resposta será semelhante a:

      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
      

      Dois de dois contêineres são Running. Um contêiner é o aplicativo de teste, e o outro é o arquivo secundário do proxy.

      O pod está sendo executado em um nó no pool de nós padrão.

    8. Verifique se não é possível fazer uma solicitação HTTP do contêiner 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
      

      Uma mensagem de erro do proxy sidecar é gerada porque a regra de firewall global-deny-egress-all nega a conexão upstream.

    Como usar o recurso do arquivo secundário para restringir o escopo da configuração de proxy sidcar

    Use o recurso do arquivo secundário para restringir o escopo do listener de saída configurado para proxies sidecar. Para reduzir a ocupação excessiva da configuração e do uso da memória, é recomendável aplicar um recurso Sidecar padrão para cada namespace.

    O proxy executado pelo Cloud Service Mesh no arquivo secundário é o Envoy. Na terminologia Envoy, um cluster é um grupo logicamente similar de endpoints upstream usados como destinos para balanceamento 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
      

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

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

      Definir o modo de política de tráfego de saída como REGISTRY_ONLY restringe a configuração de proxy para incluir somente os hosts externos que foram explicitamente adicionados ao registro de serviço da malha definindo entradas de serviço.

      Definir egress.hosts especifica que o proxy sidecar seleciona apenas rotas do namespace de saída disponibilizadas usando o atributo exportTo. A parte "team-x/*" inclui todas as rotas que foram configuradas localmente no namespace team-x.

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

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

      Você verá clusters para o gateway de saída e um para o próprio pod de teste.

    Como configurar o Cloud Service Mesh para rotear o tráfego pelo gateway de saída

    1. Configure um Gateway para tráfego HTTP na porta 80. O Gateway seleciona o proxy do gateway de saída que você implantou no namespace de saída. A configuração Gateway é aplicada ao namespace de saída e processa o tráfego para qualquer 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. Criar um DestinationRule para o gateway de saída com TLS mútua para autenticação e criptografia. Usar uma única regra de destino compartilhada para todos os hosts 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 namespace de saída para registrar explicitamente example.com no registro de serviço da malha para o namespace 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 rotear o tráfego para example.com por meio do gateway de saída. Há 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 host de destino. A propriedade exportTo controla quais namespaces 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 há erros de configuração:

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

      A resposta será semelhante a:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Envie várias solicitações pelo gateway de saída ao 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
      

      Você verá 200 códigos de status para as quatro respostas.

    7. Verifique se as solicitações foram direcionadas por meio do gateway de saída. Para isso, confira os registros de acesso do proxy. Primeiro, verifique o registro de acesso para o proxy sidecar implantado com o aplicativo 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 solicitação enviada, você vê uma entrada de registro semelhante a esta:

      [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 registro 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 solicitação enviada, você vê uma entrada de registro de acesso ao gateway de saída semelhante a esta:

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

    Configurar um roteamento diferente para um segundo namespace

    Configure o roteamento para um segundo host externo e saiba como diferentes conectividades diferentes podem ser configuradas para equipes diferentes.

    1. Crie um recurso Sidecar para o 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. Implante o aplicativo de teste no namespace team-y:

      kubectl -n team-y create -f ./test.yaml
      
    3. Registre um segundo host externo e exporte para o team-x e o namespace 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 rotear o tráfego para httpbin.org por meio 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 há erros de configuração:

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

      Você verá:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Faça uma solicitação para httpbin.org pelo 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
      

      Você verá uma resposta 200 OK.

    7. Faça também uma solicitação para httpbin.org do 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
      

      Você verá uma resposta 200 OK.

    8. Tente fazer uma solicitação para example.com pelo namespace 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
      

      A solicitação falha porque não há uma rota de saída configurada para o host example.com.

    Como usar a política de autorização para fornecer mais controle sobre o tráfego

    Neste tutorial, as políticas de autorização para o gateway de saída são criadas no namespace istio-egress. É possível configurar o RBAC do Kubernetes para que apenas administradores de rede possam acessar o namespace istio-egress.

    1. Crie um AuthorizationPolicy para que os aplicativos no namespace team-x possam se conectar a example.com, mas não a outros hosts externos ao enviar solicitações usando a porta 80. O 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 é possível fazer uma solicitação para example.com pelo aplicativo de teste no namespace 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
      

      Você verá uma resposta 200 OK.

    3. Tente fazer uma solicitação para httpbin.org pelo aplicativo de teste no namespace 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
      

      A solicitação falha com uma mensagem RBAC: access denied e um código de status "403 Forbidden". Aguarde alguns segundos, porque às vezes ocorre um pequeno atraso antes que a política de autorização entre em vigor.

    4. As políticas de autorização fornecem controle avançado sobre qual tráfego é permitido ou negado. Aplique a seguinte política de autorização para permitir que o app de teste no namespace team-y faça solicitações a httpbin.org usando um caminho de URL específico ao enviar solicitações usando a porta 80. O 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 se conectar a httpbin.org pelo app de teste no namespace 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
      

      A solicitação falha com uma mensagem de RBAC: acesso negado e um código de status "403 Forbidden".

    6. Agora, faça uma solicitação para httpbin.org/status/418 no mesmo 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
      

      A solicitação é bem-sucedida porque o caminho corresponde ao padrão na política de autorização. A resposta será semelhante a:

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

    Origem da TLS no gateway de saída

    É possível configurar gateways de saída para solicitações HTTP simples (upgrade) de origem para TLS ou TLS mútuo. Permitir que os aplicativos façam solicitações HTTP simples tem muitas vantagens quando usados com a TLS mútua do Istio e do TLS. Para mais informações, consulte o guia de práticas recomendadas.

    Origem de TLS no gateway de saída

    1. Criar um DestinationRule. The DestinationRule especifica que o gateway originou uma conexão TLS com 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 de example.com para que as solicitações para a porta 80 no gateway sejam upgraded para TLS na porta 443 quando forem enviadas ao host 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árias solicitações para example.com pelo app de teste no 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 -I http://example.com
      done
      

      Como antes, as solicitações são bem-sucedidas com respostas 200 OK.

    4. Verifique o registro do gateway de saída para verificar se o gateway roteou as solicitações para o host de destino originando conexõ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
      

      A resposta será semelhante a:

      [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 proxy sidecar enviou a solicitação para o gateway usando a porta 80 e a TLS originada na porta 443 para enviar a solicitação ao host de destino.

    Passagem de conexões HTTPS/TLS

    Talvez seus aplicativos atuais já estejam usando conexões TLS ao se comunicar com serviços externos. É possível configurar o gateway de saída para transmitir conexões TLS sem descriptografá-lo.

    passagem de tls

    1. Modifique sua configuração para que o gateway de saída use a passagem TLS para conexões com a 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 e adicione um segundo subconjunto para a porta 443 no gateway. Esse novo subconjunto não usa TLS mútuo. O TLS mútuo do Istio não é compatível com a passagem de conexões TLS. As conexões na porta 80 ainda usam 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 para que o tráfego TLS na porta 443 seja transmitido por meio 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 para que o tráfego TLS na porta 443 seja transmitido por meio 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. O targetPort correspondente nos pods de 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 há erros de configuração:

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

      Você verá:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    7. Faça uma solicitação HTTP simples para example.com do aplicativo de teste no namespace 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
      

      A solicitação é bem-sucedida com uma resposta 200 OK.

    8. Agora, faça várias solicitações TLS (HTTPS) do aplicativo de teste no 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
      

      Você vê 200 respostas.

    9. Verifique o registro do gateway de saída novamente:

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

      Você verá entradas de registro semelhantes a estas:

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

      A solicitação HTTPS foi tratada como tráfego TCP e passada pelo gateway para o host de destino. Portanto, nenhuma informação HTTP está incluída no registro.

    Como usar o Kubernetes NetworkPolicy como controle adicional

    Há muitas situações em que um aplicativo pode ignorar um proxy sidecar. Use o Kubernetes NetworkPolicy para especificar ainda mais quais conexões podem ser feitas. Depois que uma única política de rede é aplicada, todas as conexões que não são especificamente permitidas são negadas.

    Neste tutorial, são consideradas somente conexões de saída e seletores de saída para políticas de rede. Se você controlar a entrada com políticas de rede nos seus próprios clusters, precisará criar políticas de entrada para corresponder às suas políticas de saída. Por exemplo, se você permitir a saída de cargas de trabalho no namespace team-x para o namespace team-y, também precisará permitir a entrada para o namespace team-y do namespace team-x.

    1. Permita que cargas de trabalho e proxies implantados no namespace team-x se conectem a istiod e o 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. Permitir que cargas de trabalho e proxies consultem 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 cargas de trabalho e proxies se conectem aos IPs que disponibilizam APIs e serviços do 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 cargas de trabalho e proxies se conectem 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 cargas de trabalho e proxies no namespace team-x se conectem umas às outras:

      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 cargas de trabalho e proxies no namespace team-x se conectem a cargas de trabalho implantadas por outra equipe:

      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 conexões entre proxies sidecar permanecem. As conexões atuais não são encerradas quando você aplica uma nova política de rede. Reinicie as cargas de trabalho no namespace team-x para garantir que as conexões atuais sejam fechadas:

      kubectl -n team-x rollout restart deployment
      
    8. Verifique se ainda é possível fazer uma solicitação HTTP para example.com pelo aplicativo de teste no namespace 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
      

      A solicitação é bem-sucedida com uma resposta 200 OK.

    Como acessar diretamente as APIs do Google usando o Acesso privado do Google e as permissões do IAM

    As APIs e os serviços do Google são expostos usando endereços IP externos. Quando os pods com endereços IP de alias nativos de VPC fazem conexões com as APIs do Google usando o Acesso privado do Google, o tráfego nunca sai da rede do Google.

    Ao configurar a infraestrutura para este tutorial, você ativou o Acesso privado do Google para a sub-rede usada pelos pods do GKE. Para permitir o acesso aos endereços IP usados pelo Acesso privado do Google, você criou uma rota, uma regra de firewall VPC e uma zona de DNS particular. Essa configuração permite que os pods alcancem as APIs do Google diretamente sem enviar tráfego por meio do gateway de saída. É possível controlar quais APIs estão disponíveis para contas de serviço específicas do Kubernetes e, portanto, namespaces, usando a federação de identidade da carga de trabalho do GKE e o IAM. A autorização do Istio não tem efeito porque o gateway de saída não processa conexões com as APIs do Google.

    Antes que os pods chamem APIs do Google, você precisa usar o IAM para conceder permissões. O cluster que você está usando para este tutorial está configurado para usar a federação de identidade da carga de trabalho para GKE, que permite que uma conta de serviço do Kubernetes atue como uma conta de serviço do Google.

    1. Crie uma conta de serviço do Google para o aplicativo usar:

      gcloud iam service-accounts create sa-test-app-team-x
      
    2. Permita que a conta de serviço do Kubernetes personifique a conta de serviço do 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 app de teste no namespace team-x com o endereço de e-mail da conta de serviço do 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 do aplicativo de teste precisa acessar o servidor de metadados do Google, executado como um DaemonSet, para receber credenciais temporárias de chamada de APIs do 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 atuar como a conta de serviço do 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
      

      Você verá a conta de serviço do Google listada como a identidade ativa e única.

    7. Crie um arquivo de teste em um bucket 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 permissão à conta de serviço para listar e visualizar arquivos no 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. Verifique se o aplicativo de teste pode acessar o bucket 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ê verá:

      Hello, World!
      

    Limpeza

    Para evitar cobranças na sua conta do Google Cloud pelos recursos usados no tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

    Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, conclua as etapas nas seções a seguir:

    Excluir o projeto

    A maneira mais fácil de evitar o faturamento é excluir o projeto criado 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.

    A seguir