承認済みビューとマテリアライズド ビュー

このドキュメントでは、BigQuery で承認済みビューとマテリアライズド ビューを作成する方法について説明します。

承認済みビューと承認済みマテリアライズド ビューを使用すると、元のソースデータへのアクセス権を与えることなく、クエリの結果を特定のユーザーやグループと共有できます。ビューやマテリアライズド ビューには、ユーザーではなくデータへのアクセス権が付与されます。ビューまたはマテリアライズド ビューを作成する SQL クエリを使用して、ユーザーがクエリを実行できる列とフィールドを制限することもできます。

承認済みビューまたはマテリアライズド ビューを別のデータセットに作成する場合は、ソースデータのデータセットと承認済みビューのデータセットの両方が同じリージョンのロケーションに存在する必要があります。

個々のビューを承認するのではなく、データセット内のすべてのビューを承認する場合については、承認済みデータセットをご覧ください。

始める前に

このドキュメントの各タスクを実行するために必要な権限をユーザーに与える Identity and Access Management(IAM)のロールを付与します。

必要な権限

承認済みビューを作成および更新するには、ビューを含むデータセットに対する権限と、ビューへのアクセス権を提供するデータセットに対する権限が必要です。

ビューを含むデータセットに対する権限

BigQuery では、ビューはテーブル リソースとして扱われます。このため、ビューを作成するには、テーブルの作成と同じ権限が必要になります。また、ビューの SQL クエリで参照されるテーブルにクエリを実行する権限も必要です。

ビューを作成するには、bigquery.tables.create IAM 権限が必要です。事前定義された IAM ロールの roles/bigquery.dataEditor には、ビューの作成に必要な権限が含まれています。

また、bigquery.datasets.create 権限がある場合は、作成したデータセットにビューを作成できます。所有していないデータのビューを作成するには、そのテーブルに対する bigquery.tables.getData 権限が必要です。

BigQuery での IAM のロールと権限については、事前定義ロールと権限をご覧ください。

ビューへのアクセス権を提供するデータセットに対する権限

データセット プロパティを更新するには、次の IAM 権限が必要です。

  • bigquery.datasets.update
  • bigquery.datasets.setIamPolicy(Google Cloud コンソールでデータセットのアクセス制御を更新する場合にのみ必要)

事前定義されたAM ロールの roles/bigquery.dataOwner には、データセットのプロパティを更新するために必要な権限が含まれています。

また、bigquery.datasets.create 権限がある場合は、作成したデータセットのプロパティを更新できます。

BigQuery での IAM のロールと権限については、事前定義ロールと権限をご覧ください。

ビューを承認する

データセットへの表示アクセス権を付与するには:

コンソール

  1. Google Cloud Console の [BigQuery] ページに移動します。

    BigQuery に移動

  2. [エクスプローラ] ペインでプロジェクトを開いて、データセットを選択します。

  3. [アクションを表示] をクリックし、[開く] をクリックします。

  4. [データセット情報] ペインで、 [共有] をクリックし、[ビューを承認] を選択します。

  5. [ビューを承認] に、承認するビューの名前を入力します。

  6. [承認を追加] をクリックします。

  7. [閉じる] をクリックします。

