以下の内容はhttps://techblog.forgevision.com/entry/2026/02/26/230736より取得しました。


自分ではうまくいかなかったAmazon S3 Metadataの外部参照を、Kiroに設計させて検証する

こんにちは、開発グループの寺田です。

本記事では、私自身が過去に検証してうまく実現できなかった
「Amazon S3 Metadata を外部システムから参照する機能」について、
Kiroに設計と実装を委ねた場合に成立するのかを検証します。

はじめに

Amazon S3 Metadataは、S3オブジェクトに関する情報を自動収集し、
検索・分析を可能にする機能です。
収集された情報はInventory(オブジェクト一覧)とJournal(変更履歴)の2つのテーブルに格納されます。
なお、データの反映タイミングはテーブルによって異なり、Journalはリアルタイムで反映されますが、 Inventoryは15分〜数時間後の定期更新となります。

Amazon S3 Metadataは、AthenaやSageMakerなどAWSサービスから利用する機能として紹介されることが多いですが、実際の現場ではそれだけでは十分とは言えません。
業務システムやBIツール、検索システム、社内ポータルなどからデータの内容を把握できて初めて、データレイクは継続的に利用されます。
多くの場合、データが活用されない理由は「データが無い」ことではなく、「何があり、何を表しているのか分からない」ことにあります。

以前、Athena + Lambda + API Gatewayを用いて、 Amazon S3 MetadataのInventory / Journalテーブルから データを取得する構成を検証していましたが、
当時は期待した形での取得を実現できませんでした。

今回はその検証を前提として、「Amazon S3 Metadata を外部から参照させる」という機能要件にスコープを絞り、 Kiroに設計および実装を行わせた結果、Athena + Lambda + API Gateway 構成で Inventory / Journalテーブルのデータ取得が可能であることを確認しました。

本記事では、あくまで「外部参照機能」という一点に絞って、 どのような構成で実現できたのか、また、どの点に注意が必要かを整理します。

Kiroに依頼

それでは、KiroにAmazon S3 Metadataを利用したアーキテクチャ設計をSpecモードで依頼します。
依頼にあたってはプロンプトをある程度練った上で渡しました。
特に意識したのは、従来のオブジェクトタグやuser-defined metadataではなく、 Amazon S3 Metadata(Inventory / Journal)のデータを必ず活用した設計にすることです。
この点を明示しないと、Kiroが既存のメタデータ機能を使った構成を提案してしまう可能性があるためです。

実際に使用したプロンプト ▼

あなたはAWSを利用したデータ基盤のアーキテクトです。
本検証では、2024年に発表された「Amazon S3 Metadata」機能を中核とし、
S3に保存されたデータを利用者が発見・理解・利用できる仕組みを設計してください。
ここでいうAmazon S3 Metadataは、従来のオブジェクトタグや
user-defined metadataではなく、S3オブジェクトに対して意味情報を付与し、
検索や理解を支援する情報層として扱います。

本設計では、Amazon S3 Metadataを外部システムから参照する機能を成立させることを目的とします。
■背景
現在、S3には様々なシステムからデータが蓄積されていますが、
利用者はどのデータが存在するのか分からず、ほとんど活用されていません。
データ自体は存在しているものの、「何があり、何を表しているのか」が
把握されていないため、データ利用が属人化しています。
■前提
・データは様々な形式でS3に保存される
・データのスキーマは将来的に変更される可能性がある
・利用者はSQLやAWSサービスに詳しくない
・データの場所や内容が分からず、活用が進まない状況を改善したい
■要求事項
・Amazon S3 Metadataを中心にしたアーキテクチャを提案すること
・利用者が「どのデータが何を表しているか」を把握できること
・外部システムからメタデータを参照できること
・データ追加時にメタデータが自動更新されること
・運用者の手作業を最小化すること
■制約
・特定のBIツールやDWH製品に依存しない構成とする
・手動登録の運用を前提にしない
・将来的なデータ量増加に耐えられる構成とする

提案では、使用するAWSサービス、処理フロー、運用方法について具体的に説明してください。

実際に作成されたrequirements.md ▼

# 要件定義書

## はじめに

