Créer des vues autorisées

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

Vous pouvez créer une vue autorisée dans BigQuery selon les méthodes suivantes :

  • Utiliser Cloud Console
  • En exécutant la commande bq mk de l'outil de ligne de commande bq
  • En appelant la méthode API tables.insert
  • Utiliser les bibliothèques clientes

Présentation

En créant une vue autorisée dans BigQuery, vous permettez à cette vue d'accéder à un ensemble de données. Une vue autorisée vous permet 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. Vous pouvez également utiliser la requête SQL de la vue pour limiter les colonnes (champs) que les utilisateurs peuvent interroger.

Lorsque vous créez une vue autorisé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 consulter un tutoriel sur la création d'une vue autorisée, consultez la page Créer une vue autorisée.

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.

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. Pour créer une vue, vous devez au minimum disposer des autorisations bigquery.tables.create. Les rôles IAM prédéfinis suivants incluent les autorisations bigquery.tables.create :

  • bigquery.dataEditor
  • bigquery.dataOwner
  • bigquery.admin

En outre, si un utilisateur possède les autorisations bigquery.datasets.create, il obtient également un accès bigquery.dataOwner à l'ensemble de données qu'il crée. L'accès bigquery.dataOwner permet à l'utilisateur de créer des vues dans l'ensemble de données.

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

Ensemble de données donnant accès à la vue

Pour mettre à jour les propriétés d'un ensemble de données, vous devez au minimum disposer des autorisations bigquery.datasets.update et bigquery.datasets.get. Les rôles IAM prédéfinis suivants incluent les autorisations bigquery.datasets.update et bigquery.datasets.get :

  • bigquery.dataOwner
  • bigquery.admin

En outre, si un utilisateur possède les autorisations bigquery.datasets.create, il obtient également un accès bigquery.dataOwner à l'ensemble de données qu'il crée. L'accès bigquery.dataOwner permet à l'utilisateur de mettre à jour les propriétés des ensembles de données qu'il crée.

Pour en savoir plus sur les rôles et les autorisations IAM dans BigQuery, consultez la page Contrôle des accès.

Accorder aux vues l'accès aux ensembles de données

Pour accorder à une vue l'accès à un ensemble de données :

Console

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

  2. Dans le panneau de détails, cliquez sur Partager l'ensemble de données.

  3. Dans le panneau Autorisations d'ensemble de données, sélectionnez l'onglet Vues autorisées.

  4. Dans la section Partager la vue autorisée :

    • Dans le champ Sélectionner un projet, vérifiez le nom du projet. Si la vue se trouve dans un autre projet, veillez à le sélectionner.
    • Dans le champ Sélectionner un ensemble de données, choisissez l'ensemble de données contenant la vue.
    • Dans le champ Sélectionner une vue, sélectionnez la vue que vous autorisez.
  5. Cliquez sur Ajouter, puis sur OK.

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 show. Si l'ensemble de données se trouve dans un projet autre que celui par défaut, ajoutez l'ID de ce 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 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 celui par défaut, ajoutez l'ID de ce 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 l'exemple ci-dessous, suivez la procédure de configuration pour Go décrite dans le 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 en langage Go.

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 l'exemple ci-dessous, suivez la procédure de configuration pour Java décrite dans le 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 en langage Java.

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 l'exemple ci-dessous, suivez la procédure de configuration pour Python décrite dans le 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 Python.

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}")

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 permet de fournir une liste d'utilisateurs pour chaque ligne, mais 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 chaque utilisateur 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