【第21回】Azureで社内システム再現（クラウド編）｜Data FactoryでBlob→SQLの転送を自動化してみた①

## 概要

これまでの「オンプレ編」では、Azure の仮想マシン（IaaS）を使って、社員番号から名前を検索できるシンプルな社内システムを構築してきました。Active Directory、SQL Server、ADFS などを組み合わせ、オンプレミスの構成を仮想的に再現しています。

※全体構成の詳細は、[【第0回】Azureで社内システム再現（オンプレ編）｜構成図と動作の流れ](https://qiita.com/your-link-here) をご参照ください。

クラウド編では、これまでの構成をベースにしつつ、Azure のマネージドサービス（PaaS）を中心とした構成へ段階的に移行していきます。

※クラウド移行全体の設計方針については、[【第10.5回】Azureで社内システム再現（クラウド編）｜オンプレ構成をどうクラウドに移行するか？](https://qiita.com/saba_infra/items/4ff691131593e947d6cf) にまとめています。

---
## システム構成（今回の対象範囲）

今回のテーマは、**Azure Data Factory（ADF）を使って、Blob Storage に保存された社員情報の CSV ファイルを Azure SQL Database にコピーする構成を実現すること**です。

まず、下図は「クラウド編」におけるシステム全体の構成を示したものです。

![スクリーンショット 2025-04-19 11.08.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/6cce3240-3c7d-4d79-82a5-8037cceccf45.png)

このうち、**赤枠で示している「ADF → Blob Storage → SQL Database」間のデータ転送構成**が、今回の対象範囲です。

---

次に、下図がその詳細構成図です。

![cloudのhw_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/f2d5a367-c290-42ba-a75c-2521118de1f5.png)

Azure Data Factory（ADF）は、クラウド上のデータ連携や加工をノーコードで構築できる **データ統合サービス**です。  
GUI上の操作でコピー処理や条件分岐などのパイプライン（処理の流れ）を作成でき、さまざまなデータソース間の接続や処理を自動化できます。

今回は、**Blob Storage に保存された CSV ファイルを ADF で読み取り、SQL Database に転送する構成**を構築しました。

---

今回は以下の作業を行いました。

- Azure Data Factory を作成し、マネージドIDを有効化  
- Blob Storage 側にアクセス権限（ストレージ関連ロール）を付与  
- SQL Database 側にもマネージドIDを SQLユーザーとして登録し、`db_datawriter` 権限を付与  
- ADF Studio 上で「データのコピー」アクティビティを作成し、Blob Storage と SQL Database を接続  
- ストレージやSQLのネットワーク設定（ファイアウォール・アクセス許可）を調整して接続できるよう構成




## Azure Data Factory を使って Blob Storage の CSV を SQL Database にコピーする

今回は、Azure Data Factory（以下 ADF）を使って、Blob Storage に格納された社員情報の CSV ファイルを Azure SQL Database にコピーする構成を実装します。

---

### データファクトリの作成

Azure ポータルから「データファクトリ」を選択し、新しいインスタンスを作成します。  
今回は `adf-employee` という名前で作成しました。

![ADF作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/7435da1b-d35f-4a01-86fb-5bbf463e1e17.png)

---

### スタジオを起動

作成したデータファクトリのページにある「スタジオの起動」をクリックして、ADF Studio を開きます。

![スタジオ起動](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/4f6b1503-6fb2-4885-819a-c171560f7f65.png)

---

### コピーアクティビティの作成

スタジオが起動したら、「移動と変換」カテゴリから `データのコピー` アクティビティをキャンバス上にドラッグ＆ドロップします。

今回は、**Blob Storage にある CSV を SQL Database にコピー**する構成のため、アクティビティ名を `Copy_EmployeeBlobToSql` としました。

## Azure Data Factory を使って Blob Storage の CSV を SQL Database にコピーする

今回は、Azure Data Factory（以下 ADF）を使って、Blob Storage に格納された社員情報の CSV ファイルを Azure SQL Database にコピーする構成を実装します。

---

### ADF（データファクトリ）の作成

Azure ポータルから「データファクトリ」を選択し、新しいインスタンスを作成します。  
今回は `adf-employee` という名前で作成しました。

![ADF作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/7435da1b-d35f-4a01-86fb-5bbf463e1e17.png)

---

### スタジオを起動

作成したデータファクトリのブレードにある「スタジオの起動」をクリックして、ADF Studio を開きます。

![スタジオ起動](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/4f6b1503-6fb2-4885-819a-c171560f7f65.png)

---

### コピーアクティビティの作成

スタジオが起動したら、「移動と変換」カテゴリから `データのコピー` アクティビティをキャンバス上にドラッグ＆ドロップします。

今回は、Blob Storage にある CSV を SQL Database にコピーする構成のため、アクティビティ名を `Copy_EmployeeBlobToSql` としました。

![コピーアクティビティ作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/407d57ef-7309-4b55-807c-a1de67d770a2.png)

---

### コピー元（Blob Storage）の設定

コピーアクティビティの「ソース」設定から、新しいデータセットを作成します。  
今回は、Automation によって保存された **CSV形式の社員情報ファイル** をコピー対象とするため、Blob Storage を選択します。

---

#### ソースデータセットの新規作成

「新規」をクリックして、コピー元となる BLOB への接続を設定します。

![ソースデータセット作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/6e54f15a-f024-4af4-97a6-88acfb1519b1.png)

---

#### BLOB を選択

データストアの種類として「Azure Blob Storage」を選択します。

![BLOB選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/432547ac-4b1a-40a0-820c-15a953313344.png)

---

#### CSV 形式のデータセットを選択

保存されているファイルは CSV形式 なので、フォーマットとして「DelimitedText（CSV）」を選択します。

![CSV選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/1281ce0f-9ae0-45b3-a787-7d991363dfa1.png)

---

#### リンクサービスの作成

Blob Storage への接続を表すリンクサービスを新規作成します。  
ここでは `EmpBlobStorage_LS` という名前を付けました。  

![リンクサービス作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/b3848084-bf62-4a17-a517-10327f1d3f6c.png)

接続方法として「統合ランタイム」を使用します。  
これは ADF がどこで処理を実行するかを決めるもので、以下のような種類があります：

- **Azure 統合ランタイム（デフォルト）**：Azure のマネージド環境で実行され、Blob などのクラウドサービスに直接アクセス可能。  
  ※ 通信は **パブリックネットワーク経由** で行われます（対象ストレージがパブリックアクセス可能である必要あり）。

- **セルフホステッド統合ランタイム**：オンプレやVNetにあるリソースにアクセスする際に使用（Automation や Hybrid Worker に近い考え方）。

> 本当は ADF もセルフホステッド統合ランタイムを使って、全体を閉域構成で統一したかったのですが、  
> Azure のファイアウォール機能との連携も試してみたかったため、今回は Azure 統合ランタイムを採用しました。

---

### マネージドIDの有効化とストレージアクセス権の付与

接続テストを実行すると、以下の「マネージドIDが設定されていない」といった内容のエラーが表示され接続に失敗しました。
![スクリーンショット 2025-04-04 11.41.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/c11fd071-1a8e-4d14-a58d-4fdbcbffcd24.png)



---

### マネージドIDの有効化とストレージアクセス権の付与

接続テストを実行すると、「マネージドIDが設定されていない」といった内容のエラーが表示されました。

そのため、Azure Data Factory にマネージドIDを有効化し、Blob Storage 側で必要なアクセス権を付与します。

---

#### マネージドIDを有効化する

ADFの「ID」メニューから、システム割り当てを「有効」に設定します。

![マネージドID有効化](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/913b96b9-2152-4953-8f18-d5a43e154900.png)

---

#### ストレージアカウントにロールを付与

Blob Storage にアクセスできるように、マネージドIDに対して以下のロールを割り当てました。

- **ストレージアカウント共同作成者（Storage Account Contributor）**  
  → ストレージアカウント自体に対する操作権限

![共同作成者ロール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/cdd83bfb-ae31-4205-92a8-bc06b4e4b084.png)

- **ストレージ BLOB データ共同作成者（Storage Blob Data Contributor）**  
  → BLOB データの読み書き・削除が可能

![BLOBロール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/5738413a-6b39-462c-a6bf-0b7992bddb2e.png)

---

### ADF 統合ランタイム経由での接続とパブリックアクセス設定

今回、ADF は **統合ランタイム** を使ってストレージアカウントに接続しています。  
この構成では、**パブリックネットワーク経由でのアクセス**となるため、ストレージ側で **パブリックアクセスの許可設定** が必要です。

---

#### ストレージアカウントのネットワーク設定を変更

以下のように、パブリックアクセスを最小限に許可する形でネットワーク設定を行いました。

- 「選択した仮想ネットワークと IP アドレス」
- 「信頼された Azure サービスからのアクセスを許可する」

![ストレージアクセス設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/dfb0b892-6631-4b2f-8530-aec059ab27b9.png)

この「信頼されたサービス」の一覧には ADF も含まれており、有効にすることでアクセスが許可されます。

![信頼されたサービス補足](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/01f4df58-5b1b-42b9-a37b-858d75415ea6.png)

> 参考：公式ドキュメント  
> https://learn.microsoft.com/ja-jp/azure/storage/common/storage-network-security?tabs=azure-portal#exceptions

---

#### 宛先コンテナの接続テスト

ネットワーク設定を変更したあと、コピー元となる BLOB ファイルのパス（コンテナ）を指定して接続テストを実施。  
無事に成功しました。

![接続テスト成功](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/670caa2e-b2d8-45b8-822e-3e67ccd109e1.png)

---

#### コンテナ内のファイルパスを指定

最後に、ソースデータとして読み取るファイルのパスを指定します。  
今回のコンテナ名は `empdata` です。

![ファイルパス指定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/1488b412-4a4d-4225-a12f-0603d40b7e11.png)

これで、ソース（コピー元）の設定は完了です。

---

### Sink（Azure SQL Database）の設定

次に、コピー先（Sink）として Azure SQL Database を設定していきます。

---

#### データベース接続の構成

シンクに Azure SQL Database を選択し、CSVファイルの内容をこのDBにコピーする構成とします。

![SQL DB選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/22ab3539-0c7b-441a-aa48-6d7156b459c4.png)

---

#### 接続方法の指定

接続には、ソースと同様に **統合ランタイム** を使用します。

![統合ランタイム](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/75cc4937-ce6f-426c-bf0e-d091d36d177e.png)

---

#### 認証方式の選択

認証には **マネージドID** を選択しました。

![マネージドID認証](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/d9660fbe-b2ad-4bfe-99b1-0b8b5675102e.png)

---

#### 必要なロールの付与

マネージドIDが SQL Server にアクセスできるよう、以下のロールを付与します：

- **SQL Server 共同作成者**

![SQL Server 共同作成者](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/4c19e281-6df6-4d4d-b87d-d02cd378daca.png)

- **SQL Database 共同作成者**

![SQL DB 共同作成者](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/baef6e8c-1794-407e-ab40-11397201c111.png)

#### 接続テストとFWの設定

接続テストを実施すると、ファイアウォールのルールに関するエラーが表示されました。

![接続テストエラー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/de9fa66e-cdb5-4c86-b208-20fb42e970d0.png)

これは、ADF が **統合ランタイムを通じてパブリック経由で SQL に接続しており**、**SQL Server 側ではパブリックアクセスが無効化されていたため、接続が拒否されていました**。

---

#### ファイアウォールルールの追加

SQL Server の「ネットワーク」設定から、**パブリックアクセスを有効化**したうえで、  
**接続エラー時に表示された IP アドレスを許可するファイアウォールルールを追加**しました。

![FWルール追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/5e79812f-4506-4196-91ab-79b994aea7f1.png)

---


### マネージドIDでのSQL接続に失敗する理由と対処

再度接続テストを実施したら、以下のエラーが発生しました。

![接続エラー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/80bf10b2-fac3-439d-afea-13ea3993e675.png)

> Login failed for user '<token-identified principal>'  
> ⇒ ADF（マネージドID）による接続は試みられましたが、SQL側でこのIDを認識・許可できていない状態です。

---

### なぜエラーになるのか？

ここでポイントとなるのが、「マネージドIDもSQL上では“ユーザー”として登録されていないといけない」という点です。

Azureのリソースに対しては、Azureポータル上の「ロール（例：SQL DB 共同作成者）」を付与すれば操作できますが、  
**SQL Database にログインするためには、SQL内部にユーザーが存在している必要があります**。

---

### AzureのロールとSQL内部ユーザーの違い

| 種類 | 役割 | 設定する場所 | 今回必要か |
|------|------|--------------|-------------|
| SQL Server 共同作成者 / SQL DB 共同作成者 | Azure上のSQLリソースの作成・構成・削除 | Azure ポータル（IAM） | 不要（今回は関係なし） |
| SQLユーザー（EXTERNAL PROVIDER） | DBへのログインやデータ操作（SELECT, INSERT など） | SSMSやT-SQLで作成 | 必要（これがないとログイン不可） |

---

### どうやってSQLにマネージドIDのユーザーを作るのか？

SQLにユーザーを追加するには `CREATE USER FROM EXTERNAL PROVIDER` を使いますが、  
この操作は**Entra ID（旧Azure AD）で認証されたアカウント**でないと実行できません。

今回、SQL認証ユーザー（例：`sqladmin`）で試しましたが、実行権限がなく失敗しました。

![Entraログイン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/b5713523-dddb-4821-915e-b6717f75262f.png)

---


### マネージドIDをSQLユーザーとして登録する

Microsoft Entra ID 認証で SQL Server にログインし、マネージドIDのユーザーを作成します。  
以下は実際に実行したときの画面です。

![マネージドIDユーザー作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/0bcf5e9a-992d-4aaf-b664-7f49e36c2523.png)

```sql
CREATE USER [<マネージドID名>] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [<マネージドID名>];
ALTER ROLE db_datawriter ADD MEMBER [<マネージドID名>];
```

今回のADFのパイプラインでは、SQL Database に対して以下の操作を行っています。

- テーブル内の既存データをすべて削除(DELETE)

- Blob StorageのCSVファイルの内容を全件挿入(INSERT)


このため、付与するロールは db_datawriter だけで十分でした。
db_datareader（SELECT権限）は今回は不要ですが、将来的にSQL側の中身を読み取る処理が発生する可能性があれば、その際に追加すれば問題ありません。

---



### 接続テストの再実行と設定完了

マネージドIDのユーザー作成とロール付与を行ったあと、再度接続テストを実行しました。

![接続テスト成功](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037248/4751c399-7ce0-4397-b635-f1744a08e06e.png)

結果、無事に接続が成功。

これで、Azure SQL Database 側の接続設定は完了しました。