本文書は、Amazon S3 Metadata機能を中核としたデータ発見基盤の要件を定義します。この基盤は、S3に保存されたデータを利用者が発見・理解・利用できる仕組みを提供します。Amazon S3 Metadataは、S3オブジェクトに対して意味情報を付与し、検索や理解を支援する情報層として機能します。

本システムは、S3 Metadata InventoryテーブルおよびJournalテーブルを外部システムから参照し、オブジェクトメタデータを検索・表示する仕組みを構築します。

## 用語集

- **S3_Metadata_System**: Amazon S3 Metadataを中核としたデータ発見基盤システム全体
- **Inventory_Table**: S3 Metadataが提供する、オブジェクトの現在状態を保持するテーブル
- **Journal_Table**: S3 Metadataが提供する、オブジェクトの変更履歴を時系列で保持するテーブル
- **Metadata_Query_Service**: InventoryテーブルおよびJournalテーブルに対してクエリを実行するサービス
- **Discovery_Interface**: 利用者がメタデータを検索・表示するためのインターフェース
- **Access_Control_Layer**: IAMベースのアクセス制御を実施する層
- **Object_Metadata**: S3オブジェクトに付与された意味情報(キー、サイズ、最終更新日時、カスタム属性など)
- **Bucket**: S3バケット
- **Object**: S3オブジェクト

## 要件

### 要件1: メタデータ検索機能

**ユーザーストーリー:** データ利用者として、指定したバケット内のオブジェクトメタデータを検索したい。これにより、必要なデータを迅速に発見できる。

#### 受入基準

1. 利用者がバケット名を指定してメタデータ検索を要求した場合、Metadata_Query_ServiceはInventory_Tableに対してクエリを実行すること
2. Inventory_Tableへのクエリが実行された場合、Metadata_Query_Serviceはオブジェクトキー、サイズ、最終更新日時を含むメタデータを取得すること
3. メタデータ検索結果が取得された場合、Discovery_Interfaceは検索結果を利用者に表示すること
4. 検索対象バケットが存在しない場合、S3_Metadata_Systemはエラーメッセージを返すこと
5. S3_Metadata_SystemはS3オブジェクトへの直接List操作を実行しないこと

### 要件2: 更新履歴の時系列表示

**ユーザーストーリー:** データ管理者として、オブジェクトの更新履歴を時系列で確認したい。これにより、データの変更追跡とガバナンスを実現できる。

#### 受入基準

1. 利用者がオブジェクトの更新履歴を要求した場合、Metadata_Query_ServiceはJournal_Tableに対してクエリを実行すること
2. Journal_Tableへのクエリが実行された場合、Metadata_Query_Serviceは変更イベントを時系列順に取得すること
3. 変更イベントが取得された場合、Discovery_Interfaceはイベントタイプ、タイムスタンプ、変更内容を表示すること
4. 指定されたオブジェクトの履歴が存在しない場合、S3_Metadata_Systemは空の結果を返すこと

### 要件3: オブジェクト削除検知

**ユーザーストーリー:** データ管理者として、削除されたオブジェクトを検知したい。これにより、意図しないデータ削除を追跡できる。

#### 受入基準

1. オブジェクトが削除された場合、Journal_Tableは削除イベントを記録すること
2. 利用者が削除イベントを検索した場合、Metadata_Query_ServiceはJournal_Tableから削除イベントを取得すること
3. 削除イベントが表示される場合、Discovery_Interfaceは削除されたオブジェクトキーと削除タイムスタンプを表示すること

### 要件4: IAMベースのアクセス制御

**ユーザーストーリー:** セキュリティ管理者として、IAMポリシーに基づいてメタデータへのアクセスを制御したい。これにより、適切な権限を持つ利用者のみがメタデータにアクセスできる。

#### 受入基準

1. 利用者がメタデータ検索を要求した場合、Access_Control_Layerは利用者のIAM権限を検証すること
2. 利用者が必要なIAM権限を持つ場合、S3_Metadata_Systemはメタデータ検索を許可すること
3. 利用者が必要なIAM権限を持たない場合、Access_Control_Layerはアクセス拒否エラーを返すこと
4. Access_Control_LayerはS3バケットポリシーおよびIAMポリシーと整合性を保つこと

