Les rôles IAM BigQuery contrôlent si quelqu’un peut accéder à une table. Le contrôle d’accès granulaire va plus loin — en contrôlant les colonnes visibles, les lignes retournées, et l’apparence des valeurs sensibles pour ceux qui y ont accès. Ces trois mécanismes — sécurité au niveau des colonnes, sécurité au niveau des lignes et masquage dynamique des données — répondent à l’exigence réelle de la plupart des équipes : différents utilisateurs ont besoin de vues différentes des mêmes données sous-jacentes.
La base RBAC à deux couches
Avant d’utiliser les contrôles au niveau des colonnes ou des lignes, établissez une structure de rôles claire basée sur des groupes. Les rôles IAM prédéfinis (Data Viewer, Data Editor, Data Owner) forment la couche d’accès aux objets. Les groupes Google représentant des fonctions métier (typiquement loader-role, engineer-role, analyst-role) composent ces rôles IAM pour des fonctions spécifiques.
L’habitude opérationnelle essentielle : ajouter des utilisateurs à des groupes plutôt que gérer des liaisons de rôles individuelles. Un groupe Google appelé data-analysts@company.com obtient bigquery.dataViewer sur les datasets analytics. Quand un analyste arrive, vous l’ajoutez au groupe. Quand il part, vous le retirez. Vous ne touchez jamais à l’IAM directement.
Cette structure vous offre un système de contrôle d’accès auditable sans la surcharge de maintenance des liaisons par utilisateur. Elle accélère également la réponse aux incidents : “supprimer immédiatement tous les accès des analystes” est une seule modification de liaison IAM, pas une chasse à travers des centaines de permissions individuelles.
Sécurité au niveau des colonnes avec les policy tags
La sécurité au niveau des colonnes utilise les policy tags de Data Catalog pour restreindre l’accès de certains utilisateurs à des colonnes spécifiques. La mise en place implique trois composants : une taxonomie de tags, des annotations de colonnes dans les schémas BigQuery, et des autorisations IAM sur la taxonomie.
Mettre en place une taxonomie de policy tags
Organisez les tags de manière hiérarchique du plus général au plus spécifique :
PII├── High_Sensitivity│ ├── SSN│ ├── Credit_Card_Number│ └── Bank_Account└── Medium_Sensitivity ├── Email_Address ├── Phone_Number └── Date_of_Birth# Create the taxonomygcloud data-catalog taxonomies create \ --location=us \ --display-name="Data Sensitivity" \ --description="PII classification hierarchy for BigQuery column security"
# Create policy tags within the taxonomy (done through Data Catalog UI or API)Activez l’application du contrôle d’accès sur la taxonomie — c’est ce qui fait que les tags appliquent réellement des restrictions plutôt que de simplement étiqueter les colonnes :
gcloud data-catalog taxonomies set-iam-policy TAXONOMY_ID \ --location=us \ --member="group:data-analysts@company.com" \ --role="roles/datacatalog.categoryViewer"Tagging des colonnes dans BigQuery
Appliquez les policy tags directement dans les instructions CREATE TABLE ou ALTER TABLE :
-- Tag sensitive columns at table creationCREATE TABLE `project.dataset.customers` ( customer_id STRING, email STRING OPTIONS (policy_tags='["projects/my-project/locations/us/taxonomies/123/policyTags/456"]'), phone STRING OPTIONS (policy_tags='["projects/my-project/locations/us/taxonomies/123/policyTags/456"]'), date_of_birth DATE OPTIONS (policy_tags='["projects/my-project/locations/us/taxonomies/123/policyTags/789"]'), country STRING, signup_date DATE);Une fois un policy tag appliqué et le contrôle d’accès activé sur la taxonomie, les utilisateurs sans roles/datacatalog.categoryFineGrainedReader sur ce tag spécifique reçoivent une erreur lorsque leur requête touche la colonne :
Access Denied: BigQuery BigQuery: User does not have permission to access policy tag"projects/my-project/locations/us/taxonomies/123/policyTags/456" on columnproject.dataset.customers.emailLe niveau de tag approprié est important : taguez au niveau logique le plus élevé pertinent (la catégorie PII, pas les sous-tags individuels SSN ou Email_Address) à moins que différentes sous-catégories n’aient réellement des populations d’accès différentes. Gérer une seule autorisation de policy tag couvre de nombreuses colonnes ; gérer dix autorisations individuelles crée de la charge sans sécurité supplémentaire.
Sécurité au niveau des lignes avec les Row Access Policies
Les Row Access Policies filtrent les résultats de requêtes en fonction de l’identité de l’utilisateur. La même requête SELECT retourne des lignes différentes selon qui l’exécute — sans aucune logique au niveau de l’application, sans tables séparées par segment d’utilisateurs.
-- Create a row access policy: analysts see only their assigned region's dataCREATE ROW ACCESS POLICY analyst_region_filterON `project.dataset.sales`GRANT TO ("group:data-analysts@company.com")FILTER USING (region = SESSION_USER_ATTRIBUTE('region'));
-- Or simpler: filter based on session user email domainCREATE ROW ACCESS POLICY region_east_policyON `project.dataset.sales`GRANT TO ("group:east-analysts@company.com")FILTER USING (region = 'east');
-- Admins see everything (no policy restricts them)-- Multiple policies can apply to the same table -- user sees the union of all matching rowsLa fonction SESSION_USER() permet un filtrage dynamique sans coder en dur les identités des utilisateurs dans les politiques :
-- Dynamic row filtering: each analyst sees only records where owner_email matches their identityCREATE ROW ACCESS POLICY owner_only_accessON `project.dataset.campaign_data`GRANT TO ("group:campaign-managers@company.com")FILTER USING (owner_email = SESSION_USER());Les Row Access Policies s’appliquent de manière transparente. Un utilisateur exécutant SELECT * FROM campaign_data ne voit que les lignes qui passent le filtre de sa politique. Il ne peut pas savoir si des lignes ont été filtrées (il en voit simplement moins) à moins de connaître l’existence de la politique.
Plusieurs politiques se composent en union : si un utilisateur correspond à deux politiques, il voit l’union des deux ensembles de résultats. Cela signifie que vous pouvez superposer des politiques sans craindre qu’une annule l’autre.
Une mise en garde importante : les Row Access Policies n’empêchent pas un utilisateur déterminé d’inférer l’existence de lignes filtrées via des agrégations. SELECT COUNT(*) FROM campaign_data retournera des nombres différents pour différents utilisateurs — ce qui peut en soi révéler des informations. Évaluez si ce risque d’inférence est pertinent pour votre cas d’usage.
Masquage dynamique des données
Le masquage dynamique des données étend la sécurité au niveau des colonnes avec une réponse plus nuancée : au lieu de refuser complètement l’accès aux colonnes sensibles, il affiche des données masquées aux utilisateurs avec des permissions limitées. Les analystes peuvent voir qu’une colonne email existe et contient des valeurs, sans voir les adresses email réelles.
Trois approches de masquage :
Masquage par défaut — retourne la valeur par défaut de la colonne (0 pour les nombres, "" pour les chaînes, null pour les colonnes nullables) :
-- Users with maskedReader on the policy tag see "" instead of the actual email-- Users with fineGrainedReader see "user@example.com"Masquage par hachage — retourne un hash SHA256 de la valeur. Utile quand vous voulez que les analystes puissent suivre des individus entre les tables (en faisant correspondre un hash cohérent) sans exposer les données PII sous-jacentes :
-- Hash masking preserves join-ability without exposing values-- The same email always produces the same hash -- analysts can join tables on itNullification — retourne NULL quelle que soit la valeur réelle. L’option la plus stricte pour les champs qui ne doivent jamais être visibles par certains utilisateurs, même sous forme masquée.
Configurez les règles de masquage dans Data Catalog après avoir mis en place la structure des policy tags :
# Grant maskedReader instead of fineGrainedReader to the analyst groupgcloud data-catalog taxonomies policy-tags set-iam-policy POLICY_TAG_ID \ --location=us \ --member="group:data-analysts@company.com" \ --role="roles/datacatalog.categoryMaskedReader"La valeur pratique : les équipes analytics peuvent travailler avec la structure et les relations des données sans accéder aux valeurs sensibles. Un data scientist construisant un modèle de churn peut voir que les clients ont des adresses email, des numéros de téléphone et des adresses de facturation (et utiliser un hash cohérent pour suivre les individus entre les tables) sans que les données d’entraînement du modèle contiennent des PII réelles. Cela permet un travail analytique que le refus strict au niveau des colonnes bloquerait.
Combiner les trois couches
Ces mécanismes se complètent. Une configuration de contrôle d’accès réaliste pour un dataset d’analytics clients :
| Groupe d’utilisateurs | Accès aux colonnes | Accès aux lignes | Masquage des données |
|---|---|---|---|
| Data Engineers | Toutes les colonnes | Toutes les lignes | Aucun (accès complet) |
| Data Analysts | Bloqué sur SSN, CC# | Leur région uniquement | Email/téléphone haché |
| Compte de service outil BI | Bloqué sur toutes les PII | Toutes les lignes | Aucun (agrégé de toute façon) |
| Équipe de conformité | Toutes les colonnes | Toutes les lignes | Aucun (accès complet) |
La structure des rôles IAM ([[fr/patterns-iam-bigquery|jobUser + dataViewer]]) détermine s’ils peuvent interroger la table. La sécurité au niveau des colonnes avec les policy tags détermine les colonnes visibles. Les Row Access Policies déterminent les lignes qui apparaissent. Le masquage dynamique détermine l’apparence des valeurs sensibles.
Rien de tout cela ne nécessite de modifications de vos modèles dbt ou du SQL de vos applications. Ces mécanismes opèrent au niveau BigQuery — vos requêtes sont identiques, le contrôle d’accès s’applique de manière transparente.
Les anti-patterns qui créent une dette de sécurité
Appliquer les policy tags au niveau du projet plutôt qu’au niveau de la politique — cela affecte toutes les tables d’un projet, rendant impossible l’octroi d’accès à des colonnes différentes pour différents datasets au sein du même projet.
Utiliser le compte de service Compute Engine par défaut pour les charges de production — les permissions de ce compte ne peuvent pas être réduites en dessous des valeurs par défaut au niveau du projet. Toute compromission d’une charge utilisant ce compte expose davantage que prévu. Créez toujours des comptes de service dédiés pour les jobs de production.
Accorder bigquery.dataViewer sans bigquery.jobUser — les utilisateurs peuvent voir les tables dans le navigateur de schéma mais ne peuvent pas exécuter de requêtes. Cela crée de la confusion et des tickets de support sans apporter aucune valeur de sécurité. La paire va toujours ensemble.
Gérer des liaisons IAM individuelles plutôt que des groupes — quand quelqu’un quitte l’entreprise, vous cherchez dans les liaisons IAM de plusieurs projets pour supprimer son accès. La gestion par groupe signifie qu’en le retirant du groupe, son accès est supprimé partout où le groupe est utilisé.
L’investissement principal est la conception de la taxonomie des policy tags et l’établissement de la structure de groupes. La maintenance continue est minimale une fois ces fondations en place.