Ce tutoriel explique comment utiliser les passerelles de sortie Cloud Service Mesh et d'autres contrôles Google Cloud pour sécuriser le trafic sortant (sortie) à partir de charges de travail déployées sur un cluster Google Kubernetes Engine. Ce tutoriel est destiné à accompagner les bonnes pratiques d'utilisation des passerelles de sortie de Cloud Service Mesh sur les clusters GKE.
L'audience visée pour ce tutoriel comprend les ingénieurs réseau, de plate-forme et de sécurité qui gèrent les clusters Google Kubernetes Engine utilisés par une ou plusieurs équipes de livraison de logiciels. Les contrôles décrits ici peuvent être particulièrement utiles pour les organisations qui doivent démontrer leur conformité avec les réglementations en vigueur (par exemple, le RGPD et le PCI).
Objectifs
- Configurez l'infrastructure pour exécuter Cloud Service Mesh :
- Réseau VPC personnalisé et sous-réseau privé
- Cloud NAT pour l'accès à Internet
- Cluster GKE privé avec un pool de nœuds supplémentaire pour les pods de passerelle de sortie
- Règles de pare-feu VPC de sortie restrictives : seuls les nœuds de passerelle peuvent atteindre des hôtes externes
- Reportez-vous à la page Accès privé à Google pour vous connecter à Container Registry et aux API Google.
- Installer Cloud Service Mesh.
- Installez des proxys de passerelle de sortie s'exécutant sur un pool de nœuds dédié.
- Configurez des règles de routage mutualisées pour le trafic externe via la passerelle de sortie :
- Les applications dans l'espace de noms
team-x
peuvent se connecter àexample.com
- Les applications dans l'espace de noms
team-y
peuvent se connecter àhttpbin.org
- Les applications dans l'espace de noms
- Utilisez la ressource
Sidecar
pour limiter le champ d'application de la configuration de sortie du proxy sidecar pour chaque espace de noms. - Configurez des règles d'autorisation pour appliquer les règles de sortie.
- Configurez la passerelle de sortie pour mettre à niveau les requêtes HTTP simples vers TLS (initiation TLS).
- Configurez la passerelle de sortie pour qu'elle transfère le trafic TLS.
- Définissez des règles de réseau Kubernetes comme contrôle supplémentaire de sortie.
- Configurez l'accès direct aux API Google à l'aide de l'accès privé à Google et des autorisations IAM (Identity and Access Management).
Coûts
Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.
Une fois que vous aurez terminé ce tutoriel, évitez de payer des frais en supprimant les ressources que vous avez créées. Consultez la section Effectuer un nettoyage pour en savoir plus.
Avant de commencer
-
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.
Créez un répertoire de travail à utiliser pour suivre le tutoriel :
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
Créez un script d'interface système pour initialiser votre environnement pour ce tutoriel. Remplacez et modifiez les variables en fonction de votre projet et de vos préférences. Exécutez ce script avec la commande
source
pour réinitialiser votre environnement si votre session d'interface système expire :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
Activer
compute.googleapis.com
:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
Rendez le script exécutable et exécutez-le à l'aide de la commande
source
pour initialiser votre environnement. SélectionnezY
si vous êtes invité à activercompute.googleapis.com
:chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
Configurer l'infrastructure
Créer un réseau et un sous-réseau VPC
Créez un nouveau réseau VPC :
gcloud compute networks create vpc-network \ --subnet-mode custom
Créez un sous-réseau dans lequel le cluster s'exécutera avec des plages d'adresses IP secondaires pré-attribuées pour les pods et les services. L'accès privé à Google est activé, ce qui permet aux applications qui n'ont que des adresses IP internes d'accéder aux API et services 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
Configurer Cloud NAT
Cloud NAT permet aux charges de travail sans adresse IP externe de se connecter à des destinations sur Internet et de recevoir des réponses entrantes de ces destinations.
Créez un routeur Cloud Router :
gcloud compute routers create nat-router \ --network vpc-network
Ajoutez une configuration NAT au routeur :
gcloud compute routers nats create nat-config \ --router nat-router \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
Créer des comptes de service pour chaque pool de nœuds GKE
Créez deux comptes de service à utiliser avec les deux pools de nœuds GKE. Un compte de service distinct est attribué à chaque pool de nœuds afin de pouvoir appliquer des règles de pare-feu VPC à des nœuds spécifiques.
Créez un compte de service à utiliser par les nœuds du pool de nœuds par défaut :
gcloud iam service-accounts create sa-application-nodes \ --description="SA for application nodes" \ --display-name="sa-application-nodes"
Créez un compte de service à utiliser par les nœuds du pool de nœuds de passerelle :
gcloud iam service-accounts create sa-gateway-nodes \ --description="SA for gateway nodes" \ --display-name="sa-gateway-nodes"
Accorder des autorisations aux comptes de service
Ajoutez un ensemble minimal de rôles IAM aux comptes de service de l'application et de la passerelle. Ces rôles sont requis pour la journalisation, la surveillance et l'extraction d'images de conteneurs privées à partir de 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
Créer les règles de pare-feu
Dans les étapes suivantes, vous allez appliquer une règle de pare-feu au réseau VPC afin que, par défaut, tout le trafic sortant soit refusé. Une connectivité spécifique est requise pour que le cluster fonctionne et que les nœuds de passerelle puissent atteindre des destinations en dehors du VPC. Un ensemble minimal de règles de pare-feu spécifiques remplace la règle de refus par défaut afin d'autoriser la connectivité nécessaire.
Créez une règle de pare-feu par défaut (faible priorité) afin de refuser toutes les sorties du réseau 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."
Créez une règle pour n'autoriser l'accès à Internet que pour les nœuds associés au compte de service de passerelle :
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"
Autorisez les nœuds à accéder au plan de contrôle de 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."
Facultatif: Cette règle de pare-feu n'est pas nécessaire si vous utilisez Cloud Service Mesh géré.
Cloud Service Mesh utilise des webhooks lors de l'injection de proxys sidecar dans les charges de travail. Autorisez le serveur d'API GKE à appeler les webhooks exposés par le plan de contrôle du maillage de services s'exécutant sur les nœuds :
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"
Autorisez la connectivité de sortie entre les nœuds et les pods exécutés sur le cluster. GKE crée automatiquement une règle d'entrée correspondante. Aucune règle n'est requise pour la connectivité du service, car la chaîne de routage iptables convertit toujours les adresses IP de service en adresses IP de pod.
gcloud compute firewall-rules create allow-egress-nodes-and-pods \ --action ALLOW \ --direction EGRESS \ --rules all \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.0.0.0/24,10.1.0.0/16 \ --network vpc-network \ --priority 1000 \ --description "Allow egress to other Nodes and Pods"
Autorisez l'accès aux ensembles réservés d'adresses IP utilisés par l'accès privé à Google pour diffuser les API Google, Container Registry et d'autres services :
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)"
Autorisez le service du vérificateur d'état Google Cloud à accéder aux pods qui s'exécutent dans le cluster. Pour en savoir plus, consultez la section Vérifications d'état.
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"
Configurer un accès privé aux API Google Cloud
L'accès privé à Google permet aux VM et aux pods qui n'ont que des adresses IP internes d'accéder aux API et aux services de Google. Bien que les API et services Google soient diffusés à partir d'adresses IP externes, le trafic en provenance des nœuds ne quitte jamais le réseau Google lorsque vous utilisez l'accès privé à Google.
Activez l'API Cloud DNS :
gcloud services enable dns.googleapis.com
Créez une zone DNS privée, des enregistrements CNAME
et A
afin que les nœuds et les charges de travail puissent se connecter aux API et services Google à l'aide de l'accès privé à Google et du nom d'hôte 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
Configurer un accès privé à Container Registry
Créez une zone DNS privée, un enregistrement CNAME
et un enregistrement A
afin que les nœuds puissent se connecter à Container Registry à l'aide de l'accès privé à Google et du nom d'hôte 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
Créer un cluster GKE privé
Recherchez l'adresse IP externe de Cloud Shell afin de pouvoir l'ajouter à la liste des réseaux autorisés à accéder au serveur d'API de votre cluster :
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
Après une période d'inactivité, l'adresse IP externe de votre VM Cloud Shell peut changer. Dans ce cas, vous devez mettre à jour la liste des réseaux autorisés de votre cluster. Ajoutez la commande suivante à votre script d'initialisation :
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
Activez l'API Google Kubernetes Engine :
gcloud services enable container.googleapis.com
Créez un cluster GKE privé :
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 création du cluster prend quelques minutes. Le cluster inclut des nœuds privés avec des adresses IP internes. Les pods et les services se voient attribuer des adresses IP des plages secondaires nommées que vous avez définies lors de la création du sous-réseau VPC.
Cloud Service Mesh avec un plan de contrôle dans le cluster nécessite que les nœuds du cluster utilisent un type de machine comportant au moins quatre processeurs virtuels.
Google recommande que le cluster soit abonné à la version disponible "standard" pour garantir que les nœuds exécutent une version de Kubernetes compatible avec Cloud Service Mesh.
Pour en savoir plus sur les prérequis pour exécuter Cloud Service Mesh avec un plan de contrôle au sein du cluster, consultez les prérequis au sein du cluster.
Pour en savoir plus sur les exigences et les limites d'exécution de Cloud Service Mesh géré, consultez les fonctionnalités compatibles avec Cloud Service Mesh géré.
La fédération d'identité de charge de travail pour GKE est activée sur le cluster. Cloud Service Mesh nécessite la fédération d'identité de charge de travail pour GKE. Il s'agit de la méthode recommandée pour accéder aux API Google à partir des charges de travail GKE.
Créez un pool de nœuds appelé passerelle. C'est dans ce pool de nœuds que sera déployé la passerelle de sortie. Le rejet
dedicated=gateway:NoSchedule
est ajouté à chaque nœud du pool de nœuds de passerelle.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"
Les rejets et tolérances Kubernetes vous permettent de vous assurer que seuls les pods de passerelle de sortie s'exécutent sur des nœuds du pool de nœuds de passerelle.
Téléchargez les identifiants afin de pouvoir vous connecter au cluster avec kubectl :
gcloud container clusters get-credentials cluster1
Vérifiez que les nœuds de la passerelle disposent du rejet approprié :
kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \ -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
Le résultat ressemble à ce qui suit :
name taints gke-cluster1-gateway-9d65b410-cffs map[effect:NoSchedule key:dedicated value:gateway]
Installer et configurer Cloud Service Mesh
Suivez l'un des guides d'installation de Cloud Service Mesh:
Une fois Cloud Service Mesh installé, arrêtez-vous et revenez à ce tutoriel sans installer de passerelles d'entrée ou de sortie.
Installer une passerelle de sortie
Créez un espace de noms Kubernetes pour la passerelle de sortie:
kubectl create namespace istio-egress
Activez l'espace de noms pour l'injection : La procédure dépend de votre implémentation du plan de contrôle.
Géré (TD)
Appliquez le libellé d'injection par défaut à l'espace de noms:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Géré (Istiod)
Recommandation:Exécutez la commande suivante pour appliquer le libellé d'injection par défaut à l'espace de noms:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Si vous êtes déjà un utilisateur du plan de contrôle Istio géré:nous vous recommandons d'utiliser l'injection par défaut, mais l'injection basée sur les révisions est prise en charge. Suivez les instructions suivantes:
Exécutez la commande suivante pour localiser les versions disponibles:
kubectl -n istio-system get controlplanerevision
Le résultat ressemble à ce qui suit :
NAME AGE asm-managed-rapid 6d7h
Dans le résultat, la valeur de la colonne
NAME
est le libellé de révision qui correspond à la version disponible pour la version de Cloud Service Mesh.Appliquez le libellé de révision à l'espace de noms.
kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
Dans le cluster
Recommandation:Exécutez la commande suivante pour appliquer le libellé d'injection par défaut à l'espace de noms:
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
Nous vous recommandons d'utiliser l'injection par défaut, mais l'injection basée sur les révisions est prise en charge: Suivez les instructions suivantes:
Exécutez la commande suivante pour localiser le libellé de révision sur
istiod
:kubectl get deploy -n istio-system -l app=istiod -o \ jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
Appliquez le libellé de révision à l'espace de noms. Dans la commande suivante,
REVISION_LABEL
correspond à la valeur du libellé de révisionistiod
que vous avez notée à l'étape précédente.kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
Créez un fichier manifeste d'opérateur pour la passerelle de sortie:
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
Téléchargez l'outil
istioctl
. Vous devez utiliser la version 1.16.2-asm.2 ou ultérieure, même si vous utilisez la version 1.15 ou antérieure de Cloud Service Mesh. Consultez la section Télécharger la bonne version d'istioctl.Après avoir extrait l'archive téléchargée, définissez une variable d'environnement destinée à contenir le chemin d'accès à l'outil
istioctl
et ajoutez-la à votre script d'initialisation:ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
Créez le fichier manifeste d'installation de la passerelle de sortie à l'aide du fichier manifeste de l'opérateur et de
istioctl
:${ISTIOCTL} manifest generate \ --filename egressgateway-operator.yaml \ --output egressgateway \ --cluster-specific
Installez la passerelle de sortie:
kubectl apply --recursive --filename egressgateway/
Vérifiez que la passerelle de sortie s'exécute sur les nœuds du pool de nœuds
gateway
:kubectl get pods -n istio-egress -o wide
Les pods de passerelle de sortie ont
affinity
pour les nœuds du pool de nœudsgateway
et une tolérance qui leur permet de s'exécuter sur les nœuds de passerelle rejetés. Examinez l'affinité et les tolérances de nœud pour les pods de passerelle de sortie: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")]'
Le résultat ressemble à ce qui suit :
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]
Activer la journalisation des accès Envoy
La procédure à suivre pour activer les journaux d'accès Envoy dépend de votre type de Cloud Service Mesh, géré ou intégré au cluster:
Géré
Suivez les instructions pour activer les journaux d'accès dans Cloud Service Mesh géré.
Dans le cluster
Suivez les instructions pour activer les journaux d'accès dans Cloud Service Mesh au sein du cluster.
Préparer le maillage et une application de test
Assurez-vous que le protocole TLS mutuel STRICT est activé. Appliquez une règle
PeerAuthentication
par défaut pour le maillage dans l'espace de nomsistio-system
:cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOF
Vous pouvez remplacer cette configuration en créant des ressources
PeerAuthentication
dans des espaces de noms spécifiques.Créez des espaces de noms à utiliser pour déployer les charges de travail de test. Les étapes suivantes de ce tutoriel expliquent comment configurer différentes règles de routage de sortie pour chaque espace de noms.
kubectl create namespace team-x kubectl create namespace team-y
Attribuez un libellé aux espaces de noms afin de pouvoir les sélectionner en utilisant les règles de réseau Kubernetes :
kubectl label namespace team-x team=x kubectl label namespace team-y team=y
Pour que Cloud Service Mesh puisse injecter automatiquement les sidecars de proxy, vous devez définir le libellé de révision du plan de contrôle sur les espaces de noms de la charge de travail:
kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwrite
Créez un fichier YAML à utiliser pour effectuer des déploiements de 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
Déployez l'application de test dans l'espace de noms
team-x
:kubectl -n team-x create -f ./test.yaml
Vérifiez que l'application de test est déployée sur un nœud du pool par défaut et qu'un conteneur sidecar proxy est injecté. Répétez la commande suivante jusqu'à ce que l'état du pod indique
Running
:kubectl -n team-x get po -l app=test -o wide
Le résultat ressemble à ce qui suit :
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
Deux conteneurs sur deux sont
Running
. L'un est l'application de test, tandis que l'autre est le sidecar de proxy.Le pod s'exécute sur un nœud du pool de nœuds par défaut.
Vérifiez qu'il n'est pas possible d'effectuer une requête HTTP à partir du conteneur de test vers un site externe :
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
Un message d'erreur de proxy side-car est généré car la règle de pare-feu
global-deny-egress-all
refuse la connexion en amont.
Utiliser la ressource sidecar pour limiter la portée de la configuration du proxy side-car
Vous pouvez utiliser la ressource sidecar pour limiter le champ d'application de l'écouteur de sortie configuré pour les proxys sidecar. Pour réduire le volume de la configuration et l'utilisation de mémoire, il est recommandé d'appliquer une ressource Sidecar
par défaut à chaque espace de noms.
Le proxy exécuté par Cloud Service Mesh dans le side-car est Envoy. Dans la terminologie Envoy, un cluster
est un groupe similaire de points de terminaison en amont utilisés comme destinations pour l'équilibrage de charge.
Inspectez les clusters sortants configurés dans le proxy sidecar Envoy pour le pod de test en exécutant la commande
istioctl proxy-config
:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
La liste contient environ 11 clusters Envoy, dont certains pour la passerelle de sortie.
Limitez la configuration du proxy aux routes de sortie définies explicitement avec des entrées de service dans les espaces de noms "egress" et "
team-x
". Appliquez une ressourceSidecar
à l'espace de nomsteam-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
Définir le mode de règle de trafic sortant sur
REGISTRY_ONLY
limite la configuration du proxy pour n'inclure que les hôtes externes qui ont été explicitement ajoutés au registre de services du maillage en définissant des entrées de service.Le paramètre
egress.hosts
indique que le proxy side-car ne sélectionne que les routes de l'espace de noms de sortie qui sont mises à disposition à l'aide de l'attributexportTo
. La partie "team-x/*
" inclut toutes les routes qui ont été configurées localement dans l'espace de nomsteam-x
.Affichez les clusters sortants configurés dans le proxy sidecar Envoy et comparez-les à la liste des clusters configurés avant l'application de la ressource
Sidecar
:${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
Vous voyez des clusters pour la passerelle de sortie et un cluster pour le pod de test.
Configurer Cloud Service Mesh pour acheminer le trafic via la passerelle de sortie
Configurez une ressource
Gateway
pour le trafic HTTP sur le port 80.Gateway
sélectionne le proxy de la passerelle de sortie que vous avez déployé dans l'espace de noms de sortie. La configurationGateway
est appliquée à l'espace de noms de sortie et gère le trafic pour tous les hôtes.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
Créez un cluster
DestinationRule
pour la passerelle de sortie avec TLS mutuel pour l'authentification et le chiffrement. Utilisez une seule règle de destination partagée pour tous les hôtes externes.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
Créez un
ServiceEntry
dans l'espace de noms de sortie pour enregistrer explicitement example.com dans le registre de services du maillage pour l'espace de nomsteam-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
Créez une ressource
VirtualService
pour acheminer le trafic vers example.com via la passerelle de sortie. Il y a deux conditions de correspondance : la première condition dirige le trafic vers la passerelle de sortie et la seconde dirige le trafic de la passerelle de sortie vers l'hôte de destination. La propriétéexportTo
contrôle les espaces de noms qui peuvent utiliser le service virtuel.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
Exécutez
istioctl analyze
pour rechercher les erreurs de configuration :${ISTIOCTL} analyze -n istio-egress --revision REVISION
Le résultat ressemble à ce qui suit :
✔ No validation issues found when analyzing namespace: istio-egress.
Envoyez plusieurs requêtes via la passerelle de sortie vers le site externe :
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
Des codes d'état
200
s'affichent pour les quatre réponses.Vérifiez que les requêtes ont été dirigées vers la passerelle de sortie en consultant les journaux d'accès proxy. Commencez par vérifier le journal d'accès du proxy sidecar déployé avec l'application de test :
kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) istio-proxy
Pour chaque requête envoyée, une entrée de journal semblable à la suivante s'affiche :
[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 - -
Consultez également le journal d'accès de la passerelle de sortie :
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
Pour chaque requête envoyée, une entrée de journal d'accès de passerelle de sortie semblable à celle-ci s'affiche :
[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 -
Configurer un routage différent pour un second espace de noms
Configurez le routage pour un deuxième hôte externe afin de découvrir comment configurer différentes connexions externes pour différentes équipes.
Créez une ressource
Sidecar
pour l'espace de nomsteam-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
Déployez l'application de test dans l'espace de noms
team-y
:kubectl -n team-y create -f ./test.yaml
Enregistrez un deuxième hôte externe et exportez-le vers les espaces de noms
team-x
etteam-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
Créez un service virtuel pour acheminer le trafic vers httpbin.org via la passerelle de sortie :
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
Exécutez
istioctl analyze
pour rechercher les erreurs de configuration :${ISTIOCTL} analyze -n istio-egress --revision REVISION
Voici les informations disponibles :
✔ No validation issues found when analyzing namespace: istio-egress.
Envoyez une requête à httpbin.org à partir de l'application de 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
Une réponse
200 OK
s'affiche.Envoyez également une requête à httpbin.org à partir de l'application de 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
Une réponse
200 OK
s'affiche.Essayez d'envoyer une requête à example.com à partir de l'espace de noms
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 requête échoue, car aucune route sortante n'est configurée pour l'hôte
example.com
.
Utiliser la règle d'autorisation pour mieux contrôler le trafic
Dans ce tutoriel, les règles d'autorisation pour la passerelle de sortie sont créées dans l'espace de noms istio-egress
. Vous pouvez configurer Kubernetes RBAC pour que seuls les administrateurs réseau puissent accéder à l'espace de noms istio-egress
.
Créez une
AuthorizationPolicy
pour que les applications de l'espace de nomsteam-x
puissent se connecter à example.com mais pas à d'autres hôtes externes lors de l'envoi de requêtes à l'aide du port 80. La valeurtargetPort
correspondante sur les pods de la passerelle de sortie est 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
Vérifiez que vous pouvez envoyer une requête à example.com à partir de l'application de test dans l'espace de noms
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
Une réponse
200 OK
s'affiche.Essayez d'envoyer une requête à httpbin.org à partir de l'application de test dans l'espace de noms
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 requête échoue avec le message
RBAC: access denied
et le code d'état 403 Forbidden. Vous devrez peut-être attendre quelques secondes car on observe souvent un délai avant que la règle d'autorisation n'entre en vigueur.Les stratégies d'autorisation permettent de contrôler efficacement le trafic autorisé ou refusé. Appliquez la règle d'autorisation suivante pour permettre à l'application de test de l'espace de noms
team-y
d'envoyer des requêtes à httpbin.org en utilisant un chemin d'URL particulier lors de l'envoi de requêtes à l'aide du port 80. La valeurtargetPort
correspondante sur les pods de la passerelle de sortie est 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
Essayez de vous connecter à httpbin.org à partir de l'application de test dans l'espace de noms
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 requête échoue avec le RBAC : accès refusé et message d'état 403 Forbidden.
Envoyez une requête à httpbin.org/status/418 à partir de la même application :
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 requête aboutit, car le chemin correspond à celui qui figure dans la règle d'autorisation. Le résultat ressemble à ce qui suit :
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
Initiation TLS au niveau de la passerelle de sortie
Vous pouvez configurer les passerelles de sortie pour upgrade
(initier) les requêtes HTTP vers le protocole TLS ou TLS mutuel. Autoriser les applications à effectuer des requêtes HTTP simples présente plusieurs avantages lorsque ces requêtes sont utilisées avec le TLS mutuel et l'initiation TLS d'Istio. Pour en savoir plus, consultez le guide des bonnes pratiques.
Créez un fichier
DestinationRule. The DestinationRule
qui indique que la passerelle crée une connexion TLS à 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
Mettez à jour le service virtuel pour example.com afin que les requêtes envoyées au port 80 de la passerelle soient
upgraded
vers TLS sur le port 443 lorsqu'elles sont envoyées à l'hôte de destination: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
Envoyez plusieurs requêtes à example.com à partir de l'application de test dans l'espace de noms
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
Comme auparavant, les requêtes aboutissent avec les réponses
200 OK
.Consultez le journal de passerelle de sortie pour vérifier que la passerelle a acheminé les requêtes vers l'hôte de destination en initiant des connexions TLS :
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath=" {.items[0].metadata.name}") istio-proxy
Le résultat ressemble à ce qui suit :
[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 -
Le sidecar de proxy a envoyé la requête à la passerelle via le port 80 et initié une connexion TLS sur le port 443 pour envoyer la requête vers l'hôte de destination.
Transmission des connexions HTTPS/TLS
Il se peut que vos applications existantes utilisent déjà des connexions TLS lors de la communication avec des services externes. Vous pouvez configurer la passerelle de sortie pour qu'elle transmette les connexions TLS sans les déchiffrer.
Modifiez votre configuration de sorte à ce que la passerelle de sortie utilise une stratégie TLS pour les connexions au port 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
Mettez à jour le port
DestinationRule
pointant vers la passerelle de sortie afin d'ajouter un second sous-ensemble pour le port 443 sur la passerelle. Ce nouveau sous-ensemble n'utilise pas le protocole TLS mutuel. Le protocole TLS mutuel d'Istio n'est pas compatible avec la transmission des connexions TLS. Les connexions sur le port 80 utilisent toujours 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
Mettez à jour le service virtuel pour example.com afin que le trafic TLS sur le port 443 soit transmis via la passerelle :
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
Mettez à jour le service virtuel pour httpbin.org de manière à ce que le trafic TLS sur le port 443 soit transmis via la passerelle :
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
Ajoutez une règle d'autorisation qui accepte tous les types de trafic envoyés au port 443 du service de passerelle de sortie. La valeur
targetPort
correspondante sur les pods de la passerelle est 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
Exécutez
istioctl analyze
pour rechercher les erreurs de configuration :${ISTIOCTL} analyze -n istio-egress --revision REVISION
Voici les informations disponibles :
✔ No validation issues found when analyzing namespace: istio-egress.
Envoyez une requête HTTP simple à example.com à partir de l'application de test dans l'espace de noms
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 requête aboutit avec une réponse
200 OK
.Envoyez maintenant plusieurs requêtes TLS (HTTPS) à partir de l'application de test dans l'espace de noms
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
Vous pouvez voir des réponses 200.
Consultez à nouveau le journal de passerelle de sortie :
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
Vous pouvez voir des entrées de journal semblables à ce qui suit :
[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 requête HTTPS a été traitée en tant que trafic TCP et transmise via la passerelle à l'hôte de destination. Par conséquent, aucune information HTTP n'est incluse dans le journal.
Utiliser Kubernetes NetworkPolicy comme mécanisme de contrôle supplémentaire
Il existe de nombreux scénarios dans lesquels une application peut contourner un proxy sidecar.
Vous pouvez utiliser Kubernetes NetworkPolicy
pour spécifier en outre les connexions que les charges de travail sont autorisées à créer. Une fois qu'une règle de réseau est appliquée, toutes les connexions qui ne sont pas spécifiquement autorisées sont refusées.
Ce tutoriel ne prend en compte que les connexions de sortie et les sélecteurs de sortie pour les règles de réseau. Si vous contrôlez l'entrée avec des règles de réseau sur vos propres clusters, vous devez créer des règles d'entrée correspondant à vos règles de sortie. Par exemple, si vous autorisez la sortie à partir de charges de travail dans l'espace de noms team-x
vers l'espace de noms team-y
, vous devez également autoriser l'entrée de l'espace de noms team-y
à partir de l'espace de noms team-x
.
Autorisez les charges de travail et les proxys déployés dans l'espace de noms
team-x
à se connecter àistiod
et à la passerelle de sortie :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
Autorisez les charges de travail et les proxys à interroger le 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
Autorisez les charges de travail et les proxys à se connecter aux adresses IP des API et des services Google, y compris l'autorité de certification 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
Autorisez les charges de travail et les proxys à se connecter au serveur de métadonnées 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
Facultatif : autorisez les charges de travail et les proxys dans l'espace de noms
team-x
à établir des connexions entre eux :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
Facultatif : autorisez les charges de travail et les proxys dans l'espace de noms
team-x
à établir des connexions avec les charges de travail déployées par une autre équipe :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
Les connexions entre les proxys side-car persistent. Les connexions existantes ne sont pas fermées lorsque vous appliquez une nouvelle règle de réseau. Redémarrez les charges de travail dans l'espace de noms "team-x" pour vous assurer que les connexions existantes sont fermées :
kubectl -n team-x rollout restart deployment
Vérifiez que vous pouvez toujours envoyer une requête HTTP à example.com à partir de l'application de test dans l'espace de noms
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 requête aboutit avec une réponse
200 OK
.
Accéder directement aux API Google à l'aide de l'accès privé à Google et des autorisations IAM
Les API et services de Google sont exposés à l'aide d'adresses IP externes. Lorsque des pods avec des adresses IP d'alias de VPC natif établissent des connexions aux API Google à l'aide de l'accès privé à Google, le trafic ne quitte jamais le réseau de Google.
Lorsque vous avez configuré l'infrastructure de ce tutoriel, vous avez activé l'accès privé à Google pour le sous-réseau utilisé par les pods GKE. Pour autoriser l'accès aux adresses IP utilisées par l'accès privé à Google, vous avez créé une route, une règle de pare-feu VPC et une zone DNS privée. Cette configuration permet aux pods d'atteindre directement les API Google sans envoyer de trafic via la passerelle de sortie. Vous pouvez contrôler les API disponibles pour des comptes de service Kubernetes spécifiques (et donc des espaces de noms) à l'aide de la fédération d'identité de charge de travail pour GKE et d'IAM. L'autorisation Istio ne prend pas effet car la passerelle de sortie ne gère pas les connexions aux API Google.
Pour que les pods puissent appeler les API Google, vous devez utiliser IAM pour accorder des autorisations. Le cluster que vous utilisez dans ce tutoriel est configuré pour utiliser Workload Identity Federation for GKE, ce qui permet à un compte de service Kubernetes d'agir en tant que compte de service Google.
Créez un compte de service Google que votre application pourra utiliser :
gcloud iam service-accounts create sa-test-app-team-x
Autorisez le compte de service Kubernetes à emprunter l'identité du compte de service 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
Annotez le compte de service Kubernetes de l'application de test dans l'espace de noms
team-x
avec l'adresse e-mail du compte de service 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
Le pod de l'application de test doit pouvoir accéder au serveur de métadonnées Google (s'exécutant en tant que DaemonSet) afin d'obtenir des identifiants temporaires pour appeler les API Google. Créez une entrée de service pour le serveur de métadonnées 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
Créez également une entrée de service pour private.googleapis.com et 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
Vérifiez que le compte de service Kubernetes est correctement configuré pour agir en tant que compte de service 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
Le compte de service Google est répertorié comme étant l'identité active unique.
Créez un fichier de test dans 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/
Autorisez le compte de service à répertorier et à afficher les fichiers du 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
Vérifiez que l'application de test peut accéder au bucket de 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
Voici les informations disponibles :
Hello, World!
Nettoyer
Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et les ressources individuelles.
Pour éviter que les ressources utilisées lors de ce tutoriel ne soient facturées sur votre compte Google Cloud, procédez comme suit :
Supprimer le projet
Le moyen le plus simple d'empêcher la facturation est de supprimer le projet que vous avez créé pour ce tutoriel.
- 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.
Étape suivante
- Lisez le guide des bonnes pratiques associées.
- Consultez le guide de renforcement de la sécurité sur GKE.
- Découvrez comment automatiser la gestion des certificats TLS pour la passerelle d'entrée Cloud Service Mesh à l'aide de Certificate Authority Service.
- Découvrez comment gérer la configuration et les règles de manière unifiée sur l'ensemble de votre infrastructure avec la gestion de la configuration GKE Enterprise.
- Pour découvrir d'autres architectures de référence, schémas et bonnes pratiques, consultez le Centre d'architecture cloud.