### 要件5: 最小構成での実装

**ユーザーストーリー:** システム設計者として、データカタログ製品に依存せず、Amazon S3 Metadataを中心とした最小構成を実現したい。これにより、シンプルで保守性の高いシステムを構築できる。

#### 受入基準

1. S3_Metadata_SystemはAWS Glue Data Catalogを使用しないこと
2. S3_Metadata_Systemはクローラによる再収集を実施しないこと
3. S3_Metadata_Systemは独自のメタデータデータベースを構築しないこと
4. S3_Metadata_SystemはInventory_TableおよびJournal_Tableのみをメタデータソースとして使用すること
5. S3_Metadata_Systemは必要最小限のAWSサービスのみを使用すること

### 要件6: クエリ実行基盤

**ユーザーストーリー:** システム運用者として、InventoryテーブルおよびJournalテーブルに対して効率的にクエリを実行したい。これにより、高速なメタデータ検索を実現できる。

#### 受入基準

1. Metadata_Query_Serviceがクエリを実行する場合、S3_Metadata_Systemは標準的なSQLクエリ構文を使用すること
2. 大量のメタデータが存在する場合、Metadata_Query_Serviceはページネーションをサポートすること
3. クエリ実行が失敗した場合、Metadata_Query_Serviceはエラー詳細を含むログを記録すること
4. Metadata_Query_ServiceはInventory_TableおよびJournal_Tableのスキーマに準拠すること

### 要件7: リージョン設定

**ユーザーストーリー:** システム管理者として、デフォルトのAWSリージョンをap-northeast-1に設定したい。これにより、日本国内での低レイテンシアクセスを実現できる。

#### 受入基準

1. S3_Metadata_Systemはデフォルトのリージョンとしてap-northeast-1を使用すること
2. リージョンが明示的に指定された場合、S3_Metadata_Systemは指定されたリージョンを使用すること
3. リージョン設定が不正である場合、S3_Metadata_Systemは設定エラーを返すこと

実際に作成されたdesign.md ▼

# 設計書

## 概要

本設計書は、Amazon S3 Metadataを中核としたデータ発見基盤の技術設計を定義します。本システムは、S3 Metadata InventoryテーブルおよびJournalテーブルを活用し、S3オブジェクトのメタデータ検索、更新履歴表示、削除検知を実現します。

データカタログ製品やクローラに依存せず、Amazon S3 Metadataが提供するテーブルを直接クエリすることで、最小構成かつシンプルなアーキテクチャを実現します。

## アーキテクチャ

### システム構成

┌─────────────────────────────────────────────────────────────┐
│                        利用者                                │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│              Discovery Interface (API Gateway)              │
│                  + Lambda (API Handler)                     │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│            Access Control Layer (IAM Policy)                │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│         Metadata Query Service (Lambda + Athena)            │
└────────────┬───────────────────────────┬────────────────────┘
             │                           │
             ▼                           ▼
┌────────────────────────┐  ┌───────────────────────────────┐
│   Inventory Table      │  │     Journal Table             │
│  (S3 Metadata)         │  │    (S3 Metadata)              │
└────────────────────────┘  └───────────────────────────────┘
### コンポーネント概要 1. **Discovery Interface**: API GatewayとLambdaで構成されるRESTful API。利用者からのリクエストを受け付ける 2. **Access Control Layer**: IAMポリシーに基づくアクセス制御 3. **Metadata Query Service**: Amazon AthenaまたはS3 Select APIを使用してInventoryテーブル・Journalテーブルをクエリ 4. **Inventory Table**: S3 Metadataが提供する現在のオブジェクト状態テーブル 5. **Journal Table**: S3 Metadataが提供する変更履歴テーブル ## コンポーネントとインターフェース ### 1. Discovery Interface **責務**: 利用者からのHTTPリクエストを受け付け、適切なバックエンドサービスにルーティングする **技術スタック**: - Amazon API Gateway (REST API) - AWS Lambda (Python 3.12) **エンドポイント**:
GET /metadata/search
  Query Parameters:
    - bucket: バケット名 (必須)
    - prefix: オブジェクトキープレフィックス (オプション)
    - limit: 取得件数上限 (オプション、デフォルト100)
    - next_token: ページネーショントークン (オプション)
  
  Response:
    {
      "objects": [
        {
          "key": "string",
          "size": number,
          "last_modified": "ISO8601 timestamp",
          "metadata": {}
        }
      ],
      "next_token": "string or null"
    }

