Ce tutoriel explique comment utiliser les passerelles de sortie Anthos Service Mesh ainsi que 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 le guide des bonnes pratiques.
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 Anthos 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.
- Installez Anthos Service Mesh avec des passerelles 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
- 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
- Anthos Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Mise en réseau
- 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
Rendez le script exécutable et exécutez-le à l'aide de la commande
source
pour initialiser votre environnement :chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
Définissez les rôles IAM (gestion de l'authentification et des accès). Si vous êtes un propriétaire de projet, vous disposez de toutes les autorisations nécessaires pour terminer l'installation. Si vous n'êtes pas un propriétaire de projet, demandez à votre administrateur de vous accorder les rôles IAM suivants. Dans la commande suivante, remplacez PROJECT_EMAIL_ADDRESS par le compte que vous utilisez pour vous connecter à Google Cloud.
gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member user:PROJECT_EMAIL_ADDRESS \ --role=roles/editor \ --role=roles/compute.admin \ --role=roles/container.admin \ --role=roles/resourcemanager.projectIamAdmin \ --role=roles/iam.serviceAccountAdmin \ --role=roles/iam.serviceAccountKeyAdmin \ --role=roles/gkehub.admin \ --role=roles/serviceusage.serviceUsageAdmin
Activez les API requises pour le tutoriel :
gcloud services enable \ dns.googleapis.com \ container.googleapis.com \ compute.googleapis.com \ monitoring.googleapis.com \ logging.googleapis.com \ cloudtrace.googleapis.com \ meshca.googleapis.com \ meshtelemetry.googleapis.com \ meshconfig.googleapis.com \ iamcredentials.googleapis.com \ gkeconnect.googleapis.com \ gkehub.googleapis.com \ cloudresourcemanager.googleapis.com \ stackdriver.googleapis.com
L'activation des API peut prendre une minute ou plus. Lorsque les API sont activées, un résultat semblable au suivant s'affiche :
Operation "operations/acf.601db672-88e6-4f98-8ceb-aa3b5725533c" finished successfully.
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 \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
Anthos 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 \ --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 pods et les services exécutés sur le cluster. Notez que GKE crée automatiquement une règle d'entrée correspondante.
gcloud compute firewall-rules create allow-egress-pods-and-services \ --action ALLOW \ --direction EGRESS \ --rules all \ --destination-ranges 10.1.0.0/16,10.2.0.0/20 \ --network vpc-network \ --priority 1000 \ --description "Allow pods and services on nodes to reach each other"
Un service appelé Calico fournit les fonctionnalités de l'API
NetworkPolicy
pour GKE. Autorisez la connectivité pour Calico dans le sous-réseau :gcloud compute firewall-rules create allow-egress-calico \ --action ALLOW \ --direction EGRESS \ --rules tcp:5473 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow Calico Typha within the subnet"
Le port en lecture seule du kubelet est nécessaire pour que GKE puisse lire les métriques de nœud. Autorisez-le à y accéder au sein du sous-réseau :
gcloud compute firewall-rules create allow-egress-kubelet-readonly \ --action ALLOW \ --direction EGRESS \ --rules tcp:10255 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the kubelet read-only port within the subnet"
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 \ --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 :
gcloud compute firewall-rules create allow-ingress-gcp-health-checker \ --action ALLOW \ --direction INGRESS \ --rules tcp:80,tcp:443 \ --source-ranges 130.211.0.0/22,35.191.0.0/16,35.191.0.0/16,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.
Créez une zone DNS privée ainsi que des enregistrements "CNAME" et "A" de manière à ce 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 ainsi que des enregistrements "CNAME" et "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
Créez un cluster GKE privé :
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --no-enable-basic-auth \ --no-issue-client-certificate \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-network-policy \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --num-nodes "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.
Anthos Service Mesh nécessite que les nœuds du cluster utilisent un type de machine disposant d'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 Anthos Service Mesh. Pour en savoir plus, consultez les guides d'installation d'Anthos Service Mesh.
Workload Identity est activé sur le cluster. Anthos Service Mesh nécessite Workload Identity. 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 Anthos Service Mesh
Ce tutoriel utilise des fonctionnalités facultatives d'Anthos Service Mesh. Pour en savoir plus sur l'installation d'Anthos Service Mesh avec un script de lecture, consultez le guide d'installation dans la documentation.
Créez des espaces de noms pour le déploiement du plan de contrôle du maillage de services et des passerelles de sortie :
kubectl create ns istio-system kubectl create ns istio-egress
Attribuez des libellés aux espaces de noms istio-egress, istio-system et kube-system :
kubectl label ns istio-egress istio=egress istio-injection=disabled kubectl label ns istio-system istio=system kubectl label ns kube-system kube-system=true
Ces libellés seront utilisés ultérieurement pour appliquer Kubernetes NetworkPolicy. Le libellé
istio-injection=disabled
évite les avertissements parasites lors de l'analyseistioctl
.Créez un fichier de manifeste pour personnaliser l'installation d'Anthos Service Mesh à l'aide de l'API Istio Operator :
cat << 'EOF' > ./asm-custom-install.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: "egress-gateway" spec: meshConfig: accessLogFile: "/dev/stdout" components: egressGateways: - name: "istio-egressgateway" enabled: true namespace: "istio-egress" label: istio: "egress" k8s: tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
Ce fichier est fourni en tant qu'argument au script d'installation et spécifie la configuration suivante :
- Un déploiement de passerelle de sortie qui s'exécute dans l'espace de noms
istio-egress
avec une tolérance et une fonction nodeSelector afin de garantir qu'il ne s'exécute que sur les nœudsgateway
- Journalisation d'accès à "stdout" pour tous les proxys side-car.
- Un déploiement de passerelle de sortie qui s'exécute dans l'espace de noms
Téléchargez le script d'installation :
curl -O https://storage.googleapis.com/csm-artifacts/asm/install_asm
Téléchargez la signature SHA-256 du fichier dans le répertoire de travail :
curl -O https://storage.googleapis.com/csm-artifacts/asm/install_asm.sha256
Vérifiez le téléchargement avec les deux fichiers dans le même répertoire :
sha256sum -c --ignore-missing install_asm.sha256
Si la validation réussit, le résultat est le suivant :
install_asm: OK
Pour assurer la compatibilité, le fichier
install_asm.sha256
inclut la somme de contrôle deux fois pour permettre de renommer n'importe quelle version du script eninstall_asm
. Si vous obtenez une erreur indiquant que--ignore-missing
n'existe pas, réexécutez la commande précédente sans l'option--ignore-missing
.Rendez le script exécutable :
chmod +x install_asm
Installez Anthos Service Mesh en exécutant le script :
./install_asm \ --mode install \ --project_id ${PROJECT_ID} \ --cluster_name cluster1 \ --cluster_location ${ZONE} \ --custom_overlay ./asm-custom-install.yaml \ --output_dir ./ \ --enable_all
Une fois le script terminé, 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
Vérifier l'installation d'Anthos Service Mesh
Vérifiez que les composants du plan de contrôle Anthos Service Mesh sont en cours d'exécution dans l'espace de noms
istio-system
:kubectl get pod -n istio-system
Vous pouvez voir les pods
istio-ingressgateway
etistiod-asm
en cours d'exécution.Vérifiez que les pods de passerelle de sortie s'exécutent dans l'espace de noms
istio-egress
et sur les nœuds du pool de nœudsgateway
:kubectl get pods -n istio-egress -o wide
Les pods de passerelle de sortie ont un
nodeSelector
pour sélectionner les nœuds du poolgateway
et une tolérance qui leur permet de s'exécuter sur les nœuds de passerelle rejetés. Examinez le nodeSelector et les tolérances pour les pods de passerelle de sortie :kubectl -n istio-egress get pod -l app=istio-egressgateway \ -o=custom-columns='name:metadata.name,nodeSelector:spec.nodeSelector,\ tolerations:spec.tolerations[?(@.key=="dedicated")]'
Le résultat ressemble à ce qui suit :
name nodeSelector tolerations istio-egressgateway-74687946f5-dg9mp map[cloud.google.com/gke-nodepool:gateway] map[key:dedicated operator:Equal value:gateway]
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 qu'Anthos Service Mesh puisse injecter automatiquement les sidecars de proxy, vous devez définir un libellé de révision sur les espaces de noms de la charge de travail. L'étiquette de révision doit correspondre à la version du plan de contrôle d'Anthos Service Mesh qui a été déployée sur votre cluster. Recherchez le libellé de révision sur le pod
istiod
puis stockez-le dans une variable d'environnement :REVISION_LABEL=$(kubectl get pod -n istio-system -l app=istiod \ -o jsonpath='{.items[0].metadata.labels.istio\.io/rev}')
Définissez le libellé de révision sur les espaces de noms
team-x
etteam-y
:kubectl label ns team-x istio.io/rev=${REVISION_LABEL} kubectl label ns team-y istio.io/rev=${REVISION_LABEL}
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 sidecar 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 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 20 clusters Envoy, dont plusieurs pour la passerelle de sortie.
Restreignez la configuration du proxy aux routes de sortie définies explicitement avec des entrées de service dans les espaces de noms
istio-egress
etteam-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.La partie "
istio-egress/*
" indique que le proxy sidecar sélectionne des routes de l'espace de nomsistio-egress
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
Le résultat ne comprend que quelques clusters pour la passerelle de sortie et un cluster pour le pod de test.
Configurer Anthos Service Mesh pour acheminer le trafic via la passerelle de sortie
Configurez une ressource
Gateway
pour le trafic HTTP sur le port 80. LeGateway
sélectionne le proxyistio-egressgateway
déployé par le programme d'installation dans l'espace de nomsistio-egress
. La configurationGateway
est appliquée à l'espace de nomsistio-egress
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: egress 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: loadBalancer: simple: ROUND_ROBIN tls: mode: ISTIO_MUTUAL EOF
Créez un
ServiceEntry
dans l'espace de nomsistio-egress
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 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
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=egress \ -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 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
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: 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: 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 "mettre à niveau" (initier) les requêtes HTTP vers le protocole TLS. 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: loadBalancer: simple: ROUND_ROBIN 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 "mises à niveau" 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=egress \ -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: egress 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: loadBalancer: simple: ROUND_ROBIN 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: rules: - when: - key: destination.port values: ["8443"] EOF
Exécutez
istioctl analyze
pour rechercher les erreurs de configuration :${ISTIOCTL} analyze -n istio-egress
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=egress \ -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: istio: system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: istio: egress podSelector: matchLabels: istio: egress 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: kube-system: "true" 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 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 ports: - 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: 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 Workload Identity 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, 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 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 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 gsutil mb gs://${PROJECT_ID}-bucket gsutil cp /tmp/hello gs://${PROJECT_ID}-bucket/
Autorisez le compte de service à répertorier et à afficher les fichiers du bucket :
gsutil iam ch \ serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com:objectViewer \ gs://${PROJECT_ID}-bucket/
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 \ -- gsutil 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.
Étapes suivantes
- Lisez le guide des bonnes pratiques associées.
- Consultez le guide de renforcement de la sécurité sur GKE.
- Découvrez comment gérer la configuration et les règles de toute 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.