メインコンテンツまでスキップ
最新1mo ago

S3テーブルのセットアップ

本ガイドでは、2025年5月のAWSアップデートに基づいて、リソースリンクを必要としずに Amazon Data FirehoseからS3テーブルへのデータストリーミングのための新しいアプローチについて説明します。

前提条件

  • 適切な権限を持つAWSアカウント

  • インストールおよび設定済みのAWS CLI

  • AWS CDKの知識(インフラストラクチャアズコードを使用する場合)

  • AWS Analytics サービスとのS3テーブル統合の有効化

概要

新しいアプローチでは、s3tablescatalog カタログ形式を通じてFirehoseがS3テーブルに直接アクセスできるようにすることで、リソースリンク不要を実現します。


ステップ1: AWS Analyticsサービスとの S3テーブル統合を有効化

1.1 AWS コンソール経由

  1. Amazon S3 コンソールテーブルバケット に移動

  2. まだ有効化されていない場合は、統合を有効化 をクリック

  3. これにより、S3テーブルがAWSアナリティクスサービスで検出可能になります

1.2 AWS CLI経由

aws s3tables put-table-bucket-policy \
--table-bucket-arn "arn:aws:s3tables:REGION:ACCOUNT:bucket/BUCKET_NAME" \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"Service": "analytics.amazonaws.com"},
"Action": "s3tables:*",
"Resource": "*"
}
]
}' \
--region REGION


ステップ2: S3テーブルバケットとテーブルを作成

2.1 テーブルバケットを作成

aws s3tables create-table-bucket \
--name "your-table-bucket-name" \
--region REGION

2.2 ネームスペースを作成

aws s3tables create-namespace \
--table-bucket-arn "arn:aws:s3tables:REGION:ACCOUNT:bucket/BUCKET_NAME" \
--namespace "your-namespace" \
--region REGION

2.3 スキーマ付きのテーブルを作成


# テーブル定義ファイルを作成
cat > table-definition.json << 'EOF'
{
"tableBucketARN": "arn:aws:s3tables:REGION:ACCOUNT:bucket/BUCKET_NAME",
"namespace": "your-namespace",
"name": "your-table-name",
"format": "ICEBERG",
"metadata": {
"iceberg": {
"schema": {
"fields": [
{"name": "id", "type": "int", "required": true},
{"name": "timestamp", "type": "timestamp"},
{"name": "data", "type": "string"}
]
}
}
}
}
EOF

# テーブルを作成
aws s3tables create-table --cli-input-json file://table-definition.json --region REGION


ステップ3: Firehose用のIAMロールを作成

3.1 信頼ポリシーを作成

cat > firehose-trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "firehose.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF

3.2 IAMロールを作成

aws iam create-role \
--role-name "firehose-s3-tables-role" \
--assume-role-policy-document file://firehose-trust-policy.json \
--region REGION


ステップ4: S3テーブルアクセス用のIAMポリシーを作成

4.1 S3テーブルアクセスポリシーを作成

cat > s3-tables-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3TableAccessViaGlueFederation",
"Effect": "Allow",
"Action": [
"glue:GetTable",
"glue:GetDatabase",
"glue:UpdateTable"
],
"Resource": [
"arn:aws:glue:REGION:ACCOUNT:catalog/s3tablescatalog/TABLE_BUCKET_NAME",
"arn:aws:glue:REGION:ACCOUNT:catalog/s3tablescatalog",
"arn:aws:glue:REGION:ACCOUNT:catalog",
"arn:aws:glue:REGION:ACCOUNT:database/s3tablescatalog/TABLE_BUCKET_NAME/NAMESPACE_NAME",
"arn:aws:glue:REGION:ACCOUNT:table/s3tablescatalog/TABLE_BUCKET_NAME/NAMESPACE_NAME/TABLE_NAME"
]
},
{
"Sid": "LakeFormationDataAccess",
"Effect": "Allow",
"Action": [
"lakeformation:GetDataAccess"
],
"Resource": "*"
},
{
"Sid": "S3TablesDirectAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3tables:REGION:ACCOUNT:bucket/TABLE_BUCKET_NAME",
"arn:aws:s3tables:REGION:ACCOUNT:bucket/TABLE_BUCKET_NAME/*"
]
},
{
"Sid": "S3BackupBucketAccess",
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::backup-bucket-name",
"arn:aws:s3:::backup-bucket-name/*"
]
}
]
}
EOF

# ポリシーをロールにアタッチ
aws iam put-role-policy \
--role-name "firehose-s3-tables-role" \
--policy-name "S3TablesFirehosePolicy" \
--policy-document file://s3-tables-policy.json \
--region REGION

