WebAssembly for Proxies é uma nova especificação que permite aos desenvolvedores criar plug-ins portáteis usando WebAssembly (Wasm). Esses plug-ins podem ser executados em diversos servidores proxy. O Service Mesh (ASM) oferece suporte à especificação WebAssembly for Proxies. Este tópico descreve como escrever um plug-in Wasm em Go para um proxy Envoy no ASM.
Pré-requisitos
Um cluster adicionado a uma instância do ASM com versão 1.18 ou posterior. Para obter mais informações sobre como adicionar um cluster a uma instância do ASM, consulte Adicionar um cluster a uma instância do ASM.
A injeção automática de proxy sidecar ativada. Para obter mais informações, consulte Configurar políticas de injeção de sidecar.
Um gateway de entrada implantado. Para obter mais informações, consulte Criar um gateway de entrada.
Uma aplicação HTTPBin implantada e acessível. Para saber mais sobre como implantar uma aplicação HTTPBin, consulte Implantar a aplicação HTTPBin.
Uma instância do Container Registry Enterprise Edition criada. As instâncias do Container Registry Enterprise Edition suportam imagens da Open Container Initiative (OCI). Para obter mais informações, consulte Criar uma instância Enterprise Edition.
Informações básicas
O Wasm é um formato binário portátil e emergente para código executável. O código é executado com velocidade quase nativa em uma sandbox segura para memória (para o host). Essa sandbox possui restrições de recursos bem definidas e fornece uma API clara para comunicação com o ambiente host incorporado (neste caso, refere-se a um proxy).
Os plug-ins Wasm oferecem os seguintes benefícios:
Agilidade: É possível atualizar plug-ins sem reiniciar o proxy Envoy, garantindo que as requisições sejam tratadas conforme o esperado.
Confiabilidade e isolamento: Como os plug-ins são implantados dentro de uma sandbox com restrições de recursos, eles podem falhar sem derrubar o proxy Envoy.
Segurança: A implantação ocorre em uma sandbox com uma API bem definida para comunicação com o proxy, o que garante controle rigoroso.
Diversidade: Os plug-ins podem ser escritos em várias linguagens de programação, como C++, Go e Rust.
Para obter mais informações sobre plug-ins Wasm, consulte WebAssembly-in-Envoy.md e OVERVIEW.md.
Exemplo de configuração
Neste exemplo, um plug-in Wasm é escrito em Go. Após a criação do plug-in, um arquivo binário Wasm é gerado e empacotado em uma imagem. Essa imagem deve ser enviada para um repositório de imagens OCI. Depois do envio, configure o recurso WasmPlugin no ASM e aplique o plug-in ao proxy Envoy especificado.
Este exemplo desenvolve um plug-in para verificar se uma requisição contém o cabeçalho allow: true. Caso contrário, o sistema retorna o código de status 403 e um corpo específico. Se o cabeçalho estiver presente, a aplicação HTTPBin poderá ser acessada normalmente.
Etapa 1: Preparar um ambiente de desenvolvimento
Para desenvolver um plug-in Wasm em Go para um proxy Envoy, instale primeiro as seguintes ferramentas:
Go: O compilador Go e ferramentas relacionadas são usados para escrever projetos Go. Para obter mais informações, consulte The Go Programming Language.
Docker: Neste exemplo, o Docker é utilizado para compilar e enviar imagens OCI.
TinyGo: Embora o Go seja usado para escrever o plug-in Wasm, não é possível usar o compilador oficial do Go para compilar código Go no formato Wasm. Use o TinyGo. Para saber mais sobre como instalar o TinyGo, consulte Guia de instalação rápida.
Para obter mais informações sobre os SDKs dos quais o plug-in Wasm depende, consulte proxy-wasm-go-sdk no site do GitHub. Você encontra o código completo do SDK Go para Proxy-Wasm no site. Caso queira usar outros SDKs, consulte o código do SDK Go para Proxy-Wasm como referência.
Etapa 2: Escrever o código do plug-in
-
Crie uma pasta e crie um arquivo main.go com o seguinte conteúdo:
-
Execute os seguintes comandos na pasta criada para obter as dependências do SDK:
go mod init go mod tidy -
Execute o comando a seguir para compilar o código em um arquivo binário Wasm:
tinygo build -o plugin.wasm -scheduler=none -target=wasi main.goUm arquivo plugin.wasm é gerado. Esse arquivo é o executável binário Wasm.
Etapa 3: Criar uma imagem OCI do plug-in Wasm e enviá-la para a instância do Container Registry Enterprise Edition
-
Na pasta criada na Etapa 2, crie um arquivo Dockerfile com o seguinte conteúdo:
FROM scratch ADD ./plugin.wasm ./plugin.wasm -
Execute os comandos a seguir para criar uma imagem:
docker build -t header-authorization:v0.0.1 . -
Crie um repositório de imagens. Para obter mais informações, consulte as subetapas 2.a e 2.b da Etapa 1 no tópico Implementar um WAF em um gateway ASM com o plug-in Coraza Wasm.
Neste exemplo, o namespace é
test-ocie o nome do repositório éheader-authorization. A figura a seguir mostra o repositório criado.Na página de detalhes do repositório, em Image Guide, a seção Push image to the Registry fornece os comandos para fazer login na instância do Registry com
docker login, marcar a imagem comdocker tag [ImageId] <registry-url>/<namespace>/<repository>:[image-version]e enviar a imagem comdocker push <registry-url>/<namespace>/<repository>:[image-version]. Substitua[ImageId]e[image-version]pelos valores reais.Para obter mais informações sobre como enviar uma imagem para a instância do Container Registry Enterprise Edition, consulte Push image to the registry na figura anterior.
Etapa 4: Aplicar o plug-in Wasm ao gateway de entrada
-
Configure as permissões para baixar imagens. Para obter mais informações, consulte Etapa 2: Configurar permissões para baixar imagens.
Execute o comando a seguir para criar um Secret chamado
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} -
Crie um arquivo asm-plugin.yaml com o seguinte conteúdo:
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 -
Use o kubectl para conectar-se à instância do ASM com base nas informações do arquivo kubeconfig. Em seguida, execute o comando a seguir para aplicar o plug-in Wasm à instância do ASM:
kubectl apply -f wasm-plugin.yaml
Etapa 5: Verificar se o plug-in Wasm entrou em vigor
-
Use o arquivo kubeconfig do cluster no plano de dados onde reside o gateway de entrada e execute o comando a seguir para ativar o recurso de log de depuração do plug-in Wasm aplicado ao gateway de entrada:
kubectl -n istio-system exec ${Name of the pod where the ingress gateway resides} -c istio-proxy -- curl -XPOST "localhost:15000/logging?wasm=debug" -
Execute o comando a seguir para acessar a aplicação HTTPBin exposta pelo gateway de entrada:
curl ${IP address of the ingress gateway}/status/418Saída esperada:
Forbidden by ASM Wasm Plugin -
Visualize os logs do pod onde o gateway de entrada reside.
Logs de exemplo:
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"} -
Execute o comando a seguir para acessar a aplicação HTTPBin exposta pelo gateway de entrada:
curl ${IP address of the ingress gateway}/status/418 -H "allow: true"Saída esperada:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`A saída indica que a aplicação HTTPBin pode ser acessada conforme o esperado.
Vazamentos de memória no TinyGo
Existem vazamentos de memória no plug-in Wasm para um proxy Envoy compilado com o TinyGo. A comunidade proxy-wasm-go-sdk recomenda o uso do nottinygc para otimização da compilação. Siga as etapas abaixo para usar o nottinygc na otimização da compilação:
-
Adicione o seguinte código
importno início do arquivo main.go:import _ "github.com/wasilibs/nottinygc"Se nenhuma dependência for encontrada, execute o comando
go mod tidypara baixar as dependências automaticamente. -
Execute o comando a seguir para compilar o código:
tinygo build -o plugin.wasm -gc=custom -tags='custommalloc nottinygc_envoy' -target=wasi -scheduler=none main.goO comando anterior define os parâmetros
-gce-tags. Para obter mais informações, consulte nottinygc.