🧱

Azure Databricks サーバレス SQL からサービスプリンシパルで任意の ADLS Gen 2 上のデータにアクセスする

2023/01/21に公開

はじめに

本記事では、Azure Databricks サーバレス SQL からサービスプリンシパル (アプリケーションの登録) を使用してユーザー任意の Azure Data Lake Storage Gen2 (ADLS Gen2) 上のデータにアクセスする方法についてまとめました。また、一連の手順の中でストレージアカウントネットワークルールの追加を行い、ストレージアカウントに対する接続元 VNet の制限も行っています。

サーバレス SQL 自体については以前の記事を参照してください。
https://zenn.dev/ryo117/articles/784a53a110933d

方法

本記事の対象範囲は下図の赤線で囲った部分です。

手順としては基本的に下記ドキュメントに記載されている情報をベースにしています。ただし、手順がかなり複雑なためステップごとに補足説明していきます。

参考

0. 前提

1. 事前準備

1.1. サンプルデータ作成

下記を参考にサンプルデータを CSV 形式でダウンロードします。

1.2. ADLS Gen2 へアップロード

ダウンロードした CSV ファイルを ADLS Gen2 へアップロードします。下記の例では Azure Portal のストレージブラウザーから行っています。今回は手順をわかりやすくするために data という名前の Blob コンテナ直下にファイルを配置しています。ストレージアカウント名Blob コンテナ名を控えておきます。

1.3. ADLS Gen2 のネットワーク設定の変更

トラブルシューティングをしやすくするため、可能であれば一度ストレージアカウントのファイアウォールと仮想ネットワークの設定をすべてのネットワークから有効に変更します。

1.4. 動作確認

サーバレス SQL ウェアハウスから下記のクエリを実行します。ネットワーク経路としては ADLS Gen2 へアクセスできていますが、現時点で認証情報が不足しているためクエリは失敗します。<container-name><storage-account-name> は事前に控えた値と置き替えます。

DROP TABLE IF EXISTS default.nyctaxi_trips;
CREATE TABLE default.nyctaxi_trips;

COPY INTO
  default.nyctaxi_trips
FROM
  'abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/'
FILEFORMAT = CSV
FORMAT_OPTIONS (
  'mergeSchema' = 'true'
  ,'delimiter' = ','
  ,'header' = 'true'
)
COPY_OPTIONS ('mergeSchema' = 'true')
;

SELECT * FROM default.nyctaxi_trips;

# Error Message
Failure to initialize configuration

2. サービスプリンシパルの作成 (アプリケーションの登録)

Azure Active Directory から作業を行います。下記ドキュメントの手順に従い作成します。

作成が完了したら赤線で囲った部分の情報(表示名・アプリケーション ID・ディレクトリ ID)を控えておきます。

3. サービスプリンシパルへのロール割り当て

ストレージアカウントから作業を行います。下記ドキュメントの手順に従い、割り当て先に前項で作成したサービスプリンシパルを選択してストレージ BLOB データ共同作成者ロールを割り当てます。



4. Azure Databricks シークレットスコープの作成

Azure Databricks から作業を行います。下記ドキュメントの手順に従い作成します。ステップごとに補足説明します。

4.1. Azure Databricks インスタンス名の確認

下記ドキュメントを参考にして調べます。

4.2. シークレットスコープの作成

<databricks-instance> を調べたインスタンス名と置き替えてアクセスします。

https://<databricks-instance>#secrets/createScope

DNS Name と Resource ID は以下のフォーマットで入力します。<keyvault-name><subscription-id><resource-group-name> は実際の値に置き替えます。作成時に設定した Scope Name を控えておきます。

# DNS Name
https://<keyvault-name>.vault.azure.net/
# Resource ID
/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.KeyVault/vaults/<keyvault-name>

参考

シークレットスコープの一覧は Databricks CLI を使うことで確認できます。

5. サービスプリンシパルのクライアントシークレットの作成

Azure Active Directory から作業を行います。下記ドキュメントの手順に従い、上記で作成したサービスプリンシパルのクライアントシークレットを作成します。

作成が完了したらクライアントシークレットを控えておきます。
可能であれば次のステップの直前に作成して直接コピー & ペーストするなどして、クライアントシークレットは絶対に外部に漏らさないよう取り扱いに注意します

6. Azure Key Vault シークレットの作成

Azure Key Vault から作業を行います。下記ドキュメントの手順に従い、Azure Key Vault シークレットを作成します。シークレット値には、前のステップで作成したクライアントシークレットを入力します。名前を控えておきます。

7. Databricks SQL へのサービルプリンシパルの追加