GET /metadata/history
  Query Parameters:
    - bucket: バケット名 (必須)
    - key: オブジェクトキー (必須)
    - start_time: 開始時刻 (オプション)
    - end_time: 終了時刻 (オプション)
  
  Response:
    {
      "events": [
        {
          "event_type": "string",
          "timestamp": "ISO8601 timestamp",
          "details": {}
        }
      ]
    }

GET /metadata/deletions
  Query Parameters:
    - bucket: バケット名 (必須)
    - start_time: 開始時刻 (オプション)
    - end_time: 終了時刻 (オプション)
  
  Response:
    {
      "deleted_objects": [
        {
          "key": "string",
          "deleted_at": "ISO8601 timestamp"
        }
      ]
    }
### 2. Access Control Layer **責務**: IAMポリシーに基づいてリクエストの認可を行う **実装方式**: - API GatewayのIAM認証を使用 - Lambda実行ロールに必要な権限を付与 - S3バケットポリシーとの整合性を保つ **必要なIAM権限**:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::metadata-inventory-bucket/*",
        "arn:aws:s3:::metadata-journal-bucket/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "athena:StartQueryExecution",
        "athena:GetQueryExecution",
        "athena:GetQueryResults"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "glue:GetTable",
        "glue:GetDatabase"
      ],
      "Resource": "*"
    }
  ]
}
### 3. Metadata Query Service **責務**: InventoryテーブルおよびJournalテーブルに対してSQLクエリを実行し、結果を返す **技術スタック**: - AWS Lambda (Python 3.12) - Amazon Athena (SQLクエリエンジン) - Boto3 (AWS SDK for Python) **クエリ実装**:
# Inventory検索クエリ例
SELECT 
  key,
  size,
  last_modified_date,
  metadata
FROM inventory_table
WHERE bucket = '{bucket_name}'
  AND key LIKE '{prefix}%'
ORDER BY last_modified_date DESC
LIMIT {limit}
# Journal履歴クエリ例
SELECT 
  event_type,
  event_time,
  object_key,
  event_details
FROM journal_table
WHERE bucket = '{bucket_name}'
  AND object_key = '{object_key}'
  AND event_time BETWEEN '{start_time}' AND '{end_time}'
ORDER BY event_time ASC
# 削除イベント検索クエリ例
SELECT 
  object_key,
  event_time as deleted_at
FROM journal_table
WHERE bucket = '{bucket_name}'
  AND event_type = 'ObjectRemoved'
  AND event_time BETWEEN '{start_time}' AND '{end_time}'
