Déduire le routage à travers une passerelle

CloudflareBeginner
Pratiquer maintenant

Introduction

Dans le cours Workers AI, une application envoyait une invite directement à un modèle hébergé par Cloudflare. Cette méthode fonctionne, mais une application qui se développe a également besoin d’un point central pour observer et contrôler le trafic vers les modèles. Cloudflare AI Gateway joue ce rôle de point de contrôle : l’appelant envoie une requête à une passerelle nommée, puis la passerelle transmet la requête à un fournisseur de modèles en amont tel que Workers AI.

Cet atelier maintient clairement les trois rôles :

  • l’appelant est curl dans votre VM LabEx ;
  • la passerelle vérifie si l’appelant est autorisé à y accéder et enregistre la requête ;
  • le fournisseur en amont est Workers AI, qui vérifie si la requête peut exécuter le modèle.

Ces deux dernières vérifications utilisent des identifiants distincts. cf-aig-authorization authentifie l’appelant auprès d’AI Gateway. L’en-tête Authorization standard authentifie la requête de la passerelle auprès de Workers AI. Un jeton de passerelle valide n’est pas automatiquement un identifiant Workers AI, et un identifiant Workers AI ne permet pas de contourner une passerelle authentifiée.

Vous allez créer une passerelle authentifiée temporaire dans le Cloudflare Dashboard, créer un jeton AI Gateway à portée limitée, envoyer une requête courte au modèle Llama 3.3 hébergé par Cloudflare et examiner le journal correspondant. Vous remplacerez ensuite uniquement l’identifiant de la passerelle par une valeur invalide afin de vérifier quelle frontière rejette la requête. Enfin, vous supprimerez la passerelle, supprimerez son jeton afin qu’il ne puisse plus autoriser de requêtes, puis vous déconnecterez Wrangler.

Si vous avez accédé directement à ce cours, commencez par suivre Connect LabEx to Your Cloudflare Account. Cette leçon présente le terminal de la VM LabEx, l’autorisation de l’appareil Wrangler, la confirmation du compte et l’utilisation explicite des identifiants de compte. L’atelier d’inférence Workers AI constitue également un prérequis utile.

AI Gateway est disponible avec le forfait Free, et ses fonctions essentielles de journalisation sont gratuites dans les limites du compte. Le modèle sélectionné @cf/meta/llama-3.3-70b-instruct-fp8-fast peut utiliser l’allocation gratuite partagée de Workers AI avec la facturation Standard. Workers Paid et Unified Billing ne sont pas nécessaires. Si l’allocation quotidienne Workers AI du compte est indisponible, arrêtez-vous au lieu de relancer la requête à plusieurs reprises.

La configuration installe Node.js 22.22.0 ainsi que Wrangler 4.132.0, installé localement dans le projet, sous /home/labex/project/ai-gateway-route. Elle fournit des évaluations indépendantes en lecture seule, mais n’autorise pas Wrangler, ne crée ni jeton ni passerelle, n’envoie aucune inférence et ne modifie pas votre compte Cloudflare. LabEx ne conserve pas cette VM temporaire à la fin de l’atelier. Vous devrez tout de même supprimer explicitement le jeton cloud et effacer sa copie présente dans la VM afin que le nettoyage soit terminé avant la destruction de la VM.

Autoriser la VM et enregistrer les noms des ressources

Dans cette étape, vous allez connecter la nouvelle VM à votre compte d’apprentissage et enregistrer des noms qui permettront d’identifier sans ambiguïté les ressources de cet atelier.

La connexion de l’appareil Wrangler autorise l’accès à Workers AI, mais elle ne crée pas l’identifiant distinct d’appelant AI Gateway utilisé plus tard. Le fait de conserver ces identifiants séparés permet de mieux visualiser la frontière de confiance.

Accédez au projet préparé et vérifiez la version épinglée de la CLI :

cd /home/labex/project/ai-gateway-route
npx wrangler --version

Vous devez obtenir 4.132.0. Lancez l’autorisation de l’appareil avec l’identité du compte et l’accès à Workers AI :

npx wrangler login --device --browser=false --scopes account:read user:read ai:write

Ouvrez le lien affiché, saisissez le code et autorisez le compte d’apprentissage prévu. Examinez ensuite l’identité structurée :