Azure Databricks から作業を行います。下記ドキュメントの手順に従い、Databricks SQL にサービスプリンシパルの認証情報を追加します。手順 6. ワークスペースの上部バーでユーザー名をクリックし、ドロップダウンから [SQL 管理コンソール] を選択します。 から実施します。

項目
Storage Account Name ADLS Gen2 のストレージアカウント名
Application (client) ID サービスプリンシパルの作成時に控えたアプリケーション ID
Directory (tenant) ID サービスプリンシパルの作成時に控えたディレクトリ ID
Secret Scope シークレットスコープ作成時に控えた Scope Name
Secret Key シークレット作成時に控えた 名前

サービスプリンシパルの追加が完了したら。サーバレス SQL ウェアハウスを再起動します。

8. 動作確認

サーバレス SQL ウェアハウスから再び下記クエリを実行します。今度は成功して Delta Table へデータが取り込まれることを確認します。

DROP TABLE IF EXISTS default.nyctaxi_trips;
CREATE TABLE default.nyctaxi_trips;

COPY INTO
  default.nyctaxi_trips
FROM
  'abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/'
FILEFORMAT = CSV
FORMAT_OPTIONS (
  'mergeSchema' = 'true'
  ,'delimiter' = ','
  ,'header' = 'true'
)
COPY_OPTIONS ('mergeSchema' = 'true')
;

SELECT * FROM default.nyctaxi_trips;

9. ADLS Gen2 のネットワーク設定の変更

ストレージアカウントから作業を行います。ファイアウォールと仮想ネットワークの設定を選択した仮想ネットワークと IP アドレスから有効に変更します。

サーバレス SQL ウェアハウスから下記クエリをもう一度実行します。サーバレス SQL ウェアハウスから ADLS Gen2 への通信が許可されなくなるため失敗します。

DROP TABLE IF EXISTS default.nyctaxi_trips;
CREATE TABLE default.nyctaxi_trips;

COPY INTO
  default.nyctaxi_trips
FROM
  'abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/'
FILEFORMAT = CSV
FORMAT_OPTIONS (
  'mergeSchema' = 'true'
  ,'delimiter' = ','
  ,'header' = 'true'
)
COPY_OPTIONS ('mergeSchema' = 'true')
;

SELECT * FROM default.nyctaxi_trips;

# Error Message
Operation failed: "This request is not authorized to perform this operation.", 403, HEAD, https://<storage-account-name>.dfs.core.windows.net/data/?upn=false&action=getAccessControl&timeout=90

10. ストレージアカウントネットワークルールの追加

Azure CLI を使って、下記ドキュメントの手順に従って設定を行います。ステップごとに補足説明します。

10.1. サブネット ID のリストを確認する

下記ドキュメントに Azure Databricks サーバレス SQL が使用している Databricks 社 サブスクリプション上のサブネットの ID のリストが記載されています。今回サーバレス SQL ウェアハウスを作成したリージョンの値を控えておきます。

# Example of East US 2
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2-nephos4/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2-nephos5/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2-nephos6/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2-nephos7/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2-nephos8/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2-nephos9/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c2-nephos3/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c2-nephos4/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c2-nephos5/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c2-nephos6/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c2-nephos7/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c2-nephos8/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c3-nephos1/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c3-nephos2/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c3-nephos3/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c3-nephos4/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c3-nephos5/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2c3-nephos6/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet

10.2. コマンド実行

Azure CLI でサインインして作業対象のサブスクリプションを選択します。az storage account network-rule コマンドを前項で控えたサブネット ID ごとに実行します。例えば、本記事執筆時点で East US 2 リージョンではサーバレス SQL により 18 のサブネットが使われているようですので 18 回コマンドを実行します。<subscription-id><resource-group-name>は作業環境の値と置き替えます。<storage-account-name>は対象 ADLS Gen2 のストレージアカウント名で置き換えます。<databricks-sql-subnet-name>はサブネット ID で置き換えます。

# Command Example
az storage account network-rule add --subscription "<subscription-id>" --resource-group "<resource-group-name>" --account-name "<storage-account-name>" --subnet "<databricks-sql-subnet-name>"
# <databricks-sql-subnet-name> Example
/subscriptions/8453a5d5-9e9e-40c7-87a4-0ab4cc197f48/resourceGroups/prod-azure-eastus2-nephos5/providers/Microsoft.Network/virtualNetworks/kaas-vnet/subnets/worker-subnet

一部サブネットの追加に失敗

本記事執筆時に East US 2 リージョンにて検証した際に、下記 2 つのリソースグループに存在するサブネットの追加に失敗してしまいました。エラーメッセージによるとリソースグループが存在していないとのことで、ドキュメントに記載されている情報に間違いが含まれている可能性があるのですが真実は不明です。これによる影響も不明ですが特に対応方法が存在しないためそのまま進めます。

  • prod-azure-eastus2-nephos4
  • prod-azure-eastus2c2-nephos3
