L’approche traditionnelle pour l’isolation des données par ligne consiste à maintenir des vues distinctes par segment :
CREATE VIEW sales_emea AS SELECT * FROM sales WHERE region = 'EMEA';CREATE VIEW sales_apac AS SELECT * FROM sales WHERE region = 'APAC';CREATE VIEW sales_americas AS SELECT * FROM sales WHERE region = 'AMERICAS';Cela crée un problème de maintenance : ajouter une région nécessite une nouvelle vue, ajouter une colonne nécessite de mettre à jour chaque vue, et les outils BI codés en dur sur un nom de vue spécifique nécessitent une coordination pour être refactorisés.
Les politiques d’accès aux lignes BigQuery remplacent cela par un filtrage dynamique basé sur l’identité de l’utilisateur qui interroge — aucune gestion de vues requise.
Créer des politiques d’accès aux lignes
CREATE ROW ACCESS POLICY region_filter_emeaON project.dataset.salesGRANT TO ("group:sales-emea@yourdomain.com")FILTER USING (region = 'EMEA');
CREATE ROW ACCESS POLICY region_filter_apacON project.dataset.salesGRANT TO ("group:sales-apac@yourdomain.com")FILTER USING (region = 'APAC');Lorsqu’un utilisateur du groupe sales-emea interroge directement la table des ventes, il ne voit que les lignes EMEA. Lorsqu’un utilisateur de sales-apac interroge la même table, il ne voit que les lignes APAC. Les deux utilisateurs interrogent la même table avec le même SQL — le filtre leur est invisible.
Pour les utilisateurs qui doivent tout voir (administrateurs, pipelines de reporting) :
CREATE ROW ACCESS POLICY full_accessON project.dataset.salesGRANT TO ("group:data-engineers@yourdomain.com")FILTER USING (TRUE);FILTER USING (TRUE) est le pattern pour un accès non restreint dans un cadre de politiques d’accès aux lignes. Il est explicite quant à l’intention : ce groupe se voit accorder l’accès à toutes les lignes, et cette décision est documentée dans la politique plutôt qu’impliquée par l’absence de filtre.
Filtrage dynamique avec SESSION_USER()
Les filtres statiques (région = constante) fonctionnent pour une segmentation géographique ou organisationnelle claire. Mais parfois le filtre doit dépendre de qui exécute spécifiquement la requête, pas seulement du groupe auquel il appartient.
SESSION_USER() retourne l’adresse e-mail du principal exécutant la requête :
CREATE ROW ACCESS POLICY manager_sees_their_teamON project.dataset.employee_metricsGRANT TO ("group:managers@yourdomain.com")FILTER USING ( manager_email = SESSION_USER() OR SESSION_USER() IN (SELECT email FROM project.dataset.hr_admins));Les managers voient les métriques des employés où manager_email correspond à leur propre e-mail. Les administrateurs RH — maintenus dans une table de référence séparée — voient tout le monde. Le filtre référence des données en direct ; lorsqu’une personne est ajoutée à la table hr_admins, elle gagne immédiatement un accès complet. Aucune mise à jour de politique requise.
Ce pattern fonctionne bien lorsque vous avez une relation naturelle de propriété ou de hiérarchie dans vos données et que vous souhaitez appliquer “vous ne pouvez voir que vos enregistrements” sans gérer des autorisations d’utilisateurs individuels.
Comportements importants à connaître
Les politiques sont combinées avec OR pour les appartenances multi-groupes. Si un utilisateur appartient aux groupes sales-emea et sales-apac, il voit les lignes EMEA et APAC. Les filtres se combinent avec une logique OR. Planifiez votre structure de groupes en conséquence.
Les politiques ne se cumulent pas avec des politiques manquantes. Si une politique d’accès aux lignes existe sur une table, les utilisateurs sans politique correspondante ne voient aucune ligne — pas toutes les lignes. C’est le bon comportement de sécurité par défaut (refuser sauf autorisation explicite), mais cela surprend les équipes qui ajoutent la première politique et voient soudain les utilisateurs existants ne voir plus rien.
CREATE OR REPLACE met à jour de manière atomique. Lors de la mise à jour d’une politique, utilisez CREATE OR REPLACE ROW ACCESS POLICY pour éviter une fenêtre où la politique n’existe pas :
CREATE OR REPLACE ROW ACCESS POLICY region_filter_emeaON project.dataset.salesGRANT TO ("group:sales-emea@yourdomain.com")FILTER USING (region = 'EMEA');Les politiques disparaissent lorsque les tables sont recréées. Si dbt supprime et recrée la table, toutes les politiques d’accès aux lignes sont supprimées avec elle. C’est pourquoi Secured Table Materialization in dbt existe — elle réapplique les politiques après chaque reconstruction.
Politiques de lignes et de colonnes combinées
Les politiques d’accès aux lignes et les policy tags au niveau des colonnes fonctionnent indépendamment et se composent naturellement. Un utilisateur de sales-emea peut ne voir que les lignes EMEA (politique de lignes) et ne pas voir la colonne margin (policy tag). Les deux restrictions s’appliquent sans que l’une ne connaisse l’autre.
Le BigQuery Dynamic Data Masking ajoute une troisième couche : l’utilisateur peut voir la colonne, mais les valeurs sont masquées. Un analyste commercial peut voir toutes les lignes de sa région, voir qu’il y a une colonne email, mais voir des valeurs d’e-mail hashées plutôt que les adresses réelles.
Concevez les couches séparément. Les politiques de lignes répondent à “quels enregistrements ?”. Les policy tags répondent à “quels champs ?”. Le masquage répond à “quelle quantité du champ ?”. Chaque couche peut être ajustée indépendamment à mesure que les exigences d’accès évoluent.
Gérer la prolifération des politiques
Ajoutez les politiques progressivement, en commençant par les données les plus sensibles et les exigences de segmentation les plus claires. Les politiques ajoutent une surcharge de requête et une complexité de gouvernance ; ne les appliquez qu’aux tables qui nécessitent une isolation au niveau des lignes.
Un seuil pratique : remplacez les vues par segment existantes par des politiques d’accès aux lignes. Si les données sont accédées via une vue partagée unique ou directement, les politiques d’accès aux lignes ne sont appropriées que lorsqu’une exigence de contrôle d’accès spécifique le justifie.
Révisez les politiques trimestriellement en parallèle des permissions IAM. Les politiques sur les tables désactivées persistent jusqu’à ce qu’elles soient explicitement supprimées. DROP ALL ROW ACCESS POLICIES ON project.dataset.table nettoie tout en une seule opération lors de la mise hors service d’une table.