重要: 以下のプレースホルダーを置換してください:

  • REGION: AWSリージョン(例: ap-northeast-1

  • ACCOUNT: AWSアカウントID

  • TABLE_BUCKET_NAME: S3テーブルバケット名

  • NAMESPACE_NAME: S3テーブルネームスペース

  • TABLE_NAME: S3テーブルテーブル名

  • backup-bucket-name: バックアップS3バケット名


ステップ5: Lake Formationのパーミッションを設定

5.1 AWSコンソール経由でパーミッションを付与

  1. AWS Lake Formation コンソール に移動

  2. データパーミッション付与 に移動

  3. 名前付きデータカタログリソース を選択

  4. プリンシパル: Firehoseロール(firehose-s3-tables-role)を選択

  5. カタログ: ACCOUNT:s3tablescatalog/TABLE_BUCKET_NAME を選択

  6. データベース: ネームスペースを選択

  7. テーブル: テーブルまたは「すべてのテーブル」を選択

  8. パーミッション: スーパー パーミッションを付与

  9. 付与 をクリック

5.2 AWS CLI経由でパーミッションを付与

aws lakeformation grant-permissions \
--principal "arn:aws:iam::ACCOUNT:role/firehose-s3-tables-role" \
--resource '{
"Table": {
"CatalogId": "ACCOUNT:s3tablescatalog/TABLE_BUCKET_NAME",
"DatabaseName": "NAMESPACE_NAME",
"Name": "TABLE_NAME"
}
}' \
--permissions "ALL" \
--region REGION


ステップ6: Firehose配信ストリームを作成

6.1 AWSコンソール経由

  1. Amazon Data Firehose コンソール に移動

  2. 配信ストリームを作成 をクリック

  3. ソース: Direct PUT を選択

  4. 宛先: Apache Iceberg Tables を選択

  5. ストリーム名: ストリーム名を入力

  6. 宛先設定:

  • カタログ: ACCOUNT:s3tablescatalog/TABLE_BUCKET_NAME

  • データベース: ネームスペース名

  • テーブル: テーブル名

  1. IAMロール: Firehoseロールを選択

  2. S3バックアップ: バックアップバケットを設定

  3. 配信ストリームを作成 をクリック

6.2 AWS CLI経由

cat > firehose-config.json << 'EOF'
{
"DeliveryStreamName": "your-firehose-stream-name",
"DeliveryStreamType": "DirectPut",
"IcebergDestinationConfiguration": {
"RoleARN": "arn:aws:iam::ACCOUNT:role/firehose-s3-tables-role",
"CatalogConfiguration": {
"CatalogARN": "arn:aws:glue:REGION:ACCOUNT:catalog/s3tablescatalog/TABLE_BUCKET_NAME"
},
"DestinationTableConfigurationList": [
{
"DestinationDatabaseName": "NAMESPACE_NAME",
"DestinationTableName": "TABLE_NAME"
}
],
"BufferingHints": {
"IntervalInSeconds": 60,
"SizeInMBs": 64
},
"S3Configuration": {
"RoleARN": "arn:aws:iam::ACCOUNT:role/firehose-s3-tables-role",
"BucketARN": "arn:aws:s3:::backup-bucket-name"
}
}
}
EOF

aws firehose create-delivery-stream --cli-input-json file://firehose-config.json --region REGION


ステップ7: CDK実装(オプション)

7.1 CDKコンストラクト例

import { ITableBucket } from '@aws-cdk/aws-s3tables-alpha';
import {
aws_kinesisfirehose as firehose,
aws_iam as iam,
aws_s3 as s3,
Stack,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class S3TablesFirehoseConstruct extends Construct {
readonly deliveryStream: firehose.CfnDeliveryStream;
readonly firehoseRole: iam.IRole;

constructor(scope: Construct, id: string, props: {
namespaceName: string;
tableName: string;
tableBucket: ITableBucket;
}) {
super(scope, id);

const { region, account } = Stack.of(this);

// Create backup bucket
const backupBucket = new s3.Bucket(this, 'FirehoseBackupBucket');

// Create Firehose role
this.firehoseRole = new iam.Role(this, 'FirehoseRole', {
assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com'),
inlinePolicies: {
S3TablesAccess: new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
sid: 'S3TableDirectCatalogAccess',
actions: ['glue:GetDatabase', 'glue:GetTable', 'glue:UpdateTable'],
resources: [
`arn:aws:glue:${region}:${account}:catalog/s3tablescatalog/${props.tableBucket.tableBucketName}`,
`arn:aws:glue:${region}:${account}:catalog/s3tablescatalog`,
`arn:aws:glue:${region}:${account}:catalog`,
`arn:aws:glue:${region}:${account}:database/s3tablescatalog/${props.tableBucket.tableBucketName}/${props.namespaceName}`,
`arn:aws:glue:${region}:${account}:table/s3tablescatalog/${props.tableBucket.tableBucketName}/${props.namespaceName}/${props.tableName}`,
],
}),
new iam.PolicyStatement({
sid: 'LakeFormationDataAccess',
actions: ['lakeformation:GetDataAccess'],
resources: ['*'],
}),
new iam.PolicyStatement({
sid: 'S3TablesDirectBucketAccess',
actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject', 's3:ListBucket'],
resources: [
props.tableBucket.tableBucketArn,
`${props.tableBucket.tableBucketArn}/*`,
],
}),
],
}),
},
});

