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: true
sont 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.name
est 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 |