Vistas autorizadas y vistas materializadas

En este documento, se describe cómo crear vistas autorizadas y vistas materializadas en BigQuery.

Las vistas autorizadas y las vistas materializadas autorizadas te permiten compartir resultados de consultas con usuarios y grupos específicos sin darles acceso a los datos de origen subyacentes. Se otorga acceso a los datos a la vista o la vista materializada, en lugar de al usuario. También puedes usar la consulta en SQL que crea la vista o la vista materializada para restringir las columnas y los campos que los usuarios pueden consultar.

Cuando realizas una vista autorizada o una vista materializada en otro conjunto de datos, el conjunto de datos de origen y el de la vista autorizada deben estar en la misma ubicación regional.

Si deseas obtener información para autorizar todas las vistas de un conjunto de datos, en lugar de autorizar vistas individuales, consulta Conjuntos de datos autorizados.

Antes de comenzar

Otorga funciones de Identity and Access Management (IAM) que les brindan a los usuarios los permisos necesarios para realizar cada tarea de este documento.

Permisos necesarios

Para crear o actualizar una vista autorizada, necesitas permisos en el conjunto de datos que contiene la vista y en el conjunto de datos que proporciona acceso a la vista.

Permisos del conjunto de datos que contiene la vista

Las vistas se tratan como recursos de tabla en BigQuery, por lo que la creación de una vista requiere los mismos permisos que la creación de una tabla. También debes tener permisos para consultar las tablas a las que hace referencia la consulta en SQL de la vista.

Para crear una vista, necesitas el permiso bigquery.tables.create de IAM. El rol predefinido de IAM roles/bigquery.dataEditor incluye los permisos que necesitas para crear una configuración.

Además, si tienes el permiso bigquery.datasets.create, puedes crear vistas en los conjuntos de datos que crees. Si deseas crear una vista para datos que no son de tu propiedad, debes tener el permiso bigquery.tables.getData para esa tabla.

Para obtener más información sobre los roles y los permisos de IAM en BigQuery, consulta Roles y permisos predefinidos.

Permisos del conjunto de datos que otorga acceso a la vista

Para actualizar las propiedades del conjunto de datos, necesitas los siguientes permisos de IAM:

  • bigquery.datasets.update
  • bigquery.datasets.setIamPolicy (solo es necesaria cuando se actualizan los controles de acceso del conjunto de datos en la consola de Google Cloud)

El rol predefinido de IAM roles/bigquery.dataOwner incluye los permisos que necesitas para actualizar las propiedades de un conjunto de datos.

Además, si tienes el permiso bigquery.datasets.create, puedes actualizar las etiquetas de los conjuntos de datos que crees.

Para obtener más información sobre los roles y los permisos de IAM en BigQuery, consulta Funciones y permisos predefinidos.

Autoriza una vista

Para otorgar acceso de lectura a un conjunto de datos, sigue estos pasos:

Console

  1. Ve a la página de BigQuery en la consola de Google Cloud.

    Ir a BigQuery

  2. En el panel Explorador, expande tu proyecto y elige un conjunto de datos.

  3. Haz clic en Ver acciones y, luego, en Abrir.

  4. En el panel Información del conjunto de datos, haz clic en Compartir y, luego, selecciona Autorizar vistas.

  5. En Autorizar vistas, escribe el nombre de la vista que quieras autorizar.

  6. Haz clic en Agregar autorización.

  7. Haz clic en Cerrar.

