tech

Tracking des accès à la donnée dans AWS

Franck Cussac

Franck Cussac

Senior Data Engineer

24 juin 2025 15 min de lecture
Architecture AWS de tracking des accès à la donnée : CloudTrail, EventBridge, Lambda et Firehose

Surveiller les accès à la donnée dans AWS

Au sein d’une Data Platform nous pouvons avoir besoin de surveiller les accès à la donnée en lecture de l’ensemble de nos utilisateurs. AWS a d’ailleurs publié un article nommé Auditing, inspecting, and visualizing Amazon Athena usage and cost qui propose une solution pour le mettre en place.

Dans cet article je vais expliciter comment j’ai implémenté l’architecture décrite par AWS et vous partager mes conseils.

Les exemples de code qui seront donnés dans l’article seront des extraits pour éviter la surcharge. Pour récupérer les exemples complets, je vous invite à aller voir notre repository GitHub sur le tracking d’accès à la donnée sur AWS.

Voici ce que nous allons déployer ensemble dans cet article :

Architecture AWS : CloudTrail collecte les événements S3 et Athena, EventBridge déclenche une Lambda qui écrit via Firehose dans S3 et le catalogue Glue

Quels types d’accès surveiller ?

Dans l’exemple que nous allons implémenter, nous choisirons de surveiller les types d’accès les plus courants sur AWS :

  • Un GetObject sur S3
  • Une requête via Athena

Quelles informations collecter ?

Ce qui est intéressant c’est de pouvoir vérifier qui a accédé à de la donnée, quand, et quelle donnée ? Pour cela il est intéressant de récupérer à minima :

  • Le chemin dans S3 du fichier
  • L’identifiant de la personne
  • La date et l’heure à laquelle la requête a été lancée
  • La requête SQL (si c’est Athena)
  • L’action (si c’est S3)

Les événements à collecter

Les événements S3

Sur S3 nous n’avons qu’un événement à collecter, c’est le GetObject. C’est l’événement produit quand on télécharge un fichier, peu importe comment. Directement depuis la console web ou via son terminal en local avec un simple aws s3 cp, les deux produiront un GetObject.

Pour le récupérer nous avons besoin de créer un CloudTrail spécifique. Dans la documentation Terraform de aws_cloudtrail, on trouve un exemple qui s’appelle Logging All S3 Object Events Except For Two S3 Buckets By Using Advanced Event Selectors.

Cet exemple est intéressant car comme son nom l’indique, il permet de récupérer tous les événements venant de S3 sur des objets sauf pour 2 buckets. C’est un pattern très pratique quand par défaut on veut tout surveiller, sauf exception.

Notre exception sera le bucket S3 qui stockera les données de surveillance d’accès à la donnée, qui ne fait pas partie de la donnée métier de la data platform.

Les événements Athena

Sur Athena c’est un peu plus compliqué. Par défaut lorsqu’on lance une requête, on peut capter les types d’événements avec EventBridge.

Nous avons bien l’heure à laquelle la requête a été lancée, mais c’est tout. Pour avoir les informations sur l’identité de l’utilisateur, il va falloir passer par un CloudTrail encore une fois.

Capter les événements

CloudTrail nous permet de collecter les événements pour les stocker sur S3. Sauf qu’en l’état, ces événements ne sont pas requêtables simplement via Athena.

Nous avons besoin d’une étape de traitement des événements pour récupérer les informations qui nous intéressent. Pour cela nous pouvons utiliser une Lambda. Mais pour la déclencher il faut capter les événements de CloudTrail et les envoyer vers notre Lambda.

EventBridge est la solution poussée par AWS pour ce cas d’usage. Je trouve également que ce service est idéal dans notre cas car :

  • Le service est gratuit tant qu’on est sur des événements managés par AWS envoyés à un service managé du même compte, c’est notre cas ici
  • Nous n’avons pas besoin d’un temps de réaction très rapide
  • Nous n’avons pas besoin d’une garantie dans l’ordre de traitement des événements

