Questo tutorial mostra come utilizzare i gateway di uscita di Cloud Service Mesh e altri controlli Google Cloud per proteggere il traffico in uscita (di uscita) dai carichi di lavoro di cui è stato eseguito il deployment in un cluster Google Kubernetes Engine. Il tutorial è pensato come complemento delle best practice per l'utilizzo dei gateway in uscita di Cloud Service Mesh su cluster GKE.
Il pubblico di destinazione di questo tutorial include esperti di rete, della piattaforma e della sicurezza che amministrano i cluster Google Kubernetes Engine utilizzati da uno o più team di distribuzione del software. I controlli descritti qui sono particolarmente utili per le organizzazioni che devono dimostrare la conformità alle normative, ad esempio il GDPR e lo standard PCI.
Obiettivi
- Configura l'infrastruttura per l'esecuzione di Cloud Service Mesh:
- Rete VPC e subnet privata personalizzate
- Cloud NAT per l'accesso a internet
- Cluster GKE privato con un pool di nodi aggiuntivo per i pod di gateway in uscita
- Regole firewall VPC in uscita restrittive; solo i nodi gateway possono raggiungere gli host esterni
- Accesso privato Google per collegarti a Container Registry e alle API di Google
- Installa Cloud Service Mesh.
- Installa i proxy del gateway in uscita in esecuzione su un pool di nodi dedicato.
- Configura le regole di routing multi-tenant per il traffico esterno tramite il gateway in uscita:
- Le applicazioni nello spazio dei nomi
team-x
possono connettersi aexample.com
- Le applicazioni nello spazio dei nomi
team-y
possono connettersi ahttpbin.org
- Le applicazioni nello spazio dei nomi
- Utilizza la risorsa
Sidecar
per limitare l'ambito della configurazione di uscita del proxy sidecar per ogni spazio dei nomi. - Configura i criteri di autorizzazione per applicare le regole in uscita.
- Configura il gateway in uscita per eseguire l'upgrade delle richieste HTTP semplici a TLS (origine TLS).
- Configura il gateway in uscita in modo che trasmetta il traffico TLS.
- Configura i criteri di rete di Kubernetes come controllo in uscita aggiuntivo.
- Configura l'accesso diretto alle API di Google utilizzando le autorizzazioni accesso privato Google e Identity and Access Management (IAM).
Costi
In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
Per generare una stima dei costi in base all'utilizzo previsto,
utilizza il Calcolatore prezzi.
Al termine di questo tutorial, puoi evitare costi ricorrenti eliminando le risorse che hai creato. Per ulteriori informazioni, vedi Eseguire la pulizia.
Prima di iniziare
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
Crea una directory di lavoro da utilizzare durante il tutorial:
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
Crea uno script shell per inizializzare l'ambiente per il tutorial. Sostituisci e modifica le variabili in base al progetto e alle tue preferenze. Esegui questo script con il comando
source
per reinizializzare l'ambiente se la sessione della shell scade: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
Attiva
compute.googleapis.com
:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
Rendi eseguibile lo script ed eseguilo con il comando
source
per inizializzare l'ambiente. SelezionaY
se ti viene chiesto di attivarecompute.googleapis.com
:chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
Configurazione dell'infrastruttura
Crea una rete e una subnet VPC
Crea una nuova rete VPC:
gcloud compute networks create vpc-network \ --subnet-mode custom
Crea una subnet in cui eseguire il cluster con intervalli di indirizzi IP secondari preassegnati per pod e servizi. L'accesso privato Google è attivo in modo che le applicazioni con solo indirizzi IP interni possano raggiungere le API e i servizi 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
Configurazione di Cloud NAT
Cloud NAT consente ai workload senza indirizzi IP esterni di connettersi alle destinazioni su internet e di ricevere risposte in entrata da queste destinazioni.
Crea un router Cloud:
gcloud compute routers create nat-router \ --network vpc-network
Aggiungi una configurazione NAT al router:
gcloud compute routers nats create nat-config \ --router nat-router \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
Crea account di servizio per ogni pool di nodi GKE
Crea due account di servizio da utilizzare per i due pool di nodi GKE. A ogni pool di nodi viene assegnato un account di servizio separato per consentirti di applicare regole firewall VPC a nodi specifici.
Crea un account di servizio da utilizzare dai nodi nel pool di nodi predefinito:
gcloud iam service-accounts create sa-application-nodes \ --description="SA for application nodes" \ --display-name="sa-application-nodes"
Crea un account di servizio da utilizzare dai nodi nel pool di nodi del gateway:
gcloud iam service-accounts create sa-gateway-nodes \ --description="SA for gateway nodes" \ --display-name="sa-gateway-nodes"
Concedi le autorizzazioni agli account di servizio
Aggiungi un insieme minimo di ruoli IAM agli account di servizio dell'applicazione e del gateway. Questi ruoli sono necessari per il logging, il monitoraggio e il recupero di immagini container private da 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
Creazione delle regole firewall
Nei passaggi seguenti, applichi una regola firewall alla rete VPC in modo che, per impostazione predefinita, tutto il traffico in uscita venga negato. È necessaria una connettività specifica per il funzionamento del cluster e per consentire ai nodi gateway di raggiungere destinazioni al di fuori della VPC. Un insieme minimo di regole firewall specifiche sostituisce la regola predefinita di rifiuto di tutto per consentire la connettività necessaria.
Crea una regola firewall predefinita (a bassa priorità) per negare tutto il traffico in uscita dalla rete 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."
Crea una regola per consentire solo ai nodi con l'account di servizio del gateway di raggiungere 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"
Consenti ai nodi di raggiungere il piano di controllo 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."
(Facoltativo) Questa regola del firewall non è necessaria se utilizzi Cloud Service Mesh gestito.
Cloud Service Mesh utilizza i webhook quando inietta i proxy sidecar nei carichi di lavoro. Consenti al server API GKE di chiamare i webhook esposti dal piano di controllo di mesh di servizi in esecuzione sui nodi:
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"
Consenti la connettività in uscita tra i nodi e i pod in esecuzione sul cluster. GKE crea automaticamente una regola di ingresso corrispondente. Non è richiesta alcuna regola per la connettività del servizio perché la catena di routing iptables converte sempre gli indirizzi IP del servizio in indirizzi IP del 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"
Consenti l'accesso agli insiemi riservati di indirizzi IP utilizzati da Accesso privato Google per la pubblicazione di API Google, Container Registry e altri servizi:
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)"
Consenti al servizio di controllo dell'integrità di Google Cloud di accedere ai pod in esecuzione nel cluster. Per ulteriori informazioni, consulta i controlli di integrità.
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"
Configurazione dell'accesso privato alle API di Google Cloud
L'accesso privato Google consente alle VM e ai pod che hanno solo indirizzi IP interni di accedere alle API e ai servizi Google. Anche se le API e i servizi Google vengono pubblicati da indirizzi IP esterni, il traffico dai nodi non esce mai dalla rete di Google quando utilizzi l'accesso privato Google.
Abilita l'API Cloud DNS:
gcloud services enable dns.googleapis.com
Crea una zona DNS privata, un record CNAME
e un record A
in modo che i nodi e i carichi di lavoro possano connettersi alle API e ai servizi Google utilizzando l'accesso privato Google e l'hostname 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
Configurazione dell'accesso privato a Container Registry
Crea una zona DNS privata, un record CNAME
e un record A
in modo che i nodi possano collegarsi a Container Registry utilizzando l'accesso privato Google e il nome 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
Crea un cluster GKE privato
Trova l'indirizzo IP esterno di Cloud Shell in modo da poterlo aggiungere all'elenco delle reti autorizzate ad accedere al server API del tuo cluster:
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
Dopo un periodo di inattività, l'indirizzo IP esterno della VM Cloud Shell può cambiare. In questo caso, devi aggiornare l'elenco delle reti autorizzate del tuo cluster. Aggiungi il seguente comando allo script di inizializzazione:
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
Attiva l'API Google Kubernetes Engine:
gcloud services enable container.googleapis.com
Crea un cluster GKE privato:
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}
La creazione del cluster richiede alcuni minuti. Il cluster ha nodi privati con indirizzi IP interni. A pod e servizi vengono assegnati gli IP degli intervalli secondari denominati che hai definito durante la creazione della subnet VPC.
Cloud Service Mesh con un piano di controllo in-cluster richiede che i nodi del cluster utilizzino un tipo di macchina con almeno 4 vCPU.
Google consiglia di abbonare il cluster al canale di release "standard" per assicurarsi che i nodi eseguano una versione di Kubernetes supportata da Cloud Service Mesh.
Per ulteriori informazioni sui prerequisiti per l'esecuzione di Cloud Service Mesh con un control plane in-cluster, consulta i prerequisiti in-cluster.
Per ulteriori informazioni sui requisiti e sulle limitazioni per l'esecuzione di Cloud Service Mesh gestito, consulta le funzionalità supportate di Cloud Service Mesh gestito.
Workload Identity Federation for GKE è attivata sul cluster. Cloud Service Mesh richiede Workload Identity Federation for GKE ed è il metodo consigliato per accedere alle API di Google dai carichi di lavoro GKE.
Crea un pool di nodi denominato gateway. In questo pool di nodi viene eseguito il deployment del gateway di uscita. L'incompatibilità
dedicated=gateway:NoSchedule
viene aggiunta a ogni nodo nel pool di nodi del 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"
Le incompatibilità e le tolleranze di Kubernetes contribuiscono a garantire che solo i pod del gateway in uscita vengano eseguiti sui nodi del pool di nodi del gateway.
Scarica le credenziali per poterti connettere al cluster con kubectl:
gcloud container clusters get-credentials cluster1
Verifica che i nodi gateway abbiano l'alterazione corretta:
kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \ -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
L'output è simile al seguente:
name taints gke-cluster1-gateway-9d65b410-cffs map[effect:NoSchedule key:dedicated value:gateway]
Installazione e configurazione di Cloud Service Mesh
Segui una delle guide all'installazione di Cloud Service Mesh:
Dopo aver installato Cloud Service Mesh, interrompi e torna a questo tutorial senza installare gateway in entrata o in uscita.
Installare un gateway in uscita
Crea uno spazio dei nomi Kubernetes per il gateway in uscita:
kubectl create namespace istio-egress
Attiva lo spazio dei nomi per l'iniezione. I passaggi dipendono dall'implementazione del piano di controllo.
Gestito (TD)
Applica l'etichetta di inserimento predefinita allo spazio dei nomi:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Gestito (Istiod)
Consigliato:esegui il seguente comando per applicare l'etichetta di inserimento predefinita allo spazio dei nomi:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Se sei già un utente con il piano di controllo Istiod gestito: consigliamo di utilizzare l'iniezione predefinita, ma è supportata anche l'iniezione basata su revisione. Segui le istruzioni riportate di seguito:
Esegui il comando seguente per individuare i canali di rilascio disponibili:
kubectl -n istio-system get controlplanerevision
L'output è simile al seguente:
NAME AGE asm-managed-rapid 6d7h
Nell'output, il valore nella colonna
NAME
è l'etichetta di revisione corrispondente al canale di rilascio disponibile per la versione di Cloud Service Mesh.Applica l'etichetta di revisione allo spazio dei nomi:
kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
All'interno del cluster
Consigliato:esegui il seguente comando per applicare l'etichetta di inserimento predefinita allo spazio dei nomi:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Ti consigliamo di utilizzare l'inserimento predefinito, ma è supportato anche l'inserimento basato sulle revisioni: segui le istruzioni riportate di seguito:
Utilizza il seguente comando per individuare l'etichetta di revisione su
istiod
:kubectl get deploy -n istio-system -l app=istiod -o \ jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
Applica l'etichetta di revisione allo spazio dei nomi. Nel seguente comando,
REVISION_LABEL
è il valore dell'etichetta della revisioneistiod
che hai annotato nel passaggio precedente.kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
Crea un manifest dell'operatore per il gateway in uscita:
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
Scarica lo strumento
istioctl
. Devi utilizzare la versione 1.16.2-asm.2 o successiva anche se utilizzi Cloud Service Mesh 1.15 o versioni precedenti. Consulta Download della versione corretta di istioctl.Dopo aver estratto l'archivio scaricato, imposta una variabile di ambiente per memorizzare il percorso dello strumento
istioctl
e aggiungila allo script di inizializzazione:ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
Crea il manifest di installazione del gateway in uscita utilizzando il manifest dell'operatore e
istioctl
:${ISTIOCTL} manifest generate \ --filename egressgateway-operator.yaml \ --output egressgateway \ --cluster-specific
Installa il gateway in uscita:
kubectl apply --recursive --filename egressgateway/
Verifica che il gateway in uscita sia in esecuzione sui nodi del pool di nodi
gateway
:kubectl get pods -n istio-egress -o wide
I pod del gateway in uscita hanno
affinity
per i nodi del pool di nodigateway
e una tolleranza che consente loro di essere eseguiti sui nodi del gateway incompatibili. Esamina l'affinità dei nodi e le tolleranze per i pod del gateway in uscita: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")]'
L'output è simile al seguente:
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]
Attivare il logging degli accessi di Envoy
I passaggi necessari per abilitare i log di accesso di Envoy dipendono dal tipo di Cloud Service Mesh, gestito o in-cluster:
Gestito
Segui le istruzioni per abilitare i log di accesso in Cloud Service Mesh gestito.
All'interno del cluster
Segui le istruzioni per abilitare i log di accesso in Cloud Service Mesh nel cluster.
Preparazione della rete mesh e di un'applicazione di test
Assicurati che l'autenticazione TLS reciproca STRICT sia abilitata. Applica un criterio
PeerAuthentication
predefinito per il mesh nello spazio dei nomiistio-system
:cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOF
Puoi eseguire l'override di questa configurazione creando risorse
PeerAuthentication
in spazi dei nomi specifici.Crea gli spazi dei nomi da utilizzare per il deployment dei carichi di lavoro di test. I passaggi successivi di questo tutorial spiegano come configurare regole di routing in uscita diverse per ogni spazio dei nomi.
kubectl create namespace team-x kubectl create namespace team-y
Etichetta gli spazi dei nomi in modo che possano essere selezionati dalle norme di rete Kubernetes:
kubectl label namespace team-x team=x kubectl label namespace team-y team=y
Affinché Cloud Service Mesh inietti automaticamente i proxy sidecar, imposta l'etichetta di revisione del piano di controllo negli spazi dei nomi del carico di lavoro:
kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwrite
Crea un file YAML da utilizzare per eseguire i deployment di test:
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
Esegui il deployment dell'applicazione di test nello spazio dei nomi
team-x
:kubectl -n team-x create -f ./test.yaml
Verifica che l'applicazione di test sia dispiattata su un nodo nel pool predefinito e che sia stato inserito un contenitore sidecar proxy. Ripeti il seguente comando finché lo stato del pod non è
Running
:kubectl -n team-x get po -l app=test -o wide
L'output è simile al seguente:
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 contenitori su 2 sono
Running
. Un contenitore è l'applicazione di test e l'altro è il sidecar proxy.Il pod è in esecuzione su un nodo del pool di nodi predefinito.
Verifica che non sia possibile effettuare una richiesta HTTP dal contenitore di test a un sito esterno:
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
Viene generato un messaggio di errore dal proxy sidecar perché la regola del firewall
global-deny-egress-all
nega la connessione a monte.
Utilizzo della risorsa Sidecar per limitare l'ambito della configurazione del proxy sidecar
Puoi utilizzare la risorsa Sidecar per limitare l'ambito dell'ascoltatore in uscita configurato per i proxy sidecar. Per ridurre il bloat della configurazione e l'utilizzo della memoria, è buona norma applicare una risorsa Sidecar
predefinita per ogni spazio dei nomi.
Il proxy eseguito da Cloud Service Mesh nel sidecar è Envoy. Nella
terminologia di Envoy,
un cluster
è un gruppo di endpoint upstream logicamente simile utilizzato come
destinazioni per il bilanciamento del carico.
Controlla i cluster in uscita configurati nel proxy sidecar Envoy per il pod di test eseguendo il 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
Nell'elenco sono presenti circa 11 cluster Envoy, inclusi alcuni per il gateway di uscita.
Limita la configurazione del proxy ai route di uscita che sono stati definiti esplicitamente con voci di servizio nei namespace di uscita e
team-x
. Applica una risorsaSidecar
allo spazio dei nomiteam-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
L'impostazione della modalità del criterio di traffico in uscita su
REGISTRY_ONLY
limita la configurazione del proxy in modo da includere solo gli host esterni che sono stati aggiunti esplicitamente al registry dei servizi del mesh definendo le voci di servizio.L'impostazione
egress.hosts
specifica che il proxy sidecar seleziona solo i percorsi dello spazio dei nomi di uscita resi disponibili utilizzando l'attributoexportTo
. La parte "team-x/*
" include tutti i percorsi che sono stati configurati localmente nello spazio dei nomiteam-x
.Visualizza i cluster in uscita configurati nel proxy sidecar Envoy e confrontali con l'elenco dei cluster configurati prima di applicare la risorsa
Sidecar
:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
Vedrai i cluster per la porta di uscita e uno per il pod di test stesso.
Configurare Cloud Service Mesh per instradare il traffico tramite il gateway in uscita
Configura un
Gateway
per il traffico HTTP sulla porta 80.Gateway
seleziona il proxy del gateway di uscita di cui hai eseguito il deployment nello spazio dei nomi di uscita. La configurazioneGateway
viene applicata al nome di spazio in uscita e gestisce il traffico per qualsiasi 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
Crea un
DestinationRule
per il gateway di uscita con TLS reciproco per l'autenticazione e la crittografia. Utilizza una singola regola di destinazione condivisa per tutti gli host esterni.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
Crea un
ServiceEntry
nello spazio dei nomi di uscita per registrare esplicitamente example.com nel registry dei servizi del mesh per lo spazio dei nomiteam-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
Crea un
VirtualService
per instradare il traffico verso example.com tramite il gateway di uscita. Esistono due condizioni di corrispondenza: la prima indirizza il traffico al gateway di uscita e la seconda indirizza il traffico dal gateway di uscita all'host di destinazione. La proprietàexportTo
controlla quali spazi dei nomi possono utilizzare il servizio virtuale.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
Esegui
istioctl analyze
per verificare la presenza di errori di configurazione:${ISTIOCTL} analyze -n istio-egress --revision REVISION
L'output è simile al seguente:
✔ No validation issues found when analyzing namespace: istio-egress.
Invia diverse richieste tramite il gateway in uscita al sito esterno:
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
Visualizzi i codici di stato
200
per tutte e quattro le risposte.Verifica che le richieste siano state indirizzate tramite il gateway in uscita controllando i log di accesso del proxy. Innanzitutto, controlla il log di accesso del sidecar proxy di cui è stato eseguito il deployment con l'applicazione di test:
kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) istio-proxy
Per ogni richiesta inviata, viene visualizzata una voce di log simile alla seguente:
[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 - -
Controlla anche il log di accesso del gateway in uscita:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
Per ogni richiesta inviata, viene visualizzata una voce di log di accesso al gateway in uscita simile alla seguente:
[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 -
Configurare un routing diverso per un secondo spazio dei nomi
Configura il routing per un secondo host esterno per scoprire come è possibile configurare diverse connettività esterne per team diversi.
Crea una risorsa
Sidecar
per lo spazio dei nomiteam-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
Esegui il deployment dell'applicazione di test nello spazio dei nomi
team-y
:kubectl -n team-y create -f ./test.yaml
Registra un secondo host esterno ed esportalo nello spazio dei nomi
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
Crea un servizio virtuale per instradare il traffico verso httpbin.org tramite il gateway di uscita:
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
Esegui
istioctl analyze
per verificare la presenza di errori di configurazione:${ISTIOCTL} analyze -n istio-egress --revision REVISION
Le voci della tabella sono:
✔ No validation issues found when analyzing namespace: istio-egress.
Invia una richiesta a httpbin.org dall'app di test
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
Viene visualizzata una risposta
200 OK
.Effettua anche una richiesta ad httpbin.org dall'app di test
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
Viene visualizzata una risposta
200 OK
.Prova a effettuare una richiesta a example.com dallo spazio dei nomi
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
La richiesta non va a buon fine perché non è configurato alcun percorso in uscita per l'
example.com
host.
Utilizzo del criterio di autorizzazione per fornire un controllo aggiuntivo sul traffico
In questo tutorial, i criteri di autorizzazione per il gateway in uscita vengono creati nello
spazio dei nomi istio-egress
. Puoi configurare Kubernetes RBAC in modo che solo gli amministratori di rete possano accedere allo spazio dei nomi istio-egress
.
Crea un
AuthorizationPolicy
in modo che le applicazioni nello spazio dei nomiteam-x
possano connettersi a example.com, ma non ad altri host esterni quando inviano richieste utilizzando la porta 80. Il valoretargetPort
corrispondente sui pod del gateway di uscita è 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
Verifica di poter effettuare una richiesta a example.com dall'applicazione di test nello spazio dei nomi
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
Viene visualizzata una risposta
200 OK
.Prova a effettuare una richiesta a httpbin.org dall'applicazione di test nello spazio dei nomi
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
La richiesta non va a buon fine con un messaggio
RBAC: access denied
e un codice stato 403 Forbidden. Potresti dover attendere qualche secondo perché spesso si verifica un breve ritardo prima che il criterio di autorizzazione venga applicato.I criteri di autorizzazione forniscono un controllo avanzato sul traffico che viene autorizzato o negato. Applica il seguente criterio di autorizzazione per consentire all'app di test nello spazio dei nomi
team-y
di inviare richieste a httpbin.org utilizzando un determinato percorso dell'URL quando invia richieste utilizzando la porta 80.targetPort
corrispondente sui pod del gateway in uscita è 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
Prova a connetterti a httpbin.org dall'app di test nello spazio dei nomi
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
La richiesta non va a buon fine con un messaggio RBAC: accesso negato e un codice di stato 403 forbidden.
Ora invia una richiesta a httpbin.org/status/418 dalla stessa 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
La richiesta va a buon fine perché il percorso corrisponde al pattern nel precedente criterio di autorizzazione. L'output è simile al seguente:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
Originazione TLS al gateway in uscita
Puoi configurare i gateway in uscita in modo che upgrade
(originino) richieste HTTP non protette
a TLS o TLS reciproco. Consentire alle applicazioni di effettuare richieste HTTP semplici offre diversi vantaggi se utilizzato con TLS mutuale e l'originazione TLS di Istio. Per maggiori informazioni, consulta la guida alle best practice.
Crea un
DestinationRule. The DestinationRule
che specifica che il gateway deve avviare una connessione 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
Aggiorna il servizio virtuale per example.com in modo che le richieste alla porta 80 sul gateway siano
upgraded
a TLS sulla porta 443 quando vengono inviate all'host di destinazione: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
Effettua diverse richieste a example.com dall'app di test nello spazio dei nomi
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
Come prima, le richieste vanno a buon fine con risposte
200 OK
.Controlla il log del gateway in uscita per verificare che il gateway abbia inoltrato le richieste all'host di destinazione tramite le connessioni TLS di origine:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath=" {.items[0].metadata.name}") istio-proxy
L'output è simile al seguente:
[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 -
Il sidecar proxy ha inviato la richiesta al gateway utilizzando la porta 80 e TLS originata sulla porta 443 per inviare la richiesta all'host di destinazione.
Passaggio delle connessioni HTTPS/TLS
Le tue applicazioni esistenti potrebbero già utilizzare connessioni TLS quando si comunicano con servizi esterni. Puoi configurare il gateway in uscita in modo che trasmetta le connessioni TLS senza decriptarle.
Modifica la configurazione in modo che il gateway in uscita utilizzi il passthrough TLS per le connessioni alla 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
Aggiorna
DestinationRule
che rimanda al gateway in uscita per aggiungere un secondo sottoinsieme per la porta 443 sul gateway. Questo nuovo sottoinsieme non utilizza TLS mutuale. Il TLS mutuale di Istio non è supportato per il passthrough delle connessioni TLS. Le connessioni sulla porta 80 utilizzano ancora 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
Aggiorna il servizio virtuale per example.com in modo che il traffico TLS sulla porta 443 venga trasmesso tramite il 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
Aggiorna il servizio virtuale per httpbin.org in modo che il traffico TLS sulla porta 443 venga trasmesso tramite il 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
Aggiungi un criterio di autorizzazione che accetti qualsiasi tipo di traffico inviato alla porta 443 del servizio gateway in uscita. Il valore
targetPort
corrispondente sui pod 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
Esegui
istioctl analyze
per verificare la presenza di errori di configurazione:${ISTIOCTL} analyze -n istio-egress --revision REVISION
Le voci della tabella sono:
✔ No validation issues found when analyzing namespace: istio-egress.
Invia una richiesta HTTP normale a example.com dall'applicazione di test nell'
team-x
spazio dei nomi: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
La richiesta ha esito positivo con una risposta
200 OK
.Ora effettua diverse richieste TLS (HTTPS) dall'applicazione di test nello spazio dei nomi
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
Visualizzi 200 risposte.
Esamina di nuovo il log del gateway in uscita:
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
Visualizzi voci di log simili alle seguenti:
[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 -
La richiesta HTTPS è stata trattata come traffico TCP e trasmessa tramite il gateway all'host di destinazione, pertanto nel log non sono incluse informazioni HTTP.
Utilizzo di NetworkPolicy di Kubernetes come controllo aggiuntivo
Esistono molti scenari in cui un'applicazione può bypassare un proxy sidecar.
Puoi utilizzare Kubernetes NetworkPolicy
per specificare inoltre quali connessioni possono essere effettuate dai carichi di lavoro. Dopo l'applicazione di un singolo criterio di rete, tutte le connessioni non consentite specificamente vengono negate.
Questo tutorial prende in considerazione solo le connessioni in uscita e i selettori in uscita per i criteri di rete. Se controlli l'ingresso con i criteri di rete sui tuoi cluster, devi creare criteri di ingresso corrispondenti ai criteri di uscita. Ad esempio, se consenti l'uscita dai carichi di lavoro nello spazio dei nomi team-x
allo spazio dei nomi team-y
, devi consentire anche l'ingresso nello spazio dei nomi team-y
dallo spazio dei nomi team-x
.
Consenti ai carichi di lavoro e ai proxy di cui è stato eseguito il deployment nello spazio dei nomi
team-x
di collegarsi aistiod
e al gateway di uscita: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
Consenti ai carichi di lavoro e ai proxy di eseguire query sul 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
Consenti ai workload e ai proxy di connettersi agli IP che pubblicano API e servizi Google, inclusa l'autorità di certificazione 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
Consenti ai carichi di lavoro e ai proxy di connettersi al server di metadati 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
(Facoltativo) Consenti ai carichi di lavoro e ai proxy nello spazio dei nomi
team-x
di effettuare tra loro connessioni: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
(Facoltativo) Consenti ai carichi di lavoro e ai proxy nello spazio dei nomi
team-x
di effettuare connessioni ai carichi di lavoro di un altro team: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
Le connessioni tra i proxy sidecar vengono conservate. Le connessioni esistenti non vengono chiuse quando applichi una nuova norma di rete. Riavvia i carichi di lavoro nello spazio dei nomi team-x per assicurarti che le connessioni esistenti siano chiuse:
kubectl -n team-x rollout restart deployment
Verifica di poter comunque effettuare una richiesta HTTP a example.com dall'applicazione di test nello spazio dei nomi
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
La richiesta ha esito positivo con una risposta
200 OK
.
Accedere direttamente alle API Google utilizzando le autorizzazioni di accesso privato Google e IAM
Le API e i servizi Google sono esposti utilizzando indirizzi IP esterni. Quando i pod con indirizzi IP di alias VPC nativi effettuano connessioni alle API di Google utilizzando Accesso privato Google, il traffico non esce mai dalla rete di Google.
Quando hai configurato l'infrastruttura per questo tutorial, hai abilitato l'accesso privato Google per la subnet utilizzata dai pod GKE. Per consentire l'accesso agli indirizzi IP utilizzati da accesso privato Google, hai creato una route, una regola firewall VPC e una zona DNS privata. Questa configurazione consente ai pod di raggiungere direttamente le API di Google senza inviare traffico tramite il gateway di uscita. Puoi controllare quali API sono disponibili per account di servizio Kubernetes specifici (e quindi per i relativi spazi dei nomi) utilizzando la federazione delle identità per i carichi di lavoro per GKE e IAM. L'autorizzazione Istio non viene applicata perché il gateway di uscita non gestisce le connessioni alle API di Google.
Prima che i pod possano chiamare le API Google, devi utilizzare IAM per concedere le autorizzazioni. Il cluster che utilizzi per questo tutorial è configurato per utilizzare la federazione delle identità per i carichi di lavoro per GKE, che consente a un account di servizio Kubernetes di agire come account di servizio Google.
Crea un account di servizio Google da utilizzare per la tua applicazione:
gcloud iam service-accounts create sa-test-app-team-x
Consenti all'account di servizio Kubernetes di rubare l'identità dell'account di servizio 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
Annota l'account di servizio Kubernetes per l'app di test nello spazio dei nomi
team-x
con l'indirizzo email dell'account di servizio 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
Il pod dell'applicazione di test deve essere in grado di accedere al server di metadati di Google (in esecuzione come DaemonSet) per ottenere credenziali temporanee per chiamare le API di Google. Crea una voce di servizio per il server di metadati 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
Crea anche una voce di servizio per 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
Verifica che l'account di servizio Kubernetes sia configurato correttamente per fungere da account di servizio 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
Vedrai il account di servizio Google elencato come unica identità attiva.
Crea un file di test in un bucket Cloud Storage:
echo "Hello, World!" > /tmp/hello gcloud storage buckets create gs://${PROJECT_ID}-bucket gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
Concedi all'account di servizio l'autorizzazione per elencare e visualizzare i file nel 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
Verifica che l'applicazione di test possa accedere al bucket di test:
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
Le voci della tabella sono:
Hello, World!
Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, completa i passaggi descritti nelle sezioni seguenti:
Elimina il progetto
Il modo più semplice per eliminare la fatturazione è quello di eliminare il progetto che hai creato per il 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.
Passaggi successivi
- Leggi la guida alle best practice complementari.
- Consulta la guida alla protezione di GKE.
- Scopri come automatizzare la gestione dei certificati TLS per il gateway di ingresso Cloud Service Mesh utilizzando CA Service.
- Scopri come gestire la configurazione e le norme in tutta l'infrastruttura con GKE Enterprise Configuration Management.
- Per altre architetture di riferimento, diagrammi e best practice, visita il Centro architetture di Google Cloud.