Vues autorisées et vues matérialisées

Ce document explique comment créer des vues autorisées et des vues matérialisées dans BigQuery.

Les vues autorisées et les vues matérialisées autorisées vous permettent de partager des résultats de requête avec des utilisateurs et des groupes particuliers sans leur donner accès aux données sources sous-jacentes. L'accès aux données est accordé à la vue ou à la vue matérialisée, et non à l'utilisateur. Vous pouvez également utiliser la requête SQL qui crée la vue ou la vue matérialisée pour limiter les colonnes et les champs que les utilisateurs peuvent interroger.

Lorsque vous créez une vue autorisée ou une vue matérialisée dans un autre ensemble de données, l'ensemble de données source et celui de la vue autorisée doivent se trouver dans le même emplacement régional.

Pour en savoir plus sur l'autorisation de toutes les vues d'un ensemble de données plutôt que d'autoriser des vues individuelles, consultez la page Ensembles de données autorisés.

Avant de commencer

Attribuez aux utilisateurs des rôles IAM (Identity and Access Management) incluant les autorisations nécessaires pour effectuer l'ensemble des tâches du présent document.

Autorisations requises

Pour créer ou mettre à jour une vue autorisée, vous devez disposer d'autorisations sur l'ensemble de données qui contient la vue et sur celui qui lui donne accès.

Autorisations sur l'ensemble de données contenant la vue

Les vues sont traitées comme des ressources de table dans BigQuery. Par conséquent, la création d'une vue nécessite les mêmes autorisations que la création d'une table. Vous devez également être autorisé à interroger les tables référencées par la requête SQL de la vue.

Pour créer une vue, vous avez besoin de l'autorisation IAM bigquery.tables.create. Le rôle IAM prédéfini roles/bigquery.dataEditor inclut les autorisations dont vous avez besoin pour créer une vue.

En outre, si vous disposez de l'autorisation bigquery.datasets.create, vous pouvez créer des vues dans les ensembles de données que vous créez. Pour créer une vue pour des données qui ne vous appartiennent pas, vous devez disposer de l'autorisation bigquery.tables.getData pour cette table.

Pour en savoir plus sur les rôles et les autorisations IAM dans BigQuery, consultez la page Rôles prédéfinis et autorisations.

Autorisations sur l'ensemble de données donnant accès à la vue

Pour mettre à jour les propriétés d'un ensemble de données, vous devez disposer des autorisations IAM suivantes :

  • bigquery.datasets.update
  • bigquery.datasets.setIamPolicy (obligatoire uniquement lors de la mise à jour des contrôles d'accès d'un ensemble de données dans la console Google Cloud)

Le rôle IAM prédéfini roles/bigquery.dataOwner inclut les autorisations dont vous avez besoin pour mettre à jour les propriétés d'un ensemble de données.

En outre, si vous disposez de l'autorisation bigquery.datasets.create, vous pouvez mettre à jour les propriétés des ensembles de données que vous créez.

Pour en savoir plus sur les rôles et les autorisations IAM dans BigQuery, consultez la page Rôles prédéfinis et autorisations.

Autoriser une vue

Pour accorder l'accès en lecture à un ensemble de données, procédez comme suit :

Console

  1. Accédez à la page BigQuery de Google Cloud Console.

    Accéder à BigQuery

  2. Dans le volet Explorateur, développez votre projet et sélectionnez un ensemble de données.

  3. Cliquez sur Afficher les actions, puis sur Ouvrir.

  4. Dans le volet Informations sur l'ensemble de données, cliquez sur Partager, puis sélectionnez Autoriser les vues.

  5. Dans le champ Autoriser la vue, saisissez le nom de la vue à autoriser.

  6. Cliquez sur Ajouter une autorisation.

  7. Cliquez sur Fermer.