bq

  1. bq show コマンドを使用して、既存のデータセット情報(アクセス制御も含む)を JSON ファイルに書き込みます。データセットがデフォルト プロジェクト以外のプロジェクトにある場合は、project_id:dataset の形式でプロジェクト ID をデータセット名に追加します。

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

    ここで

    • project_id はプロジェクト ID です。
    • dataset はデータセットの名前です。
    • path_to_file は、ローカルマシン上の JSON ファイルへのパスです。

    例:

    次のコマンドを入力すると、mydataset のアクセス制御が JSON ファイルに書き込まれます。mydataset はデフォルト プロジェクトにあります。

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

    次のコマンドを入力すると、mydataset のアクセス制御が JSON ファイルに書き込まれます。mydatasetmyotherproject にあります。

    bq show --format=prettyjson \
    myotherproject:mydataset > /tmp/mydataset.json
    
  2. JSON ファイルの access セクションに承認済みビューを追加します。

    たとえば、データセットの JSON ファイルの access セクションは次のようになります。

    {
     "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. 編集が完了したら、bq update コマンドを実行します。その際、--source フラグを使用して JSON ファイルを指定します。データセットがデフォルト プロジェクト以外のプロジェクトにある場合は、project_id:dataset の形式でプロジェクト ID をデータセット名に追加します。

    bq update \
    --source path_to_file \
    project_id:dataset

    ここで

    • path_to_file は、ローカルマシン上の JSON ファイルへのパスです。
    • project_id はプロジェクト ID です。
    • dataset はデータセットの名前です。

    例:

    次のコマンドを入力すると、mydataset のアクセス制御が更新されます。mydataset はデフォルト プロジェクトにあります。

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

    次のコマンドを入力すると、mydataset のアクセス制御が更新されます。mydatasetmyotherproject にあります。

     bq update --source /tmp/mydataset.json myotherproject:mydataset
    
  4. アクセス制御の変更を確認するには、show コマンドをもう一度入力します。ただし、今回は情報をファイルに書き込む指定を省略します。

    bq show --format=prettyjson [DATASET]
    

    または

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

API

datasets.patch を呼び出し、access プロパティを使用してアクセス制御を更新します。詳細については、データセットをご覧ください。

datasets.update メソッドはデータセット リソース全体を置き換えます。そのため、アクセス制御の更新には datasets.patch メソッドの方が適切です。

Go

このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Go の設定手順を完了してください。詳細については、BigQuery Go API のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

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

このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Java の設定手順を完了してください。詳細については、BigQuery Java API のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

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

このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Python の設定手順を完了してください。詳細については、BigQuery Python API のリファレンス ドキュメントをご覧ください。

BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

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

ビューへの承認を解除する

ビューへの承認を解除するには:

コンソール

  1. Google Cloud Console の [BigQuery] ページに移動します。

    BigQuery に移動

  2. [エクスプローラ] ペインでプロジェクトを開いて、データセットを選択します。

  3. [共有] > [ビューを承認] をクリックします。

  4. [承認を解除] をクリックします。

  5. [閉じる] をクリックします。

割り当てと上限

  • 承認済みビューは、データセットの制限を受けます。詳細については、データセットの上限をご覧ください。
  • 承認済みビューを削除すると、そのビューへのすべての参照がシステムから削除されるまで最大 24 時間かかることがあります。エラーを回避するには、24 時間待った後で削除されたビューの名前を再利用するか、ビューに一意の名前を作成します。

ビューを使用して行レベルのアクセス権を適用する

ビューを使用して、特定の列(フィールド)へのアクセスを制限できます。テーブルの個々の行へのアクセスを制限する場合、ユーザーまたはグループごとに別々のビューを作成する必要はありません。その代わりに、SESSION_USER() 関数を使用して現在のユーザーのメールアドレスを取得できます。

ユーザーごとに異なる行を表示するには、行の表示を許可するユーザーを含むテーブルに別のフィールドを追加します。次に、SESSION_USER() 関数を使用するビューを作成します。次の例では、ユーザー名が allowed_viewer フィールドに格納されます。

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

この方法では、複数のユーザーに一度にアクセスを許可することはできません。この制限を回避するには、allowed_viewer を繰り返しフィールドにします。これにより、各行に対してユーザーのリストを指定できます。ただし、繰り返しフィールドを使用する場合でも、テーブルにユーザー名を保存するときに、各行にアクセスする個々のユーザーを手動で設定しなければなりません。

代わりの方法としては、allowed_viewer フィールドにグループ名を入力し、グループとユーザーをマッピングする別のテーブルを作成します。グループとユーザーをマッピングするテーブルには、グループ名とユーザー名を保存するスキーマがあります。例: {group:string, user_name:string}。これにより、データを含むテーブルとは別にユーザーとグループの情報を管理できます。

マッピングするテーブルの名前が private.access_control の場合、承認済みのビューを作成する SQL クエリは次のようになります。

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

次のステップ