Leçon 4 — Réseau privé et protection des données

VPC Service Controls autour de Vertex AI

5 min de lecture

VPC Service Controls autour de Vertex AI

Ce que IAM ne fait pas

IAM répond à « qui » ; il ne regarde pas « d'où ». Si le jeton du compte de service de l'assistant fuit (journal mal filtré, poste compromis), l'attaquant peut, depuis chez lui, lire le bucket de documents et le copier dans son projet : IAM l'y autorise, puisque c'est le bon compte.

VPC Service Controls (VPC-SC) ajoute une frontière de contexte : un périmètre de service regroupe des projets et des services restreints. Les appels qui traversent la frontière (entrée depuis l'extérieur, sortie vers un projet hors périmètre) sont refusés, même avec un IAM valide.

flowchart LR
  subgraph P["Périmètre lab_archi_ia"]
    CR["Cloud Run (VPC privé)"] --> V["Vertex AI"]
    CR --> G["Bucket documents"]
    V --> G
  end
  X["Attaquant avec le jeton volé (internet)"] -.->|"refusé : hors périmètre"| G
  G -.->|"copie vers un projet externe : refusée"| E["Projet de l'attaquant"]
  ADM["Admin depuis un poste géré"] -->|"règle d'entrée (ingress) + niveau d'accès"| G
Sans VPC-SCAvec VPC-SC
jeton volé = accès depuis n'importe oùjeton volé inutilisable hors du périmètre
gsutil cp vers un bucket externe possiblesortie refusée, journalisée
Vertex AI peut lire un bucket d'un autre projetseulement les ressources du périmètre (ou règles explicites)

Prérequis : une organisation

Un périmètre appartient à une politique d'accès (Access Context Manager) de l'organisation. Le module le crée seulement si vous fournissez access_policy_id :

gcloud access-context-manager policies list --organization=ORG_ID

Le code : spec ou status

files/perimeter.tf (extrait)
resource "google_access_context_manager_service_perimeter" "ai" {
  count  = var.access_policy_id == null ? 0 : 1
  parent = "accessPolicies/${var.access_policy_id}"
  name   = "accessPolicies/${var.access_policy_id}/servicePerimeters/${replace(var.prefix, "-", "_")}"
  title  = "${var.prefix} - plateforme IA"

  use_explicit_dry_run_spec = var.vpcsc_dry_run

  dynamic "spec" {                     # configuration de test : journalise, ne bloque pas
    for_each = var.vpcsc_dry_run ? [local.perimeter_config] : []
    content {
      resources           = spec.value.resources   # ["projects/NUMERO"]
      restricted_services = spec.value.restricted_services
      vpc_accessible_services {
        enable_restriction = true
        allowed_services   = ["RESTRICTED-SERVICES"]
      }
    }
  }
  # dynamic "status" { ... }  même contenu, appliqué quand vpcsc_dry_run = false
}
  • spec = configuration dry run : les violations sont journalisées (dryRun: true dans les journaux d'audit) mais rien n'est bloqué.
  • status = configuration appliquée.
  • vpc_accessible_services restreint ce que le VPC peut appeler aux services du périmètre : c'est le pendant du point PSC vpc-sc.

Le compte de service de l'assistant a roles/storage.objectViewer sur le bucket. Un attaquant vole son jeton et tente de lire le bucket depuis internet. Le périmètre est appliqué (status). Que se passe-t-il ?

Trouver les violations en dry run

Dans l'explorateur de journaux, ou en ligne de commande :

gcloud logging read \
  'protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   AND protoPayload.metadata.dryRun=true' \
  --project=mon-projet-ia-dev --freshness=7d --limit=20 \
  --format='table(timestamp, protoPayload.methodName, protoPayload.authenticationInfo.principalEmail)'

Chaque ligne est un appel qui serait bloqué. Pour chacun : soit c'est légitime (règle d'entrée pour le groupe admin depuis les postes gérés, règle de sortie vers le projet KMS central), soit c'est exactement ce que le périmètre doit empêcher.

Pourquoi le module place-t-il la configuration dans spec quand vpcsc_dry_run = true ?

Exercice

Les administrateurs de la plateforme, membres du groupe admins-ia@exemple.fr, doivent pouvoir lire les journaux et les objets du bucket depuis la console, depuis les postes de l'entreprise uniquement. Esquissez la règle d'entrée (ingress) à ajouter dans spec.

Voir la solution

D'abord un niveau d'accès (access level) qui décrit « poste de l'entreprise » (plage IP de sortie du proxy, ou appareil géré via Endpoint Verification), par exemple accessPolicies/123/accessLevels/postes_geres. Puis :

ingress_policies {
  title = "admins depuis postes geres"
  ingress_from {
    identities = ["group:admins-ia@exemple.fr"]
    sources {
      access_level = "accessPolicies/${var.access_policy_id}/accessLevels/postes_geres"
    }
  }
  ingress_to {
    resources = ["*"]
    operations {
      service_name = "storage.googleapis.com"
      method_selectors { method = "google.storage.objects.get" }
      method_selectors { method = "google.storage.objects.list" }
    }
  }
}

On cible des méthodes précises plutôt que * : les admins lisent, ils ne copient pas vers l'extérieur.

Résultat obtenu

terraform plan réel le 2026-10-15 avec un identifiant de politique factice (access_policy_id=123456789012) : la ressource est planifiée en mode test, rien n'est créé.

  # google_access_context_manager_service_perimeter.ai[0] will be created
      + use_explicit_dry_run_spec = true
          + restricted_services = [
              + "aiplatform.googleapis.com",
              + "cloudkms.googleapis.com",
              + "modelarmor.googleapis.com",
              + "storage.googleapis.com",
            ]
...
Plan: 40 to add, 0 to change, 0 to destroy.

Le périmètre lui-même n'a pas été créé : notre projet de test n'est pas rattaché à une organisation.

Je sais faire

  • Expliquer ce que VPC-SC ajoute à IAM, avec l'exemple du jeton volé
  • Déclarer un périmètre en dry run puis l'appliquer
  • Retrouver les violations dry run dans les journaux
  • Écrire une règle d'entrée ciblée sur des identités, une source et des méthodes
Suivant