bq

  1. Écrivez les informations sur l'ensemble de données existant (y compris les contrôles d'accès) dans un fichier JSON à l'aide de la commande bq show. Si l'ensemble de données se trouve dans un projet autre que votre projet par défaut, ajoutez l'ID du projet au nom de l'ensemble de données, en respectant le format suivant : project_id:dataset.

    bq show \
    --format=prettyjson \
    project_id:dataset > path_to_file

    Où :

    • project_id est l'ID de votre projet.
    • dataset est le nom de votre ensemble de données ;
    • path_to_file est le chemin d'accès au fichier JSON sur votre ordinateur local.

    Exemples :

    Saisissez la commande suivante pour écrire les contrôles d'accès pour mydataset dans un fichier JSON. mydataset se trouve dans votre projet par défaut.

    bq show --format=prettyjson mydataset > /tmp/mydataset.json
    

    Saisissez la commande suivante pour écrire les contrôles d'accès pour mydataset dans un fichier JSON. mydataset se trouve dans myotherproject.

    bq show --format=prettyjson \
    myotherproject:mydataset > /tmp/mydataset.json
    
  2. Ajoutez la vue autorisée à la section "access" du fichier JSON.

    Par exemple, la section d'accès du fichier JSON d'un ensemble de données ressemblerait à ceci :

    {
     "access": [
      {
       "role": "READER",
       "specialGroup": "projectReaders"
      },
      {
       "role": "WRITER",
       "specialGroup": "projectWriters"
      },
      {
       "role": "OWNER",
       "specialGroup": "projectOwners"
      }
      {
       "role": "READER",
       "specialGroup": "allAuthenticatedUsers"
      }
      {
       "role": "READER",
       "domain": "[DOMAIN_NAME]"
      }
      {
       "role": "WRITER",
       "userByEmail": "[USER_EMAIL]"
      }
      {
       "role": "READER",
       "groupByEmail": "[GROUP_EMAIL]"
      },
      {
       "view":{
       "datasetId": "[DATASET_NAME]",
       "projectId": "[PROJECT_NAME]",
       "tableId": "[VIEW_NAME]"
       }
      }
     ],
    }

  3. Une fois vos modifications terminées, exécutez la commande bq update et incluez le fichier JSON à l'aide de l'option --source. Si l'ensemble de données se trouve dans un projet autre que votre projet par défaut, ajoutez l'ID du projet au nom de l'ensemble de données, en respectant le format suivant : project_id:dataset.

    bq update \
    --source path_to_file \
    project_id:dataset

    Où :

    • path_to_file est le chemin d'accès au fichier JSON sur votre ordinateur local.
    • project_id est l'ID de votre projet.
    • dataset est le nom de votre ensemble de données.

    Exemples :

    Saisissez la commande suivante pour mettre à jour les contrôles d'accès pour mydataset. mydataset se trouve dans votre projet par défaut.

     bq update --source /tmp/mydataset.json mydataset
    

    Saisissez la commande suivante pour mettre à jour les contrôles d'accès pour mydataset. mydataset se trouve dans myotherproject.

     bq update --source /tmp/mydataset.json myotherproject:mydataset
    
  4. Pour vérifier les modifications apportées aux contrôles d'accès, saisissez à nouveau la commande show sans écrire les informations dans un fichier.

    bq show --format=prettyjson [DATASET]
    

    ou

    bq show --format=prettyjson [PROJECT_ID]:[DATASET]
    

API

Appelez la méthode datasets.patch et utilisez la propriété access pour mettre à jour vos contrôles d'accès. Pour en savoir plus, consultez la page Ensembles de données.

Comme la méthode datasets.update remplace l'intégralité de la ressource d'ensemble de données, il est préférable d'utiliser la méthode datasets.patch pour mettre à jour les contrôles d'accès.

Go

Avant d'essayer cet exemple, suivez les instructions de configuration pour Go du guide de démarrage rapide de BigQuery : Utiliser les bibliothèques clientes. Pour en savoir plus, consultez la documentation de référence de l'API BigQuery pour Go.

Pour vous authentifier auprès de BigQuery, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez la page Configurer l'authentification pour les bibliothèques clientes.

import (
	"context"
	"fmt"

	"cloud.google.com/go/bigquery"
)

