Ce tutoriel explique comment utiliser les passerelles d'entrée et de sortie Anthos Service Mesh pour sécuriser le trafic entre les clusters à l'aide de l'authentification TLS mutuelle (mTLS). Il est destiné aux administrateurs de cluster Kubernetes chargés des aspects réseau, sécurité et plate-forme. Les contrôles décrits ici peuvent être particulièrement utiles pour les organisations ayant des exigences de sécurité accrues ou pour satisfaire des prérequis réglementaires. Ce tutoriel est accompagné d'un guide conceptuel complémentaire.
Dans ce tutoriel, nous partons du principe que vous connaissez bien Kubernetes et Anthos Service Mesh.
Objectifs
- Utilisez Terraform pour configurer l'infrastructure :
- Créez un réseau VPC personnalisé avec deux sous-réseaux privés.
- Créez deux clusters Kubernetes avec Anthos Service Mesh activé :
- Un cluster GKE
- Un cluster Kubernetes Operations (kOps) s'exécutant dans le réseau VPC personnalisé
- Enregistrer des clusters dans GKE Hub.
- Déployez un client MySQL sur un cluster GKE.
- Déployez un serveur MySQL sur un cluster kOps.
- Configurez les passerelles de sortie et d'entrée pour exposer un serveur à l'aide de mTLS.
- Testez l'accès à un serveur MySQL à l'aide d'un client MySQL qui s'exécute dans différents clusters ou VPC.
Coûts
Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :
- Google Kubernetes Engine (GKE)
- Compute Engine
- Container Registry
- Anthos Service Mesh
- Mise en réseau et équilibrage de charge cloud
Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.
Une fois que vous avez terminé les tâches décrites dans ce document, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.
Avant de commencer
Pour ce tutoriel, vous avez besoin d'un projet Google Cloud. Vous pouvez en créer un ou sélectionner un projet existant :
-
Dans Google Cloud Console, accédez à la page de sélection du projet.
-
Sélectionnez ou créez un projet Google Cloud.
-
Vérifiez que la facturation est activée pour votre projet Google Cloud.
Dans la console Google Cloud, accédez à Cloud Shell.
En bas de la fenêtre de la console Google Cloud, une session Cloud Shell s'ouvre et affiche une invite de ligne de commande. Cloud Shell est un environnement shell dans lequel Google Cloud CLI est déjà installé, et qui inclut Google Cloud CLI. L'initialisation de la session peut prendre quelques secondes.
- Dans Cloud Shell, assurez-vous que vous travaillez dans le projet que vous avez créé ou sélectionné :
export PROJECT_ID=PROJECT_ID gcloud config set project ${PROJECT_ID}
Remplacez
PROJECT_ID
par l'ID du projet. - Créez une variable d'environnement pour l'adresse e-mail que vous utilisez pour Google Cloud :
export GOOGLE_CLOUD_EMAIL_ADDRESS=GOOGLE_CLOUD_EMAIL_ADDRESS
Remplacez
GOOGLE_CLOUD_EMAIL_ADDRESS
par l'adresse e-mail que vous utilisez dans Google Cloud. - Définissez la région et la zone pour vos ressources de calcul :
export REGION=us-central1 export ZONE=us-central1-b gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE}
Ce tutoriel utilise
us-central1
pour la région etus-central1-b
pour la zone. Vous pouvez effectuer le déploiement dans la région de votre choix. - 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. Sinon, demandez à votre administrateur de vous attribuer des rôles IAM (Identity and Access Management) en exécutant la commande suivante dans Cloud Shell :
ROLES=( 'roles/container.admin' \ 'roles/gkehub.admin' \ 'roles/iam.serviceAccountAdmin' \ 'roles/iam.serviceAccountKeyAdmin' \ 'roles/resourcemanager.projectIamAdmin' \ 'roles/compute.securityAdmin' \ 'roles/compute.instanceAdmin' \ 'roles/storage.admin' \ 'roles/serviceusage.serviceUsageAdmin' ) for role in "${ROLES[@]}" do gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "user:${GOOGLE_CLOUD_EMAIL_ADDRESS}" \ --role="$role" done
- Activez les API requises pour le tutoriel :
gcloud services enable \ anthos.googleapis.com \ anthosgke.googleapis.com \ anthosaudit.googleapis.com \ compute.googleapis.com \ container.googleapis.com \ cloudresourcemanager.googleapis.com \ serviceusage.googleapis.com \ stackdriver.googleapis.com \ monitoring.googleapis.com \ logging.googleapis.com \ cloudtrace.googleapis.com \ meshca.googleapis.com \ meshconfig.googleapis.com \ iamcredentials.googleapis.com \ gkeconnect.googleapis.com \ gkehub.googleapis.com
Préparer l'environnement
Dans Cloud Shell, clonez le dépôt suivant :
git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples cd anthos-service-mesh-samples/docs/mtls-egress-ingress
Mettez à jour Terraform pour votre environnement. Par défaut, la console Google Cloud est fournie avec Terraform 0.12. Dans ce tutoriel, nous partons du principe que vous disposez de Terraform 0.13.5 ou d'une version ultérieure. Vous pouvez utiliser temporairement une autre version de Terraform en exécutant les commandes suivantes :
mkdir ~/bin curl https://releases.hashicorp.com/terraform/0.13.5/terraform_0.13.5_linux_amd64.zip -o ~/bin/terraform.zip unzip ~/bin/terraform.zip -d ~/bin/
Accédez au sous-dossier
terraform
et initialisez Terraform :cd terraform/ ~/bin/terraform init
Créez un fichier
terraform.tfvars
(en fonction des variables d'environnement que vous avez créées précédemment) :cat << EOF > terraform.tfvars project_id = "${PROJECT_ID}" region = "${REGION}" zones = ["${ZONE}"] EOF
À l'étape suivante, vous allez créer l'infrastructure initiale. Pour ce faire, vous devez créer et appliquer le plan d'exécution Terraform pour cette configuration. Les scripts et les modules de ce plan créent les éléments suivants :
- Un réseau VPC personnalisé avec deux sous-réseaux privés.
- Deux clusters Kubernetes avec Anthos Service Mesh activé
- Un cluster GKE
- Un cluster kOps s'exécutant dans le réseau VPC personnalisé
Le plan d'exécution enregistre également les clusters dans GKE Hub.
Exécutez le plan d'exécution :
~/bin/terraform plan -out mtls-terraform-plan ~/bin/terraform apply "mtls-terraform-plan"
Le résultat ressemble à ce qui suit :
Apply complete! Resources: 27 added, 0 changed, 0 destroyed. Outputs: server_token = <sensitive>
La partie
<sensitive>
est une variable de sortie Terraform qui n'est pas affichée sur la console mais qui peut être interrogée, par exemple~/bin/terraform output server_token
.Récupérez le fichier
kubeconfig
du cluster de serveur à partir du répertoireterraform
. Ensuite, fusionnez-le avec le fichier de configurationclient-cluster
:cd .. export KUBECONFIG=client-server-kubeconfig cp ./terraform/server-kubeconfig $KUBECONFIG gcloud container clusters get-credentials client-cluster --zone ${ZONE} --project ${PROJECT_ID}
Le fichier
client-server-kubeconfig
contient désormais la configuration des deux clusters, que vous pouvez vérifier en exécutant la commande suivante :kubectl config view -ojson | jq -r '.clusters[].name'
Le résultat est le suivant :
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Obtenez le contexte des deux clusters pour une utilisation ultérieure :
export CLIENT_CLUSTER=$(kubectl config view -ojson | jq -r '.clusters[].name' | grep client) export SERVER_CLUSTER=$(kubectl config view -ojson | jq -r '.clusters[].name' | grep server) echo -e "${CLIENT_CLUSTER}\n${SERVER_CLUSTER}"
Le résultat est (à nouveau) le suivant :
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Vous pouvez maintenant utiliser ces noms de cluster comme contexte pour d'autres commandes
kubectl
.Référencez le cluster client :
kubectl --context ${CLIENT_CLUSTER} get pods -n istio-system
Référencez le cluster serveur :
kubectl --context ${SERVER_CLUSTER} get pods -n istio-system
Configurer le côté client
Comme indiqué dans le guide conceptuel, la partie client nécessite la configuration de la passerelle de sortie dans Anthos Service Mesh.
Dans cette section, vous configurez les éléments de Anthos Service Mesh afin d'identifier le trafic externe en fonction de son origine et d'utiliser un certificat personnalisé pour chiffrer la communication. En outre, vous ne souhaitez acheminer que ce trafic vers sa destination (la base de données MySQL dans un conteneur). Pour ce faire, vous utilisez généralement un service dans Kubernetes. Dans ce cas, vous devez intercepter ce trafic dans les communication du maillage. Pour intercepter le trafic, vous devez utiliser des éléments Istio afin de créer une définition spéciale du service. Vous définissez les éléments suivants :
- Passerelle de sortie
- Entrée de service
- Service virtuel
- Certificats TLS (dans un secret)
- Règles de destination
Dans Cloud Shell, récupérez l'adresse IP de la passerelle d'entrée côté serveur en interrogeant l'adresse IP de l'équilibreur de charge de la
istio-ingressgateway
en utilisant le contexte côté serveur ($SERVER_CLUSTER
, que vous avez créé précédemment) :INGRESS_HOST=$(kubectl -n istio-system --context ${SERVER_CLUSTER} get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
Comme
INGRESS_HOST
n'est que la partie d'adresse IP de votre hôte, vous devez créer un nom de domaine complet. Cette étape est nécessaire car pour fonctionner correctement, les certificats requièrent un nom de domaine.Dans ce tutoriel, vous utilisez le service DNS générique nip.io pour créer un nom de domaine complet pour l'adresse IP d'entrée. Ce service vous permet de créer le nom de domaine complet sans posséder de domaine.
Stockez l'URL de service du nom de domaine complet dans une variable d'environnement :
export SERVICE_URL="${INGRESS_HOST}.nip.io"
Maintenant que le
SERVICE_URL
est défini comme nom de domaine complet, vous pouvez commencer à définir la partie Istio du cluster client.
Créer la passerelle de sortie
Vous allez commencer par créer la passerelle de sortie afin d'écouter le trafic à destination du service externe.
Dans Cloud Shell, créez le fichier YAML suivant et nommez-le
client-egress-gateway.yaml
:cat <<EOF > client-egress-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway-mysql spec: selector: istio: egressgateway servers: - port: number: 15443 name: tls protocol: TLS hosts: - $SERVICE_URL tls: mode: ISTIO_MUTUAL EOF
Appliquez le fichier YAML précédent au cluster client :
kubectl --context ${CLIENT_CLUSTER} apply -f client-egress-gateway.yaml
Portez une attention particulière aux ports. Vous avez ici utilisé les ports
default
pour le commutateur de serveurs de sortie, à savoir le port15443
. Si vous souhaitez utiliser un port différent, vous devez modifier l'objetservice
de la passerelle de sortie pour ajouter vos ports personnalisés.Le commutateur
hosts
définit le point de terminaison, c'est-à-dire l'emplacement vers lequel le trafic doit être dirigé.
Définir l'entrée de service
L'étape suivante consiste à informer le maillage de services du service externe. Istio dispose de son propre registre dans lequel il stocke les points de terminaison de service pour le maillage. Si Istio est installé sur Kubernetes, les services définis dans le cluster sont automatiquement ajoutés au registre Istio. Avec la définition de l'entrée de service, vous ajoutez un nouveau point de terminaison au registre Istio comme indiqué dans le schéma suivant.
Dans Cloud Shell, créez le fichier YAML suivant et nommez-le
client-service-entry.yaml
:cat <<EOF > client-service-entry.yaml apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: mysql-external spec: hosts: - $SERVICE_URL location: MESH_EXTERNAL ports: - number: 3306 name: tcp protocol: TCP - number: 13306 name: tls protocol: TLS resolution: DNS endpoints: - address: $SERVICE_URL ports: tls: 13306 EOF
Appliquez le fichier YAML précédent au cluster client :
kubectl --context ${CLIENT_CLUSTER} apply -f client-service-entry.yaml
La définition de service client dans ce fichier YAML indique au service le type de trafic à attendre (MySQL L4, couche réseau 4, sur le port 3306). Vous définissez également que la communication sera externe au maillage ("mesh external"). Dans la section des points de terminaison, vous définissez que le flux doit être dirigé vers l'adresse du nom de domaine complet
$SERVICE_URL
que vous avez définie précédemment et qui est mappée sur la passerelle d'entrée du cluster de serveur (kOps).
Définir le service virtuel
Un service virtuel est un ensemble de règles de routage qui s'appliquent au trafic à destination d'un hôte spécifique. Chaque règle de routage définit des critères de correspondance pour le trafic d'un protocole spécifique. Si le trafic est mis en correspondance, il est envoyé à un service de destination nommé (ou à un sous-ensemble ou à une version de celui-ci) qui est défini dans le registre. Pour plus d'informations, consultez la documentation d'Istio.
La définition de service virtuel indique à Istio comment appliquer le routage pour le trafic qui atteint le service externe. Avec la définition suivante, vous demandez au maillage de diriger le trafic du client vers la passerelle de sortie sur le port 15443
. Depuis la passerelle de sortie, vous routez le trafic vers l'hôte $SERVICE_URL
sur le port 13306
(qui est écouté par la passerelle d'entrée côté serveur).
Créez le fichier YAML suivant et nommez-le
client-virtual-service.yaml
:cat <<EOF > client-virtual-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mysql-through-egress-gateway spec: hosts: - $SERVICE_URL gateways: - istio-egressgateway-mysql - mesh tcp: - match: - gateways: - mesh port: 3306 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: mysql port: number: 15443 weight: 100 - match: - gateways: - istio-egressgateway-mysql port: 15443 route: - destination: host: $SERVICE_URL port: number: 13306 weight: 100 EOF
Appliquez la définition YAML au cluster client :
kubectl --context ${CLIENT_CLUSTER} apply -f client-virtual-service.yaml
Vous pouvez indiquer les passerelles auxquelles la configuration doit s'appliquer en modifiant le commutateur
gateways
dans le fichier YAML.La partie importante de cette définition est l'utilisation du mot réservé
mesh
, qui implique tous les side-cars du maillage. Selon la documentation d'Istio, lorsque ce champ est omis, la passerelle par défaut (maillage) est utilisée et applique la règle à tous les side-cars du maillage. Si vous fournissez une liste de noms de passerelles, les règles ne s'appliquent qu'aux passerelles. Pour appliquer les règles aux passerelles et aux side-cars, spécifiezmesh
comme nom de passerelle.
Dans la section suivante, vous allez définir comment gérer le trafic sortant du proxy client de production (match.gateways.mesh
). Vous définissez également comment acheminer le trafic de la sortie vers le service externe à l'aide du commutateur match.gateways.istio-egressgateway-mysql
.
Définir une règle de destination (du client à la passerelle de sortie)
Maintenant que vous avez défini comment acheminer le trafic vers le service externe, vous devez définir quelles règles de trafic s'appliquent. Le service virtuel que vous venez de définir gère deux cas de routage à la fois. L'un gère le trafic du proxy side-car vers la passerelle de sortie et l'autre gère le trafic de la passerelle de sortie vers le service externe.
Pour faire correspondre ces cas avec les règles de destination, vous devez utiliser deux règles distinctes. Le schéma suivant illustre la première règle, qui gère le trafic du proxy vers la passerelle de sortie. Dans cette définition, vous indiquez à Anthos Service Mesh d'utiliser ses certificats par défaut pour la communication mTLS.
Dans Cloud Shell, créez le fichier YAML suivant et nommez-le
client-destination-rule-to-egress-gateway.yaml
:cat <<EOF > client-destination-rule-to-egress-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-mysql spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: mysql trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 15443 tls: mode: ISTIO_MUTUAL sni: $SERVICE_URL EOF
Appliquez la définition YAML précédente au cluster client :
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-egress-gateway.yaml
Dans le fichier YAML précédent, vous avez utilisé le commutateur
hosts
pour définir comment acheminer le trafic du proxy client vers la passerelle de sortie. Vous avez également configuré le maillage pour utiliserISTIO_MUTUAL
sur le port15443
, qui est l'un des ports ouverts automatiquement sur la passerelle de sortie.
Créer une règle de destination (de la passerelle de sortie au service externe)
Le schéma suivant illustre la deuxième règle de destination qui indique au maillage comment gérer le trafic de la passerelle de sortie vers le service externe.
Vous devez indiquer au maillage d'utiliser vos certificats injectés pour la communication TLS mutuelle avec le service externe.
Dans Cloud Shell, créez les certificats à partir du répertoire
anthos-service-mesh-samples/docs/mtls-egress-ingress
:./create-keys.sh
Assurez-vous de fournir un mot de passe lorsque le script l'exige.
Copiez les fichiers générés dans le répertoire actuel :
cp ./certs/2_intermediate/certs/ca-chain.cert.pem ca-chain.cert.pem cp ./certs/4_client/private/$SERVICE_URL.key.pem client-$SERVICE_URL.key.pem cp ./certs/4_client/certs/$SERVICE_URL.cert.pem client-$SERVICE_URL.cert.pem
Créez un secret Kubernetes qui stocke les certificats afin de pouvoir les référencer ultérieurement dans la passerelle :
kubectl --context ${CLIENT_CLUSTER} create secret -n istio-system \ generic client-credential \ --from-file=tls.key=client-$SERVICE_URL.key.pem \ --from-file=tls.crt=client-$SERVICE_URL.cert.pem \ --from-file=ca.crt=ca-chain.cert.pem
La commande précédente ajoute les fichiers de certificat suivants au secret :
client-$SERVICE_URL.key.pem client-$SERVICE_URL.cert.pem ca-chain.cert.pem
Nous appliquons ici la bonne pratique recommandée pour la distribution des certificats, à savoir l'utilisation du service de détection de secrets (SDS) plutôt que les montages de fichiers. Cette pratique évite de redémarrer les pods lors de l'ajout d'un nouveau certificat. À partir de la version 1.8/1.9 d'Istio et avec cette technique, vous n'avez plus besoin de droits d'accès en lecture (RBAC) pour le secret des passerelles.
Ajoutez les certificats à la
DestinationRule
et nommez-laclient-destination-rule-to-external-service.yaml
:cat <<EOF > client-destination-rule-to-external-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-mtls-for-mysql spec: host: $SERVICE_URL trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 13306 tls: mode: MUTUAL credentialName: client-credential sni: $SERVICE_URL EOF
Appliquez la définition YAML précédente au cluster client :
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-external-service.yaml
Cette règle ne fonctionne que si vous avez créé le secret au préalable. Le secret garantit que les certificats sont utilisés pour le chiffrement mTLS de la passerelle de sortie vers le point de terminaison externe.
Une fois ces étapes terminées, la configuration côté client est terminée et est reflétée par le schéma suivant.
Configurer le côté serveur
Comme indiqué dans le guide de concept, vous devez configurer la passerelle d'entrée pour le côté serveur dans Anthos Service Mesh. Avant de créer les fichiers nécessaires, il est judicieux d'examiner les composants requis pour exécuter la partie serveur de la solution.
En résumé, vous souhaitez identifier le trafic entrant en fonction de son origine et de son certificat. Vous souhaitez également acheminer uniquement ce trafic vers sa destination : votre base de données MySQL dans un conteneur. Pour ce faire, vous utilisez généralement un service dans Kubernetes. Toutefois, dans cet exemple, vous allez identifier le trafic entrant dans les communications du maillage. Vous avez donc besoin d'une définition spéciale d'un service incluant les éléments suivants :
- Certificats TLS (dans un secret)
- Passerelle d'entrée
- Service virtuel
Créer le secret de la passerelle d'entrée
Comme pour la passerelle de sortie, vous aurez besoin des mêmes certificats pour sécuriser les communications de la passerelle d'entrée. Pour ce faire, stockez les certificats dans un secret et définissez ce secret avec votre objet de passerelle d'entrée.
Dans Cloud Shell, copiez les fichiers générés à l'emplacement où vous exécuterez la commande suivante :
cp ./certs/3_application/private/$SERVICE_URL.key.pem server-$SERVICE_URL.key.pem cp ./certs/3_application/certs/$SERVICE_URL.cert.pem server-$SERVICE_URL.cert.pem
Créez le secret du serveur :
kubectl --context ${SERVER_CLUSTER} create secret -n istio-system \ generic mysql-credential \ --from-file=tls.key=server-$SERVICE_URL.key.pem \ --from-file=tls.crt=server-$SERVICE_URL.cert.pem \ --from-file=ca.crt=ca-chain.cert.pem
Vous venez d'ajouter les fichiers de certificat suivants au secret :
server-$SERVICE_URL.key.pem server-$SERVICE_URL.cert.pem ca-chain.cert.pem
Définir la passerelle d'entrée
Pour recevoir le trafic du cluster côté client, vous devez spécifier une passerelle d'entrée capable de déchiffrer et de vérifier les communications TLS en utilisant les certificats.
Ce schéma indique l'emplacement de la passerelle d'entrée dans votre cluster. Le trafic est transmis puis examiné s'il satisfait les critères de sécurité et de transfert.
Dans Cloud Shell, utilisez le fichier YAML suivant et nommez-le
server-ingress-gatway.yaml
:cat <<EOF > server-ingress-gatway.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: gateway-mysql spec: selector: istio: ingressgateway # Istio default gateway implementation servers: - port: number: 13306 name: tls-mysql protocol: TLS tls: mode: MUTUAL credentialName: mysql-credential hosts: - "$SERVICE_URL" EOF
Appliquez la définition YAML précédente au cluster client :
kubectl --context ${SERVER_CLUSTER} apply -f server-ingress-gatway.yaml
Portez une attention particulière à la section
tls:
car elle est particulièrement importante. Dans cette section, vous allez définir l'authentification mTLS. Pour que tout cela fonctionne comme prévu, vous devez fournir le secret que vous avez créé et qui contient les certificats.Activez le port
13306
en appliquant un correctif au service d'entrée. Pour activer ce port, créez le fichier JSON suivant et nommez-legateway-patch.json
:cat <<EOF > gateway-patch.json [{ "op": "add", "path": "/spec/ports/0", "value": { "name": "tls-mysql", "protocol": "TCP", "targetPort": 13306, "port": 13306 } }] EOF
Appliquez le correctif au service de passerelle :
kubectl --context ${SERVER_CLUSTER} -n istio-system patch --type=json svc istio-ingressgateway -p "$(cat gateway-patch.json)"
Maintenant que vous avez ouvert le port sur la passerelle d'entrée, vous devez intercepter le trafic provenant de votre nouvelle passerelle d'entrée et l'acheminer vers votre pod de base de données. Pour ce faire, vous allez utiliser un objet interne de maillage : le service virtuel.
Définir le service virtuel
Comme indiqué précédemment, le service virtuel est une définition de modèles de correspondance de trafic qui façonnent le trafic au sein de votre maillage. Vous devez identifier et transférer correctement le trafic de votre passerelle d'entrée vers votre service MySQL DB, comme illustré dans le schéma suivant.
Dans Cloud Shell, créez le fichier YAML suivant et nommez-le
server-virtual-service.yaml
:cat <<EOF > server-virtual-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: mysql-virtual-service spec: hosts: - "$SERVICE_URL" gateways: - gateway-mysql tcp: - route: - destination: port: number: 3306 host: mysql.default.svc.cluster.local EOF
Il est important que ce service virtuel fasse référence à la passerelle d'entrée d'où provient le trafic. La passerelle est nommée
gateway-mysql
.Comme ce service virtuel est appliqué sur la L4, vous devez utiliser l'option
tcp
pour décrire votre trafic MySQL. Cette option permet d'indiquer au maillage que la L4 doit être utilisée pour ce trafic.Vous avez peut-être remarqué que le service d'entrée utilise le port
13306
pour transférer le trafic. Le service virtuel récupère cette valeur et la traduit en3306
.Enfin, vous transférez le trafic vers le serveur MySQL dans le cluster Kubernetes de serveur. Pour cet exemple, le serveur écoute sur le port MySQL standard
3306
.Appliquez la définition YAML au cluster de serveur :
kubectl --context ${SERVER_CLUSTER} apply -f server-virtual-service.yaml
Ces deux définitions déchiffrent la requête client MySQL encapsulée par mTLS avant de la transférer vers la base de données MySQL à l'intérieur du maillage.
Il est important de comprendre que les transferts internes au maillage sont également chiffrés. Cependant, dans le cas présent, le chiffrement est basé sur les certificats internes du maillage. La résiliation mTLS se produit au niveau de la passerelle.
Vous disposez à présent d'une méthode de communication entièrement et mutuellement chiffrée pour communiquer avec votre serveur MySQL. Cette forme de chiffrement étant transparente pour le client et le serveur MySQL, aucune modification de votre application n'est nécessaire. Cela facilite les tâches comme la modification ou la rotation des certificats. De plus, ce mode de communication peut être utilisé dans de nombreux scénarios différents.
Tester la configuration
Maintenant que le côté client et le côté serveur sont tous deux correctement déployés, vous pouvez tester la configuration.
Il est temps de générer du trafic côté client à destination du côté serveur. Votre objectif est de suivre le flux de trafic pour vous assurer que le trafic est bien acheminé, chiffré et déchiffré comme vous le souhaitez.
Dans Cloud Shell, déployez le serveur MySQL dans le cluster de serveur :
kubectl --context ${SERVER_CLUSTER} apply -f server/mysql-server/mysql.yaml
Démarrez un client MySQL sur le cluster client :
kubectl run --context ${CLIENT_CLUSTER} --env=SERVICE_URL=$SERVICE_URL -it --image=mysql:5.6 mysql-client-1 --restart=Never -- /bin/bash
Une fois le conteneur démarré, une interface système s'affiche. Elle doit ressembler à ceci :
root@mysql-client-1:/#
Connectez-vous à votre serveur MySQL :
mysql -pyougottoknowme -h $SERVICE_URL
Utilisez les commandes suivantes pour ajouter une base de données et une table :
CREATE DATABASE test_encrypted_connection; USE test_encrypted_connection; CREATE TABLE message (id INT, content VARCHAR(20)); INSERT INTO message (id,content) VALUES(1,"Crypto Hi");
Après vous être connecté et avoir ajouté la table, fermez la connexion MySQL et le pod :
exit exit
Vous devez utiliser la commande "exit" deux fois : d'abord pour fermer la connexion de base de données, puis pour quitter le pod. Si le pod cesse de répondre après la fermeture de la connexion, appuyez sur Control+C pour quitter l'interface système bash.
En suivant ces étapes, vous devriez générer un résultat de journalisation pertinent que vous pourrez alors analyser plus en détail.
Dans la section suivante, vous allez vérifier que le trafic côté client passe bien par le proxy et par la passerelle de sortie. Vous pouvez également vérifier que vous voyez bien le trafic entrant côté serveur qui passe par la passerelle d'entrée.
Tester le proxy côté client et la passerelle de sortie
Dans Cloud Shell, sur le proxy côté client, vérifiez que vous pouvez afficher les journaux du proxy Istio :
kubectl --context ${CLIENT_CLUSTER} logs -l run=mysql-client-1 -c istio-proxy -f
La sortie de débogage doit ressembler à ceci :
[2021-02-10T21:19:08.292Z] "- - -" 0 - "-" "-" 176 115 10 - "-" "-" "-" "-" "192.168.1.4:15443" outbound|15443|mysql|istio-egressgateway.istio-system.svc.cluster.local 192.168.1.12:58614 34.66.165.46:3306 192.168.1.12:39642 - -
Appuyez sur Ctrl+C pour quitter le journal.
Dans cette entrée de journal, vous pouvez voir que le client envoie une requête au serveur qui s'exécute sur l'adresse IP
34.66.165.46
, sur le port3306
. La requête est transmise (outbound
) àistio-egressgateway
qui écoute sur le port15443
de l'adresse IP192.168.1.4
. Vous avez défini ce transfert dans votre service virtuel (client-virtual-service.yaml
).Lisez les journaux du proxy de la passerelle de sortie :
kubectl --context ${CLIENT_CLUSTER} logs -n istio-system -l app=istio-egressgateway -f
La sortie de débogage doit ressembler à ceci :
[2021-02-10T21:19:08.292Z] "- - -" 0 - "-" "-" 176 115 19 - "-" "-" "-" "-" "34.66.165.46:13306" outbound|13306||34.66.165.46.nip.io 192.168.1.4:53542 192.168.1.4:15443 192.168.1.12:58614 34.66.165.46.nip.io -
Appuyez sur Ctrl+C pour quitter le journal.
Dans cette entrée de journal, vous pouvez voir que la requête client est acheminée vers
istio-egressgateway
qui écoute sur le port192.168.1.4
de l'adresse IP15443
avant d'être transférée vers l'extérieur du maillage de services vers le service externe qui écoute sur le port13306.
de l'adresse IP34.66.165.46
(vous avez défini ce transfert dans la deuxième partie de votre service virtuel,client-virtual-service.yaml
).
Tester la passerelle d'entrée côté serveur
Dans Cloud Shell, côté serveur, affichez les journaux du proxy de passerelle d'entrée :
kubectl --context ${SERVER_CLUSTER} logs -n istio-system -l app=istio-ingressgateway -f
La sortie dans le journal ressemble à ceci :
[2021-02-10T21:22:27.381Z] "- - -" 0 - "-" "-" 0 78 5 - "-" "-" "-" "-" "100.96.4.8:3306" outbound|3306||mysql.default.svc.cluster.local 100.96.1.3:55730 100.96.1.3:13306 100.96.1.1:42244 34.66.165.46.nip.io -
Appuyez sur Ctrl+C pour quitter le journal.
Dans cette entrée de journal, vous pouvez voir que la requête client externe est acheminée vers
istio-ingressgateway
qui écoute sur le port34.66.165.46
de l'adresse IP13306
avant d'être transférée vers le service MySQL à l'intérieur du maillage identifié par le nom de servicemysql.default.svc.cluster.local
sur le port3306.
(vous avez défini ce transfert dans la passerelle d'entréeserver-ingress-gateway.yaml
).Pour le serveur MySQL, affichez les journaux du proxy Istio :
kubectl --context ${SERVER_CLUSTER} logs -l app=mysql -c istio-proxy -f
La sortie ressemble à ceci :
[2021-02-10T21:22:27.382Z] "- - -" 0 - "-" "-" 1555 1471 4 - "-" "-" "-" "-" "127.0.0.1:3306" inbound|3306|mysql|mysql.default.svc.cluster.local 127.0.0.1:45894 100.96.4.8:3306 100.96.1.3:55730 outbound_.3306_._.mysql.default.svc.cluster.local -
Appuyez sur Ctrl+C pour quitter le journal.
Dans cette entrée de journal, vous pouvez voir l'appel entrant vers le serveur de base de données MySQL qui écoute sur le port
3306
de l'adresse IP100.96.4.8
. L'appel provient du pod d'entrée associé à l'adresse IP100.96.1.3
.Pour plus d'informations sur le format de journalisation Envoy, consultez la section Obtenir les journaux d'accès Envoy.
Testez votre base de données pour voir l'entrée générée :
MYSQL=$(kubectl --context ${SERVER_CLUSTER} get pods -n default | tail -n 1 | awk '{print $1}') kubectl --context ${SERVER_CLUSTER} exec $MYSQL -ti -- /bin/bash
Vérifiez la base de données créée :
mysql -pyougottoknowme USE test_encrypted_connection; SELECT * from message;
Le résultat ressemble à ce qui suit :
+------+-----------+ | id | content | +------+-----------+ | 1 | Crypto Hi | +------+-----------+ 1 row in set (0.00 sec)
Quittez la base de données MySQL :
exit exit
Vous devez utiliser la commande
exit
deux fois : une première fois pour fermer la connexion de base de données et une seconde fois pour quitter le pod.
Tester l'accès en omettant les certificats
Maintenant que vous avez testé et vérifié que l'accès fonctionne correctement avec les certificats injectés, vous pouvez faire le test inverse afin de vérifier ce qui se passe si vous omettez la passerelle de sortie et l'injection de certificats ? Ce type de test est également appelé test négatif.
Vous pouvez effectuer ce test en démarrant un autre pod dans un espace de noms dans lequel l'injection de proxy secondaire est désactivée.
Dans Cloud Shell, créez un espace de noms :
kubectl --context ${CLIENT_CLUSTER} create ns unencrypted
Créez un pod et démarrez une interface système interactive à l'intérieur du conteneur :
kubectl --context ${CLIENT_CLUSTER} run -it --image=mysql:5.6 \ mysql-client-2 --env=SERVICE_URL=$SERVICE_URL \ -n unencrypted --restart=Never -- /bin/bash
Essayez de vous connecter à la base de données une fois que l'interface système interactive a démarré :
mysql -pyougottoknowme -h $SERVICE_URL
Au bout de 30 secondes, un résultat semblable à celui-ci s'affiche :
Warning: Using a password on the command line interface can be insecure. ERROR 2003 (HY000): Can't connect to MySQL server on '104.154.164.12.nip.io' (110)
Cet avertissement est attendu car le pod omet la passerelle de sortie et tente d'atteindre la passerelle d'entrée (
$SERVICE_URL
) directement via Internet.Essayez de résoudre l'adresse IP du service :
resolveip $SERVICE_URL
Le résultat renvoyé ressemble à ceci : Votre adresse IP sera différente.
IP address of 104.154.164.12.nip.io is 104.154.164.12
Cela prouve que le nom de domaine complet peut être résolu et que l'échec de la connexion est effectivement dû à l'absence d'injection de certificats.
Fermez la connexion MySQL et quittez le pod du serveur MySQL :
exit exit
Approfondir l'enquête
Un sujet non abordé dans ce tutoriel est le fait que les configurations de sortie appartiennent généralement à un autre rôle ou à une autre organisation au sein de votre entreprise, car elles sont hébergées dans l'espace de noms istio-system
. Configurez les autorisations Kubernetes RBAC de sorte à ce que seuls les administrateurs réseau puissent créer et modifier directement les ressources décrites dans le présent tutoriel.
Maintenant que vous savez utiliser un maillage de services pour assurer une communication sécurisée, vous pouvez essayer de créer une application qui doit échanger des données de manière sécurisée et contrôler le chiffrement jusqu'à la couche de certificat. Pour commencer, vous pouvez installer Anthos Service Mesh.
Essayez d'utiliser deux clusters GKE et de les combiner à l'aide de la technique décrite dans le présent tutoriel. Cette technique fonctionne également sur la plate-forme GKE Enterprise entre deux clusters Kubernetes étrangers.
Les maillages de services sont un excellent moyen d'améliorer la sécurité au sein de votre cluster mais aussi lors des interactions avec des services externes. Un autre exercice consiste à avoir un point de terminaison mTLS qui n'est pas un deuxième cluster Kubernetes mais plutôt un fournisseur tiers (un fournisseur de paiement, par exemple).
Nettoyer
Pour éviter que les ressources utilisées lors de ce tutoriel ne soient facturées sur votre compte Google Cloud, vous pouvez supprimer le projet.
Supprimer le projet
- Dans la console Google Cloud, accédez à la page Gérer les ressources.
- Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
- Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.
Étape suivante
- Consultez le guide conceptuel associé.
- Pour connaître les bonnes pratiques relatives à la configuration de votre passerelle de sortie, consultez la page Utiliser les passerelles de sortie d'Anthos Service Mesh sur des clusters GKE : tutoriel.
- Consultez le guide de renforcement de GKE et le module Terraform associé.
- Découvrez des architectures de référence, des schémas et des bonnes pratiques concernant Google Cloud. Consultez notre Centre d'architecture cloud.