ORDER BY event_time DESC
**クエリ実行フロー**: 1. Lambda関数がAthena StartQueryExecutionを呼び出し 2. クエリ実行IDを取得 3. GetQueryExecutionでクエリステータスをポーリング 4. クエリ完了後、GetQueryResultsで結果を取得 5. 結果をJSON形式に変換して返却 ### 4. Inventory Table / Journal Table **データソース**: Amazon S3 Metadataが自動生成するテーブル **Inventory Tableスキーマ(想定)**:
- bucket: string
- key: string
- size: bigint
- last_modified_date: timestamp
- etag: string
- storage_class: string
- metadata: map<string, string>
**Journal Tableスキーマ(想定)**:
- bucket: string
- object_key: string
- event_type: string (ObjectCreated, ObjectRemoved, ObjectRestored, etc.)
- event_time: timestamp
- event_details: map<string, string>
- request_id: string
**注意**: 実際のスキーマはAWS S3 Metadataの仕様に依存します。実装時にはAWS公式ドキュメントを参照してください。 ## データモデル ### MetadataSearchRequest
{
  "bucket": str,           # 必須
  "prefix": str | None,    # オプション
  "limit": int,            # デフォルト100
  "next_token": str | None # オプション
}
### MetadataSearchResponse
{
  "objects": [
    {
      "key": str,
      "size": int,
      "last_modified": str,  # ISO8601形式
      "metadata": dict
    }
  ],
  "next_token": str | None
}
### HistoryRequest
{
  "bucket": str,              # 必須
  "key": str,                 # 必須
  "start_time": str | None,   # ISO8601形式、オプション
  "end_time": str | None      # ISO8601形式、オプション
}
### HistoryResponse
{
  "events": [
    {
      "event_type": str,
      "timestamp": str,  # ISO8601形式
      "details": dict
    }
  ]
}
### DeletionRequest
{
  "bucket": str,              # 必須
  "start_time": str | None,   # ISO8601形式、オプション
  "end_time": str | None      # ISO8601形式、オプション
}
### DeletionResponse
{
  "deleted_objects": [
    {
      "key": str,
      "deleted_at": str  # ISO8601形式
    }
  ]
}
## 正しさの性質(Correctness Properties) *性質(Property)とは、システムのすべての有効な実行において真であるべき特性や振る舞いのことです。本質的には、システムが何をすべきかについての形式的な記述です。性質は、人間が読める仕様と機械で検証可能な正しさの保証との橋渡しとなります。* ### Property 1: メタデータ検索レスポンススキーマ準拠 *任意の*有効なバケット名に対してメタデータ検索を実行した場合、返却されるすべてのオブジェクトメタデータは、必須フィールド(key, size, last_modified)を含み、定義されたスキーマに準拠する必要があります。 **検証要件: 1.2, 6.4** ### Property 2: 履歴イベントレスポンススキーマ準拠 *任意の*有効なバケット名とオブジェクトキーに対して履歴検索を実行した場合、返却されるすべてのイベントは、必須フィールド(event_type, timestamp, details)を含み、定義されたスキーマに準拠する必要があります。 **検証要件: 2.3, 6.4** ### Property 3: 削除イベントレスポンススキーマ準拠 *任意の*有効なバケット名に対して削除イベント検索を実行した場合、返却されるすべての削除イベントは、必須フィールド(key, deleted_at)を含み、定義されたスキーマに準拠する必要があります。 **検証要件: 3.3, 6.4** ### Property 4: 履歴イベントの時系列順序 *任意の*オブジェクトの履歴イベントを取得した場合、返却されるイベントのタイムスタンプは昇順にソートされている必要があります。 **検証要件: 2.2** ### Property 5: 存在しないバケットのエラーハンドリング *任意の*存在しないバケット名に対してメタデータ検索を実行した場合、システムはエラーメッセージを返す必要があります。 **検証要件: 1.4** ### Property 6: ページネーション機能 *任意の*大量のメタデータが存在するバケットに対して検索を実行した場合、limitパラメータで指定された件数以下の結果が返され、さらに結果が存在する場合はnext_tokenが返される必要があります。 **検証要件: 6.2** ### Property 7: リージョン指定の反映 *任意の*有効なAWSリージョンを明示的に指定した場合、システムは指定されたリージョンを使用してクエリを実行する必要があります。 **検証要件: 7.2** ### Property 8: 不正なリージョンのエラーハンドリング *任意の*不正なリージョン名を指定した場合、システムは設定エラーを返す必要があります。 **検証要件: 7.3** ## エラーハンドリング ### エラー分類 1. **クライアントエラー (4xx)** - 400 Bad Request: 不正なリクエストパラメータ - 403 Forbidden: IAM権限不足 - 404 Not Found: 指定されたバケットまたはオブジェクトが存在しない 2. **サーバーエラー (5xx)** - 500 Internal Server Error: Lambda関数の実行エラー - 503 Service Unavailable: Athenaクエリのタイムアウトまたは一時的な障害 ### エラーレスポンス形式
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {}
  }
}
### エラーハンドリング戦略 1. **入力検証**: リクエストパラメータの検証をLambda関数の最初で実施 2. **リトライロジック**: Athenaクエリ実行時の一時的なエラーに対して指数バックオフでリトライ 3. **ログ記録**: すべてのエラーをCloudWatch Logsに記録(エラーコード、メッセージ、スタックトレース) 4. **タイムアウト設定**: Lambda関数のタイムアウトを適切に設定(推奨: 30秒) 5. **デッドレターキュー**: 処理失敗時のメッセージをSQS DLQに送信(オプション) ### 具体的なエラーケース **ケース1: バケットが存在しない**
# 検証ロジック
if not bucket_exists(bucket_name):
    return {
        "statusCode": 404,
        "body": json.dumps({
            "error": {
                "code": "BucketNotFound",
                "message": f"Bucket '{bucket_name}' does not exist"
            }
        })
    }