npx wrangler whoami --json

Vérifiez que loggedIn: true apparaît. Créez un identifiant de passerelle unique ainsi que le nom du jeton associé. Remplacez YOUR_ACCOUNT_ID par l’identifiant réel de 32 caractères affiché pour le compte prévu :

GATEWAY_ID="labex-c09-g01-$(openssl rand -hex 6)"
TOKEN_NAME="$GATEWAY_ID-token"
cat > .labex/state.json <<JSON
{
  "accountId": "YOUR_ACCOUNT_ID",
  "gatewayId": "$GATEWAY_ID",
  "tokenName": "$TOKEN_NAME"
}
JSON
cat .labex/state.json

Le suffixe aléatoire évite les collisions. Le fichier d’état contient des identifiants de ressources, et non des identifiants secrets. Il permet à toutes les commandes suivantes de cibler exactement les ressources créées par cet atelier.

Créer une passerelle authentifiée et un jeton d’appelant

Dans cette étape, vous allez créer le point de contrôle ainsi qu’un identifiant permettant de l’appeler et de l’inspecter.

Ouvrez le Cloudflare Dashboard et sélectionnez AI → AI Gateway → Create gateway → Custom gateway. Utilisez la valeur gatewayId du fichier .labex/state.json comme nom de la passerelle. Conservez les paramètres suivants :

  • journalisation des requêtes : activée ;
  • authentification de la passerelle : activée ;
  • cache, limites de débit, limites de dépenses et nouvelles tentatives : désactivés ;
  • facturation Workers AI : Standard.

La facturation Standard conserve l’utilisation de Workers AI dans son allocation habituelle. Unified Billing correspond à un autre mode de paiement et n’est pas couvert par cet atelier pour débutants.

Lorsque Cloudflare ouvre la nouvelle ressource, utilisez le fil d’Ariane et l’onglet Overview sélectionné pour vérifier que vous êtes bien dans la passerelle temporaire exacte, et non dans la liste des passerelles du compte.

La vue Overview de la nouvelle passerelle, avec son identifiant unique et des métriques encore vides

Après la création, ouvrez Settings. Vérifiez que l’identifiant de passerelle affiché correspond exactement à celui que vous avez enregistré, et que la journalisation ainsi que l’authentification sont activées.

Choisissez ensuite Create an AI Gateway authentication token. Donnez-lui le nom enregistré dans tokenName, sélectionnez uniquement le compte d’apprentissage prévu et ajoutez les autorisations suivantes :

  • AI Gateway — Run permet à l’appelant d’accéder à une passerelle authentifiée ;
  • AI Gateway — Edit permet à l’atelier de lire et de supprimer les ressources AI Gateway via l’API de gestion.

N’ajoutez pas d’autorisation Workers AI à ce jeton. Workers AI reste autorisé par l’identifiant distinct et à courte durée obtenu avec Wrangler.

Le formulaire d’autorisations du jeton, limité à AI Gateway Run et Edit

Créez le jeton uniquement après avoir vérifié le compte et les autorisations. Cloudflare n’affiche sa valeur qu’une seule fois. Enregistrez-la de manière privée sans l’afficher dans le terminal :

bash -c '
while :; do
  read -rsp "Paste the AI Gateway token: " GATEWAY_TOKEN
  printf "\n"
  [ -n "$GATEWAY_TOKEN" ] && break
  printf "Token cannot be empty; paste it again.\n" >&2
done
umask 077
printf "%s" "$GATEWAY_TOKEN" > .labex/gateway-token
unset GATEWAY_TOKEN
chmod 600 .labex/gateway-token
'

Le terminal préparé utilise zsh de manière interactive. Ce bloc démarre donc un court sous-processus Bash pour utiliser l’invite masquée de read. Une saisie vide est refusée avant le retour de la commande vers le shell. Le jeton reste uniquement dans le sous-processus et dans le fichier privé.

Le jeton est volontairement conservé en dehors de la configuration et de la sortie des commandes. Vérifiez la passerelle réelle via l’API de gestion authentifiée :

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s),g=b.result||{};console.log(JSON.stringify({success:b.success,id:g.id,collect_logs:g.collect_logs,authentication:g.authentication},null,2))})'
unset GATEWAY_TOKEN

