Lección 8 — Mise en œuvre de la note

01. Préparer Terraform et reprendre ce qui a été fait en console

6 min de lectura

Este contenido aún no está traducido. Se muestra la versión original.

Pour qui : DevOps / plateforme. Durée : une demi-journée.


1. Se connecter

Terraform utilise les identifiants applicatifs (ADC), pas ceux de la commande gcloud. Il faut les deux :

gcloud auth login                          # pour gcloud
gcloud auth application-default login      # pour Terraform et les scripts Python
gcloud config set project acme-ge-recette

En CI, pas de connexion manuelle : la CI utilise une fédération d'identité (fiche 06).


2. Un état distant, partagé et protégé

L'état (terraform.tfstate) est la mémoire de Terraform : la liste de ce qu'il a créé. En équipe, il doit être partagé (un seul état, pas un par poste), verrouillé (deux apply en même temps = corruption) et protégé (il contient des identifiants de ressources).

gcloud storage buckets create gs://acme-tfstate-gemini-enterprise \
  --location=EU --uniform-bucket-level-access --public-access-prevention
gcloud storage buckets update gs://acme-tfstate-gemini-enterprise --versioning   # retour arrière possible

Puis décommenter dans terraform/versions.tf :

backend "gcs" {
  bucket = "acme-tfstate-gemini-enterprise"
  prefix = "securite-acme/recette"      # un préfixe par environnement / domaine
}

Accès au bucket : lecture/écriture pour le compte de la CI seulement, lecture pour l'équipe plateforme. Le verrou est natif avec le backend GCS.

Si Acme a déjà un service Terraform managé (voir le guide Terraform et le projet 07), c'est lui qui porte l'état : ne pas créer ce bucket, utiliser le backend fourni.


3. Remplir terraform.tfvars

cd terraform
cp terraform.tfvars.example terraform.tfvars     # ne JAMAIS committer ce fichier (.gitignore)
Section du fichierÀ remplir avecQui fournit
project_idID du projetPlateforme
user_groups, admin_groups, security_groups, viewer_groupsGroupes au format group:nom@acme.exampleAdmins Workspace / Entra
alert_emailBoîte de l'équipe sécuritéSécurité
connectorsUne entrée par source (voir docs/00 §7)Admins GE + propriétaires des sources
Palier A : armor_agent_platform_mode, agent_developer_groups"inspect", groupe développeursSécurité, plateforme
Paliers B, C, DLaisser commenté au début—

Les valeurs fausses sont arrêtées avant d'appeler Google : variables.tf contient des validation (ex. armor_agent_platform_mode n'accepte que off, inspect, block).


4. Premier init et validate

terraform init          # télécharge le provider google 8.x et external, configure l'état
terraform validate      # vérifie la syntaxe et les types, sans appeler Google

5. Reprendre ce qui a été créé en console (import)

Le problème. En phase 1, des ressources ont été créées à la main (templates, plancher, buckets…). Si Terraform essaie de les créer, Google répond « already exists » et l'apply échoue.

La solution. Dire à Terraform : « cette ressource existe déjà, elle correspond à tel bloc de mon code ». Depuis Terraform 1.5, cela s'écrit dans un fichier :

import {
  to = google_model_armor_template.shield["ge-prompt-shield"]          # l'adresse dans NOTRE code
  id = "projects/PROJECT_ID/locations/eu/templates/ge-prompt-shield"   # la ressource existante chez Google
}

Procédure.

cp imports.tf.example imports.tf
# 1. Supprimer les blocs des ressources NON créées en console (voir le journal de bord de la phase 1).
# 2. Remplacer PROJECT_ID partout.
sed -i "s/PROJECT_ID/$PROJECT_ID/g" imports.tf
terraform plan -out=tfplan

Correspondance journal de bord → bloc import.

