AWS DataZone を本番導入して6ヶ月、「誰もデータの場所を知らない」問題は解決したのか
「このテーブルどこにある?」という質問が週20件……。DataZone導入でメタデータ管理は本当に改善したのか。3ヶ月かかってやっと軌道に乗った実体験と、最初の1ヶ月に遭遇した落とし穴を正直に書きます。
DataZone導入のきっかけ:「誰がどのデータを持ってるか、誰も知らない」問題
半年前、うちのデータ基盤チームで深刻な問題が表面化した。データエンジニアが8人いて、Redshift・S3・Aurora・Glueカタログと複数のデータストアを管理しているんだけど、アナリストから「このテーブル、どこにある?」「このカラムって何を意味するの?」という質問が毎週20件以上来るようになっていた。
以前からデータ品質管理2026年版の記事でも書いたように、品質問題とメタデータ管理は切り離せない。でも当時のうちの状況は、データ品質どころかデータの存在自体が把握できていない状態だった。Confluenceにドキュメントを書いても1ヶ月後には古くなる。Slackで聞いても「たぶんこっち」で終わる。これは組織の問題でもあるけど、ツール的な解決策を探しているタイミングで「AWS DataZone、そろそろ本格的に使えるんじゃ?」という話になった。
結論を先に言うと、導入してよかったと思っている。ただ「よかった」と言えるまでに3ヶ月かかって、最初の1ヶ月は正直しんどかった。その過程を書いていく。
DataZoneのアーキテクチャと、うちが実際に組んだ構成
まず構成の全体像を見てほしい。DataZoneをシンプルに言うと「データポータル + メタデータ管理 + アクセス制御」を一体化したサービスだけど、既存のデータ基盤との統合方法によって複雑度が全然違う。
graph TB
subgraph "AWS DataZone ドメイン"
DZ_Portal["DataZone ポータル\n(ビジネスユーザー向け)"]
DZ_Catalog["データカタログ\n(メタデータ管理)"]
DZ_Glossary["ビジネスグロッサリー\n(用語定義)"]
DZ_Projects["プロジェクト管理\n(アクセス制御)"]
end
subgraph "データ生産者アカウント (Prod)"
subgraph "VPC"
RDS_Aurora["Aurora PostgreSQL\n(トランザクションDB)"]
Glue_ETL["AWS Glue 5.0\n(ETLジョブ)"]
end
S3_Raw["S3 Raw Layer\n(データレイク)"]
Glue_Catalog["Glue Data Catalog\n(スキーマ管理)"]
LF_Producer["Lake Formation\n(権限管理)"]
end
subgraph "データ分析アカウント (Analytics)"
Redshift_SW["Redshift Serverless\n(DWH)"]
Athena["Amazon Athena\n(クエリ)"]
LF_Consumer["Lake Formation\n(権限管理)"]
QS["QuickSight\n(BI)"]
end
subgraph "ガバナンスアカウント"
DZ_Domain["DataZone ドメイン\n(管理コンソール)"]
LF_Central["Lake Formation\n(集中管理)"]
CT["CloudTrail\n(監査ログ)"]
end
Glue_ETL --> S3_Raw
RDS_Aurora --> Glue_ETL
S3_Raw --> Glue_Catalog
Glue_Catalog --> LF_Producer
LF_Producer --> DZ_Catalog
DZ_Catalog --> DZ_Portal
DZ_Catalog --> DZ_Glossary
DZ_Portal --> DZ_Projects
DZ_Projects --> LF_Consumer
LF_Consumer --> Redshift_SW
LF_Consumer --> Athena
Athena --> QS
DZ_Domain --> LF_Central
LF_Central --> LF_Producer
LF_Central --> LF_Consumer
CT --> DZ_Domain
2026年時点のベストプラクティスはマルチアカウント構成が前提になる。データ生産者アカウント(本番データがある)、データ分析アカウント(アナリストが触る)、ガバナンスアカウント(DataZoneドメインを置く)の3層構造にした。最初は1アカウントで試したんだけど、Lake Formationの権限管理が破滅的にカオスになるので、マルチアカウント構成を強く推奨する。
ドメイン設計で最初に詰まった話
DataZoneの「ドメイン」という概念が最初ピンとこなかった。Salesforceのドメインでも、Auth0のドメインでもない。DataZoneにおけるドメインは「データ管理の組織単位」で、プロジェクトやメンバーシップの親になる概念だ。
最初に1つのドメインで全部管理しようとしたら、事業部ごとのアクセス権限が混在してしまい、「マーケチームがFinanceのデータにアクセスできる」という事態が起きた。今は事業部単位でドメインを分けている。
import boto3
datazone_client = boto3.client('datazone', region_name='ap-northeast-1')
# ドメイン作成
response = datazone_client.create_domain(
name='marketing-data-domain',
description='マーケティング部門のデータカタログドメイン',
domainExecutionRole='arn:aws:iam::123456789012:role/DataZoneDomainExecutionRole',
singleSignOn={
'type': 'IAM_IDC', # IAM Identity Centerとの統合
'userAssignment': 'AUTOMATIC'
},
tags={
'Department': 'Marketing',
'Environment': 'Production',
'CostCenter': 'MKT-001'
}
)
print(f"Domain ID: {response['id']}")
print(f"Portal URL: {response['portalUrl']}")
実行結果:
Domain ID: dzd_xxxxxxxxxxxxxxxxx
Portal URL: https://dzd_xxx.datazone.ap-northeast-1.amazonaws.com
Glue Data Catalog連携とアセット登録の実態
DataZoneで一番時間を使ったのがここだ。GlueカタログのテーブルをDataZoneのアセットとして登録する作業は、自動化できる部分と手作業が必要な部分が混在している。
データソース設定(自動クロール)
# データソース作成(Glueカタログ連携)
ds_response = datazone_client.create_data_source(
domainIdentifier='dzd_xxxxxxxxxxxxxxxxx',
projectIdentifier='prj_xxxxxxxxxxxxxxxxx',
name='s3-datalake-source',
type='GLUE',
configuration={
'glueRunConfiguration': {
'relationalFilterConfigurations': [
{
'databaseName': 'marketing_db',
'filterExpressions': [
{
'type': 'INCLUDE',
'expression': 'campaign_*' # campaign_で始まるテーブルのみ
}
]
}
],
'autoImportDataQualityResult': True # データ品質スコアを自動取り込み
}
},
enableSetting='ENABLED',
publishOnImport=True,
schedule={
'schedule': 'cron(0 2 * * ? *)', # 毎日AM2時にクロール
'timezone': 'Asia/Tokyo'
}
)
print(f"Data Source ID: {ds_response['id']}")
print(f"Status: {ds_response['status']}")
自動クロールで登録されるのはスキーマ情報(カラム名・データ型・パーティション)だけ。業務的な意味(「このカラムは売上税抜き金額」とか「このテーブルは翌日AM6時に更新される」)は手作業で追加する必要がある。これが思ったより大変だった。
ビジネスグロッサリーの構築が地味に重要
DataZoneには「ビジネスグロッサリー」という機能があって、組織内の用語定義を管理できる。個人的にはこの機能、最初は地味に見えるんだけど実際には相当重要だと思っている。「売上」という言葉がマーケ部門では「粗売上」を指し、Finance部門では「税引後純売上」を指していた、みたいな混乱を防ぐためのものだ。
# グロッサリー作成
glossary_response = datazone_client.create_glossary(
domainIdentifier='dzd_xxxxxxxxxxxxxxxxx',
owningProjectIdentifier='prj_xxxxxxxxxxxxxxxxx',
name='マーケティング部門 共通用語集',
description='全マーケティングデータの用語定義。不明点はdata-team@example.comまで',
status='ENABLED'
)
glossary_id = glossary_response['id']
# グロッサリーターム追加
term_response = datazone_client.create_glossary_term(
domainIdentifier='dzd_xxxxxxxxxxxxxxxxx',
glossaryIdentifier=glossary_id,
name='セッション',
shortDescription='Webサイトへの訪問単位',
longDescription='''
ユーザーがWebサイトを訪問してから離脱するまでの一連の操作を指す。
タイムアウト基準:30分間操作がない場合はセッション終了として扱う。
計測基準:Google Analytics 4の定義に準拠。
注意:2024年1月以前のデータはUA基準のため定義が異なる。
''',
status='ENABLED'
)
print(f"Term ID: {term_response['id']}")
このグロッサリー、正直「どうせ使われないでしょ」と思ってたんだけど、意外と反響があった。アナリストチームから「ようやくこれが公式定義になった、Confluenceのページが50個あってどれが正しいかわからなかった」という声が来たときは、作っておいてよかったと思った。地味に便利。
本番運用6ヶ月で気づいた落とし穴
正直しんどかったことを書く。
落とし穴①:Lake Formation権限との二重管理地獄
DataZoneのアクセス制御はLake Formationと統合されているんだけど、どちらで権限を管理するかが曖昧になりやすい。最初はDataZoneのプロジェクトメンバーシップで制御していたが、既存のLake Formation設定と競合して「DataZoneでは承認されているのにクエリが失敗する」という問題が3回発生した。
エラー例:
An error occurred (AccessDeniedException) when calling the GetTable operation:
User: arn:aws:sts::123456789012:assumed-role/DataZoneUserRole/user@example.com
is not authorized to perform: glue:GetTable on resource:
arn:aws:glue:ap-northeast-1:123456789012:table/marketing_db/campaign_events
解決策は「DataZoneに権限管理を一元化し、Lake Formationはデータソースの登録のみに使う」という方針を明確にすること。既存のLake Formation設定をDataZone経由に移行するスクリプトを書いたのが2ヶ月目の主な作業だった。
Lake Formation本番導入で3時間ハマった話の記事でも書いた通り、Lake Formationは設定ミスが検出しにくいのが本当に厄介なんだけど、DataZoneと組み合わせると複雑度がさらに一段上がる。方針の明確化は早いほどいい。
落とし穴②:メタデータの陳腐化
自動クロールでスキーマは常に最新に保たれるが、ビジネスメタデータ(カラムの説明・データオーナー・更新頻度)は誰かが手動で更新しないといけない。これを誰の責任にするかを決めないと死ぬ。
うちはデータエンジニアが新テーブルを作るたびにDataZoneへのアセット登録+メタデータ記入をPRレビューの必須項目にした。具体的にはdbtのschema.ymlと連携させている。
# dbt schema.yml
models:
- name: campaign_events
description: "キャンペーンイベントの集計テーブル。毎日AM4時に更新"
meta:
owner: "data-team@example.com"
datazone_asset_id: "ast_xxxxxxxxxxxxxxxxx" # DataZoneアセットIDを記録
update_frequency: "daily"
sla: "AM6時までに更新完了"
columns:
- name: campaign_id
description: "キャンペーン識別子。campaign_masterテーブルのidと結合可能"
tests:
- not_null
- unique
- name: revenue_excl_tax
description: "税抜売上金額(円)。マーケティング部門定義の粗売上に相当"
tests:
- not_null
落とし穴③:データサブスクリプション承認フローが意外と運用コストが高い
DataZoneの「サブスクリプション」機能は、アナリストがデータへのアクセスをリクエストし、データオーナーが承認するというフローだ。ガバナンス的には正しいんだけど、最初は手動承認にしていたため、週30件の承認依頼がデータチームに来て処理できなくなった。これは完全に設計ミスだった。
sequenceDiagram
participant A as アナリスト
participant P as DataZone Portal
participant D as データオーナー
participant LF as Lake Formation
A->>P: データアクセスリクエスト
P->>D: 承認依頼通知 (EventBridge)
alt 自動承認条件を満たす場合
P->>LF: 権限付与 (自動)
P->>A: アクセス承認通知
else 手動承認が必要な場合
D->>P: 承認 or 却下
P->>LF: 権限付与 or 拒否
P->>A: 結果通知
end
A->>LF: Athena/Redshiftでクエリ実行
EventBridgeを使って自動承認ルールを実装することで解決した。「同じ部門のメンバーが、既に公開済みのアセットにアクセスする場合は自動承認」というルールだけで件数が70%減った。
import json
# EventBridgeルール:自動承認Lambda
def lambda_handler(event, context):
detail = event['detail']
# サブスクリプションリクエストの詳細取得
requester_project = detail.get('requestingProjectId')
asset_domain = detail.get('domainId')
subscription_id = detail.get('subscriptionRequestId')
datazone_client = boto3.client('datazone')
# リクエスト詳細取得
request = datazone_client.get_subscription_request_details(
domainIdentifier=asset_domain,
identifier=subscription_id
)
# 自動承認条件チェック
asset_listing = request['subscribedListings'][0]
asset_type = asset_listing['item']['assetListing']['assetType']
# GlueTableアセットかつPublishedステータスなら自動承認
if asset_type == 'amazon.datazone.GlueTableAssetType':
requester_dept = get_department_from_project(requester_project)
asset_dept = get_department_from_asset(asset_listing)
if requester_dept == asset_dept: # 同一部門内アクセスは自動承認
datazone_client.accept_subscription_request(
domainIdentifier=asset_domain,
identifier=subscription_id,
decisionComment='同一部門内アクセスのため自動承認'
)
return {'status': 'auto_approved'}
# 条件を満たさない場合は手動承認フローへ
notify_data_owner(request)
return {'status': 'manual_review_required'}
自動承認ルールの実装自体は1週間程度で終わる。正直これは最初からやっておくべきだったと反省している。
6ヶ月の効果測定
数値で見ると変化が見えやすい。「データの場所・意味に関する質問件数」の推移はこんな感じだ。
xychart-beta
title "データ探索系の質問件数推移(月次)"
x-axis ["導入前", "1ヶ月目", "2ヶ月目", "3ヶ月目", "4ヶ月目", "5ヶ月目", "6ヶ月目"]
y-axis "件数" 0 --> 50
bar [38, 42, 35, 28, 18, 12, 8]
line [38, 42, 35, 28, 18, 12, 8]
1ヶ月目が導入前より増えているのは、「DataZoneにアクセスできない」「使い方がわからない」系の質問が上乗せされたためだ。あれは地獄だった。
| 指標 | 導入前 | 6ヶ月後 | 変化 |
|---|---|---|---|
| データ探索の平均時間 | 45分 | 8分 | -82% |
| Slackでのデータ系質問数/月 | 38件 | 8件 | -79% |
| 未使用テーブルの発見数 | 不明 | 127テーブル判明 | — |
| データアクセス申請の処理時間 | 3営業日 | 自動承認で即時 / 要確認は1日 | 大幅短縮 |
| メタデータ記入率(主要テーブル) | 12% | 78% | +66pt |
データ探索時間が82%短縮されたのは、アナリストにとって一番体感があった変化らしい。「Confluenceで30分検索してもわからなかったものが、DataZoneで3回クリックすれば見つかる」という声が複数来た。
ただし、「未使用テーブル127個が判明」という副産物も興味深かった。誰も使っていないのに毎日Glueジョブが走っているテーブルが山ほどあって、それを整理したらGlue・S3・Redshiftのコストが合計で月17万円削減できた。これは完全に想定外だったし、正直DataZone導入のROIとしてはこっちの方がインパクトが大きかったかもしれない。
データカタログ完全ガイド2026の記事でも触れているように、データカタログを入れると「データの棚卸し」という効果が生まれる。DataZone固有の話ではないけど、実際に経験するとその価値を実感できる。
まとめ
6ヶ月本番運用して言えることを3点にまとめる。
1. マルチアカウント構成は最初から設計すること
Lake Formationの権限管理と競合しやすいので、DataZoneに権限管理を一元化する方針を初期に決めないと後で地獄になる。うちは2ヶ月目に設計を作り直す羽目になった。最初からやっておけばよかった、と一番後悔したポイントだ。
2. ビジネスメタデータの更新責任を明確にすること
スキーマは自動クロールで取れるが、業務的な意味・オーナー・更新頻度は誰かが書かないといけない。dbtのschema.ymlとDataZoneを連携させてPRレビューの必須項目にするのが、現実的に機能した方法だった。「誰でもやれる=誰もやらない」にすると一瞬でカタログが陳腐化する。
3. サブスクリプション承認フローは最初から自動化を考えること
手動承認オンリーだと運用コストが爆発する。EventBridgeで自動承認ルールを実装するのに1週間かかるけど、やらないと週30件の承認依頼に溺れる。これは後回しにしていい作業じゃなかった。
直近はAmazon Q Business(旧Amazon Q)とDataZoneの統合を検証中だ。DataZoneのメタデータをQ Businessのインデックスに取り込んで「このデータ、何に使えますか?」という自然言語での問い合わせに答えさせようとしている。まだ検証段階だけど、これが動けばアナリストの自己解決率がさらに上がりそうで期待している。
皆さんのチームはデータカタログどうやって運用してます? DataZone以外の選択肢を試してる人がいたら話聞いてみたい。