目次
- データレイクのセキュリティ・ガバナンス・アクセス制御基盤
- 概要と本質
- 課題解決
- 主な特徴
- アーキテクチャ
- コアコンポーネント
- アクセス制御モデル
- テーブルレベルのアクセス制御
- 列レベルセキュリティ
- 行レベルセキュリティ
- セルレベルセキュリティ
- LF-TAGS:タグベースアクセス制御
- 属性ベースアクセス制御(ABAC)
- Blueprints:データ取り込みの自動化
- クロスアカウント・クロスオーガニゼーション共有
- Hybrid Access Mode
- 外部メタストア・フェデレーション
- Redshift 統合
- ACID テーブル(Iceberg・Hudi・Delta Lake)
- 監査・コンプライアンス・CloudTrail
- セキュリティベストプラクティス
- CLI 実装例
- SDK 実装例
- Infrastructure as Code
- 比較
- トラブルシューティング
- 2025-2026 最新動向
- 学習リソース
- 実装チェックリスト
- まとめ
AWS Lake Formation v2.0 完全ガイド 2026
データレイクのセキュリティ・ガバナンス・アクセス制御基盤
AWS Lake Formation は、Amazon S3 データレイクのセキュリティ・アクセス制御・ガバナンスをフルマネージドで提供するサービス です。Glue Data Catalog・Athena・EMR・Redshift Spectrum が参照するデータへの列レベル・行レベル・セルレベルのきめ細かいアクセス制御(FGAC)を一元管理し、エンタープライズデータレイクのガバナンス基盤となります。本ドキュメントは Lake Formation の概念・アーキテクチャ・実装・最新動向を体系的に解説します。
ドキュメントの目的
本ガイドは以下を対象としています。
- 初心者向け:Lake Formation とは何か、IAM との違いを学びたい方
- データエンジニア向け:Glue Catalog と Lake Formation の連携・権限設計
- セキュリティアーキテクト向け:細粒度アクセス制御・RBAC・ABAC の実装
- コンプライアンス向け:データ分類・監査ログ・規制対応
- 意思決定者向け:Apache Ranger・Unity Catalog・Snowflake RBAC との比較
目次
- 概要と本質
- Lake Formation が解決する課題
- 主な特徴
- アーキテクチャ
- コアコンポーネント
- アクセス制御モデル
- テーブルレベルのアクセス制御
- 列レベルセキュリティ(Column-level Security)
- 行レベルセキュリティ(Row-level Filtering)
- セルレベルセキュリティ(Cell-level Security)
- LF-TAGS:タグベースアクセス制御
- 属性ベースアクセス制御(ABAC)
- Blueprints:データ取り込みの自動化
- クロスアカウント・クロスオーガニゼーション共有
- Hybrid Access Mode
- 外部メタストア・フェデレーション
- Redshift 統合
- Iceberg・Hudi・Delta Lake サポート
- 監査・コンプライアンス・CloudTrail
- セキュリティベストプラクティス
- CLI による実装例
- SDK による実装例
- Infrastructure as Code
- 類似サービス比較
- トラブルシューティング
- 2025-2026 最新動向
- 学習リソース
- 実装チェックリスト
- まとめ
概要と本質
初心者向けメモ:Lake Formation は「IAM では実現できない列・行レベルのアクセス制御を、データレイク全体で一元管理するサービス」です。
従来:IAM ポリシー
├── S3 バケット全体:アクセス OK / NG
└── 欠点:テーブル・列・行のレベルで制御不可
Lake Formation:
├── テーブル:SELECT 可能
├── 列:email・phone は見えない
├── 行:region='Japan' のみ表示
└── 統一管理:Athena・EMR・Redshift に自動適用
Lake Formation の位置づけ
graph TB
subgraph DataSources["データソース"]
S3["Amazon S3<br/>データレイク"]
RDS["RDS/DynamoDB<br/>Redshift"]
end
subgraph Catalog["メタデータ管理"]
Glue["Glue Data Catalog<br/>スキーマ定義"]
end
subgraph Governance["ガバナンス"]
LF["Lake Formation<br/>アクセス制御"]
end
subgraph Services["分析サービス"]
Athena["Amazon Athena"]
EMR["Amazon EMR"]
Redshift["Redshift<br/>Spectrum"]
end
DataSources -->|メタデータ| Catalog
Catalog -->|権限管理| Governance
Governance -->|統一制御| Services
課題解決
| 課題 | 従来のアプローチ | Lake Formation による解決 |
|---|---|---|
| 列・行レベルアクセス | IAM では実現不可 | Lake Formation で 統一制御 |
| 複数サービスへの権限適用 | Athena・EMR・Redshift に個別設定 | 一度の設定で全サービスに自動適用 |
| PII 保護 | オンプレミス DB でのマスク | Lake Formation の行・列フィルター自動適用 |
| クロスアカウント共有 | S3 バケットポリシー複雑化 | Lake Formation クロスアカウント権限で簡潔 |
| GDPR/HIPAA 準拠 | 手作業でアクセス制御 | Lake Formation 監査ログで自動追跡 |
| データメッシュ実現 | 部門別 DB 管理が分散・複雑 | Lake Formation + DataZone で データ民主化 |
主な特徴
1. 階層的アクセス制御(Hierarchical Permissions)
Database
├── Table_A
│ ├── Column_1 (SELECT)
│ └── Column_2(SELECT + INSERT)
└── Table_B
├── Column_X (SELECT)
└── Column_Y(見えない)
→ 1つのテーブルで複数の列に異なる権限を適用可能
2. データフィルター(Row-Level & Cell-Level)
-- Row-Level Filter(行制限)
CREATE ROW FILTER japan_filter ON table_orders AS "region = 'Japan'"
GRANT SELECT ON table_orders WITH ROW FILTER japan_filter TO japan_team_role;
-- Cell-Level Filter(列+行制限)
GRANT SELECT (order_id, amount) ON table_orders
WITH ROW FILTER japan_filter
TO analyst_role;
3. LF-TAGS(タグベース RBAC)
タグ付与:
Classification: [PII, Public, Confidential, Internal]
Department: [Finance, Sales, Engineering, Marketing]
DataSensitivity: [Low, Medium, High, Critical]
権限設定:
Finance_Role:
→ Classification=Internal AND Department=Finance
→ すべての関連データへのアクセス自動付与
4. Hybrid Access Mode(段階的導入)
段階 1:IAM オンリー(既存状態)
→ 全テーブル・全ユーザーは IAM のみで動作
段階 2:Hybrid Mode
→ finance_table:Lake Formation で制御開始
→ その他テーブル:IAM で継続
段階 3:Lake Formation オンリー
→ すべてのテーブル・権限を Lake Formation 管理
アーキテクチャ
Lake Formation 統合アーキテクチャ図
graph TB
subgraph Sources["データソース"]
S3["Amazon S3<br/>Raw / Processed Data"]
RDS["RDS<br/>PostgreSQL/MySQL"]
DDB["DynamoDB"]
Redshift["Redshift"]
end
subgraph LFCore["Lake Formation"]
Admin["データレイク管理者"]
Perms["権限管理<br/>テーブル・列・行"]
Tags["LF-TAGS<br/>タグベース RBAC"]
Audit["監査ログ<br/>CloudTrail"]
end
subgraph Catalog["Glue Data Catalog"]
Metadata["メタデータ<br/>スキーマ・パーティション"]
end
subgraph Services["分析サービス"]
Athena["Athena"]
EMR["EMR"]
Spectrum["Redshift Spectrum"]
SageMaker["SageMaker"]
end
subgraph Users["ユーザー"]
DataEng["データエンジニア"]
Analyst["アナリスト"]
DataSci["データサイエンティスト"]
end
Sources -->|Glue Crawler| Metadata
Metadata -->|権限確認| Perms
Perms -->|ポリシー適用| Services
Tags -->|自動タグ付与| Perms
Services -->|アクセス要求| Users
Services -->|監査イベント| Audit
コアコンポーネント
1. データレイク管理者(Data Lake Administrator)
責務:
- Lake Formation 全体の初期化・セットアップ
- IAM Role の作成・権限委譲
- Glue Data Catalog の管理
- LF-TAGS の定義・運用ルール決定
- 監査ログ監視・コンプライアンス確認
IAM 権限:
- lakeformation:*
- glue:CreateCatalog, glue:CreateDatabase, glue:CreateTable
- s3:CreateBucket, s3:GetObject, s3:PutObject
2. Glue Data Catalog との統合
Catalog 管理:
Database:
- raw_data:生データ
- processed_data:加工済みデータ
- analytics:BI 用データ
Table:
- customers:顧客マスター
- orders:注文トランザクション
- products:商品マスター
Lake Formation 権限層:
→ Catalog メタデータアクセス = Lake Formation で制御
3. Governed Tables(管理対象テーブル)
Standard Table:
└── S3 オブジェクト = テーブル定義が分散
Governed Table:
├── S3 オブジェクト ← 厳密なスキーマ管理
├── ACID トランザクション(Iceberg・Hudi)
├── 行・列レベルセキュリティ
└── データバージョニング
4. S3 Data Locations(ストレージ登録)
Lake Formation に S3 ロケーション登録:
s3://data-lake/raw/ → Lake Formation 管理下
s3://data-lake/processed/ → Lake Formation 管理下
s3://data-lake/external/ → IAM ポリシーで制御(除外)
→ Lake Formation 管理下のデータにのみ権限ルール適用
アクセス制御モデル
IAM ベース vs Lake Formation
| 項目 | IAM(S3 ベース) | Lake Formation |
|---|---|---|
| 制御粒度 | バケット・オブジェクト | テーブル・列・行・セル |
| 適用単位 | IAM Role / User | IAM Role + Lake Formation Catalog |
| 複数サービス統一 | 個別設定が必要 | 自動同期(Athena・EMR・Redshift) |
| パフォーマンス | ポリシー評価オーバーヘッド | Catalog 統合で効率的 |
| クロスアカウント | 複雑(信頼関係設定) | 簡潔(Lake Formation 権限) |
テーブルレベルのアクセス制御
基本的な権限付与(SQL)
-- テーブル全体への SELECT 権限
GRANT SELECT ON TABLE customers TO ROLE analyst_role;
-- テーブルへの DESCRIBE(スキーマ確認)
GRANT DESCRIBE ON TABLE customers TO ROLE analyst_role;
-- テーブルへの INSERT/UPDATE/DELETE(DML)
GRANT INSERT, UPDATE, DELETE ON TABLE orders TO ROLE etl_role;
-- テーブルの変更(スキーマ変更)
GRANT ALTER ON TABLE customers TO ROLE admin_role;
-- 権限確認
SHOW GRANT ON TABLE customers;
-- 権限取り消し
REVOKE SELECT ON TABLE customers FROM ROLE analyst_role;
Python / Boto3 による権限付与
import boto3
import json
lf = boto3.client('lakeformation', region_name='ap-northeast-1')
# テーブルへの SELECT 権限付与
lf.grant_permissions(
CatalogId='123456789012',
Principal={
'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst_role'
},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'sales_db',
'Name': 'orders'
}
},
Permissions=['SELECT', 'DESCRIBE']
)
# 権限取り消し
lf.revoke_permissions(
CatalogId='123456789012',
Principal={
'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst_role'
},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'sales_db',
'Name': 'orders'
}
},
Permissions=['SELECT']
)
列レベルセキュリティ
実装例
-- 列制限:アナリストは PII(email・phone)が見えない
GRANT SELECT (order_id, customer_id, amount, created_at)
ON TABLE orders
TO ROLE analyst_role;
-- 注:email・phone 列は自動的に除外される
-- 例:Athena クエリ
SELECT
order_id,
customer_id,
amount,
created_at
FROM orders;
-- → email・phone は返されない(エラーではなく自動フィルター)
複数列の異なる権限
-- 財務チーム:金額列含む
GRANT SELECT (order_id, amount, total_revenue)
ON TABLE orders
TO ROLE finance_role;
-- マーケティングチーム:顧客フィードバック列
GRANT SELECT (order_id, customer_id, satisfaction_score)
ON TABLE orders
TO ROLE marketing_role;
-- セキュリティ監視チーム:全列読み取り可能
GRANT SELECT (order_id, customer_id, amount, total_revenue, satisfaction_score)
ON TABLE orders
TO ROLE security_role;
行レベルセキュリティ
Data Filtering(行制限)
-- 日本リージョンの行のみを japan_team_role に表示
CREATE ROW FILTER japan_region_filter AS (region = 'Japan')
ON TABLE orders;
GRANT SELECT ON TABLE orders
WITH ROW FILTER japan_region_filter
TO ROLE japan_team_role;
-- 米国データチーム:米国のみ
CREATE ROW FILTER us_region_filter AS (region = 'US')
ON TABLE orders;
GRANT SELECT ON TABLE orders
WITH ROW FILTER us_region_filter
TO ROLE us_team_role;
パラメータ化された行フィルター
-- ユーザーの地域に基づいた動的フィルター
CREATE ROW FILTER user_region_filter AS
(region = session.get_user_property('Region'))
ON TABLE orders;
GRANT SELECT ON TABLE orders
WITH ROW FILTER user_region_filter
TO ROLE regional_teams;
-- ユーザー tokyo_analyst にログイン時に Region='Japan' を自動セット
セルレベルセキュリティ
列 + 行の組み合わせフィルター
-- シナリオ:金融機関の規制対応
-- - 一般アナリスト:日本・非 PII データのみ
-- - 金融監督担当者:全データ・全列
-- 一般アナリスト:制限版
CREATE ROW FILTER japan_only_filter AS (region = 'Japan')
ON TABLE customer_accounts;
GRANT SELECT (account_id, balance, account_type)
ON TABLE customer_accounts
WITH ROW FILTER japan_only_filter
TO ROLE general_analyst;
-- 金融監督担当者:完全アクセス
GRANT SELECT (account_id, customer_name, ssn, balance, account_type)
ON TABLE customer_accounts
TO ROLE compliance_officer;
LF-TAGS:タグベースアクセス制御
LF-TAG 定義と運用
import boto3
lf = boto3.client('lakeformation')
# LF-TAG 定義:Classification
lf.create_lf_tag(
TagKey='Classification',
TagValues=['PII', 'Internal', 'Public', 'Confidential']
)
# LF-TAG 定義:Department
lf.create_lf_tag(
TagKey='Department',
TagValues=['Finance', 'Sales', 'Engineering', 'Marketing']
)
# LF-TAG 定義:DataOwner
lf.create_lf_tag(
TagKey='DataOwner',
TagValues=['team-finance', 'team-sales', 'team-eng']
)
# テーブルに LF-TAG を付与
lf.tag_resource(
ResourceInfo={
'Catalog': {},
'Database': {
'CatalogId': '123456789012',
'Name': 'finance_db'
}
},
TagsToAdd=[
{'TagKey': 'Department', 'TagValue': 'Finance'},
{'TagKey': 'Classification', 'TagValue': 'Confidential'}
]
)
# テーブルに LF-TAG を付与
lf.tag_resource(
ResourceInfo={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'finance_db',
'TableWildcard': {}
}
},
TagsToAdd=[
{'TagKey': 'Department', 'TagValue': 'Finance'},
{'TagKey': 'Classification', 'TagValue': 'Internal'}
]
)
# 列に LF-TAG を付与(Column-level)
lf.tag_resource(
ResourceInfo={
'TableWithColumns': {
'CatalogId': '123456789012',
'DatabaseName': 'finance_db',
'Name': 'accounts',
'ColumnNames': ['ssn', 'customer_name', 'phone']
}
},
TagsToAdd=[
{'TagKey': 'Classification', 'TagValue': 'PII'}
]
)
LF-TAG ベース権限付与
# Role に LF-TAG ベース権限を付与
# → Finance 部門のすべての Confidential データにアクセス可能
lf.grant_permissions(
Principal={
'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/finance_analyst'
},
Resource={
'LFTagOnDatabase': {
'CatalogId': '123456789012',
'TagKey': 'Department',
'TagValues': ['Finance']
}
},
Permissions=['SELECT', 'DESCRIBE'],
PermissionsWithGrantOption=[]
)
# SQL による LF-TAG ベース権限確認
# SELECT ... FROM table
# WHERE classification:PII は自動的にフィルター
属性ベースアクセス制御(ABAC)
ABAC 実装(IAM タグ連携)
import boto3
iam = boto3.client('iam')
lf = boto3.client('lakeformation')
# IAM Role に タグを付与
iam.tag_role(
RoleName='analyst-role',
Tags=[
{'Key': 'Department', 'Value': 'Sales'},
{'Key': 'Region', 'Value': 'Tokyo'},
{'Key': 'AccessLevel', 'Value': 'Standard'}
]
)
# Lake Formation 権限設定:IAM タグに基づいたアクセス制御
lf.grant_permissions(
Principal={
'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst-role'
},
Resource={
'LFTag': {
'TagKey': 'Department',
'TagValues': ['Sales']
}
},
Permissions=['SELECT']
)
# → analyst-role(Department=Sales タグ)は
# Department=Sales タグ付きテーブルにアクセス可能
Blueprints:データ取り込みの自動化
RDS から S3 への自動取り込み
import boto3
lf = boto3.client('lakeformation')
# Blueprints:RDS MySQL の完全スナップショット
lf.create_data_lake_settings(
DataLakeSettings={
'DataLakeAdmins': [
{'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/lake-admin'}
],
'CreateDatabaseDefaultPermissions': [
{
'Principal': {'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/etl-role'},
'Permissions': ['CREATE_TABLE', 'ALTER']
}
],
'CreateTableDefaultPermissions': [
{
'Principal': {'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst-role'},
'Permissions': ['SELECT']
}
]
}
)
# Glue Workflow で自動化(毎日 2:00 AM 実行)
glue = boto3.client('glue')
glue.create_workflow(
Name='rds-to-s3-daily',
Description='Daily RDS snapshot to S3 via Glue Catalog',
DefaultRunProperties={'database': 'rds_imported'}
)
# Glue Crawler:取り込み後自動スキーマ検出
glue.create_crawler(
Name='rds-crawler',
Role='arn:aws:iam::123456789012:role/glue-role',
DatabaseName='rds_imported',
Targets={
'S3Targets': [
{'Path': 's3://data-lake/rds-imports/'}
]
},
SchemaChangePolicy={
'UpdateBehavior': 'UPDATE_IN_DATABASE',
'DeleteBehavior': 'LOG'
}
)
クロスアカウント・クロスオーガニゼーション共有
クロスアカウント権限設定
# アカウント A(データプロデューサー)
lf_producer = boto3.client('lakeformation', region_name='ap-northeast-1')
# アカウント B の IAM Principal にアクセス権付与
lf_producer.grant_permissions(
Principal={
# アカウント B のロール
'DataLakePrincipalIdentifier': 'arn:aws:iam::999999999999:role/consumer-analyst'
},
Resource={
'Table': {
'CatalogId': '111111111111', # アカウント A
'DatabaseName': 'shared_data',
'Name': 'orders'
}
},
Permissions=['SELECT', 'DESCRIBE']
)
# アカウント B(データコンシューマー)
lf_consumer = boto3.client('lakeformation', region_name='ap-northeast-1')
# アカウント A の Catalog を参照
# → Athena で s3://account-a-bucket/orders/ にアクセス可能
Organizations 経由のデータ共有
# AWS Organizations でアカウント管理
# → Lake Formation 権限を Organization Unit(OU)単位で一括管理
lf.register_resource(
ResourceArn='arn:aws:s3:::org-data-lake',
UseServiceLinkedRole=False,
RoleArn='arn:aws:iam::111111111111:role/lake-formation-service-role'
)
# OU 全体のロールに権限付与(自動伝播)
lf.grant_permissions(
Principal={
'DataLakePrincipalIdentifier': 'arn:aws:organizations::111111111111:ou/ou-xxxxxxxxx'
},
Resource={
'DataLocation': {
'Catalog': {},
'ResourceArn': 'arn:aws:s3:::org-data-lake'
}
},
Permissions=['DATA_LOCATION_ACCESS']
)
Hybrid Access Mode
段階的な Lake Formation 導入
import boto3
lf = boto3.client('lakeformation')
# ステップ 1:Hybrid Access Mode を有効化
lf.put_data_lake_settings(
DataLakeSettings={
'AllowExternalDataFiltering': True, # Hybrid Mode 有効
'AuthorizedSessionTagValueList': ['arn:aws:iam::123456789012:role/etl-role']
}
)
# ステップ 2:特定のテーブルを Lake Formation で管理開始
lf.grant_permissions(
Principal={'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst'},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'analytics',
'Name': 'customer_segments' # このテーブルのみ LF で制御
}
},
Permissions=['SELECT']
)
# ステップ 3:他のテーブルは従来 IAM で制御
# → S3 バケットポリシー / IAM ロール権限で管理継続
外部メタストア・フェデレーション
Redshift データの Catalog 化
lf = boto3.client('lakeformation')
# Redshift namespace を Glue Catalog に登録
lf.create_lake_formation_identity_center_configuration(
InstanceArn='arn:aws:redshift:ap-northeast-1:123456789012:cluster:my-redshift',
ExternalFilteringEnabled=True
)
# Redshift テーブルを Catalog に追加
glue = boto3.client('glue')
glue.create_table(
CatalogId='123456789012',
DatabaseName='redshift_federated',
TableInput={
'Name': 'customer_360',
'StorageDescriptor': {
'Columns': [
{'Name': 'customer_id', 'Type': 'bigint'},
{'Name': 'name', 'Type': 'string'},
{'Name': 'segment', 'Type': 'string'}
],
'Location': 'redshift://my-redshift/public/customer_360',
'InputFormat': 'com.amazon.emr.redshift.hive.RedshiftInputFormat',
'OutputFormat': 'com.amazon.emr.redshift.hive.RedshiftOutputFormat',
'SerdeInfo': {
'SerializationLibrary': 'com.amazon.redshift.hive.serde.RedshiftHiveSerDe'
}
}
}
)
# Lake Formation 権限で Redshift テーブルのアクセス制御
lf.grant_permissions(
Principal={'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst'},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'redshift_federated',
'Name': 'customer_360'
}
},
Permissions=['SELECT']
)
外部メタストア(Hive Metastore)の連携
# Apache Hive Metastore を Glue に接続
glue = boto3.client('glue')
glue.create_connection(
Name='hive-metastore-conn',
Description='Connect to external Hive Metastore',
ConnectionType='JDBC',
ConnectionProperties={
'JDBC_DRIVER_JAR_URI': 's3://my-bucket/hive-metastore-driver.jar',
'JDBC_URL': 'jdbc:hive2://hive-server:10000',
'USERNAME': 'hive_user'
}
)
# Lake Formation で外部 Hive テーブルのアクセス制御
lf.grant_permissions(
Principal={'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst'},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'external_hive_db',
'Name': 'external_table'
}
},
Permissions=['SELECT']
)
Redshift 統合
Redshift Spectrum + Lake Formation
# Redshift クラスター内から Lake Formation 制御下の S3 データにアクセス
# 権限は Redshift IAM Role に紐付けられた Lake Formation 権限で自動適用
redshift = boto3.client('redshift-data')
# Redshift での外部テーブル定義
redshift.execute_statement(
ClusterIdentifier='my-redshift',
Sql="""
CREATE EXTERNAL TABLE orders (
order_id BIGINT,
customer_id BIGINT,
amount DECIMAL(10, 2)
)
STORED AS PARQUET
LOCATION 's3://data-lake/orders/'
TABLE PROPERTIES ('classification'='parquet');
"""
)
# Lake Formation 権限に基づいた自動フィルター適用
# Redshift が SELECT 権限を持つ列・行のみアクセス可能
ACID テーブル(Iceberg・Hudi・Delta Lake)
Iceberg + Lake Formation
import boto3
lf = boto3.client('lakeformation')
# Iceberg テーブルを Lake Formation で管理
lf.grant_permissions(
Principal={'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/etl-role'},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'transactions',
'Name': 'orders_iceberg'
}
},
Permissions=['SELECT', 'INSERT', 'UPDATE', 'DELETE']
)
# EMR / Athena で Iceberg テーブル操作時に Lake Formation 権限自動適用
# ACID トランザクション + 細粒度アクセス制御 実現
Hudi + Lake Formation
# Hudi テーブルの ACID 操作時に Lake Formation 権限を自動確認
spark.sql("""
-- Hudi Upsert:Lake Formation SELECT・UPDATE 権限を確認
INSERT INTO TABLE default.hudi_orders
SELECT * FROM source_table
""")
# Lake Formation が UPDATE 権限を拒否 → クエリ実行失敗
# Lake Formation が UPDATE 権限を許可 → クエリ実行成功・Hudi Upsert 実行
監査・コンプライアンス・CloudTrail
Lake Formation 監査ログの設定
import boto3
lf = boto3.client('lakeformation')
s3 = boto3.client('s3')
cloudtrail = boto3.client('cloudtrail')
# CloudTrail で Lake Formation API 呼び出しを記録
cloudtrail.create_trail(
Name='lake-formation-audit',
S3BucketName='audit-logs-bucket',
IsMultiRegionTrail=True,
EnableLogFileValidation=True
)
# CloudTrail イベント監視(CloudWatch Logs へ転送)
cloudtrail.put_event_selectors(
TrailName='lake-formation-audit',
EventSelectors=[
{
'ReadWriteType': 'All',
'IncludeManagementEvents': True,
'DataResources': [
{
'Type': 'AWS::S3::Object',
'Values': ['arn:aws:s3:::data-lake/*']
}
]
}
]
)
# Lake Formation API アクセスのログ確認
cloudtrail_events = cloudtrail.lookup_events(
LookupAttributes=[
{
'AttributeKey': 'EventSource',
'AttributeValue': 'lakeformation.amazonaws.com'
}
]
)
for event in cloudtrail_events['Events']:
print(f"Time: {event['EventTime']}")
print(f"User: {event['Username']}")
print(f"Action: {event['EventName']}")
print(f"Resource: {event['Resources']}")
アクセス監査ダッシュボード(CloudWatch)
import boto3
cloudwatch = boto3.client('cloudwatch')
# カスタムメトリクス:Lake Formation 権限拒否イベント
cloudwatch.put_metric_data(
Namespace='LakeFormation',
MetricData=[
{
'MetricName': 'AccessDenied',
'Value': 1,
'Unit': 'Count',
'Dimensions': [
{'Name': 'Resource', 'Value': 'orders_table'},
{'Name': 'Principal', 'Value': 'analyst_role'}
]
}
]
)
# CloudWatch Logs Insights クエリ
# Lake Formation 関連のアクセス拒否を集計
logs = boto3.client('logs')
response = logs.start_query(
logGroupName='/aws/lakeformation/audit',
startTime=1609459200,
endTime=1609545600,
queryString="""
fields @timestamp, @message
| filter eventName like /AccessDenied/
| stats count() by Principal, Resource
"""
)
セキュリティベストプラクティス
✅ 推奨事項
| 項目 | 実装 | 効果 |
|---|---|---|
| データレイク管理者限定 | 複数管理者で運用・定期ローテーション | 権限集中のリスク低減 |
| LF-TAGS 設計 | 組織全体で統一的なタグ体系 | スケーラブルな RBAC 実現 |
| Hybrid Mode 活用 | 段階的な Lake Formation 導入 | 既存環境への影響最小化 |
| Row-Level Filter テスト | テスト環境で全フィルター条件検証 | 本番環境でのデータ漏洩防止 |
| CloudTrail 有効化 | 全 Lake Formation API を記録 | コンプライアンス監査対応 |
| Catalog 権限委譲 | データベース・テーブルごとに委譲 | 権限運用の分散化 |
| 定期的な権限レビュー | 月次で不要権限を確認・削除 | 過剰権限の排除 |
| DataZone 連携 | Lake Formation + DataZone でガバナンス統一 | データメッシュ実現 |
| 暗号化設定 | KMS で S3 データ暗号化 | 保存時セキュリティ強化 |
| VPC Endpoint | プライベート接続(IAM は不要) | ネットワークセキュリティ向上 |
❌ 反パターン
| 反パターン | 理由 | 改善策 |
|---|---|---|
| すべてのユーザーに管理者権限 | セキュリティリスク・監査不可 | 役割分離・最小権限の原則 |
| IAM のみで列・行制御を実現 | 実装困難・複雑・誤設定リスク | Lake Formation 導入 |
| LF-TAGS なし・全テーブルに個別権限 | スケール不可・運用負担 | LF-TAGS ベース RBAC 設計 |
| 監査ログなし | コンプライアンス未対応 | CloudTrail 有効化・ログ監視 |
| テーブル削除時に権限を確認せず | 想定外の権限委譲が残存 | 削除前に権限確認・削除 |
CLI 実装例
Lake Formation セットアップ
# Lake Formation 管理者設定
aws lakeformation put-data-lake-settings \
--data-lake-settings '{
"DataLakeAdmins": [
{
"DataLakePrincipalIdentifier": "arn:aws:iam::123456789012:role/lake-admin"
}
],
"CreateDatabaseDefaultPermissions": [
{
"Principal": {
"DataLakePrincipalIdentifier": "arn:aws:iam::123456789012:role/etl-role"
},
"Permissions": ["CREATE_TABLE", "ALTER"]
}
]
}'
# S3 ロケーション登録
aws lakeformation register-resource \
--resource-arn arn:aws:s3:::data-lake \
--role-arn arn:aws:iam::123456789012:role/lf-service-role
# テーブル権限付与
aws lakeformation grant-permissions \
--principal DataLakePrincipalIdentifier=arn:aws:iam::123456789012:role/analyst-role \
--resource Table='{CatalogId=123456789012,DatabaseName=analytics,Name=orders}' \
--permissions SELECT DESCRIBE
# LF-TAG 作成
aws lakeformation create-lf-tag \
--tag-key Classification \
--tag-values PII Internal Public Confidential
# テーブルに LF-TAG 付与
aws lakeformation tag-resource \
--resource-info Table='{CatalogId=123456789012,DatabaseName=analytics,Name=orders}' \
--tags-to-add '{"Key":"Classification","Value":"Internal"}'
# LF-TAG ベース権限付与
aws lakeformation grant-permissions \
--principal DataLakePrincipalIdentifier=arn:aws:iam::123456789012:role/finance-role \
--resource LFTagOnDatabase='{CatalogId=123456789012,TagKey=Department,TagValues=[Finance]}' \
--permissions SELECT
SDK 実装例
Python Boto3
import boto3
lf = boto3.client('lakeformation', region_name='ap-northeast-1')
glue = boto3.client('glue')
def setup_lake_formation():
"""Lake Formation 初期セットアップ"""
# 1. Lake Formation 管理者設定
lf.put_data_lake_settings(
DataLakeSettings={
'DataLakeAdmins': [
{'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/lake-admin'}
],
'AllowExternalDataFiltering': True # Hybrid Mode
}
)
# 2. S3 ロケーション登録
lf.register_resource(
ResourceArn='arn:aws:s3:::data-lake',
RoleArn='arn:aws:iam::123456789012:role/lf-service-role'
)
# 3. LF-TAG 定義
lf.create_lf_tag(TagKey='Classification', TagValues=['PII', 'Internal', 'Public'])
lf.create_lf_tag(TagKey='Department', TagValues=['Finance', 'Sales', 'Engineering'])
# 4. テーブル権限設定
lf.grant_permissions(
Principal={'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/analyst'},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'analytics',
'Name': 'orders'
}
},
Permissions=['SELECT', 'DESCRIBE']
)
# 5. Row-Level Filter 設定
lf.grant_permissions(
Principal={'DataLakePrincipalIdentifier': 'arn:aws:iam::123456789012:role/japan-team'},
Resource={
'Table': {
'CatalogId': '123456789012',
'DatabaseName': 'analytics',
'Name': 'orders'
}
},
Permissions=['SELECT'],
PermissionsWithGrantOption=[],
# Note: Row Filter は SQL で定義(ここでは指定できず)
)
print("Lake Formation setup completed!")
def list_lake_formation_permissions():
"""Lake Formation 権限一覧"""
resources = lf.list_resources(ResourceType='TABLE')
for resource in resources['ResourceInfoList']:
print(f"Resource: {resource['ResourceInfo']['Table']}")
# 権限確認
perms = lf.list_permissions(
Resource=resource['ResourceInfo']
)
for perm in perms['PrincipalResourcePermissions']:
print(f" Principal: {perm['Principal']}")
print(f" Permissions: {perm['Permissions']}")
if __name__ == '__main__':
setup_lake_formation()
list_lake_formation_permissions()
Infrastructure as Code
Terraform 例
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
# Lake Formation Admin Role
resource "aws_iam_role" "lf_admin" {
name = "lake-formation-admin"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lakeformation.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "lf_admin_policy" {
role = aws_iam_role.lf_admin.name
policy_arn = "arn:aws:iam::aws:policy/service-role/LakeFormationServiceLinkedRolePolicy"
}
# Lake Formation Data Lake Settings
resource "aws_lakeformation_data_lake_settings" "example" {
admins = [aws_iam_role.lf_admin.arn]
}
# S3 Data Lake Location
resource "aws_s3_bucket" "data_lake" {
bucket = "my-data-lake-${data.aws_caller_identity.current.account_id}"
}
resource "aws_lakeformation_resource" "data_lake_location" {
arn = aws_s3_bucket.data_lake.arn
role_arn = aws_iam_role.lf_admin.arn
depends_on = [aws_lakeformation_data_lake_settings.example]
}
# LF-TAG
resource "aws_lakeformation_lf_tag" "classification" {
key = "Classification"
values = ["PII", "Internal", "Public", "Confidential"]
}
resource "aws_lakeformation_lf_tag" "department" {
key = "Department"
values = ["Finance", "Sales", "Engineering"]
}
# Analyst Role
resource "aws_iam_role" "analyst" {
name = "analyst-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::123456789012:user/analyst-user"
}
}]
})
}
# Grant Table Permissions
resource "aws_lakeformation_permissions" "analyst_orders_select" {
principal = aws_iam_role.analyst.arn
permissions = ["SELECT"]
table {
database_name = "analytics"
name = "orders"
}
depends_on = [aws_lakeformation_resource.data_lake_location]
}
data "aws_caller_identity" "current" {}
比較
Lake Formation vs Apache Ranger
| 項目 | Lake Formation | Apache Ranger |
|---|---|---|
| クラウド | AWS ネイティブ(S3・Redshift) | オンプレ・ハイブリッド |
| 運用 | マネージドサービス | セルフマネージド |
| ABAC | LF-TAGS で実装 | Ranger Attributes |
| 監査 | CloudTrail 統合 | 別途 Audit DB 必要 |
| コスト | AWS 課金に含む | オンプレ 運用コスト |
| 採用 | AWS クラウド中心企業 | Hadoop エコシステム企業 |
Lake Formation vs Unity Catalog(Databricks)
| 項目 | Lake Formation | Unity Catalog |
|---|---|---|
| プロバイダー | AWS | Databricks |
| 基盤 | Glue Data Catalog | Metastore |
| マルチクラウド | AWS のみ | AWS・Azure・GCP |
| ACID テーブル | Iceberg・Hudi・Delta サポート | Delta Lake 最適化 |
| アクセス制御 | 細粒度(列・行・セル) | 同等機能 |
| コスト | AWS クレジット | Databricks 別課金 |
| Lock-in | AWS 依存度高い | マルチクラウド対応 |
トラブルシューティング
| 症状 | 原因 | 解決策 |
|---|---|---|
| Column not found / Access Denied | 列レベル権限が見えない | SELECT (列名 ) 権限を明示的に付与 |
| Row Filter が適用されない | SQL 構文エラー・フィルター条件不正 | Row Filter テーブルで EXPLAIN で確認 |
| LF-TAG が見つからない | タグが削除・誤字 | list_lf_tags で確認・再作成 |
| Cross-Account Access が失敗 | Trust Relationship 未設定 | Consumer Account IAM Role の信頼関係を確認 |
| CloudTrail に Lake Formation イベントなし | CloudTrail が無効 | CloudTrail を有効化・S3 ロケーション確認 |
| Athena / EMR で列・行フィルター未適用 | Hybrid Mode / Lake Formation 権限なし | 権限確認・Hybrid Mode 確認 |
| Glue Crawler が新列を検出・LF-TAG が引き継がれない | スキーマ更新時に LF-TAG を再適用 | Crawler 実行後に LF-TAG を確認・更新 |
2025-2026 最新動向
1. Row-Level Lineage(データ系統追跡)
- 2026 新機能:Iceberg v3 との統合で行単位のデータ系統を追跡
- ✅ どの行がどこから来たかを自動記録
- ✅ データ品質・規制対応で重要
2. Generative AI による権限推奨
- 2026 以降の予想:
- ✅ CloudTrail + Bedrock で「このロールには何を見せるべき?」を AI が提案
- ✅ 権限設計の自動化・運用効率化
3. S3 Tables との統合
- 2026 新機能:S3 Tables がネイティブ Apache Iceberg サポート
- ✅ S3 テーブルを Lake Formation で直接管理
- ✅ セットアップ簡素化
学習リソース
公式ドキュメント
- AWS Lake Formation Developer Guide
- Fine-grained Access Control
- LF-TAGS and Attribute-based Access Control
AWS ブログ・記事
技術ブログ・コミュニティ
実装チェックリスト
フェーズ 1:導入準備
- [ ] Lake Formation vs IAM only での権限設計比較
- [ ] 既存データ分類・タグ体系の設計
- [ ] LF-TAGS キーの定義(Classification・Department など)
- [ ] Glue Data Catalog への移行スケジュール
フェーズ 2:パイロット実装
- [ ] テスト環境で Lake Formation セットアップ
- [ ] LF-TAG 定義・テーブル分類完了
- [ ] 数個テーブルに列・行レベル権限設定
- [ ] Athena / EMR での権限適用確認
フェーズ 3:本番運用
- [ ] Hybrid Mode で既存環境との並行運用
- [ ] CloudTrail 有効化・監査ログ監視
- [ ] Row-Level Filter テスト・本番適用
- [ ] DataZone との連携設定
フェーズ 4:最適化・高度な運用
- [ ] Iceberg / Hudi による ACID テーブル統合
- [ ] クロスアカウント・クロスオーガニゼーション共有導入
- [ ] 自動化スクリプト(権限管理・監査報告)
- [ ] データメッシュ戦略への統合
まとめ
AWS Lake Formation は 「S3 データレイクの細粒度アクセス制御・ガバナンス基盤」。IAM では実現できない列・行・セルレベルのアクセス制御を一元管理し、Athena・EMR・Redshift に統一的に適用できます。
成功の鍵:
- LF-TAGS 設計で スケーラブルな RBAC 実現
- Hybrid Mode で既存環境への影響を最小化
- CloudTrail 監査 でコンプライアンス対応
- Iceberg・Hudi との ACID 統合
- DataZone との組み合わせでデータメッシュ実現
2025-2026 年は Generative AI による権限推奨・S3 Tables ネイティブ統合など、運用効率化が進む予定です。
最終更新:2026-04-26 バージョン:v2.0