// Grant backup bucket permissions
backupBucket.grantReadWrite(this.firehoseRole);

// Create Firehose delivery stream
this.deliveryStream = new firehose.CfnDeliveryStream(this, 'DeliveryStream', {
deliveryStreamType: 'DirectPut',
icebergDestinationConfiguration: {
roleArn: this.firehoseRole.roleArn,
catalogConfiguration: {
catalogArn: `arn:aws:glue:${region}:${account}:catalog/s3tablescatalog/${props.tableBucket.tableBucketName}`,
},
destinationTableConfigurationList: [{
destinationDatabaseName: props.namespaceName,
destinationTableName: props.tableName,
}],
bufferingHints: {
intervalInSeconds: 60,
sizeInMBs: 64,
},
s3Configuration: {
roleArn: this.firehoseRole.roleArn,
bucketArn: backupBucket.bucketArn,
},
} as any,
});
}
}


ステップ8: セットアップをテスト

8.1 テストデータを送信


# テストデータを作成
cat > test-data.json << 'EOF'
{"id": 1, "timestamp": "2025-07-18T10:00:00Z", "data": "test message"}
EOF

# Firehoseにデータを送信
aws firehose put-record \
--delivery-stream-name "your-firehose-stream-name" \
--record '{"Data": "{\"id\": 1, \"timestamp\": \"2025-07-18T10:00:00Z\", \"data\": \"test message\"}"}' \
--region REGION

8.2 S3テーブルのデータを検証


# Athenaを使用してクエリ
aws athena start-query-execution \
--query-string "SELECT * FROM\"s3tablescatalog/TABLE_BUCKET_NAME\".\"NAMESPACE_NAME\".\"TABLE_NAME\" LIMIT 10" \
--result-configuration "OutputLocation=s3://athena-results-bucket/" \
--region REGION


以前のアプローチとの主な違い

❌ 旧アプローチ(リソースリンク付き)

  • デフォルトGlueカタログでのリソースリンク作成が必要

  • 複数カタログを使用した複雑なセットアップ

  • 潜在的な同期の問題

✅ 新アプローチ(S3テーブルの直接アクセス)

  • リソースリンク不要

  • s3tablescatalog を通じたS3テーブルへの直接アクセス

  • よりシンプルで信頼性の高いセットアップ

  • パフォーマンスの向上


トラブルシューティング

一般的な問題

  1. パーミッションエラー
  • IAMロールにすべての必要な権限があることを確認

  • Lake Formationのパーミッションが付与されていることを確認

  • S3テーブル統合が有効化されていることを確認

  1. テーブルが見つからない
  • テーブルがS3テーブルに存在することを確認

  • ネームスペースとテーブル名が正確に一致することを確認

  • カタログARN形式を確認

  1. アクセス拒否
  • Lake Formationのパーミッションを確認

  • IAMポリシーが正しいARN形式を使用していることを確認

  • S3テーブルバケットのパーミッションを確認

検証コマンド


# S3テーブルリソースを確認
aws s3tables list-table-buckets --region REGION
aws s3tables list-namespaces --table-bucket-arn "arn:aws:s3tables:REGION:ACCOUNT:bucket/BUCKET_NAME" --region REGION
aws s3tables list-tables --table-bucket-arn "arn:aws:s3tables:REGION:ACCOUNT:bucket/BUCKET_NAME" --namespace "NAMESPACE_NAME" --region REGION

# IAMロールを確認
aws iam get-role --role-name "firehose-s3-tables-role"
aws iam list-role-policies --role-name "firehose-s3-tables-role"

# Lake Formationのパーミッションを確認
aws lakeformation list-permissions --principal "arn:aws:iam::ACCOUNT:role/firehose-s3-tables-role" --region REGION


まとめ

この新しいアプローチにより、リソースリンク不要にすることで、FirehoseとS3テーブルのセットアップが大幅に簡素化されます。直接カタログアクセスにより、より高いパフォーマンスと信頼性が得られ、全体的なアーキテクチャの複雑さが軽減されます。 成功の重要な要素は以下の通りです:

  1. 新しいARN形式による適切なIAMパーミッション

  2. 正確なLake Formationのパーミッション

  3. s3tablescatalog カタログARN形式の使用

  4. ネームスペースとテーブルの直接参照

Related Articles