// updateViewDelegated demonstrates the setup of an authorized view, which allows access to a view's results
// without the caller having direct access to the underlying source data.
func updateViewDelegated(projectID, srcDatasetID, viewDatasetID, viewID string) error {
	// projectID := "my-project-id"
	// srcDatasetID := "sourcedata"
	// viewDatasetID := "views"
	// viewID := "myview"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	srcDataset := client.Dataset(srcDatasetID)
	viewDataset := client.Dataset(viewDatasetID)
	view := viewDataset.Table(viewID)

	// First, we'll add a group to the ACL for the dataset containing the view.  This will allow users within
	// that group to query the view, but they must have direct access to any tables referenced by the view.
	vMeta, err := viewDataset.Metadata(ctx)
	if err != nil {
		return err
	}
	vUpdateMeta := bigquery.DatasetMetadataToUpdate{
		Access: append(vMeta.Access, &bigquery.AccessEntry{
			Role:       bigquery.ReaderRole,
			EntityType: bigquery.GroupEmailEntity,
			Entity:     "example-analyst-group@google.com",
		}),
	}
	if _, err := viewDataset.Update(ctx, vUpdateMeta, vMeta.ETag); err != nil {
		return err
	}

	// Now, we'll authorize a specific view against a source dataset, delegating access enforcement.
	// Once this has been completed, members of the group previously added to the view dataset's ACL
	// no longer require access to the source dataset to successfully query the view.
	srcMeta, err := srcDataset.Metadata(ctx)
	if err != nil {
		return err
	}
	srcUpdateMeta := bigquery.DatasetMetadataToUpdate{
		Access: append(srcMeta.Access, &bigquery.AccessEntry{
			EntityType: bigquery.ViewEntity,
			View:       view,
		}),
	}
	if _, err := srcDataset.Update(ctx, srcUpdateMeta, srcMeta.ETag); err != nil {
		return err
	}
	return nil
}

Java

Avant d'essayer cet exemple, suivez les instructions de configuration pour Java du guide de démarrage rapide de BigQuery : Utiliser les bibliothèques clientes. Pour en savoir plus, consultez la documentation de référence de l'API BigQuery pour Java.

Pour vous authentifier auprès de BigQuery, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez la page Configurer l'authentification pour les bibliothèques clientes.

import com.google.cloud.bigquery.Acl;
import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.Dataset;
import com.google.cloud.bigquery.DatasetId;
import com.google.cloud.bigquery.Table;
import java.util.ArrayList;
import java.util.List;

// Sample to grant view access on dataset
public class GrantViewAccess {

  public static void runGrantViewAccess() {
    // TODO(developer): Replace these variables before running the sample.
    String srcDatasetId = "MY_DATASET_ID";
    String viewDatasetId = "MY_VIEW_DATASET_ID";
    String viewId = "MY_VIEW_ID";
    grantViewAccess(srcDatasetId, viewDatasetId, viewId);
  }

  public static void grantViewAccess(String srcDatasetId, String viewDatasetId, String viewId) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      Dataset srcDataset = bigquery.getDataset(DatasetId.of(srcDatasetId));
      Dataset viewDataset = bigquery.getDataset(DatasetId.of(viewDatasetId));
      Table view = viewDataset.get(viewId);

      // First, we'll add a group to the ACL for the dataset containing the view. This will allow
      // users within that group to query the view, but they must have direct access to any tables
      // referenced by the view.
      List<Acl> viewAcl = new ArrayList<>();
      viewAcl.addAll(viewDataset.getAcl());
      viewAcl.add(Acl.of(new Acl.Group("example-analyst-group@google.com"), Acl.Role.READER));
      viewDataset.toBuilder().setAcl(viewAcl).build().update();

      // Now, we'll authorize a specific view against a source dataset, delegating access
      // enforcement. Once this has been completed, members of the group previously added to the
      // view dataset's ACL no longer require access to the source dataset to successfully query the
      // view
      List<Acl> srcAcl = new ArrayList<>();
      srcAcl.addAll(srcDataset.getAcl());
      srcAcl.add(Acl.of(new Acl.View(view.getTableId())));
      srcDataset.toBuilder().setAcl(srcAcl).build().update();
      System.out.println("Grant view access successfully");
    } catch (BigQueryException e) {
      System.out.println("Grant view access was not success. \n" + e.toString());
    }
  }
}

Python

Avant d'essayer cet exemple, suivez les instructions de configuration pour Python du guide de démarrage rapide de BigQuery : Utiliser les bibliothèques clientes. Pour en savoir plus, consultez la documentation de référence de l'API BigQuery pour Python.

Pour vous authentifier auprès de BigQuery, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez la page Configurer l'authentification pour les bibliothèques clientes.

from google.cloud import bigquery

client = bigquery.Client()

# To use a view, the analyst requires ACLs to both the view and the source
# table. Create an authorized view to allow an analyst to use a view
# without direct access permissions to the source table.
view_dataset_id = "my-project.my_view_dataset"
# Make an API request to get the view dataset ACLs.
view_dataset = client.get_dataset(view_dataset_id)

