WebAssembly for Proxies est une nouvelle spécification qui permet aux développeurs de créer des plug-ins portables avec WebAssembly (Wasm). Ces plug-ins s'exécutent sur divers serveurs proxy. Service Mesh (ASM) prend en charge la spécification WebAssembly for Proxies. Cette rubrique explique comment écrire un plug-in Wasm en Go pour un proxy Envoy dans ASM.
Prérequis
Un cluster est ajouté à une instance ASM version 1.18 ou ultérieure. Pour plus d'informations sur l'ajout d'un cluster à une instance ASM, reportez-vous à la rubrique Ajouter un cluster à une instance ASM.
L'injection automatique du proxy sidecar est activée. Pour plus d'informations, consultez la section Configurer les politiques d'injection de sidecar.
Une passerelle d'entrée est déployée. Pour plus d'informations, voir Créer une passerelle d'entrée.
Une application HTTPBin est déployée et accessible. Pour savoir comment déployer une application HTTPBin, consultez la rubrique Déployer l'application HTTPBin.
Une instance Container Registry Enterprise Edition est créée. Les instances Container Registry Enterprise Edition prennent en charge les images Open Container Initiative (OCI). Pour plus d'informations, voir Créer une instance Enterprise Edition.
Informations générales
Wasm est un format binaire portable et émergent pour le code exécutable. Le code s'exécute à une vitesse quasi native dans un bac à sable sécurisé pour la mémoire (pour l'hôte). Ce bac à sable impose des contraintes de ressources clairement définies et fournit une API explicite pour communiquer avec l'environnement hôte d'intégration (ici, un proxy).
Les plug-ins Wasm offrent les avantages suivants :
Agilité : vous pouvez mettre à jour les plug-ins sans redémarrer le proxy Envoy. Ainsi, les requêtes sont traitées comme prévu.
Fiabilité et isolation : comme les plug-ins sont déployés dans un bac à sable avec des contraintes de ressources, ils peuvent planter sans entraîner l'arrêt du proxy Envoy.
Sécurité : étant déployés dans un bac à sable disposant d'une API clairement définie pour communiquer avec un proxy, les plug-ins sont strictement contrôlés.
Diversité : les plug-ins peuvent être écrits dans plusieurs langages de programmation, tels que C++, Go et Rust.
Pour en savoir plus sur les plug-ins Wasm, consultez WebAssembly-in-Envoy.md et OVERVIEW.md.
Exemple de configuration
Dans cet exemple, nous écrivons un plug-in Wasm en Go. Une fois le plug-in développé, nous générons un fichier binaire Wasm, puis nous l'encapsulons dans une image. L'image doit être poussée vers un registre d'images OCI. Après le push de l'image, configurez la ressource WasmPlugin dans ASM et appliquez le plug-in au proxy Envoy spécifié.
Dans cet exemple, un plug-in vérifie si une requête contient l'en-tête allow: true. Si ce n'est pas le cas, le code d'état 403 et le corps spécifié sont renvoyés. Sinon, l'application HTTPBin est accessible comme prévu.
Étape 1 : Préparer l'environnement de développement
Pour développer un plug-in Wasm en Go destiné à un proxy Envoy, installez d'abord les outils suivants :
Go : le compilateur Go et les outils associés servent à écrire des projets Go. Pour plus d'informations, voir The Go Programming Language.
Docker : dans cet exemple, Docker sert à construire et pousser des images OCI.
TinyGo : bien que Go soit utilisé pour écrire le plug-in Wasm, vous ne pouvez pas utiliser le compilateur Go officiel pour compiler le code Go au format Wasm. Vous devez utiliser TinyGo. Pour savoir comment installer TinyGo, consultez le Guide d'installation rapide.
Pour plus d'informations sur les SDK dont dépend le plug-in Wasm, consultez proxy-wasm-go-sdk sur GitHub. Vous y trouverez le code complet du SDK Go pour Proxy-Wasm. Si vous souhaitez utiliser d'autres SDK, inspirez-vous du code du SDK Go pour Proxy-Wasm.
Étape 2 : Écrire le code du plug-in
-
Créez un dossier et créez un fichier main.go contenant le contenu suivant :
-
Exécutez les commandes suivantes dans le dossier créé pour obtenir les dépendances du SDK :
go mod init go mod tidy -
Exécutez la commande suivante pour compiler le code en un fichier binaire Wasm :
tinygo build -o plugin.wasm -scheduler=none -target=wasi main.goUn fichier plugin.wasm est généré. Il s'agit du fichier exécutable binaire Wasm.
Étape 3 : Créer une image OCI du plug-in Wasm et la pousser vers l'instance Container Registry Enterprise Edition
-
Dans le dossier créé à l'étape Étape 2, créez un fichier Dockerfile contenant le contenu suivant :
FROM scratch ADD ./plugin.wasm ./plugin.wasm -
Exécutez la commande suivante pour créer une image :
docker build -t header-authorization:v0.0.1 . -
Créez un référentiel d'images. Pour plus d'informations, consultez les sous-étapes 2.a et 2.b de l'étape 1 de la rubrique Implémenter un WAF sur une passerelle ASM avec le plug-in Coraza Wasm.
Dans cet exemple, le namespace est
test-ociet le nom du référentiel estheader-authorization. La figure suivante montre le référentiel créé.Sur la page des détails du référentiel, dans la section Image Guide, la partie Push image to the Registry fournit les commandes pour se connecter à l'instance Registry avec
docker login, étiqueter l'image avecdocker tag [ImageId] <registry-url>/<namespace>/<repository>:[image-version]et pousser l'image avecdocker push <registry-url>/<namespace>/<repository>:[image-version]. Remplacez[ImageId]et[image-version]par les valeurs réelles.Pour plus d'informations sur la façon de pousser une image vers l'instance Container Registry Enterprise Edition, consultez Push image to the registry dans la figure précédente.
Étape 4 : Appliquer le plug-in Wasm à la passerelle d'entrée
-
Configurez les autorisations pour extraire les images. Pour plus d'informations, voir Étape 2 : Configurer les autorisations pour extraire les images.
Exécutez la commande suivante pour créer un Secret nommé
wasm-secret:kubectl create secret docker-registry -n istio-system wasm-secret --docker-server=${Domain name of the Container Registry Enterprise Edition instance} --docker-username =${Username} --docker-password =${Password} -
Créez un fichier asm-plugin.yaml contenant le contenu suivant :
apiVersion: extensions.istio.io/v1alpha1 kind: WasmPlugin metadata: name: header-authorization namespace: istio-system spec: imagePullPolicy: IfNotPresent imagePullSecret: wasm-secret selector: matchLabels: istio: ingressgateway url: oci://${Domain name of the Container Registry Enterprise Edition instance}/test-oci/header-authorization:v0.0.1 phase: AUTHN -
Connectez-vous à l'instance ASM avec kubectl en utilisant les informations du fichier kubeconfig. Ensuite, exécutez la commande suivante pour appliquer le plug-in Wasm à l'instance ASM :
kubectl apply -f wasm-plugin.yaml
Étape 5 : Vérifier que le plug-in Wasm prend effet
-
Utilisez le fichier kubeconfig du cluster sur le plan de données où réside la passerelle d'entrée et exécutez la commande suivante pour activer la fonctionnalité de journalisation de débogage pour le plug-in Wasm appliqué à la passerelle d'entrée :
kubectl -n istio-system exec ${Name of the pod where the ingress gateway resides} -c istio-proxy -- curl -XPOST "localhost:15000/logging?wasm=debug" -
Exécutez la commande suivante pour accéder à l'application HTTPBin exposée via la passerelle d'entrée :
curl ${IP address of the ingress gateway}/status/418Résultat attendu :
Forbidden by ASM Wasm Plugin -
Consultez les journaux du pod où réside la passerelle d'entrée.
Exemple de journaux :
2024-03-08T08:16:46.747394Z debug envoy wasm external/envoy/source/extensions/common/wasm/context.cc:1168 wasm log istio-system.header-authorization: request header: 'allow' is , only true can passthrough thread=24 {"bytes_received":"0","bytes_sent":"28","downstream_local_address":"xxxxxxx","downstream_remote_address":"xxxxxxxx","duration":"0","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"780c8493-13e4-4f97-9771-486efe30347c","requested_server_name":"-","response_code":"403","response_flags":"-","route_name":"httpbin","start_time":"2024-03-08T08:16:46.747Z","trace_id":"-","upstream_cluster":"outbound|8000||httpbin.default.svc.cluster.local","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_response_time":"-","upstream_transport_failure_reason":"-","user_agent":"curl/8.4.0","x_forwarded_for":"xxxxxx","authority_for":"xxxxxx"} -
Exécutez la commande suivante pour accéder à l'application HTTPBin exposée via la passerelle d'entrée :
curl ${IP address of the ingress gateway}/status/418 -H "allow: true"Résultat attendu :
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`Le résultat indique que l'application HTTPBin est accessible comme prévu.
Fuites de mémoire dans TinyGo
Des fuites de mémoire existent dans le plug-in Wasm pour un proxy Envoy compilé à l'aide de TinyGo. La communauté proxy-wasm-go-sdk recommande d'utiliser nottinygc pour optimiser la compilation. Suivez les étapes ci-dessous pour utiliser nottinygc afin d'optimiser la compilation :
-
Ajoutez le code
importsuivant au début du fichier main.go :import _ "github.com/wasilibs/nottinygc"Si aucune dépendance n'est trouvée, exécutez la commande
go mod tidypour télécharger automatiquement les dépendances. -
Exécutez la commande suivante pour compiler le code :
tinygo build -o plugin.wasm -gc=custom -tags='custommalloc nottinygc_envoy' -target=wasi -scheduler=none main.goLa commande précédente définit les paramètres
-gcet-tags. Pour plus d'informations, consultez nottinygc.