**ケース2: IAM権限不足**
# API Gatewayレベルで自動的に403を返す
# Lambda関数内では追加の権限チェックを実施
try:
    athena_client.start_query_execution(...)
except ClientError as e:
    if e.response['Error']['Code'] == 'AccessDeniedException':
        return {
            "statusCode": 403,
            "body": json.dumps({
                "error": {
                    "code": "AccessDenied",
                    "message": "Insufficient permissions to access metadata"
                }
            })
        }
**ケース3: Athenaクエリタイムアウト**
# タイムアウト検知とリトライ
max_retries = 3
for attempt in range(max_retries):
    try:
        result = execute_athena_query(query)
        return result
    except QueryTimeoutError:
        if attempt == max_retries - 1:
            return {
                "statusCode": 503,
                "body": json.dumps({
                    "error": {
                        "code": "QueryTimeout",
                        "message": "Query execution timed out"
                    }
                })
            }
        time.sleep(2 ** attempt)  # 指数バックオフ
## テスト戦略 ### デュアルテストアプローチ 本システムでは、ユニットテストとプロパティベーステストの両方を実施します。これらは相補的であり、包括的なカバレッジを実現するために両方が必要です。 **ユニットテスト**: - 特定の例、エッジケース、エラー条件を検証 - コンポーネント間の統合ポイントをテスト - モックを使用してAWSサービスの動作をシミュレート **プロパティベーステスト**: - すべての入力に対して成立する普遍的な性質を検証 - ランダム化による包括的な入力カバレッジ - 各プロパティテストは最低100回の反復実行 ### プロパティベーステストの設定 **使用ライブラリ**: Hypothesis (Python) **設定**:
from hypothesis import given, settings
import hypothesis.strategies as st

@settings(max_examples=100)
@given(
    bucket_name=st.text(min_size=3, max_size=63, alphabet=st.characters(whitelist_categories=('Ll', 'Nd'), whitelist_characters='-')),
    prefix=st.text(max_size=1024)
)
def test_metadata_search_response_schema(bucket_name, prefix):
    """
    Feature: s3-metadata-discovery-platform, Property 1: メタデータ検索レスポンススキーマ準拠
    """
    # テスト実装
    pass
**タグ形式**: 各プロパティテストには、設計書のプロパティ番号を参照するコメントを付与します。 ### テストカバレッジ 1. **API層のテスト** - エンドポイントの入力検証 - レスポンス形式の検証 - エラーハンドリング 2. **クエリサービス層のテスト** - SQLクエリ生成の正確性 - Athenaクエリ実行フロー - 結果のパース処理 3. **統合テスト** - API Gateway → Lambda → Athena の完全なフロー - IAM認証・認可 - 実際のS3 Metadataテーブルとの連携(テスト環境) 4. **プロパティベーステスト** - Property 1-8の検証 - ランダムな入力に対する堅牢性確認 ### テスト環境 **ローカル開発環境**: - LocalStack または Moto を使用したAWSサービスのモック - pytest によるユニットテスト実行 **CI/CD環境**: - GitHub Actions または AWS CodePipeline - テスト用のAWSアカウント(専用のS3 Metadataテーブルを使用) - カバレッジレポートの自動生成 ### テストデータ **モックデータ生成**:
# Inventory Tableのモックデータ
mock_inventory_data = [
    {
        "bucket": "test-bucket",
        "key": "data/file1.json",
        "size": 1024,
        "last_modified_date": "2024-01-15T10:30:00Z",
        "metadata": {"content-type": "application/json"}
    },
    # ...
]