analyst_group_email = "data_analysts@example.com"
access_entries = view_dataset.access_entries
access_entries.append(
    bigquery.AccessEntry("READER", "groupByEmail", analyst_group_email)
)
view_dataset.access_entries = access_entries

# Make an API request to update the ACLs property of the view dataset.
view_dataset = client.update_dataset(view_dataset, ["access_entries"])
print(f"Access to view: {view_dataset.access_entries}")

# Group members of "data_analysts@example.com" now have access to the view,
# but they require access to the source table to use it. To remove this
# restriction, authorize the view to access the source dataset.
source_dataset_id = "my-project.my_source_dataset"
# Make an API request to set the source dataset ACLs.
source_dataset = client.get_dataset(source_dataset_id)

view_reference = {
    "projectId": "my-project",
    "datasetId": "my_view_dataset",
    "tableId": "my_authorized_view",
}
access_entries = source_dataset.access_entries
access_entries.append(bigquery.AccessEntry(None, "view", view_reference))
source_dataset.access_entries = access_entries

# Make an API request to update the ACLs property of the source dataset.
source_dataset = client.update_dataset(source_dataset, ["access_entries"])
print(f"Access to source: {source_dataset.access_entries}")

Supprimer une autorisation associée à une vue

Pour supprimer une autorisation d'affichage, procédez comme suit :

Console

  1. Accédez à la page BigQuery de Google Cloud Console.

    Accéder à BigQuery

  2. Dans le volet Explorateur, développez votre projet et sélectionnez un ensemble de données.

  3. Cliquez sur Partage > Autoriser les vues.

  4. Cliquez sur Supprimer l'autorisation.

  5. Cliquez sur Fermer.

Quotas et limites

  • Les vues autorisées sont soumises à des limites. Pour en savoir plus, consultez la section Limites des ensembles de données.
  • Si vous supprimez une vue autorisée, la suppression de toutes les références à la vue dans le système peut prendre jusqu'à 24 heures. Pour éviter les erreurs, attendez 24 heures avant de réutiliser le nom d'une vue supprimée ou utilisez un nom unique.

Appliquer un accès de niveau ligne à l'aide d'une vue

Les vues peuvent permettre de restreindre l'accès à des colonnes (champs) spécifiques. Si vous souhaitez restreindre l'accès à des lignes individuelles de votre table, vous n'avez pas besoin de créer des vues distinctes pour chaque utilisateur ou groupe. Au lieu de cela, vous pouvez utiliser la fonction SESSION_USER() pour renvoyer l'adresse e-mail de l'utilisateur actuel.

Pour afficher différentes lignes pour différents utilisateurs, ajoutez à votre table un champ contenant l'utilisateur autorisé à voir la ligne. Ensuite, créez une vue qui utilise la fonction SESSION_USER(). Dans l'exemple suivant, les noms d'utilisateur sont stockés dans le champ allowed_viewer :

SELECT
  COLUMN_1,
  COLUMN_2
FROM
  `dataset.view`
WHERE
  allowed_viewer = SESSION_USER()

La limite de cette approche est que vous ne pouvez accorder l'accès qu'à un seul utilisateur à la fois. Vous pouvez contourner cette limite en faisant de allowed_viewer un champ répété. Cette approche vous permet de fournir une liste d'utilisateurs pour chaque ligne. Toutefois, même si vous utilisez un champ répété, le stockage des noms d'utilisateur dans la table nécessite toujours de suivre manuellement les utilisateurs individuels ayant accès à chaque ligne.

À la place, indiquez des noms de groupe dans le champ allowed_viewer, puis créez une table distincte mappant les groupes avec les utilisateurs. La table qui mappe les groupes avec les utilisateurs possède un schéma qui stocke les noms de groupe et les noms d'utilisateur. Exemple : {group:string, user_name:string}. Cette approche vous permet de gérer les informations sur les utilisateurs et les groupes séparément de la table contenant les données.

Si la table de mappage est nommée private.access_control, la requête SQL utilisée pour créer la vue autorisée est :

SELECT
  c.customer,
  c.id
FROM
  `private.customers` c
INNER JOIN (
  SELECT
    group
  FROM
    `private.access_control`
  WHERE
    SESSION_USER() = user_name) g
ON
  c.allowed_group = g.group

Étapes suivantes