Exfiltration GCS et BigQuery : les preuves dans l'audit
Prouver ou écarter un vol de données Cloud Storage et BigQuery : storage.objects.get en rafale, buckets publics, clés HMAC, copies entre projets.
En bref. Un vol de données dans Google Cloud se voit à quatre endroits : les lectures (rafales de storage.objects.get, uniquement avec les journaux Data Access), l'exposition (allUsers ajouté à la stratégie d'un bucket ou d'un jeu de données, toujours journalisé), les copies vers un autre projet (jobs BigQuery avec une destination étrangère, images et instantanés partagés) et les identifiants de contournement (clés HMAC). Établissez la fenêtre d'exposition à partir des journaux Admin Activity même quand les lectures sont invisibles, et dites-le explicitement dans le rapport.
« Des données ont-elles été prises ? » est la première question que posent le juridique et la direction, et celle à laquelle les journaux d'audit répondent le moins complètement. Voici ce que chaque journal peut prouver, et ce qu'il ne peut pas prouver.
Les lectures : storage.objects.get
Chaque téléchargement d'objet via l'API JSON ou XML de Cloud Storage est un appel storage.objects.get, enregistré comme journal d'audit Data Access (DATA_READ) si la journalisation Data Access était activée pour Cloud Storage (journaux d'audit Cloud Storage). L'entrée donne l'objet dans resourceName (projects/_/buckets/BUCKET/objects/NAME), le principal, l'IP d'appel et le user agent.
logName:"cloudaudit.googleapis.com%2Fdata_access"
protoPayload.methodName="storage.objects.get"
resource.labels.bucket_name="BUCKET"
Ce qu'il faut en extraire :
- Le volume et le rythme par principal : une centaine d'objets en quelques minutes par un principal qui en lit habituellement quatre par jour.
- Les noms d'objets : ils disent ce qui a été pris (
customers/…,backups/…). - Le principal : un compte grand public, une clé de compte de service depuis une IP inconnue, ou un agent de service qui fait son travail normal.
- Aussi
storage.objects.list(découverte avant téléchargement) et, si l'attaquant copie au lieu de télécharger,storage.objects.create/ rewrite dans un bucket de destination qu'il contrôle.
Cela correspond à T1530, Data from Cloud Storage. La réserve est lourde : les journaux Data Access sont désactivés par défaut, et Google signale que les activer pour Cloud Storage peut, dans certains cas, faire échouer des téléchargements authentifiés depuis le navigateur (configurer les journaux d'audit Data Access) ; c'est pourquoi beaucoup de projets ne les activent jamais. Voir les limites des journaux Data Access.
L'exposition : allUsers et allAuthenticatedUsers
Rendre un bucket public est un changement de stratégie, donc Admin Activity, donc toujours journalisé. Pour les buckets, la méthode est storage.setIamPermissions ; le delta se trouve dans serviceData.policyDelta.bindingDeltas :
{ "action": "ADD", "role": "roles/storage.objectViewer", "member": "allUsers" }
Dès que allUsers peut lire un bucket, des téléchargements anonymes sont possibles et vous ne les verrez pas : Google indique que Cloud Audit Logs ne suit pas l'accès aux objets publics (journaux d'audit Cloud Storage). Seuls les journaux d'utilisation de Cloud Storage, s'ils avaient été configurés, enregistrent ce trafic. La conclusion honnête est une fenêtre d'exposition : de l'ADD au REMOVE (ou jusqu'à maintenant), le contenu était accessible à quiconque connaissait ou devinait le nom du bucket. Cette fenêtre, et la liste des objets présents dans le bucket pendant ce temps, sont ce dont une analyse d'impact sur la protection des données a besoin. La page rendre des données publiques de Google explique le mécanisme ; la prévention de l'accès public le bloque.
La même logique s'applique à allUsers sur des jeux de données BigQuery, des services Cloud Run, des Cloud Functions ou des images.
Les portes latérales : les clés HMAC
storage.hmacKeys.create crée une paire identifiant d'accès / secret pour l'API XML compatible S3. C'est de la persistance plus que de l'exfiltration : la clé continue de fonctionner après le renouvellement des autres identifiants du compte de service. Considérez toute clé HMAC créée pendant l'incident comme contrôlée par l'attaquant (T1098.001).
BigQuery : les copies vers un autre projet
BigQuery diffère sur un point utile : les journaux d'audit Data Access sont activés par défaut pour certains services BigQuery (présentation de Cloud Audit Logs). Les jobs (requêtes, copies, extractions) sont enregistrés avec leur configuration (journaux d'audit BigQuery).
Le signal à chercher est une destination hors du projet : un job de copie ou de requête dont la destinationTable appartient à un autre ID de projet. Un attaquant qui peut lire votre jeu de données et écrire dans son propre projet déplace une table entière en un seul appel : T1537, Transfer Data to Cloud Account. Passez aussi en revue les jobs d'extraction (destinationUris vers des buckets gs:// qui ne vous appartiennent pas) et les changements de stratégie des jeux de données (metadata.datasetChange.bindingDeltas).
Images disque et instantanés
Partager une image disque ou un instantané avec un autre projet revient à copier tout le disque à l'extérieur, bases de données et identifiants compris. Cherchez les setIamPolicy sur compute.images, compute.snapshots, compute.disks et compute.machineImages, puis vérifiez quels membres ont été ajoutés.
Le trafic sortant
Des données lues par une VM compromise puis envoyées à l'extérieur n'apparaissent pas du tout dans les journaux d'audit. Les VPC Flow Logs sont la seule source : les octets envoyés par IP externe.
Ce que l'analyseur signale
| Règle | Sévérité | Condition |
|---|---|---|
bulk_object_reads | Haute | 100 storage.objects.get par le même principal en 10 minutes (quel que soit le résultat) |
public_access_granted | Critique | allUsers / allAuthenticatedUsers ajouté à une stratégie IAM |
bq_foreign_export | Haute | Job BigQuery de copie ou de requête dont la table de destination est dans un autre projet |
image_shared | Moyenne | Stratégie IAM d'une image, d'un instantané, d'un disque ou d'une image de machine modifiée |
hmac_key_created | Moyenne | storage.hmacKeys.create |
flow_large_egress (analyse) | Moyenne | 1 Gio ou plus envoyé par vos VM vers une même IP publique (VPC Flow Logs) |
Limites des règles actuelles : les jobs d'extraction BigQuery vers des buckets externes ne sont pas encore signalés, et un compte de service ETL très actif qui lit en continu peut franchir le seuil de lecture massive. L'outil avertit aussi quand un export ne contient aucun journal Data Access, puisque bulk_object_reads ne peut pas se déclencher sans eux.
La rédaction
Pour chaque jeu de données ou bucket concerné, distinguez : ce dont la lecture est prouvée (noms d'objets, principal, heure), ce qui a été exposé (fenêtre, objets présents), ce qui a été copié (projet, table, image de destination) et ce qui ne peut pas être connu faute de journaux. La checklist de remédiation de l'outil invite à cette évaluation, car des obligations de notification comme le délai de 72 heures du RGPD peuvent en dépendre.
Questions fréquentes
Peut-on voir quels fichiers ont été téléchargés depuis un bucket Cloud Storage ?
Seulement si les journaux d'audit Data Access (DATA_READ) étaient activés pour Cloud Storage avant le téléchargement. Chaque lecture produit alors une entrée storage.objects.get avec le nom de l'objet, le principal et l'IP d'appel. Sans eux, les lectures ne sont pas enregistrées dans les journaux d'audit.
Comment savoir si un bucket a été rendu public ?
Cherchez les entrées Admin Activity (storage.setIamPermissions pour les buckets) dont le delta de stratégie ajoute allUsers ou allAuthenticatedUsers. Les journaux Admin Activity sont toujours actifs : ce changement est enregistré même quand les lectures ne le sont pas.
Pour aller plus loin
- Cloud Audit Logs avec Cloud Storage — documentation Google Cloud.
- Présentation des journaux d'audit BigQuery — documentation Google Cloud.
- Abus de SetIamPolicy : repérer les Owner et les intrus.