# Journal Tableのモックデータ
mock_journal_data = [
    {
        "bucket": "test-bucket",
        "object_key": "data/file1.json",
        "event_type": "ObjectCreated:Put",
        "event_time": "2024-01-15T10:30:00Z",
        "event_details": {"request_id": "ABC123"}
    },
    # ...
]
## 実装上の注意事項 ### S3 Metadataの制約 1. **テーブルの可用性**: S3 Metadataテーブルは、バケットでS3 Metadata機能を有効化した後に利用可能になります 2. **スキーマの確認**: 実装前にAWS公式ドキュメントで最新のスキーマを確認してください 3. **クエリコスト**: Athenaクエリは実行ごとに課金されるため、クエリの最適化が重要です 4. **レイテンシ**: Athenaクエリは数秒かかる場合があるため、非同期処理やキャッシュの検討が必要です ### パフォーマンス最適化 1. **クエリの最適化**: WHERE句でパーティションキーを使用 2. **結果のキャッシュ**: 頻繁にアクセスされるクエリ結果をElastiCacheに保存(オプション) 3. **ページネーション**: 大量の結果を一度に返さず、適切なページサイズを設定 4. **並列処理**: 複数のクエリを並列実行する場合はLambdaの同時実行数制限に注意 ### セキュリティ考慮事項 1. **最小権限の原則**: Lambda実行ロールには必要最小限の権限のみを付与 2. **VPC配置**: 必要に応じてLambda関数をVPC内に配置 3. **暗号化**: API GatewayでHTTPSを強制、S3バケットの暗号化を有効化 4. **監査ログ**: CloudTrailでAPIアクセスログを記録 5. **入力サニタイゼーション**: SQLインジェクション対策としてパラメータ化クエリを使用 ### 運用監視 1. **メトリクス**: CloudWatch Metricsで以下を監視 - API呼び出し回数 - Lambda実行時間 - Athenaクエリ実行時間 - エラー率 2. **アラート**: 以下の条件でアラートを設定 - エラー率が5%を超える - Lambda実行時間が20秒を超える - Athenaクエリ失敗率が10%を超える 3. **ログ**: CloudWatch Logsで構造化ログを記録 ```python import json import logging logger = logging.getLogger() logger.setLevel(logging.INFO) logger.info(json.dumps({ "event": "metadata_search", "bucket": bucket_name, "prefix": prefix, "result_count": len(results), "execution_time_ms": execution_time })) ``` ## デプロイメント ### インフラストラクチャ as Code **推奨ツール**: AWS SAM (Serverless Application Model) または Terraform **SAM テンプレート例**:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Parameters:
  DefaultRegion:
    Type: String
    Default: ap-northeast-1

Resources:
  MetadataSearchFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: metadata_search.lambda_handler
      Runtime: python3.12
      Timeout: 30
      Environment:
        Variables:
          DEFAULT_REGION: !Ref DefaultRegion
      Policies:
        - S3ReadPolicy:
            BucketName: !Ref InventoryBucket
        - Statement:
          - Effect: Allow
            Action:
              - athena:StartQueryExecution
              - athena:GetQueryExecution
              - athena:GetQueryResults
            Resource: '*'
      Events:
        SearchApi:
          Type: Api
          Properties:
            Path: /metadata/search
            Method: get
            Auth:
              Authorizer: AWS_IAM

  MetadataApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        DefaultAuthorizer: AWS_IAM
### デプロイ手順 1. **前提条件の確認** - S3バケットでS3 Metadata機能が有効化されていること - Inventory TableおよびJournal Tableが作成されていること 2. **SAMアプリケーションのビルド** ```bash sam build ``` 3. **デプロイ** ```bash sam deploy --guided --region ap-northeast-1 ``` 4. **動作確認** ```bash # API Gatewayエンドポイントを取得 aws cloudformation describe-stacks \ --stack-name s3-metadata-discovery-platform \ --query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \ --output text # テストリクエスト curl -X GET "https://.execute-api.ap-northeast-1.amazonaws.com/prod/metadata/search?bucket=test-bucket" \ --aws-sigv4 "aws:amz:ap-northeast-1:execute-api" ``` ### 環境分離 - **開発環境**: 開発者個人のAWSアカウントまたは共有開発アカウント - **ステージング環境**: 本番相当の設定でテスト - **本番環境**: 本番データを使用 各環境でスタック名とパラメータを変更してデプロイします。