Vous devez obtenir l’identifiant créé, avec collect_logs et authentication définis sur true. Aucun secret ne doit s’afficher.

La vue Settings de la passerelle, affichant l’authentification, les journaux et la facturation Standard

Acheminer une requête Workers AI via la passerelle

Dans cette étape, vous allez envoyer une petite requête via la passerelle au lieu de l’envoyer directement à Workers AI.

L’URL de la passerelle propre au fournisseur contient le compte, la passerelle, le fournisseur et le modèle. Les deux en-têtes d’autorisation restent volontairement séparés :

caller → cf-aig-authorization → AI Gateway → Authorization → Workers AI model

Obtenez le jeton Workers AI à courte durée actuellement utilisé par Wrangler sous forme de données structurées, puis envoyez la requête. La commande écrit uniquement la réponse JSON sur le disque ; aucun des deux identifiants n’est affiché :

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(npx wrangler auth token --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
curl --http1.1 -fsS \
  -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"In one sentence, explain why an AI gateway is useful.","max_tokens":64}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL" \
  > .labex/valid-response.json
unset GATEWAY_TOKEN UPSTREAM_TOKEN
node -e 'const b=require("./.labex/valid-response.json"); console.log(b.result?.response ?? b.result)'

La formulation peut varier, car la génération n’est pas déterministe. L’évaluation vérifie uniquement que le fournisseur a renvoyé un résultat non vide et réussi via la passerelle créée par cet atelier.

Isoler la frontière d’authentification de la passerelle

Dans cette étape, vous allez conserver l’identifiant Workers AI valide, mais remplacer uniquement l’identifiant de la passerelle.

Un test négatif contrôlé doit modifier une seule condition à la fois. Si les deux identifiants étaient invalides, un échec HTTP ne permettrait pas de savoir quel système a rejeté la requête. Cette requête conserve le jeton amont valide de Wrangler et envoie une valeur cf-aig-authorization clairement invalide :

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
UPSTREAM_TOKEN=$(npx wrangler auth token --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
STATUS=$(curl --http1.1 -sS -o .labex/invalid-response.json -w '%{http_code}' \
  -H 'cf-aig-authorization: Bearer deliberately-invalid' \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"This request must not reach the model.","max_tokens":8}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset UPSTREAM_TOKEN
printf '%s\n' "$STATUS" | tee .labex/invalid-status.txt

Vous devez obtenir 401 ou 403. N’affichez pas le corps de la réponse : le statut fournit une preuve suffisante, et limiter la sortie d’erreur réduit le risque d’exposer des détails de la requête.

Relier la requête à son journal de passerelle

Dans cette étape, vous allez utiliser l’observabilité pour relier le comportement à l’exécution à une entrée visible de la passerelle.

L’observabilité consiste à recueillir suffisamment d’éléments pour expliquer ce qu’un système a fait après le départ d’une requête de l’appelant. Un journal de passerelle peut afficher le fournisseur, le modèle, le statut, la latence et l’utilisation des jetons sans demander une nouvelle fois au modèle. Les journaux peuvent mettre un court moment à apparaître.

Lisez les journaux existants via l’API de gestion authentifiée. Cette vérification est en lecture seule ; elle n’envoie aucune nouvelle requête au modèle :

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID/logs?per_page=50" \
  > .labex/logs.json
unset GATEWAY_TOKEN
node - <<'NODE'
const body = require('./.labex/logs.json')
const model = '@cf/meta/llama-3.3-70b-instruct-fp8-fast'
const matches = (body.result || []).filter(row =>
  row.provider === 'workers-ai' && row.model === model
)
console.log(matches.map(row => ({
  id: row.id,
  provider: row.provider,
  model: row.model,
  success: row.success,
  created_at: row.created_at
})))
if (!matches.some(row => row.success === true)) process.exit(2)
NODE

Vous devez obtenir une entrée avec provider: "workers-ai", le modèle prévu et success: true. Si la commande se termine sans cette entrée, attendez environ 20 secondes et réexécutez ce même bloc en lecture seule au lieu d’envoyer d’autres requêtes d’inférence.

Ouvrez la vue Logs de la passerelle dans le Dashboard. Repérez la ligne Workers AI réussie correspondant à @cf/meta/llama-3.3-70b-instruct-fp8-fast. Vérifiez le succès, le fournisseur et le modèle avant d’ouvrir le panneau de détails.

Le tableau Logs de la passerelle, avec la requête Workers AI réussie mise en évidence

La durée exacte, le nombre de jetons et le texte généré peuvent varier. Ces valeurs décrivent cette requête ; elles ne constituent pas des résultats à reproduire exactement. Ne placez jamais d’identifiants ni d’informations personnelles dans une invite uniquement pour retrouver plus facilement un journal.

Le panneau de détails du journal affichant le modèle, le statut, la latence et l’utilisation des jetons

Supprimer la passerelle temporaire

Dans cette étape, vous allez supprimer la ressource cloud tant que son identifiant de gestion est encore disponible.

Le nettoyage doit cibler l’identifiant exact de la ressource créée par cet atelier et doit être confirmé par un inventaire authentifié. Une page introuvable causée par une déconnexion ou une défaillance réseau ne prouve pas la suppression.

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS -X DELETE \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s);if(!b.success)process.exit(1);console.log("gateway deletion accepted")})'
unset GATEWAY_TOKEN

GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways" \
  > .labex/gateways-after-delete.json
unset GATEWAY_TOKEN
node -e 'const b=require("./.labex/gateways-after-delete.json"),id=process.argv[1],found=(b.result||[]).some(g=>g.id===id);console.log("gateway absent:",!found);if(found)process.exit(1)' "$GATEWAY_ID"

Vous devez obtenir gateway absent: true. Cette seconde requête répertorie les passerelles avec une autorisation valide et échoue si l’identifiant créé par l’atelier existe encore. Les autres passerelles de votre compte ne sont jamais modifiées.

Supprimer le jeton et se déconnecter

Dans cette étape, vous allez supprimer les deux identifiants indépendants dans l’ordre inverse de leur utilisation.

Dans le Cloudflare Dashboard, ouvrez My Profile → API Tokens. Recherchez le nom exact du jeton enregistré dans .labex/state.json, ouvrez son menu Actions, choisissez Delete, vérifiez la confirmation, puis supprimez uniquement ce jeton. La suppression du jeton révoque immédiatement son accès. Vous pouvez le supprimer maintenant, car la passerelle a déjà été supprimée.

Supprimez sa copie locale, puis terminez l’autorisation distincte de Wrangler dans la VM :

shred -u .labex/gateway-token
npx wrangler logout
npx wrangler whoami --json || true

Vous devez obtenir une sortie structurée contenant loggedIn: false. La session du navigateur dans le Dashboard est distincte et reste ouverte. Exécutez la dernière vérification locale :

test ! -e .labex/gateway-token && echo "local gateway token removed"

Le message confirme que la copie présente dans la VM a disparu. Le bouton Check de LabEx répète indépendamment les vérifications du fichier local et de la déconnexion de Wrangler ; son script backend ne fait volontairement pas partie du projet de l’apprenant.

Vous avez maintenant supprimé la passerelle, supprimé son jeton d’appelant et de gestion, effacé la copie locale du jeton et déconnecté la nouvelle VM. Lorsque vous terminerez l’atelier, LabEx détruira cette VM temporaire au lieu de la conserver ; le nettoyage cloud reste néanmoins important, car la destruction d’une VM ne peut ni révoquer un jeton Cloudflare ni supprimer une passerelle.

Résumé

Vous avez créé une Cloudflare AI Gateway authentifiée et acheminé une véritable inférence Workers AI à travers celle-ci. Vous avez séparé l’autorisation de la passerelle de celle du modèle en amont, modifié un seul identifiant pour identifier la frontière qui rejetait la requête et relié la requête réussie à son journal de passerelle. Enfin, vous avez prouvé la suppression authentifiée de la ressource avant de supprimer le jeton et de déconnecter la VM.

L’atelier suivant s’appuie sur ce chemin de requête observable. Vous y associerez de petites métadonnées non secrètes, suivrez un échec volontaire et utiliserez les éléments fournis par la passerelle au lieu de deviner où la requête a échoué.