Le but : déployer les mêmes agents qu'en 12-1-1 (shell) et
12-1-2 (Terraform), mais comme une équipe Acme le fait sur la 3S :
personne ne lance terraform apply depuis son poste. On pousse du code sur GitHub, une pull request est relue,
et le merge sur main déploie, avec une identité de pipeline, un état Terraform partagé et aucune clé.
Le dossier : 03-bis-stack-3s/. Il réutilise le Terraform du
01-bis tel quel (aucune copie) : seul le chemin jusqu'à apply change.
Ce qu'est la 3S, et ce que ce guide n'invente pas. La 3S (Self Service Stack) est la plateforme cloud interne de Acme, sur GCP. Ce qui en est public (offres d'emploi, présentations) : GCP (Cloud Run, GKE), Terraform, GitHub Actions, FluxCD (GitOps sur GKE), Aiven (PostgreSQL, Kafka), Datadog / OpenTelemetry. Ses modules, ses noms de projets et son portail sont internes : ce guide ne les reproduit pas. Il construit le même modèle (Git → pipeline → Terraform → GCP) sur un projet à vous, pour comprendre ce que la 3S fait à votre place et savoir quoi demander à l'équipe 3S. Là où la 3S fournit déjà la brique, c'est indiqué « 3S : ».
Vérifié (15 octobre 2026, projet de test
second-project-511608) :terraform validateetfmtdu socle, du déploiement et du workflow ;terraform planréels du socle (24 ressources) et du déploiement (1 agent : 23, 2 agents : 31, tous : 87). Ce test a trouvé un défaut du 01-bis et du 02-bis, corrigé : avecagents = ["meteo"], le plan échouait (« Inconsistent conditional result types »), car les agents du catalogue n'ont pas tous les mêmes champs. Pas encore exécuté :terraform applydu socle et le premier passage du workflow dans GitHub (parties 3 à 6).
Sommaire
- Les mots à connaître
- Ce qui change par rapport à 12-1-1 et 12-1-2
- Pourquoi Cloud Run, et pas GKE + FluxCD
- Le socle : bucket d'état, compte de déploiement, confiance GitHub (une fois)
- Brancher le dépôt GitHub
- Déployer : une pull request, puis un merge
- Tester le pipeline sans GitHub (option)
- Ajouter un agent, en retirer un, connecter l'app
- Tout nettoyer
- Ce qui peut arriver
- Ce qu'il faut demander à l'équipe 3S
0. Les mots à connaître
| Mot | En clair |
|---|---|
| 3S | Self Service Stack : la plateforme interne de Acme qui donne aux équipes un projet GCP, des modules Terraform et un pipeline, déjà conformes (sécurité, réseau, observabilité). |
| GitOps | Git est la source de vérité : ce qui est sur main est ce qui tourne. On change l'infrastructure par une pull request, jamais à la main. |
| GitHub Actions | Les pipelines de GitHub : un fichier YAML dans .github/workflows/ lancé à chaque push ou pull request. |
| Workload Identity Federation (WIF) | Google fait confiance au jeton OIDC que GitHub donne à chaque exécution. Le pipeline obtient un jeton Google sans clé de compte de service. |
| Compte de déploiement | agents-deployer-sa : l'identité du pipeline. C'est lui qui crée les agents, plus votre compte personnel. |
| État Terraform distant | Le fichier d'état est dans un bucket GCS partagé (versionné), et non sur un poste : tout le monde, et le pipeline, voient le même. |
| Socle (bootstrap) | Ce qu'on crée une fois, avant le pipeline : le bucket, le compte de déploiement, la confiance GitHub. 3S : fourni par la plateforme. |
1. Ce qui change par rapport à 12-1-1 et 12-1-2
12-1-2 (Terraform local) 12-1-9 (« à la 3S »)
┌────────────┐ ┌────────────┐ PR ┌──────────────────────┐ merge ┌──────────────────────────┐
│ votre poste │ gcloud auth login │ votre poste │ ────▶ │ GitHub : relecture │ ────▶ │ GitHub Actions │
│ terraform │ terraform apply ──▶ GCP │ git push │ │ + terraform validate │ │ jeton OIDC ─▶ WIF ─▶ │
│ état local │ (votre compte, vos droits) └────────────┘ └──────────────────────┘ │ agents-deployer-sa │
└────────────┘ │ terraform plan + apply │
│ état : bucket GCS │
└────────────┬─────────────┘
▼
Projet des agents : exactement les ressources du 01-bis
(images Cloud Build, Cloud Run privés, identités, Agent Registry)
| 12-1-2 Terraform local | 12-1-9 « à la 3S » | |
|---|---|---|
Qui lance apply | Vous, sur votre poste | Le pipeline, au merge sur main |
| Avec quels droits | Les vôtres (souvent Owner) | Ceux de agents-deployer-sa, listés et limités |
| Où est l'état | terraform.tfstate.d/ sur le poste | gs://<projet>-tfstate/09-agents-a2a/ |
| Où sont les valeurs | config/…env ou terraform.tfvars (non versionné) | 03-bis-stack-3s/deploy/agents.auto.tfvars (versionné) |
| Clé de compte de service | — | Aucune (WIF) |
| Code Terraform des agents | 01-bis-cloud-run-a2a/terraform | Le même, appelé comme module |
Les fichiers :
| Fichier | Rôle |
|---|---|
03-bis-stack-3s/bootstrap/ | Le socle, appliqué une fois par un administrateur du projet. 3S : déjà fait pour vous |
03-bis-stack-3s/deploy/main.tf | Le backend GCS + l'appel du module ../../01-bis-cloud-run-a2a/terraform |
03-bis-stack-3s/deploy/agents.auto.tfvars | La configuration déployée : projet, agents, numéro du projet de l'app |
03-bis-stack-3s/github/deploy-agents.yml | Le workflow GitHub Actions, à copier dans .github/workflows/ |
2. Pourquoi Cloud Run, et pas GKE + FluxCD
La 3S propose aussi GKE avec FluxCD (des manifestes Kubernetes dans Git, synchronisés par Flux). Pour ces agents, on reste sur Cloud Run :
- Gemini Enterprise appelle un agent A2A avec son propre compte (
service-NUM_APP@gcp-sa-discoveryengine…) et un jeton d'identité Google. Cloud Run vérifie ce jeton tout seul (run.invoker). Sur GKE, il faudrait exposer l'agent (Ingress, certificat, IAP ou vérification du jeton dans le code) : plus de pièces, même résultat. - L'URL
.run.appest exigée pour l'authentification automatique (voir 01-bis, partie 1). - Coût : Cloud Run descend à 0 instance ; un agent peu utilisé ne coûte presque rien.
GKE + FluxCD reste le bon choix pour une API métier qui tourne déjà sur le cluster de l'équipe. L'agent, lui, peut appeler cette API depuis Cloud Run.
3. Le socle (une fois)
3S : sautez cette partie. Demandez à l'équipe 3S les trois valeurs de la partie 4 (fournisseur WIF, compte de déploiement, bucket d'état) et vérifiez que le compte a les rôles de la liste ci-dessous.
Qui : un administrateur du projet des agents (rôle Owner, ou resourcemanager.projectIamAdmin +
iam.workloadIdentityPoolAdmin + iam.serviceAccountAdmin + storage.admin), depuis son poste, une seule fois.
cd 09-agents-multi-projets-gemini-enterprise/03-bis-stack-3s/bootstrap
gcloud auth application-default login
cp terraform.tfvars.example terraform.tfvars # projet des agents + dépôt GitHub « organisation/depot »
terraform init
terraform plan # 24 ressources à créer
terraform apply
terraform output github_variablesCe que le socle crée :
| Ressource | Pourquoi |
|---|---|
Bucket <projet>-tfstate (versionné, jamais public) | L'état Terraform partagé ; le versionnement permet de revenir en arrière |
Compte agents-deployer-sa + 12 rôles | L'identité du pipeline : exactement ce que le 01-bis (et le projet 10) créent |
Pool WIF github + fournisseur github-oidc | Google accepte les jetons de GitHub, seulement ceux de votre dépôt (attribute_condition) |
workloadIdentityUser sur le compte | Seule la branche main peut emprunter le compte (…:ref:refs/heads/main) |
Les 12 rôles du compte de déploiement, et pourquoi (bootstrap/variables.tf) :
| Rôle | Pour |
|---|---|
serviceusage.serviceUsageAdmin | Activer les API (Cloud Run, Vertex AI, Agent Registry…) |
iam.serviceAccountAdmin | Créer l'identité de chaque agent |
iam.serviceAccountUser | Attacher ces identités aux services ; lancer Cloud Build avec agents-a2a-build-sa |
resourcemanager.projectIamAdmin | Donner à chaque identité ses rôles (aiplatform.user, logging.logWriter…) |
artifactregistry.admin | Le dépôt d'images agents-a2a |
cloudbuild.builds.editor, storage.admin, logging.viewer | gcloud builds submit : envoyer le code, construire, suivre le journal |
run.admin | Les services Cloud Run et leur droit d'appel (run.invoker de Gemini Enterprise) |
modelarmor.admin | Les templates Model Armor (si non fournis par le projet 08) |
agentregistry.admin | Les entrées Agent Registry |
aiplatform.admin | L'agent Agent Runtime du projet 10 (option) |
Attention,
projectIamAdminest puissant : le compte peut se donner d'autres rôles. C'est pour cela que seulmain(branche protégée, relecture obligatoire) peut l'utiliser. En production, on peut le restreindre avec une condition IAM qui liste les rôles qu'il a le droit de donner. 3S : c'est le genre de règle que la plateforme pose.
4. Brancher le dépôt GitHub
-
Copier le workflow à la racine du dépôt (GitHub ne lit que
.github/workflows/) :mkdir -p .github/workflows cp 09-agents-multi-projets-gemini-enterprise/03-bis-stack-3s/github/deploy-agents.yml .github/workflows/Si le dossier
09-…n'est pas à la racine de votre dépôt, corrigezpathsetWORKDIRdans le fichier. -
Les 3 variables (pas des secrets, rien de sensible) : GitHub → Settings → Secrets and variables → Actions → onglet Variables → New repository variable, avec la sortie
github_variables:Variable Exemple GCP_WIF_PROVIDERprojects/100000000002/locations/global/workloadIdentityPools/github/providers/github-oidcGCP_DEPLOYER_SAagents-deployer-sa@aiml-gemini-ent-exp-0zga.iam.gserviceaccount.comGCP_TFSTATE_BUCKETaiml-gemini-ent-exp-0zga-tfstate -
Protéger
main: Settings → Branches → règle surmain: pull request obligatoire, 1 relecture, le contrôleverifierdoit passer. -
Option, approbation manuelle avant chaque déploiement : Settings → Environments →
production→ Required reviewers. Le jobdeployerattend alors un clic « Approve ».
5. Déployer : une pull request, puis un merge
Choisir les agents dans 03-bis-stack-3s/deploy/agents.auto.tfvars :
agents_project_id = "aiml-gemini-ent-exp-0zga"
ge_project_number = "" # rempli à la partie 7
agents = ["meteo"] # [] = tous les agents de agents/trio/catalogue.jsongit switch -c agents/meteo
git add 09-agents-multi-projets-gemini-enterprise/03-bis-stack-3s/deploy/agents.auto.tfvars
git commit -m "agents : déployer meteo"
git push -u origin agents/meteo # puis ouvrir la pull request sur GitHubSur la pull request, le job verifier lance terraform fmt -check et terraform validate, sans accès à
Google Cloud (le jeton d'une PR ne peut pas emprunter le compte, partie 3). Un relecteur approuve, on merge.
Sur main, le job deployer :
| Étape | Ce qui se passe | Durée |
|---|---|---|
google-github-actions/auth | Jeton OIDC GitHub → jeton Google de agents-deployer-sa | 5 s |
terraform init | État lu dans gs://…-tfstate/09-agents-a2a/ | 10 s |
terraform plan | 23 ressources pour meteo au premier passage (vérifié) | 30 s |
terraform apply | Comme au 01-bis : API, identités, image construite par Cloud Build, service Cloud Run privé, Agent Registry | 4 à 6 min |
Vérifier : les journaux du job (onglet Actions du dépôt), puis la console (Cloud Run → meteo-a2a, Agent
Registry → région europe-west1) ou le test A2A du 01-bis :
cd 09-agents-multi-projets-gemini-enterprise/01-bis-cloud-run-a2a && ./test.sh6. Tester le pipeline sans GitHub (option)
Pour vérifier que le compte de déploiement suffit (aucun rôle oublié), on peut jouer le pipeline depuis son poste en empruntant ce compte. Il faut, une fois, le droit de l'emprunter :
PROJET=aiml-gemini-ent-exp-0zga
SA=agents-deployer-sa@$PROJET.iam.gserviceaccount.com
gcloud iam service-accounts add-iam-policy-binding $SA --project=$PROJET \
--member="user:$(gcloud config get-value account)" --role=roles/iam.serviceAccountTokenCreator
cd 09-agents-multi-projets-gemini-enterprise/03-bis-stack-3s/deploy
export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=$SA # Terraform agit en tant que le compte
export CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT=$SA # gcloud builds submit aussi
terraform init -backend-config=bucket=$PROJET-tfstate
terraform plan
terraform apply
unset GOOGLE_IMPERSONATE_SERVICE_ACCOUNT CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNTUn 403 Permission denied désigne le rôle manquant : ajoutez-le à roles dans bootstrap/variables.tf, puis
terraform apply dans bootstrap/. Retirez ensuite votre droit d'emprunt (remove-iam-policy-binding, mêmes options).
7. Ajouter un agent, en retirer un, connecter l'app
Toujours une pull request sur agents.auto.tfvars :
| Je veux | Je change | Effet au merge |
|---|---|---|
Ajouter taille | agents = ["meteo", "taille"] | Image, identité, service, entrée de registre de taille (8 ressources) ; meteo intact |
Retirer meteo | agents = ["taille"] | Supprime les ressources de meteo (le plan du job le montre : à relire) |
| Donner l'accès à l'app | ge_project_number = "<NUMÉRO du projet de l'app>" | run.invoker pour le compte de Gemini Enterprise sur chaque agent |
| Modifier le code d'un agent | agents/trio/<agent>/… | Nouvelle empreinte → nouvelle image → nouvelle révision de cet agent |
L'ajout dans l'app Gemini Enterprise reste l'étape de l'admin de l'app : 12-1-4
et 12-1-6. Publier depuis le pipeline (ge_app_id) est possible,
mais il faut alors donner au compte de déploiement un rôle d'admin Gemini Enterprise dans le projet de l'app :
à décider avec l'admin de l'app, pas par défaut.
8. Tout nettoyer
# 1. Les agents (avec le compte du pipeline, partie 6, ou un compte Owner)
cd 09-agents-multi-projets-gemini-enterprise/03-bis-stack-3s/deploy
terraform init -backend-config=bucket=<PROJET>-tfstate
terraform destroy
# 2. Le socle (supprime aussi le bucket d'état : à faire en dernier)
cd ../bootstrap && terraform destroyPuis retirer .github/workflows/deploy-agents.yml et les 3 variables du dépôt. Le pool WIF supprimé reste
30 jours en état « supprimé » : recréer un pool github avant ce délai demande gcloud iam workload-identity-pools undelete github --location=global.
9. Ce qui peut arriver
| Symptôme | Cause | Solution |
|---|---|---|
Unable to exchange token / unauthorized_client dans auth | Le dépôt ne correspond pas à github_repo (casse comprise) ou le job ne tourne pas sur main | Vérifier github_repo et la branche ; une PR n'a pas le droit (voulu) |
id-token absent | permissions: id-token: write manquant | Le garder dans le workflow |
Error acquiring the state lock | Un autre apply en cours, ou un job interrompu | Attendre ; sinon terraform force-unlock <ID> (l'ID est dans le message) |
403 sur cloudbuild ou storage pendant l'image | Rôle manquant au compte de déploiement | Partie 6, puis ajouter le rôle au socle |
Inconsistent conditional result types | Ancien 01-bis (avant le 15 octobre 2026) | Mettre à jour le dépôt (corrigé) |
| Le plan veut recréer des agents déjà déployés en local | État local (12-1-2) et état GCS distincts | Migrer l'état (même méthode que 10-15, partie 5, vérifiée), avec module.agents. comme préfixe ; ou détruire en local avant |
10. Ce qu'il faut demander à l'équipe 3S
- Le projet des agents, et s'il est déjà relié à un dépôt GitHub par la 3S (fournisseur WIF, compte de déploiement).
- Le bucket d'état (et son préfixe) à utiliser.
- Les rôles du compte de déploiement : comparer à la liste de la partie 3 ; ceux qui manquent sont souvent
agentregistry.adminetmodelarmor.admin(services récents). - Si la 3S impose ses modules Terraform (Cloud Run, comptes de service) : le 01-bis s'y adapte en remplaçant ses
ressources
google_cloud_run_v2_serviceetgoogle_service_accountpar ces modules ; la carte A2A, Agent Registry et le droit de Gemini Enterprise restent identiques. - Les règles d'organisation (VPC-SC, domaines autorisés, régions) : docs/05.