Il nous faut créer 2 règles pour nos 2 types d’événements.

Il y a une petite subtilité pour les événements de GetObject sur S3. Lorsque nous lançons une requête avec Athena par exemple, celui-ci va s’occuper à notre place de faire des GetObject sur S3. Si vous avez une source de données composée de milliers de fichiers que Athena doit lire, cela va créer 1000 lignes dans notre table de surveillance des accès à la donnée.

Comme nous avons prévu de traquer les requêtes faites avec Athena, il est plus pratique d’ignorer les GetObject de celui-ci pour éviter d’être inondé d’événements redondants. Pour cela il suffit de surveiller le champ sourceIPAddress pour filtrer l’IP de Athena.

Traitement sur les événements

Pour traiter nos événements et conserver que les informations qui nous intéressent, on va utiliser une Lambda.

Ce qui va le plus nous intéresser c’est le code de la Lambda, que je vous propose en Python.

Le handler

Comme nous pouvons recevoir 2 événements différents dans notre Lambda, le handler est un simple if / else qui redirige le parsing en fonction du type d’événement reçu.

Une fois le parsing fait, on l’envoie à Firehose pour qu’il écrive des micro batchs en parquet sur S3.

Récupérer les informations d’un GetObject sur S3

Ici pas trop de surprise, l’événement contient tout ce dont on a besoin, il n’y a qu’à se servir.

Récupérer les informations d’une requête Athena

L’événement que reçoit notre Lambda en sortie de EventBridge contient tout sauf 1 information : la requête SQL lancée. Le champ queryString qui contient la requête SQL est caché.

Pour obtenir cette information, il faut requêter Athena via le queryExecutionId.

Écrire les informations dans S3

Dernière étape, écrire dans S3 ce qu’on a collecté et rendre la donnée accessible dans le Glue Catalog.

Pour cela Firehose est notre ami. Ce service fonctionne comme un accumulateur de données qui va écrire après qu’une de ses 2 conditions soit remplie :

  • Un certain temps s’est écoulé
  • Une certaine quantité de données a été reçue

Nous pouvons également configurer Firehose pour qu’il écrive au format parquet. Pour cela il faut lui donner une table Glue décrivant le schéma de la donnée cible.

Dernier point à ne jamais négliger quand on traite de la donnée : le partitionnement. Dans 5 ans, lorsqu’on aura collecté quelques centaines de Go de données, il sera beaucoup plus confortable et moins cher de pouvoir optimiser nos recherches d’accès en filtrant sur des partitions. La date du jour est l’exemple le plus typique.

Attention : on va rencontrer un problème avec Firehose et le partitionnement, c’est qu’il ne gère pas lui-même la mise à jour dans le catalogue Glue des nouvelles partitions créées. Cela signifie que dans notre cas, où chaque jour nous créons une nouvelle partition, il va falloir mettre à jour la table, par exemple avec la commande MSCK REPAIR TABLE.

Mais pour une version plus automatisée, on pourrait utiliser les crawlers de Glue. Un prochain article peut-être.

Plus qu’à tester !

Pour tester je vous invite à suivre les instructions du repository GitHub où vous retrouverez le terraform complet ainsi que le code de la Lambda.

Aller plus loin

Quelques idées pour aller plus loin.

Nous aurions pu collecter d’autres informations comme :

  • l’adresse IP de l’utilisateur
  • la quantité de données traitée par la requête Athena

Actuellement chaque requête sur la table qui historise les accès à la donnée est elle-même historisée dans cette table, ce qui pourrait être filtré.

Nous pourrions mettre en place une DLQ en cas d’échec de traitement d’un événement par la Lambda, pour éviter d’en perdre.

Dans l’article d’AWS sur lequel je me suis basé, il est proposé de créer 1 pipeline d’ingestion par type d’événement afin de bien tout séparer. Cela signifie dans notre cas qu’on devrait créer 2 lambdas, 2 firehoses et 2 tables Glue.