bq

  1. Escribe la información del conjunto de datos existente (incluidos los controles de acceso) en un archivo JSON mediante el comando bq show. Si el conjunto de datos está en un proyecto que no es tu proyecto predeterminado, agrega el ID del proyecto al nombre del conjunto de datos en el siguiente formato: project_id:dataset.

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

    En el ejemplo anterior, se ilustra lo siguiente:

    • project_id es el ID del proyecto.
    • dataset es el nombre del conjunto de datos.
    • path_to_file es la ruta al archivo JSON en tu máquina local.

    Ejemplos:

    Ingresa el siguiente comando para escribir los controles de acceso de mydataset en un archivo JSON. mydataset está en tu proyecto predeterminado.

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

    Ingresa el siguiente comando para escribir los controles de acceso de mydataset en un archivo JSON. mydataset está en myotherproject.

    bq show --format=prettyjson \
    myotherproject:mydataset > /tmp/mydataset.json
    
  2. Agrega la vista autorizada a la sección "acceso" del archivo JSON.

    Por ejemplo, la sección de acceso del archivo JSON de un conjunto de datos se vería de la siguiente manera:

    {
     "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. Cuando tus ediciones estén completas, usa el comando bq update con la marca --source para incluir el archivo JSON. Si el conjunto de datos está en un proyecto que no es tu proyecto predeterminado, agrega el ID del proyecto al nombre del conjunto de datos en el siguiente formato: project_id:dataset.

    bq update \
    --source path_to_file \
    project_id:dataset
    

    En el ejemplo anterior, se ilustra lo siguiente:

    • path_to_file es la ruta al archivo JSON en tu máquina local.
    • project_id es el ID del proyecto.
    • dataset es el nombre del conjunto de datos.

    Ejemplos:

    Ingresa el siguiente comando a fin de actualizar los controles de acceso para mydataset. mydataset está en tu proyecto predeterminado.

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

    Ingresa el siguiente comando a fin de actualizar los controles de acceso para mydataset. mydataset está en myotherproject.

     bq update --source /tmp/mydataset.json myotherproject:mydataset
    
  4. Para verificar los cambios del control de acceso, ingresa otra vez el comando show sin escribir la información en un archivo.

    bq show --format=prettyjson [DATASET]
    

    o

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

API

Llama a datasets.patch y usa la propiedad access para actualizar tus controles de acceso. Para obtener más información, consulta Conjuntos de datos.

Debido a que el método datasets.update reemplaza todo el recurso de conjunto de datos, es preferible usar el método datasets.patch para actualizar los controles de acceso.

Go

Antes de probar este ejemplo, sigue las instrucciones de configuración para Go incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Go.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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

Antes de probar este ejemplo, sigue las instrucciones de configuración para Java incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Java.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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

Antes de probar este ejemplo, sigue las instrucciones de configuración para Python incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Python.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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

Quita la autorización a una vista

Para quitar la autorización de una vista, haz lo siguiente:

Consola

  1. Ve a la página de BigQuery en la consola de Google Cloud.

    Ir a BigQuery

  2. En el panel Explorador, expande tu proyecto y elige un conjunto de datos.

  3. Haz clic en Compartir > Autorizar vistas.

  4. Haz clic en Quitar autorización.

  5. Haz clic en Cerrar.

Cuotas y límites

  • Las vistas autorizadas están sujetas a los límites de los conjuntos de datos. Para obtener más información, consulta Límites de conjuntos de datos.
  • Si quitas una vista autorizada, pueden pasar hasta 24 horas para que se quiten del sistema todas las referencias a la vista. Para evitar errores, espera 24 horas antes de reutilizar el nombre de una vista que se quitó o crea un nombre único para tu vista.

Aplica accesos a nivel de fila con una vista

Las vistas se pueden usar para restringir el acceso a columnas específicas (campos). Si deseas restringir el acceso a las filas individuales en tu tabla, no necesitas crear vistas por separado para cada usuario o grupo. En su lugar, puedes usar la función SESSION_USER() para mostrar la dirección de correo electrónico del usuario actual.

A fin de mostrar filas diferentes a distintos usuarios, agrega otro campo a la tabla que contiene el usuario que tiene permiso para ver la fila. Luego, crea una vista que use la función SESSION_USER(). En el siguiente ejemplo, los nombres de usuario se almacenan en el campo allowed_viewer:

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

La limitación de este método es que puedes otorgar acceso a un solo usuario a la vez. Puedes evitar esta limitación si haces que allowed_viewer sea un campo repetido. Este enfoque te permite proporcionar una lista de usuarios para cada fila. Pero incluso si usas un campo repetido, almacenar los nombres de usuario en la tabla requerirá que realices el seguimiento manual de los usuarios individuales que tienen acceso a cada fila.

En su lugar, propaga el campo allowed_viewer con nombres de grupos y crea una tabla aparte que asigne los grupos a los usuarios. La tabla que asigna los grupos a los usuarios tendría un esquema que almacene los nombres de grupos y de usuarios. Por ejemplo: {group:string, user_name:string} Este método te permite administrar la información del usuario y del grupo por separado desde la tabla que contiene los datos.

Si la tabla de asignación se llama private.access_control, la consulta de SQL que se usa para crear la vista autorizada sería como la que se ve a continuación:

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

¿Qué sigue?