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) de cargas de trabalho implantadas em um cluster do Google Kubernetes Engine. Tutorial é um complemento das Práticas recomendadas para o uso de 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:
- Rede VPC personalizada e sub-rede privada.
- Cloud NAT para acesso à Internet
- Cluster do GKE privado com um pool de nós extra para pods de gateway de saída
- Regras de firewall VPC de saída restritiva. Somente nós de gateway podem alcançar hosts externos
- Acesso privado do Google para conexão com Container Registry e APIs do Google
- 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 aexample.com
- Os aplicativos no namespace
team-y
podem se conectar ahttpbin.org
- Os aplicativos no namespace
- 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ê usará os seguintes componentes faturáveis do Google Cloud:
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços.
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
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Verifique se a cobrança está ativada para o seu projeto do Google Cloud.
-
In the Google Cloud console, activate Cloud Shell.
Crie um diretório de trabalho para usar e siga este tutorial:
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
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
Ativar
compute.googleapis.com
:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
Torne o script executável e o execute com o comando
source
para inicializar seu ambiente. SelecioneY
se for necessário ativarcompute.googleapis.com
:chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
Como configurar a infraestrutura
Crie uma rede e uma sub-rede VPC
Crie uma nova rede VPC:
gcloud compute networks create vpc-network \ --subnet-mode custom
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.
Criar um Cloud Router
gcloud compute routers create nat-router \ --network vpc-network
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.
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"
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.
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."
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"
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."
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"
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"
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)"
Permita que o serviço do verificador de integridade do Google Cloud acesse os pods em execução no cluster. Consulte para mais informações em verificações de integridade.
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
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
Ative a API Google Kubernetes Engine:
gcloud services enable container.googleapis.com
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 exige 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 pré-requisitos no cluster.
Para mais informações sobre os requisitos e as limitações para executar o Cloud Service Mesh gerenciado, consulte os Recursos compatíveis do Cloud Service Mesh gerenciado.
A federação de identidade da carga de trabalho do GKE é ativados 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 nas cargas de trabalho do GKE.
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.
Faça o download de credenciais para se conectar ao cluster com a kubectl:
gcloud container clusters get-credentials cluster1
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
Crie um namespace do Kubernetes para o gateway de saída:
kubectl create namespace istio-egress
Ativar o namespace para injeção. As etapas dependem da 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ê for um usuário com o plano de controle Managed Istiod: Recomendamos que você use a injeção padrão, mas a injeção baseada em revisão é suporte. Siga estas instruções:
Execute o seguinte comando 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.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 tem suporte: Siga estas instruções:
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"}'
Aplique o rótulo de revisão ao namespace. No comando a seguir,
REVISION_LABEL
é o valor do rótulo de revisãoistiod
que você anotou na etapa anterior.kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
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
Faça o download da ferramenta
istioctl
. Você precisa usar a versão 1.16.2-asm.2 ou mais recente se você estiver usando o Cloud Service Mesh versão 1.15 ou anterior. Consulte Como fazer o download da versão correta do istioctl.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
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
Instale o gateway de saída:
kubectl apply --recursive --filename egressgateway/
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
Os pods do gateway de saída têm
affinity
para os nós no pool de nósgateway
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 tipo de Cloud Service Mesh, gerenciado ou no cluster:
Gerenciado
Siga as instruções para Ativar os registros de acesso no Cloud Service Mesh gerenciado.
No cluster
Siga as instruções para ativar registros de acesso no Cloud Service Mesh no cluster.
Como preparar a malha e um aplicativo de teste
Verifique se a TLS mútuo do STRICT está ativada. Aplique uma política de
PeerAuthentication
padrão para a malha no namespaceistio-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.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
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
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
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
Implante o aplicativo de teste no namespace
team-x
:kubectl -n team-x create -f ./test.yaml
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.
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
Você pode usar o
Recurso do arquivo secundário
para restringir o escopo do listener de saída configurado para arquivo secundário
proxies. 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 sidecar é o Envoy. Na
terminologia Envoy,
um cluster
é um grupo logicamente similar de endpoints upstream usados como
destinos para balanceamento de carga.
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.
Restrinja a configuração do proxy às rotas de saída que foram definidas explicitamente com as entradas de serviço nos namespaces de saída e
team-x
. Aplique um recursoSidecar
ao namespaceteam-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 atributoexportTo
. A parte "team-x/*
" inclui todas as rotas que foram configuradas localmente no namespaceteam-x
.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
Configure um
Gateway
para tráfego HTTP na porta 80. OGateway
seleciona o proxy do gateway de saída que você implantou no namespace de saída. A configuraçãoGateway
é 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
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
Crie um
ServiceEntry
no namespace de saída para registrar explicitamente example.com no registro de serviço da malha para o namespaceteam-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
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 propriedadeexportTo
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
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.
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.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 - -
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.
Crie um recurso
Sidecar
para o namespaceteam-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
Implante o aplicativo de teste no namespace
team-y
:kubectl -n team-y create -f ./test.yaml
Registre um segundo host externo e exporte para o
team-x
e o namespaceteam-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
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
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.
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
.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
.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
.
Crie um
AuthorizationPolicy
para que os aplicativos no namespaceteam-x
possam se conectar a example.com, mas não a outros hosts externos ao enviar solicitações usando a porta 80. OtargetPort
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
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
.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.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. OtargetPort
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
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".
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.
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
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
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
.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.
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
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
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
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
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
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.
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
.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.
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
.
Permita que cargas de trabalho e proxies implantados no namespace
team-x
se conectem aistiod
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
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
Permita que cargas de trabalho e proxies se conectem aos IPs que disponibilizam o Google APIs e serviços, incluindo a autoridade certificadora 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
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
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
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
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
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 determinados contas de serviço do Kubernetes (e, portanto, namespaces) usando Federação de identidade da carga de trabalho para GKE e do 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, o que permite que uma conta de serviço do Kubernetes atue como uma conta de serviço do Google.
Crie uma conta de serviço do Google para o aplicativo usar:
gcloud iam service-accounts create sa-test-app-team-x
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
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
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
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
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.
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/
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
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 sobre os recursos usados neste tutorial na conta do Google Cloud, conclua as etapas nas seções a seguir:
Exclua o projeto
A maneira mais fácil de evitar o faturamento é excluir o projeto criado para
o tutorial.
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
A seguir
- Leia o guia de práticas recomendadas para campanhas complementares.
- Consulte o guia de aumento da proteção do GKE.
- Saiba como automatizar o gerenciamento de certificados TLS para o Cloud Service Mesh de entrada usando o CA Service.
- Aprenda a gerenciar configurações e políticas em toda a infraestrutura com o Gerenciamento de configurações do GKE Enterprise.
- Para mais arquiteturas de referência, diagramas e práticas recomendadas, confira a Central de arquitetura do Cloud.