Este tutorial mostra como usar gateways de saída do Cloud Service Mesh e outros Google Cloud controlos para proteger o tráfego de saída (saída) de cargas de trabalho implementadas num cluster do Google Kubernetes Engine. Este tutorial destina-se a complementar o artigo Práticas recomendadas para usar gateways de saída da malha de serviços na nuvem em clusters do GKE.
O público-alvo deste tutorial inclui engenheiros de rede, plataforma e segurança que administram clusters do Google Kubernetes Engine usados por uma ou mais equipas de entrega de software. Os controlos descritos aqui são especialmente úteis para organizações que têm de demonstrar a conformidade com os regulamentos, por exemplo, o RGPD e a PCI.
Objetivos
- Configure a infraestrutura para executar o Cloud Service Mesh:
- Rede VPC personalizada e sub-rede privada
- Cloud NAT para acesso à Internet
- Cluster do GKE privado com um conjunto de nós adicional para pods de gateway de saída
- Regras de firewall da VPC de saída restritivas; apenas os nós de gateway podem alcançar anfitriões externos
- Acesso privado Google para estabelecer ligação ao Container Registry e às APIs Google
- Instale o Cloud Service Mesh.
- Instale proxies de gateway de saída em execução num node pool dedicado.
- Configure regras de encaminhamento multi-inquilino para tráfego externo através do gateway de saída:
- As aplicações no espaço de nomes
team-x
podem estabelecer ligação aexample.com
- As aplicações no espaço de nomes
team-y
podem estabelecer ligação ahttpbin.org
- As aplicações no espaço de nomes
- Use o recurso
Sidecar
para restringir o âmbito da configuração de saída do proxy sidecar para cada espaço de nomes. - Configure políticas de autorização para aplicar regras de saída.
- Configure o gateway de saída para atualizar pedidos HTTP simples para TLS (originação de TLS).
- Configure o gateway de saída para transmitir tráfego TLS.
- Configure políticas de rede do Kubernetes como um controlo de saída adicional.
- Configure o acesso direto às APIs Google através do acesso privado Google e das autorizações da gestão de identidade e de acesso (IAM).
Custos
Neste documento, usa os seguintes componentes faturáveis do Google Cloud:
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
Para gerar uma estimativa de custos com base na sua utilização projetada,
use a calculadora de preços.
Quando terminar este tutorial, pode evitar custos contínuos eliminando os recursos que criou. Para mais informações, consulte o artigo Limpar.
Antes de começar
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator
(
roles/resourcemanager.projectCreator
), which contains theresourcemanager.projects.create
permission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
Crie um diretório de trabalho para usar enquanto segue o tutorial:
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
Crie um script de shell para inicializar o seu ambiente para o tutorial. Substitua e edite as variáveis de acordo com o seu projeto e preferências. Execute este script com o comando
source
para reinicializar o seu ambiente se a sessão da shell expirar:cat << 'EOF' > ./init-egress-tutorial.sh #! /usr/bin/env bash PROJECT_ID=YOUR_PROJECT_ID REGION=REGION ZONE=ZONE gcloud config set project ${PROJECT_ID} gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE} EOF
Ative
compute.googleapis.com
:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
Torne o script executável e execute-o com o comando
source
para inicializar o seu ambiente. Se lhe for pedido que ative a opçãocompute.googleapis.com
, selecioneY
:chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
Criar uma nova rede de VPC:
gcloud compute networks create vpc-network \ --subnet-mode custom
Crie uma sub-rede para o cluster ser executado com intervalos de endereços IP secundários pré-atribuídos para pods e serviços. O acesso privado à Google está ativado para que as aplicações com apenas endereços IP internos possam alcançar as APIs e os serviços Google:
gcloud compute networks subnets create subnet-gke \ --network vpc-network \ --range 10.0.0.0/24 \ --secondary-range pods=10.1.0.0/16,services=10.2.0.0/20 \ --enable-private-ip-google-access
Crie um Cloud Router:
gcloud compute routers create nat-router \ --network vpc-network
Adicione uma configuração NAT ao router:
gcloud compute routers nats create nat-config \ --router nat-router \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
Crie uma conta de serviço para utilização pelos nós no node pool predefinido:
gcloud iam service-accounts create sa-application-nodes \ --description="SA for application nodes" \ --display-name="sa-application-nodes"
Crie uma conta de serviço para utilização pelos nós no node pool do gateway:
gcloud iam service-accounts create sa-gateway-nodes \ --description="SA for gateway nodes" \ --display-name="sa-gateway-nodes"
Crie uma regra de firewall predefinida (prioridade baixa) para negar toda a saída da rede VPC:
gcloud compute firewall-rules create global-deny-egress-all \ --action DENY \ --direction EGRESS \ --rules all \ --destination-ranges 0.0.0.0/0 \ --network vpc-network \ --priority 65535 \ --description "Default rule to deny all egress from the network."
Crie uma regra para permitir que apenas os nós com a conta do serviço de gateway acedam à Internet:
gcloud compute firewall-rules create gateway-allow-egress-web \ --action ALLOW \ --direction EGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --network vpc-network \ --priority 1000 \ --description "Allow the nodes running the egress gateways to connect to the web"
Permita que os nós alcancem o plano de controlo do Kubernetes:
gcloud compute firewall-rules create allow-egress-to-api-server \ --action ALLOW \ --direction EGRESS \ --rules tcp:443,tcp:10250 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
Opcional: esta regra de firewall não é necessária se usar o Managed Cloud Service Mesh.
O Cloud Service Mesh usa webhooks quando injeta proxies sidecar em cargas de trabalho. Permita que o servidor da API GKE chame os webhooks expostos pelo plano de controlo da malha de serviços em execução nos nós:
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow the API server to call the webhooks exposed by istiod discovery"
Permita a conetividade de saída entre os nós e os pods em execução no cluster. O GKE cria automaticamente uma regra de entrada correspondente. Não é necessária nenhuma regra para a conetividade do serviço, porque a cadeia de encaminhamento iptables converte sempre os endereços IP do serviço em endereços IP do pod.
gcloud compute firewall-rules create allow-egress-nodes-and-pods \ --action ALLOW \ --direction EGRESS \ --rules all \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.0.0.0/24,10.1.0.0/16 \ --network vpc-network \ --priority 1000 \ --description "Allow egress to other Nodes and Pods"
Permita o acesso aos conjuntos reservados de endereços IP usados pelo acesso privado Google para publicar APIs Google, pelo Container Registry e por outros serviços:
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 199.36.153.8/30 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the VIPs used by Google Cloud APIs (Private Google Access)"
Permita que o serviço de verificação de saúde Google Cloud aceda aos pods em execução no cluster. Consulte as verificações de estado: para mais informações.
gcloud compute firewall-rules create allow-ingress-gcp-health-checker \ --action ALLOW \ --direction INGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 35.191.0.0/16,130.211.0.0/22,209.85.152.0/22,209.85.204.0/22 \ --network vpc-network \ --priority 1000 \ --description "Allow workloads to respond to Google Cloud health checks"
Encontre o endereço IP externo do Cloud Shell para que o possa adicionar à lista de redes autorizadas a aceder ao servidor da API do cluster:
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
Após um período de inatividade, o endereço IP externo da sua VM do Cloud Shell pode mudar. Se isso acontecer, tem de atualizar a lista de redes autorizadas do cluster. Adicione o seguinte comando ao script de inicialização:
cat << 'EOF' >> ./init-egress-tutorial.sh SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com) gcloud container clusters update cluster1 \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 EOF
Ative a API Google Kubernetes Engine:
gcloud services enable container.googleapis.com
Crie um cluster privado do GKE:
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-dataplane-v2 \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --network "vpc-network" \ --subnetwork "subnet-gke" \ --cluster-secondary-range-name "pods" \ --services-secondary-range-name "services" \ --workload-pool "${PROJECT_ID}.svc.id.goog" \ --zone ${ZONE}
A criação do cluster demora alguns minutos. O cluster tem nós privados com endereços IP internos. Os pods e os serviços são atribuídos a IPs dos intervalos secundários com nomes que definiu quando criou a sub-rede da VPC.
A Cloud Service Mesh com um plano de controlo no cluster requer que os nós do cluster usem um tipo de máquina com, pelo menos, 4 vCPUs.
A Google recomenda que o cluster esteja subscrito no canal de lançamento "regular" para garantir que os nós estão a executar uma versão do Kubernetes suportada pelo Cloud Service Mesh.
Para mais informações sobre os pré-requisitos para executar o Cloud Service Mesh com um plano de controlo no cluster, consulte os pré-requisitos no cluster.
Para mais informações sobre os requisitos e as limitações da execução do Cloud Service Mesh gerido, consulte as funcionalidades suportadas do Cloud Service Mesh gerido.
A federação de identidade da carga de trabalho para o GKE está ativada no cluster. O Cloud Service Mesh requer a Workload Identity Federation para o GKE e é a forma recomendada de aceder às APIs Google a partir de cargas de trabalho do GKE.
Crie um node pool denominado gateway. É neste conjunto de nós que o gateway de saída é implementado. O
dedicated=gateway:NoSchedule
taint é adicionado a todos os nós no conjunto de nós do gateway.gcloud container node-pools create "gateway" \ --cluster "cluster1" \ --machine-type "e2-standard-4" \ --node-taints dedicated=gateway:NoSchedule \ --service-account "sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --num-nodes "1"
As restrições e as tolerâncias do Kubernetes ajudam a garantir que apenas os pods do gateway de saída são executados em nós no conjunto de nós do gateway.
Transfira as credenciais para poder estabelecer ligação ao cluster com o kubectl:
gcloud container clusters get-credentials cluster1
Verifique se os nós de gateway têm a rejeição correta:
kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \ -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
O resultado é semelhante ao seguinte:
name taints gke-cluster1-gateway-9d65b410-cffs map[effect:NoSchedule key:dedicated value:gateway]
Crie um espaço de nomes do Kubernetes para o gateway de saída:
kubectl create namespace istio-egress
Ative o espaço de nomes para injeção. Os passos dependem da sua implementação do plano de controlo.
Gerido (TD)
Aplique a etiqueta de injeção predefinida ao espaço de nomes:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Gerido (Istiod)
Recomendado: execute o seguinte comando para aplicar a etiqueta de injeção predefinida ao espaço de nomes:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Se for um utilizador existente com o plano de controlo do Istiod gerido: recomendamos que use a injeção predefinida, mas a injeção baseada em revisões é suportada. Siga as instruções abaixo:
Execute o seguinte comando para localizar os canais de lançamento disponíveis:
kubectl -n istio-system get controlplanerevision
O resultado é semelhante ao seguinte:
NAME AGE asm-managed-rapid 6d7h
Na saída, o valor na coluna
NAME
é a etiqueta de revisão que corresponde ao canal de lançamento disponível para a versão do Cloud Service Mesh.Aplique a etiqueta de revisão ao espaço de nomes:
kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
No cluster
Recomendado: execute o seguinte comando para aplicar a etiqueta de injeção predefinida ao espaço de nomes:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Recomendamos que use a injeção predefinida, mas a injeção baseada em revisões é suportada: siga estas instruções:
Use o seguinte comando para localizar a etiqueta de revisão em
istiod
:kubectl get deploy -n istio-system -l app=istiod -o \ jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
Aplique a etiqueta de revisão ao espaço de nomes. No comando seguinte,
REVISION_LABEL
é o valor da etiqueta de revisãoistiod
que anotou no passo 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
Transfira a ferramenta
istioctl
. Tem de usar a versão 1.16.2-asm.2 ou mais recente, mesmo que esteja a usar a versão 1.15 ou inferior do Cloud Service Mesh. Consulte o artigo Transferir a versão correta do istioctl.Depois de extrair o arquivo transferido, defina uma variável de ambiente para guardar o caminho para a ferramenta
istioctl
e adicione-o ao script de inicialização:ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
Crie o manifesto de instalação do gateway de saída com o manifesto do operador e
istioctl
:${ISTIOCTL} manifest generate \ --filename egressgateway-operator.yaml \ --output egressgateway \ --cluster-specific
Instale o gateway de saída:
kubectl apply --recursive --filename egressgateway/
Verifique se o gateway de saída está a ser executado em nós no conjunto de nós
gateway
:kubectl get pods -n istio-egress -o wide
Os pods do gateway de saída têm
affinity
para nós no conjunto de nósgateway
e uma tolerância que lhes permite serem executados nos nós do gateway contaminados. Examine a afinidade de nós e as tolerâncias para os pods do gateway de saída:kubectl -n istio-egress get pod -l istio=egressgateway \ -o=custom-columns='name:metadata.name,node-affinity:spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,tolerations:spec.tolerations[?(@.key=="dedicated")]'
O resultado é semelhante ao seguinte:
name node-affinity tolerations istio-egressgateway-754d9684d5-jjkdz [map[matchExpressions:[map[key:cloud.google.com/gke-nodepool operator:In values:[gateway]]]]] map[key:dedicated operator:Equal value:gateway]
Certifique-se de que o TLS mútuo STRICT está ativado. Aplique uma política
PeerAuthentication
predefinida para a malha no espaço de nomesistio-system
:cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOF
Pode substituir esta configuração criando
PeerAuthentication
recursos em espaços de nomes específicos.Crie espaços de nomes para usar na implementação de cargas de trabalho de teste. Os passos posteriores neste tutorial explicam como configurar diferentes regras de encaminhamento de saída para cada espaço de nomes.
kubectl create namespace team-x kubectl create namespace team-y
Etiquete os espaços de nomes para que possam ser selecionados pelas políticas de rede do Kubernetes:
kubectl label namespace team-x team=x kubectl label namespace team-y team=y
Para que o Cloud Service Mesh injete automaticamente sidecars de proxy, tem de definir a etiqueta de revisão do plano de controlo nos espaços de nomes da carga de trabalho:
kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwrite
Crie um ficheiro YAML para usar na criação de implementações de teste:
cat << 'EOF' > ./test.yaml apiVersion: v1 kind: ServiceAccount metadata: name: test --- apiVersion: v1 kind: Service metadata: name: test labels: app: test spec: ports: - port: 80 name: http selector: app: test --- apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 selector: matchLabels: app: test template: metadata: labels: app: test spec: serviceAccountName: test containers: - name: test image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim command: ["/bin/sleep", "infinity"] imagePullPolicy: IfNotPresent EOF
Implemente a aplicação de teste no espaço de nomes
team-x
:kubectl -n team-x create -f ./test.yaml
Verifique se a aplicação de teste está implementada num nó no conjunto predefinido e se é injetado um contentor sidecar de proxy. Repita o seguinte comando até que o estado do pod seja
Running
:kubectl -n team-x get po -l app=test -o wide
O resultado é semelhante ao seguinte:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-d5bdf6f4f-9nxfv 2/2 Running 0 19h 10.1.1.25 gke-cluster1-default-pool-f6c7a51f-wbzj
2 de 2 contentores estão
Running
. Um contentor é a aplicação de teste e o outro é o sidecar do proxy.O pod está a ser executado num nó no conjunto de nós predefinido.
Verifique se não é possível fazer um pedido HTTP do contentor de teste para um site externo:
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test -- curl -v http://example.com
É gerada uma mensagem de erro do proxy sidecar porque a regra de firewall
global-deny-egress-all
nega a ligação a montante.Inspecione os clusters de saída configurados no proxy sidecar do Envoy para o pod de teste executando o comando
istioctl proxy-config
:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
Existem aproximadamente 11 clusters do Envoy na lista, incluindo alguns para o gateway de saída.
Restrinja a configuração do proxy a rotas de saída que foram explicitamente definidas com entradas de serviço nos espaços de nomes de saída e
team-x
. Aplique um recursoSidecar
ao espaço de nomesteam-x
:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-x spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-x/*' EOF
A definição do modo de política de tráfego de saída para
REGISTRY_ONLY
restringe a configuração do proxy para incluir apenas os anfitriões externos que foram adicionados explicitamente ao registo de serviços da malha através da definição de entradas de serviço.A definição de
egress.hosts
especifica que o proxy sidecar só seleciona rotas do espaço de nomes de saída que são disponibilizadas através do atributoexportTo
. A parte "team-x/*
" inclui todas as rotas que foram configuradas localmente no espaço de nomesteam-x
.Veja os clusters de saída configurados no proxy sidecar do Envoy e compare-os com a lista de clusters que foram configurados antes de aplicar o recurso
Sidecar
:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
São apresentados clusters para o gateway de saída e um para o próprio pod de teste.
Configure um
Gateway
para tráfego HTTP na porta 80. OGateway
seleciona o proxy de gateway de saída que implementou no namespace de saída. A configuraçãoGateway
é aplicada ao espaço de nomes de saída e processa o tráfego de qualquer anfitrião.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL EOF
Crie um
DestinationRule
para o gateway de saída com TLS mútuo para autenticação e encriptação. Use uma única regra de destino partilhada para todos os anfitriões externos.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: tls: mode: ISTIO_MUTUAL EOF
Crie um
ServiceEntry
no espaço de nomes de saída para registar explicitamente o example.com no registo de serviços da malha para o espaço de nomesteam-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 encaminhar o tráfego para example.com através do gateway de saída. Existem duas condições de correspondência: a primeira condição direciona o tráfego para o gateway de saída e a segunda direciona o tráfego do gateway de saída para o anfitrião de destino. A propriedadeexportTo
controla que espaços de nomes podem usar o serviço virtual.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
Execute
istioctl analyze
para verificar se existem erros de configuração:${ISTIOCTL} analyze -n istio-egress --revision REVISION
O resultado é semelhante ao seguinte:
✔ No validation issues found when analyzing namespace: istio-egress.
Envie vários pedidos através do gateway de saída para o site externo:
for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- \ curl -s -o /dev/null -w "%{http_code}\n" http://example.com done
Vê códigos de estado
200
para todas as quatro respostas.Verifique se os pedidos foram encaminhados através do gateway de saída, verificando os registos de acesso do proxy. Primeiro, verifique o registo de acesso do sidecar do proxy implementado com a aplicação de teste:
kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) istio-proxy
Para cada pedido que enviar, é apresentada uma entrada de registo semelhante à seguinte:
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/1.1" 200 - "-" "-" 0 0 5 4 "-" "curl/7.67.0" "d57ea5ad-90e9-46d9-8b55-8e6e404a8f9b" "example.com" "10.1.4.12:8080" outbound|80||istio-egressgateway.istio-egress.svc.cluster.local 10.1.0.17:42140 93.184.216.34:80 10.1.0.17:60326 - -
Verifique também o registo de acesso do gateway de saída:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
Para cada pedido que enviar, vê uma entrada do registo de acesso do gateway de saída semelhante à seguinte:
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 4 3 "10.1.0.17" "curl/7.67.0" "095711e6-64ef-4de0-983e-59158e3c55e7" "example.com" "93.184.216.34:80" outbound|80||example.com 10.1.4.12:37636 10.1.4.12:8080 10.1.0.17:44404 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
Crie um recurso
Sidecar
para o espaço de nomesteam-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
Implemente a aplicação de teste no espaço de nomes
team-y
:kubectl -n team-y create -f ./test.yaml
Registe um segundo anfitrião externo e exporte-o para o espaço de nomes
team-x
eteam-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 encaminhar o tráfego para httpbin.org através do gateway de saída:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
Execute
istioctl analyze
para verificar se existem erros de configuração:${ISTIOCTL} analyze -n istio-egress --revision REVISION
Você vê:
✔ No validation issues found when analyzing namespace: istio-egress.
Faça um pedido a httpbin.org a partir da app de teste
team-y
:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test -o \ jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
Ver uma resposta
200 OK
.Faça também um pedido a httpbin.org a partir da app de teste
team-x
:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
Ver uma resposta
200 OK
.Tentar fazer um pedido a example.com a partir do espaço de nomes
team-y
:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
O pedido falha porque não existe uma rota de saída configurada para o anfitrião
example.com
.Crie um
AuthorizationPolicy
para que as aplicações no espaço de nomesteam-x
possam estabelecer ligação a example.com, mas não a outros anfitriões externos quando enviam pedidos através da porta 80. A portatargetPort
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 pode fazer um pedido a example.com a partir da aplicação de teste no espaço de nomes
team-x
:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
Ver uma resposta
200 OK
.Tente fazer um pedido a httpbin.org a partir da aplicação de teste no espaço de nomes
team-x
:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
O pedido falha com uma mensagem
RBAC: access denied
e um código de estado 403 Forbidden. Pode ter de aguardar alguns segundos porque existe, muitas vezes, um pequeno atraso antes de a política de autorização entrar em vigor.As políticas de autorização oferecem um controlo avançado sobre o tráfego que é permitido ou recusado. Aplique a seguinte política de autorização para permitir que a app de teste no espaço de nomes
team-y
faça pedidos a httpbin.org através de um caminho de URL específico quando envia pedidos através da porta 80. A portatargetPort
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 estabelecer ligação a httpbin.org a partir da app de teste no espaço de nomes
team-y
:kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
O pedido falha com uma mensagem RBAC: acesso negado e um código de estado 403 Proibido.
Agora, faça um pedido a httpbin.org/status/418 a partir da mesma app:
kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl http://httpbin.org/status/418
O pedido é bem-sucedido porque o caminho corresponde ao padrão na política de autorização. O resultado é semelhante ao seguinte:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
Create a
DestinationRule. The DestinationRule
especifica que o gateway origina uma ligação TLS a example.com.cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: example-com-originate-tls namespace: istio-egress spec: host: example.com subsets: - name: example-com-originate-TLS trafficPolicy: portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
Atualize o serviço virtual para example.com de modo que os pedidos à porta 80 no gateway sejam
upgraded
para TLS na porta 443 quando forem enviados para o anfitrião de destino:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 EOF
Faça vários pedidos a example.com a partir da app de teste no espaço de nomes
team-x
for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com done
Tal como antes, os pedidos são bem-sucedidos com
200 OK
respostas.Verifique o registo do gateway de saída para confirmar se o gateway encaminhou os pedidos para o anfitrião de destino ao originar ligações TLS:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath=" {.items[0].metadata.name}") istio-proxy
O resultado é semelhante ao seguinte:
[2020-09-24T17:58:02.548Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 6 5 "10.1.1.15" "curl/7.67.0" "83a77acb-d994-424d-83da-dd8eac902dc8" "example.com" "93.184.216.34:443" outbound|443|example-com-originate-TLS|example.com 10.1.4.31:49866 10.1.4.31:8080 10.1.1.15:37334 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
O sidecar do proxy enviou o pedido para o gateway através da porta 80 e o TLS foi originado na porta 443 para enviar o pedido para o anfitrião de destino.
Modifique a configuração para que o gateway de saída use a passagem direta de TLS para ligações à porta 443:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL - port: number: 443 name: tls protocol: TLS hosts: - '*' tls: mode: PASSTHROUGH EOF
Atualize o
DestinationRule
que aponta para o gateway de saída para adicionar um segundo subconjunto para a porta 443 no gateway. Este novo subconjunto não usa TLS mútuo. O TLS mútuo do Istio não é suportado para a transferência de ligações TLS. As ligações na porta 80 continuam a usar mTLS:cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: portLevelSettings: - port: number: 80 tls: mode: ISTIO_MUTUAL - name: target-egress-gateway-TLS-passthrough EOF
Atualize o serviço virtual para example.com de modo que o tráfego TLS na porta 443 seja transmitido através do gateway:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - example.com route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - example.com route: - destination: host: example.com port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
Atualize o serviço virtual para httpbin.org de modo que o tráfego TLS na porta 443 seja transmitido através do gateway:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - httpbin.org route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - httpbin.org route: - destination: host: httpbin.org port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
Adicione uma política de autorização que aceite qualquer tipo de tráfego enviado para a porta 443 do serviço de gateway de saída. A porta
targetPort
correspondente nos pods do gateway é 8443.cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-all-443 namespace: istio-egress spec: action: ALLOW rules: - when: - key: destination.port values: ["8443"] EOF
Execute
istioctl analyze
para verificar se existem erros de configuração:${ISTIOCTL} analyze -n istio-egress --revision REVISION
Você vê:
✔ No validation issues found when analyzing namespace: istio-egress.
Faça um pedido HTTP simples a example.com a partir da aplicação de teste no
team-x
namespace:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
O pedido é bem-sucedido com uma resposta
200 OK
.Agora, faça vários pedidos TLS (HTTPS) a partir da aplicação de teste no espaço de nomes
team-x
:for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -o /dev/null \ -w "%{http_code}\n" \ https://example.com done
Vê 200 respostas.
Veja novamente o registo do gateway de saída:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
São apresentadas entradas do registo semelhantes às seguintes:
[2020-09-24T18:04:38.608Z] "- - -" 0 - "-" "-" 1363 5539 10 - "-" "-" "-" "-" "93.184.216.34:443" outbound|443||example.com 10.1.4.31:51098 10.1.4.31:8443 10.1.1.15:57030 example.com -
O pedido HTTPS foi tratado como tráfego TCP e transmitido através do gateway para o anfitrião de destino, pelo que não são incluídas informações HTTP no registo.
Permita que as cargas de trabalho e os proxies implementados no espaço de nomes
team-x
estabeleçam ligação aistiod
e à gateway de saída:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-control-plane namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-egress podSelector: matchLabels: istio: egressgateway EOF
Permita que as cargas de trabalho e os proxies consultem o DNS:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-dns namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": kube-system ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
Permita que as cargas de trabalho e os proxies se liguem aos IPs que fornecem APIs e serviços Google, incluindo a autoridade de certificação do Cloud Service Mesh:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-google-apis namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - ipBlock: cidr: 199.36.153.4/30 - ipBlock: cidr: 199.36.153.8/30 EOF
Permita que as cargas de trabalho e os proxies se liguem ao servidor de metadados do GKE:
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-metadata-server namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: # For GKE data plane v2 - ipBlock: cidr: 169.254.169.254/32 - to: # For GKE data plane v1 - ipBlock: cidr: 127.0.0.1/32 # Prior to 1.21.0-gke.1000 - ipBlock: cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later ports: - protocol: TCP port: 987 - protocol: TCP port: 988 EOF
Opcional: permita que as cargas de trabalho e os proxies no espaço de nomes
team-x
estabeleçam ligações entre si:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-same-namespace namespace: team-x spec: podSelector: {} ingress: - from: - podSelector: {} egress: - to: - podSelector: {} EOF
Opcional: permita que as cargas de trabalho e os proxies no espaço de nomes
team-x
estabeleçam ligações a cargas de trabalho implementadas por uma equipa diferente:cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-team-y namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": team-y EOF
As associações entre proxies sidecar persistem. As ligações existentes não são fechadas quando aplica uma nova política de rede. Reinicie as cargas de trabalho no espaço de nomes team-x para garantir que as ligações existentes são fechadas:
kubectl -n team-x rollout restart deployment
Verifique se ainda pode fazer um pedido HTTP para example.com a partir da aplicação de teste no espaço de nomes
team-x
:kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
O pedido é bem-sucedido com uma resposta
200 OK
.Crie uma conta de serviço Google para a sua aplicação usar:
gcloud iam service-accounts create sa-test-app-team-x
Permita que a conta de serviço do Kubernetes se faça passar pela conta de serviço da Google:
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[team-x/test]" \ sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
Anote a conta de serviço do Kubernetes para a app de teste no espaço de nomes
team-x
com o endereço de email da conta de serviço Google:cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: annotations: iam.gke.io/gcp-service-account: sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com name: test namespace: team-x EOF
O pod da aplicação de teste tem de conseguir aceder ao servidor de metadados da Google (executado como um DaemonSet) para obter credenciais temporárias para chamar as APIs Google. Crie uma entrada de serviço para o servidor de metadados do GKE:
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: metadata-google-internal namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: metadata.google.internal spec: hosts: - metadata.google.internal ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
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 agir como a conta de serviço Google:
kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- gcloud auth list
Vê a conta de serviço Google apresentada como a identidade ativa e única.
Crie um ficheiro de teste num contentor do Cloud Storage:
echo "Hello, World!" > /tmp/hello gcloud storage buckets create gs://${PROJECT_ID}-bucket gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
Conceda autorização à conta de serviço para listar e ver ficheiros no contentor:
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-bucket/ \ --member=serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com \ --role=roles/storage.objectViewer
Verifique se a aplicação de teste consegue aceder ao contentor de teste:
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gcloud storage cat gs://${PROJECT_ID}-bucket/hello
Você vê:
Hello, World!
- 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.
- Leia o guia de práticas recomendadas complementar.
- Consulte o guia de reforço de segurança do GKE.
- Saiba como automatizar a gestão de certificados TLS para o gateway de entrada do Cloud Service Mesh usando o serviço de AC.
- Saiba como gerir a configuração e as políticas em toda a sua infraestrutura com a gestão de configuração do GKE Enterprise.
- Para ver mais arquiteturas de referência, diagramas e práticas recomendadas, explore o Centro de arquitetura na nuvem.
Configurar a infraestrutura
Crie uma rede de VPC e uma sub-rede
Configure o Cloud NAT
O Cloud NAT permite que as cargas de trabalho sem endereços IP externos se liguem a destinos na Internet e recebam respostas de entrada desses destinos.
Crie contas de serviço para cada conjunto de nós do GKE
Crie duas contas de serviço para utilização pelos dois conjuntos de nós do GKE. É atribuída uma conta de serviço separada a cada conjunto de nós para que possa aplicar regras de firewall de VPC a nós específicos.
Conceda autorizações às contas de serviço
Adicione um conjunto mínimo de funções de IAM às contas de serviço da aplicação e da gateway. Estas funções são necessárias para o registo, a monitorização e a obtenção de imagens de contentores privados do Container Registry.
project_roles=(
roles/logging.logWriter
roles/monitoring.metricWriter
roles/monitoring.viewer
roles/storage.objectViewer
)
for role in "${project_roles[@]}"
do
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
done
Criar as regras de firewall
Nos passos seguintes, aplica uma regra de firewall à rede VPC para que, por predefinição, todo o tráfego de saída seja recusado. É necessária uma conetividade específica para o cluster funcionar e para os nós de gateway poderem alcançar destinos fora da VPC. Um conjunto mínimo de regras de firewall específicas substitui a regra de recusa de tudo predefinida para permitir a conetividade necessária.
Configurar o acesso privado às Google Cloud APIs
O acesso privado à Google permite que as VMs e os pods que só têm endereços IP internos acedam às APIs e aos serviços Google. Embora as APIs e os serviços Google sejam fornecidos a partir de IPs externos, o tráfego dos nós nunca sai da rede Google quando usa o acesso privado à Google.
Ative a API Cloud DNS:
gcloud services enable dns.googleapis.com
Crie uma zona de DNS privada e registos CNAME
e A
para que os nós e as cargas de trabalho possam ligar-se às APIs e aos serviços Google através do acesso privado à Google e do nome do anfitrião private.googleapis.com
:
gcloud dns managed-zones create private-google-apis \
--description "Private DNS zone for Google APIs" \
--dns-name googleapis.com \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-google-apis
gcloud dns record-sets transaction add private.googleapis.com. \
--name "*.googleapis.com" \
--ttl 300 \
--type CNAME \
--zone private-google-apis
gcloud dns record-sets transaction add "199.36.153.8" \
"199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name private.googleapis.com \
--ttl 300 \
--type A \
--zone private-google-apis
gcloud dns record-sets transaction execute --zone private-google-apis
Configurar o acesso privado ao Container Registry
Crie uma zona DNS privada, um registo CNAME
e um registo A
para que os nós possam estabelecer ligação ao Container Registry através do acesso privado da Google e do nome de anfitrião gcr.io
:
gcloud dns managed-zones create private-gcr-io \
--description "private zone for Container Registry" \
--dns-name gcr.io \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-gcr-io
gcloud dns record-sets transaction add gcr.io. \
--name "*.gcr.io" \
--ttl 300 \
--type CNAME \
--zone private-gcr-io
gcloud dns record-sets transaction add "199.36.153.8" "199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name gcr.io \
--ttl 300 \
--type A \
--zone private-gcr-io
gcloud dns record-sets transaction execute --zone private-gcr-io
Crie um cluster privado do GKE
Instalar e configurar o Cloud Service Mesh
Siga um dos guias de instalação do Cloud Service Mesh:
Depois de instalar o Cloud Service Mesh, pare e regresse a este tutorial sem instalar gateways de entrada ou saída.
Instale um gateway de saída
Ative o registo de acesso do Envoy
Os passos necessários para ativar os registos de acesso do Envoy dependem do tipo de Cloud Service Mesh, gerido ou no cluster:
Gerido
Siga as instruções para ativar os registos de acesso na malha de serviços na nuvem gerida.
No cluster
Siga as instruções para ativar os registos de acesso na Cloud Service Mesh no cluster.
Preparar a malha e uma aplicação de teste
Usar o recurso Sidecar para restringir o âmbito da configuração do proxy sidecar
Pode usar o
recurso Sidecar
para restringir o âmbito do ouvinte de saída configurado para proxies
sidecar. Para reduzir o inchaço da configuração e a utilização de memória, é uma boa prática aplicar um recurso Sidecar
predefinido para cada espaço de nomes.
O proxy que o Cloud Service Mesh executa no sidecar é o Envoy. Na terminologia do Envoy, um cluster
é um grupo logicamente semelhante de pontos finais a montante usado como destinos para o equilíbrio de carga.
Configurar o Cloud Service Mesh para encaminhar o tráfego através do gateway de saída
Configure um encaminhamento diferente para um segundo espaço de nomes
Configure o encaminhamento para um segundo anfitrião externo para saber como a conetividade externa diferente pode ser configurada para diferentes equipas.
Usar a política de autorização para fornecer controlo adicional sobre o tráfego
Neste tutorial, as políticas de autorização para o gateway de saída são criadas no espaço de nomes istio-egress
. Pode configurar o RBAC do Kubernetes para que apenas os administradores de rede possam aceder ao espaço de nomes istio-egress
.
Originação de TLS no gateway de saída
Pode configurar gateways de saída para upgrade
(originar) pedidos HTTP simples
para TLS ou TLS mútuo. Permitir que as aplicações façam pedidos HTTP simples tem várias vantagens quando usado com o TLS mútuo do Istio e a origem do TLS. Para
mais informações, consulte o guia de práticas recomendadas.
Encaminhamento de ligações HTTPS/TLS
As suas aplicações existentes podem já estar a usar ligações TLS quando comunicam com serviços externos. Pode configurar o gateway de saída para transmitir ligações TLS sem as desencriptar.
Usar a NetworkPolicy do Kubernetes como um controlo adicional
Existem muitos cenários em que uma aplicação pode ignorar um proxy sidecar.
Pode usar o Kubernetes NetworkPolicy
para especificar adicionalmente as ligações que as cargas de trabalho podem estabelecer. Depois de aplicar uma única política de rede, todas as ligações que não sejam especificamente permitidas são recusadas.
Este tutorial considera apenas ligações de saída e seletores de saída para políticas de rede. Se controlar a entrada com políticas de rede nos seus próprios clusters, tem de criar políticas de entrada que correspondam às suas políticas de saída. Por exemplo, se permitir a saída de cargas de trabalho do espaço de nomes team-x
para o espaço de nomes team-y
, também tem de permitir a entrada no espaço de nomes team-y
a partir do espaço de nomes team-x
.
Aceder diretamente às APIs Google através do acesso privado Google e das autorizações da IAM
As APIs e os serviços da Google são expostos através de endereços IP externos. Quando os pods com endereços IP de alias nativos da VPC estabelecem ligações às APIs Google através do acesso privado à Google, o tráfego nunca sai da rede da Google.
Quando configurou a infraestrutura para este tutorial, ativou o acesso privado Google para a sub-rede usada pelos pods do GKE. Para permitir o acesso aos endereços IP usados pelo acesso privado à Google, criou uma rota, uma regra de firewall da VPC e uma zona DNS privada. Esta configuração permite que os pods alcancem as APIs Google diretamente sem enviar tráfego através do gateway de saída. Pode controlar que APIs estão disponíveis para contas de serviço do Kubernetes específicas (e, por conseguinte, espaços de nomes) através da Workload Identity Federation para o GKE e do IAM. A autorização do Istio não tem efeito porque o gateway de saída não está a processar as ligações às APIs Google.
Antes de os pods poderem chamar as APIs Google, tem de usar o IAM para conceder autorizações. O cluster que está a usar para este tutorial está configurado para usar a Workload Identity Federation para o GKE, o que permite que uma conta de serviço do Kubernetes atue como uma conta de serviço Google.
Limpar
Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.
Para evitar incorrer em custos na sua Google Cloud conta pelos recursos usados neste tutorial, conclua os passos nas secções seguintes:
Elimine o projeto
A forma mais fácil de eliminar a faturação é eliminar o projeto que criou para o tutorial.