Kiroが設計したアーキテクチャ

Kiroが設計したアーキテクチャは以下の構成です。API Gateway → Lambda → Athenaを通じて、 S3 Tables(Amazon S3 Metadataの保存先)のInventory / Journalテーブルを参照し、結果を返します。 Kiroが提案した構成は、私が以前自分で設計したものとほぼ同じでした。
設計の方向性は間違っていなかったという確認になった一方、 同じ構成であるがゆえに、私が当時解決できなかった問題が再現されました。
次章では、発生したエラーの詳細を説明します。

コンソールでは動くのにBoto3では動かない

AWS管理コンソール上のAthenaでは、Inventory・Journalの2つのテーブルを問題なく参照できていました。
・データソース:AwsDataCatalog
・データカタログ:s3tablescatalog/aws-s3
・データベース:b_fv-blog-s3-metadata
・テーブル:inventory、journal

しかし、同じ設定をBoto3経由でAthenaクエリとして実行すると、以下のエラーが発生しました。

{
  "error": {
    "code": "QueryExecutionError",
    "message": "CATALOG_NOT_FOUND: Catalog 's3tablescatalog/aws-s3' does not exist"
  }
}

コンソールでは選択・実行できているカタログが、Boto3では「存在しない」と判定されてしまう状況です。 これが私が以前の検証で直面したエラーと同じものであり、Kiroの実装においても再現されました。

Kiroにエラーメッセージをそのまま渡したところ、いくつかのやり取りを経て原因の特定と修正手順を提示してくれました。 解決までの時間は約1時間程度でした。特別な工夫は必要なく、Kiroの指示に従うだけで解決できました。

確認項目 影響
S3 TablesとGlue Data Catalogの統合 カタログが認識されない
Lake FormationのIAMアクセス制御設定 権限管理が機能しない
Athenaデータソースの登録 S3 Tablesカタログを参照できない
Lake Formationのデータアクセス権限 データにアクセスできない
Lambda実行ロールへのデータ権限付与 テーブルを参照できない

この中で、エラーの直接的な原因となっていたのは 「Athenaデータソースの登録」 でした。
マネジメントコンソールでは内部的に補完されるため気づきにくいですが、Boto3経由では明示的な登録が必要でした。

エラー修正後のアーキテクチャ

修正後のアーキテクチャでは、初期構成から以下の3点が追加・修正されています。
赤枠で示されている箇所が今回の変更ポイントです。
・AthenaへのS3 Tablesデータソース登録(カタログの明示的な指定)
・AWS Lake FormationのIAM制御有効化およびデータ権限付与
・Glue Data CatalogとS3 Tables統合の有効化

動作確認

エンドポイントに対してawscurlでリクエストを送信したところ、Athenaコンソールと同じ結果がJSON形式で返ってきました。 コンソール上での結果とAPI経由での結果が一致していることから、外部システムからS3 MetadataのInventory / Journalテーブルを正しく参照できていることが確認できました。
Inventory(オブジェクト一覧)のデータ参照

Journal(変更履歴)のデータ参照

まとめ

今回の検証では、Kiroに設計・実装を委ねることで、私が以前うまく実現できなかった「Amazon S3 Metadataの外部参照機能」を実現できました。
Kiroが提案した構成は私の設計とほぼ同じでしたが、Athenaへのデータソース登録・Lake Formationの権限設定・Glue Data Catalogとの統合という3点の設定が不足しており、それがエラーの原因でした。

これらはマネジメントコンソールでは自動補完されるため気づきにくく、Boto3経由で初めて顕在化する落とし穴です。
Kiroはエラーメッセージをそのまま渡すだけで原因を特定し、修正手順を提示してくれました。
設計の方向性は正しかったものの、細かな設定の抜け漏れを自力で発見するのが難しかった今回のケースでは、Kiroが非常に有効なパートナーになりました。
※Athenaデータソースの具体的な登録手順については、別の記事で改めて詳しく解説したいと思います。




以上の内容はhttps://techblog.forgevision.com/entry/2026/02/26/230736より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14