# Error Message
(NetworkAclsValidationFailure) Validation of network acls failure: ResourceGroupNotFound:Resource group 'prod-azure-eastus2-nephos4' could not be found..
Code: NetworkAclsValidationFailure
Message: Validation of network acls failure: ResourceGroupNotFound:Resource group 'prod-azure-eastus2-nephos4' could not be found..

10.3. 設定の確認

ストレージアカウントのファイアウォールと仮想ネットワークの設定を開きます。前項でネットワークルール追加に成功したサブネットが複数表示されていることを確認します。Warning が表示されていますが、ドキュメントのスクリーンショットでも同様に表示されているようですので気にせず進めます。

11. 最終動作確認

サーバレス SQL ウェアハウスから下記クエリを実行します。実行に成功することを確認します。

DROP TABLE IF EXISTS default.nyctaxi_trips;
CREATE TABLE default.nyctaxi_trips;

COPY INTO
  default.nyctaxi_trips
FROM
  'abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/'
FILEFORMAT = CSV
FORMAT_OPTIONS (
  'mergeSchema' = 'true'
  ,'delimiter' = ','
  ,'header' = 'true'
)
COPY_OPTIONS ('mergeSchema' = 'true')
;

SELECT * FROM default.nyctaxi_trips;

一連の設定により、利用者の ADLS Gen2 に対して Azure Databricks サーバレス SQL が使用しているサブネットからの通信が許可され、さらにサーバレス SQL ウェアハウスはサービスプリンシパル認証を使用して ADLS Gen 2 上のデータにアクセスできるようになりました。

手順としてはこれで以上です。

Appendix

サーバレス SQL ウェアハウスを使ってメダリオンアーキテクチャの Siler、Gold に相当するテーブルを作成して、Gold テーブルのデータを ADLS Gen 2 上に CSV ファイルとして書き出してみました。

Silver テーブル作成

一連の手順でデータを取り込んだ nyctaxi_trips テーブルは列のデータ型がすべて STRING になっているため、正確なデータ型を定義した nyctaxi_trips_silver テーブルを作成します。

DROP TABLE IF EXISTS default.nyctaxi_trips_silver;
CREATE TABLE default.nyctaxi_trips_silver (
  tpep_pickup_datetime  TIMESTAMP
  ,tpep_dropoff_datetime TIMESTAMP
  ,trip_distance DOUBLE
  ,fare_amount DOUBLE
  ,pickup_zip INT
  ,dropoff_zip INT
)
USING DELTA
;

INSERT INTO default.nyctaxi_trips_silver (
  tpep_pickup_datetime
  ,tpep_dropoff_datetime
  ,trip_distance
  ,fare_amount
  ,pickup_zip
  ,dropoff_zip
)
SELECT
  CAST(tpep_pickup_datetime AS TIMESTAMP)
  ,CAST(tpep_dropoff_datetime AS TIMESTAMP)
  ,CAST(trip_distance AS DOUBLE)
  ,CAST(fare_amount AS DOUBLE)
  ,CAST(pickup_zip AS INT)
  ,CAST(dropoff_zip AS INT)
FROM
  default.nyctaxi_trips
;

SELECT * FROM default.nyctaxi_trips_silver;

Gold テーブル作成

nyctaxi_trips_silver テーブルのデータから、郵便番号別乗車数の集計を行った nyctaxi_trips_gold テーブルを作成します。

DROP TABLE IF EXISTS default.nyctaxi_trips_gold;
CREATE TABLE default.nyctaxi_trips_gold (
  pickup_zip INT
  ,pickup_count INT
)
USING DELTA
;

INSERT INTO default.nyctaxi_trips_gold (
  pickup_zip
  ,pickup_count
)
SELECT
  pickup_zip
  ,count(pickup_zip)
FROM
	default.nyctaxi_trips_silver
GROUP BY
  pickup_zip
;

SELECT * FROM default.nyctaxi_trips_gold ORDER BY pickup_count DESC;

ADLS Gen2 上に CSV 形式でエクスポート

一連の設定でアクセスできるようになった ADLS Gen2 上にエクスポートします。<container-name><storage-account-name> は作業環境の値と置き替えます。

DROP TABLE IF EXISTS default.nyctaxi_trips_gold_csv;
CREATE TABLE default.nyctaxi_trips_gold_csv
USING CSV
LOCATION 'abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/nyctaxi_trips_gold_csv'
AS
SELECT * FROM default.nyctaxi_trips_gold
;



参考

おわりに

Azure Databricks サーバレス SQL の一般提供 (GA) とリージョン拡大を心待ちにしています。

以上です。🍵

Microsoft (有志)

Discussion