Lección 7 — Exposer, protéger, surveiller

Model Armor et journaux d'audit

5 min de lectura

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

Model Armor et journaux d'audit

Model Armor en deux mots

Model Armor est un service Google Cloud qui analyse un texte (le prompt de l'utilisateur, ou la réponse du modèle) et signale : injection de prompt et tentative de contournement (jailbreak), URL malveillantes, données sensibles (via Sensitive Data Protection), contenus dangereux ou haineux. L'application l'appelle avant et après Gemini.

flowchart LR
  U["Prompt utilisateur"] --> A1["Model Armor : sanitizeUserPrompt"]
  A1 -->|"bloqué"| R1["Message de refus"]
  A1 -->|"ok"| G["Gemini (Vertex AI)"]
  G --> A2["Model Armor : sanitizeModelResponse"]
  A2 -->|"bloqué"| R2["Réponse masquée"]
  A2 -->|"ok"| S["Réponse affichée"]
  A1 -.-> L["Journaux d'audit"]
  A2 -.-> L

Le modèle (template)

Un modèle Model Armor regroupe les filtres et leurs seuils ; il est régional (disponible notamment en europe-west1).

files/guardrails.tf (extrait)
resource "google_model_armor_template" "assistant" {
  location    = var.region
  template_id = "${var.prefix}-assistant"

  filter_config {
    pi_and_jailbreak_filter_settings {
      filter_enforcement = "ENABLED"
      confidence_level   = "MEDIUM_AND_ABOVE"
    }
    malicious_uri_filter_settings { filter_enforcement = "ENABLED" }
    sdp_settings {
      basic_config { filter_enforcement = "ENABLED" } # cartes bancaires, identifiants...
    }
    rai_settings { # DANGEROUS, HARASSMENT, HATE_SPEECH, SEXUALLY_EXPLICIT
      rai_filters {
        filter_type      = "DANGEROUS"
        confidence_level = "MEDIUM_AND_ABOVE"
      }
    }
  }
  template_metadata { log_sanitize_operations = true }
}
Seuil confidence_levelEffetPour
LOW_AND_ABOVEbloque au moindre doute, plus de faux positifsassistant exposé au public
MEDIUM_AND_ABOVEcompromisassistant interne (notre choix)
HIGHne bloque que l'évidentoutils d'experts, avec revue humaine

Côté application (identifiant injecté dans Cloud Run par MODEL_ARMOR_TEMPLATE), un appel ressemble à :

appel Model Armor (illustration)
from google.cloud import modelarmor_v1
client = modelarmor_v1.ModelArmorClient(
    client_options={"api_endpoint": "modelarmor.europe-west1.rep.googleapis.com"})
r = client.sanitize_user_prompt(request=modelarmor_v1.SanitizeUserPromptRequest(
    name=os.environ["MODEL_ARMOR_TEMPLATE"],
    user_prompt_data=modelarmor_v1.DataItem(text=prompt)))
if r.sanitization_result.filter_match_state == modelarmor_v1.FilterMatchState.MATCH_FOUND:
    return "Je ne peux pas traiter cette demande."

Pourquoi appeler Model Armor aussi sur la réponse du modèle, et pas seulement sur le prompt ?

Journaux d'audit : ce qui est actif par défaut, et ce qui ne l'est pas

Les journaux d'audit Cloud (Cloud Audit Logs) existent en plusieurs types :

TypeContenuPar défaut
Admin Activitycréation, modification, IAMtoujours actif, non désactivable
Data Access : ADMIN_READlecture de configurationdésactivé (sauf BigQuery)
Data Access : DATA_READ / DATA_WRITEappels aux modèles, lecture de donnéesdésactivé
Policy Deniedrefus VPC-SC, contraintestoujours actif

Sans DATA_READ/DATA_WRITE sur aiplatform.googleapis.com, vous ne savez pas qui a appelé Gemini, quand, avec quel modèle. C'est le contrôle qui était en WARN dans le rapport de posture de la leçon 1.2.

files/data_protection.tf (extrait)
resource "google_project_iam_audit_config" "ai" {
  for_each = toset(["aiplatform.googleapis.com", "modelarmor.googleapis.com"])
  service  = each.value
  audit_log_config { log_type = "ADMIN_READ" }
  audit_log_config { log_type = "DATA_READ" }
  audit_log_config { log_type = "DATA_WRITE" }
}

resource "google_logging_project_bucket_config" "audit" {
  location       = var.region          # les journaux restent dans l'UE
  bucket_id      = "${var.prefix}-audit"
  retention_days = var.log_retention_days   # 365
}

resource "google_logging_project_sink" "audit" {
  destination = "logging.googleapis.com/${google_logging_project_bucket_config.audit.id}"
  filter      = "logName:\"cloudaudit.googleapis.com\" AND (protoPayload.serviceName=\"aiplatform.googleapis.com\" OR protoPayload.serviceName=\"modelarmor.googleapis.com\")"
}

Un auditeur demande la liste des comptes qui ont appelé Gemini le mois dernier. Le projet n'a que la configuration d'audit par défaut. Que pouvez-vous fournir ?

Exercice

Écrivez la requête de l'explorateur de journaux qui liste, sur les 24 dernières heures, les appels GenerateContent à Vertex AI avec l'identité appelante.

Voir la solution
logName:"cloudaudit.googleapis.com%2Fdata_access"
protoPayload.serviceName="aiplatform.googleapis.com"
protoPayload.methodName:"GenerateContent"
timestamp>="2026-10-14T00:00:00Z"

En ligne de commande, sur le bucket de logs dédié :

gcloud logging read 'protoPayload.serviceName="aiplatform.googleapis.com" AND protoPayload.methodName:"GenerateContent"' \
  --bucket=lab-archi-ia-audit --location=europe-west1 --view=_AllLogs \
  --project=mon-projet-ia-dev --freshness=1d \
  --format='table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.resourceName)'

Résultat obtenu

terraform plan réel le 2026-10-15 (extrait garde-fous et audit) :

  # google_logging_project_bucket_config.audit will be created
  # google_logging_project_sink.audit will be created
  # google_model_armor_template.assistant will be created
  # google_project_iam_audit_config.ai["aiplatform.googleapis.com"] will be created
  # google_project_iam_audit_config.ai["modelarmor.googleapis.com"] will be created

Et l'état actuel du projet de test, d'après check_posture.py (avant tout apply) :

[WARN] Audit accès aux données Vertex AI    manque DATA_READ, DATA_WRITE

Je sais faire

  • Déclarer un modèle Model Armor régional avec des seuils adaptés à l'usage
  • Placer Model Armor avant et après l'appel au modèle
  • Activer les journaux Data Access sur les seuls services IA
  • Router les journaux d'audit vers un bucket de logs UE à rétention longue
Siguiente