Créé en console (phase 1)to =id =
Template questionsgoogle_model_armor_template.shield["ge-prompt-shield"]projects/P/locations/eu/templates/ge-prompt-shield
Template réponsesgoogle_model_armor_template.shield["ge-response-shield"]projects/P/locations/eu/templates/ge-response-shield
Planchergoogle_model_armor_floorsetting.projectprojects/P/locations/global/floorSetting
Modèle DLPgoogle_data_loss_prevention_inspect_template.fr[0]projects/P/locations/europe/inspectTemplates/ge-donnees-sensibles-fr
Journaux d'audit (un par service)google_project_iam_audit_config.audit["discoveryengine.googleapis.com"]P discoveryengine.googleapis.com (espace entre les deux)
Buckets de journauxgoogle_logging_project_bucket_config.security / .usageprojects/P/locations/eu/buckets/ge-security
Politique d'orggoogle_org_policy_policy.guardrails["run.allowedIngress"]projects/P/policies/run.allowedIngress
Access Approvalgoogle_project_access_approval_settings.this[0]projects/P/accessApprovalSettings
Périmètre VPC-SCgoogle_access_context_manager_service_perimeter.ge[0]accessPolicies/POLICY/servicePerimeters/NOM

Les noms doivent être identiques. Le code attend ge-prompt-shield, ge-security, etc. Si la console a utilisé un autre nom : soit on supprime la ressource console et Terraform la recrée, soit on renomme dans le code (PR). Pour le périmètre VPC-SC, le nom Terraform est gemini_enterprise_<projet> : le plus simple est de supprimer le périmètre dry-run de la console et de laisser Terraform le recréer (aucun effet sur le trafic).

Réglages faits en console sans ressource Terraform dédiée : le réglage Model Armor de l'assistant et les fonctionnalités de l'app sont portés par google_discovery_engine_assistant.default et google_discovery_engine_search_engine.app. Si l'app a été créée en console, importer aussi l'app et l'assistant :

import {
  to = google_discovery_engine_search_engine.app
  id = "projects/PROJECT_ID/locations/eu/collections/default_collection/engines/APP_ID"
}
import {
  to = google_discovery_engine_assistant.default
  id = "projects/PROJECT_ID/locations/eu/collections/default_collection/engines/APP_ID/assistants/default_assistant"
}

6. Lire un plan (la compétence la plus importante)

  # google_model_armor_template.shield["ge-prompt-shield"] will be imported
  # google_model_armor_floorsetting.project will be updated in-place
  ~ resource "google_model_armor_floorsetting" "project" {
      ~ integrated_services = [] -> ["AI_PLATFORM"]
    }
  # google_pubsub_topic.siem[0] will be created
  + resource "google_pubsub_topic" "siem" { ... }

Plan: 1 to import, 1 to add, 1 to change, 0 to destroy.
SymboleSensRéaction
+créationNormal pour un nouveau palier
~modification sur placeLire chaque attribut modifié
-/+suppression puis recréationStop. Comprendre pourquoi (attribut immuable changé). Une app GE ou une clé recréée = perte de données
-suppressionStop sauf si c'est voulu et écrit dans la PR
will be importedadoption sans recréationNormal après la phase 1

Un ~ sur une ressource importée = un écart entre la console et le code. Deux cas :

  • le code a raison → on applique, la console est corrigée ;
  • la console avait un meilleur réglage → on corrige le code (PR), puis on relance le plan.

Ne jamais appliquer un plan qu'on ne comprend pas.


7. Appliquer et nettoyer

terraform apply tfplan
rm imports.tf                 # les imports sont faits : le fichier ne sert plus (il est dans .gitignore)
terraform plan                # doit afficher : No changes. Your infrastructure matches the configuration.

8. Erreurs fréquentes

MessageCause → solution
Error 409: already existsRessource créée en console non importée → ajouter le bloc import
Cannot import non-existent remote objectMauvais id (nom, localisation) → vérifier dans la console
less strict than floor settingUn template du code est moins strict que le plancher → c'est le plancher qui a raison
PERMISSION_DENIED sur org_policy / access_context_managerRôle organisation manquant → palier C avec l'équipe Cloud centrale
CMEK is not supported in globalge_location = "eu"
Error acquiring the state lockUn autre apply en cours → attendre ; si orphelin : terraform force-unlock ID (avec l'équipe)
Siguiente