Tester de bout en bout et nettoyer
Les vérifications
NUM=$(gcloud projects describe "$PROJECT_ID" --format 'value(projectNumber)')
STOCK_URL="https://lab-a2a-stock-${NUM}.europe-west1.run.app"
CMD_URL="https://lab-a2a-commandes-${NUM}.europe-west1.run.app"
curl -s -o /dev/null -w "stock sans jeton : HTTP %{http_code}\n" "$STOCK_URL/.well-known/agent-card.json"
curl -s -o /dev/null -w "commandes sans jeton : HTTP %{http_code}\n" "$CMD_URL/.well-known/agent-card.json"
export ID_TOKEN=$(gcloud auth print-identity-token)
python client_a2a.py "$CMD_URL" "Je voudrais un devis pour 500 VIS-M6."
python client_a2a.py "$CMD_URL" "Devis pour 400 écrous ECR-M6 ?"flowchart LR A["curl sans jeton"] -->|"403"| S1["stock"] B["curl sans jeton"] -->|"403"| C1["commandes"] D["client_a2a.py + votre jeton"] -->|"200"| C2["commandes"] C2 -->|"200, jeton du SA lab-a2a-commandes"| S2["stock"]
L'erreur du premier essai : la propagation IAM
Notre premier appel, lancé juste après le déploiement, a renvoyé une tâche TASK_STATE_FAILED. Le message d'état de la tâche disait :
403 PERMISSION_DENIED. Permission 'aiplatform.endpoints.predict' denied on resource
'//aiplatform.googleapis.com/projects/mon-projet-gcp/locations/europe-west1/publishers/google/models/gemini-2.5-flash'Le rôle roles/aiplatform.user venait d'être accordé au compte de service : un changement IAM met en général quelques minutes à se propager. Deux minutes plus tard, le même appel réussissait, sans rien changer.
| Symptôme | Cause probable | Que faire |
|---|---|---|
403 HTML de Cloud Run, sans tâche A2A | jeton absent, expiré, mauvaise audience, ou pas de run.invoker | vérifier le jeton et la liaison IAM du service |
tâche FAILED avec PERMISSION_DENIED Vertex AI | rôle du compte de service pas encore propagé (ou absent) | attendre quelques minutes, puis vérifier les rôles |
AgentCardResolutionError | URL de carte différente de l'URL utilisée | aligner PUBLIC_URL et STOCK_URL sur la même forme d'URL |
La tâche A2A est en TASK_STATE_FAILED avec PERMISSION_DENIED sur aiplatform.endpoints.predict, cinq minutes après le déploiement. Qu'est-ce que cela prouve ?
Une tâche A2A n'est produite que par le code de l'agent : la requête est donc entrée. L'erreur vient de l'appel suivant, du conteneur vers Vertex AI, avec l'identité du service. Juste après une attribution de rôle, c'est presque toujours la propagation IAM.
Résultat obtenu
Sorties réelles du 2026-10-15 (deuxième essai), identifiants masqués :
stock sans jeton : HTTP 403
commandes sans jeton : HTTP 403
AGENT : agent_commandes
ETAT : TASK_STATE_COMPLETED
OUTILS : ['agent_stock', 'calculer_devis']
REPONSE : Voici le devis pour 500 VIS-M6 :
* **Total HT :** 40.00 €
* **TVA (20%) :** 8.00 €
* **Total TTC :** 48.00 €
AGENT : agent_commandes
ETAT : TASK_STATE_COMPLETED
OUTILS : ['agent_stock']
REPONSE : Il n'y a que 300 unités de la référence ECR-M6 disponibles. Je peux vous faire un devis pour cette quantité, ou pour une livraison partielle de 300 unités.Les journaux de requêtes du service stock montrent le refus sans jeton, puis les appels authentifiés :
gcloud logging read 'resource.type="cloud_run_revision" AND resource.labels.service_name="lab-a2a-stock" AND httpRequest.requestMethod:*' \
--project "$PROJECT_ID" --freshness 20m --limit 6 \
--format 'table(timestamp,httpRequest.requestMethod,httpRequest.status,httpRequest.requestUrl.basename())'TIMESTAMP REQUEST_METHOD STATUS REQUEST_URL
2026-10-15T14:45:06.240940Z POST 200
2026-10-15T14:44:02.656985Z GET 200 agent-card.json
2026-10-15T14:44:01.559036Z GET 403 agent-card.jsonVotre propre compte (Propriétaire du projet) peut-il appeler lab-a2a-stock directement ?
Les rôles se cumulent par héritage : Propriétaire sur le projet couvre run.invoker sur chaque service. C'est ce qui nous a permis de lire la carte du stock avec notre jeton (le GET 200). La liaison sur le service ajoute un appelant, elle n'enlève pas les droits hérités. En production, limitez qui a des rôles larges au niveau du projet.
Tout supprimer
for S in lab-a2a-stock lab-a2a-commandes; do
gcloud run services delete "$S" --region "$REGION" --project "$PROJECT_ID" --quiet
gcloud projects remove-iam-policy-binding "$PROJECT_ID" --condition None \
--member "serviceAccount:${S}@${PROJECT_ID}.iam.gserviceaccount.com" --role roles/aiplatform.user
gcloud iam service-accounts delete "${S}@${PROJECT_ID}.iam.gserviceaccount.com" --project "$PROJECT_ID" --quiet
done
gcloud artifacts repositories delete lab-agents-a2a --location "$REGION" --project "$PROJECT_ID" --quietLa liaison run.invoker disparaît avec le service. Le dépôt lab-agents-a2a étant propre au lab, on le supprime entièrement (image et couches comprises). Reste l'archive des sources envoyée par gcloud builds submit dans gs://<projet>_cloudbuild/source/ (quelques Ko) : à supprimer si ce bucket ne sert qu'à vous.
Résultat obtenu (nettoyage)
Deleted service [lab-a2a-stock].
deleted service account [lab-a2a-stock@mon-projet-gcp.iam.gserviceaccount.com]
Deleted service [lab-a2a-commandes].
deleted service account [lab-a2a-commandes@mon-projet-gcp.iam.gserviceaccount.com]
Deleted repository [lab-agents-a2a].
--- Vérification (doit être vide) ---Exercice
Ajoutez à nettoyer.sh une vérification qui échoue (code de sortie non nul) s'il reste un service, un compte de service ou un dépôt dont le nom commence par lab-a2a- ou lab-agents-a2a.
Voir la solution
RESTE=$( { gcloud run services list --project "$PROJECT_ID" --format 'value(metadata.name)';
gcloud iam service-accounts list --project "$PROJECT_ID" --format 'value(email)';
gcloud artifacts repositories list --project "$PROJECT_ID" --format 'value(name)'; } \
| grep -E 'lab-a2a-|lab-agents-a2a' )
if [ -n "$RESTE" ]; then
echo "Ressources restantes :"; echo "$RESTE"; exit 1
fi
echo "Nettoyage vérifié : rien ne reste."grep sans résultat laisse RESTE vide : le script se termine normalement. Lancez-le dans votre CI après chaque test d'intégration.
Je sais faire
- Prouver qu'un agent A2A déployé est privé
- Appeler un agent A2A sur Cloud Run avec un jeton d'identité
- Distinguer un refus IAM Cloud Run d'un refus Vertex AI dans une tâche A2A
- Supprimer services, comptes, rôles et dépôt, et le vérifier