Cet article explique comment gérer efficacement les règles de masquage de données (data masking) dans un projet dbt — surtout dans un contexte où tu dois respecter des règles de sécurité, de conformité (RGPD, etc.) ou de gouvernance.
🎯 Objectif
Créer une documentation stratégique ET technique autour des données sensibles, en combinant :
- 📄
meta:→ informations lisibles par les machines (pour automatisation, validation) - 📚
description:oudocs:→ explications humaines (raison du masquage, contexte légal)
🔍 Pourquoi c’est important ?
Dans un projet d’entreprise, tu peux avoir des champs comme :
email,num_ss,carte_bancaire,adresse_ip
Ces colonnes doivent être :
- masquées dans certains environnements (dev/staging)
- encadrées par des politiques
- bien documentées pour les data engineers, analystes, et auditeurs
🧱 Exemple concret dans un fichier schema.yml
version: 2
models:
- name: stg_clients
description: "Staging des clients"
columns:
- name: email
description: "Adresse email du client"
meta:
masking: true
masking_method: "hash"
masking_reason: "donnée personnelle - RGPD"
environments_to_mask: ["dev", "staging"]
tests:
- not_null
✅ Ce que ça apporte
| Élément | Rôle |
|---|---|
meta.masking | Marque la colonne comme devant être masquée |
meta.masking_method | Spécifie comment (hash, redaction, null, token, etc.) |
meta.environments_to_mask | Liste des environnements concernés |
description: | Utilisé pour la doc humaine |
tests: | Reste applicable pour la qualité des données |
🧠 Utilisation pratique
✅ 1. Documentation automatique
Tu peux générer avec dbt docs serve un affichage :
“⚠️ cette colonne est masquée par hash en dev/staging pour des raisons RGPD”
✅ 2. Validation automatique
Tu peux écrire des macros ou tests personnalisés qui vérifient :
- que les champs
masking: truesont bien transformés dans le modèle - que le hash est appliqué si on est dans
target.name == 'dev'
✅ 3. Génération de rapports de conformité
Tu peux exporter les meta.masking pour un rapport de conformité automatisé.
🧠 Bonus : ajout d’un bloc docs: (optionnel)
- name: email
description: "{{ doc('email_masking') }}"
docs:
- name: email_masking
description: |
Cette adresse email est considérée comme une donnée personnelle sensible.
Elle est masquée dans les environnements non production conformément à la politique RGPD interne.
✅ Résumé
| Élément | Fonction |
|---|---|
meta: | Définit des règles structurées, lisibles par des outils |
description: ou docs: | Explique le pourquoi pour les humains |
| Multi-layered | Permet à la fois automatisation + documentation claire |
| dbt docs + tests + macros | Tirent parti de ces informations pour gouverner efficacement |
Bonus
Dans le contexte d’un fichier schema.yml ou d’une macro Jinja dans dbt, column.name désigne le nom de la colonne, pas sa valeur.
📌 column.name = le nom technique de la colonne
Par exemple, dans cette définition :
columns:
- name: email
description: "Adresse email du client"
meta:
masking: true
Alors :
{{ column.name }} → donne "email"
❌ Ce n’est pas la valeur toto@titi.com ni aucune valeur de la base
column.nameest utilisé au moment de la génération du SQL (compile time),
pas à l’exécution de la requête (runtime).
Donc dbt ne connaît pas les valeurs réelles des lignes.
🧠 Utilisation typique dans une macro :
SELECT
{% for column in columns %}
{% if column.meta.masking %}
SHA2({{ column.name }}, 256) as {{ column.name }}
{% else %}
{{ column.name }}
{% endif %}
{% if not loop.last %},{% endif %}
{% endfor %}
FROM {{ ref('stg_clients') }}
Ici, {{ column.name }} est remplacé par "email", "nom", etc.,
et le SQL compilé ressemblera à :
SELECT
SHA2(email, 256) as email,
nom,
age
FROM stg_clients
✅ Résumé
| Expression Jinja | Résultat | Contexte |
|---|---|---|
{{ column.name }} | "email" | Nom de colonne |
{{ column.meta.masking }} | true ou false | Métadonnée définie dans schema.yml |
{{ column.description }} | "Adresse email du client" | Documentation |