S3 TablesのテーブルバケットをSSE-KMSで暗号化する(CloudFormation)
はじめに
東急株式会社のURBAN HACKSでサーバーサイドエンジニアをしています、一杉です。
昨年末はAWS re:Invent 2024に参加してきましたが、そこで発表されたS3 TablesにSSE-KMSでの暗号化が最近サポートされたということで実際に試してみました。
Apache Iceberg準拠のフルマネージドなテーブルを使いたく、かつセキュリティ・コンプライアンスの要件で独自のキーによるデータ暗号化が必要、という方の参考になればと思います。
今回のシナリオ
- S3のコンソールでAWS分析サービスとの統合を有効化しておく。
- テーブルバケット内のすべての新しいテーブルにデフォルトのカスタマーマネージドキーを設定する。(テーブルごとの専用キーの設定については本記事では扱わない。)
- テーブルバケットとカスタマーマネージドキーの作成・管理にはCloudFormationを用いる。
- Athenaでテーブルの作成とデータの挿入・取得を試す。
AWS分析サービスとの統合
テーブルバケットを作成するリージョンにおいて、事前にAWS分析サービスとの統合を有効化しておきます。S3のコンソールで「統合を有効にする」を押下していくだけで終わります。
統合の仕組みなどについては、以下の公式ドキュメントをご参照ください。
テーブルバケットとカスタマーマネージドキーの作成
今回はCloudFormationでテーブルバケットとカスタマーマネージドキーを作成します。
公式ドキュメントにAWS::S3Tables::TableBucketのリソースタイプが公開されていますので、こちらを基にCloudFormationテンプレートを記述できます。
また、本記事では使用しませんが、AWS::S3Tables::TableBucketPolicyのリソースタイプも公開されていますので、テーブルバケットポリシーでより細かいアクセス制御を行いたい場合にはこちらも利用するとよいでしょう。
作成してみたCloudFormationテンプレートのサンプルが以下になります。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
TableBucketName:
Type: String
Resources:
S3TablesTableBucket:
Type: AWS::S3Tables::TableBucket
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
EncryptionConfiguration:
SSEAlgorithm: aws:kms
KMSKeyArn: !GetAtt KMSKey.Arn
TableBucketName: !Ref TableBucketName
UnreferencedFileRemoval:
Status: Enabled
UnreferencedDays: 3
NoncurrentDays: 10
KMSKey:
Type: AWS::KMS::Key
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
Enabled: true
EnableKeyRotation: true
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: Allow Account
Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
- Sid: Allow Service Principals
Effect: Allow
Principal:
Service:
- 'maintenance.s3tables.amazonaws.com'
- 'metadata.s3.amazonaws.com'
AWS:
- !Sub 'arn:aws:iam::${AWS::AccountId}:role/service-role/S3TablesRoleForLakeFormation'
Action:
- 'kms:GenerateDataKey'
- 'kms:Decrypt'
Resource: '*'
Condition:
StringLike:
kms:EncryptionContext:aws:s3:arn: !Sub 'arn:aws:s3tables:${AWS::Region}:${AWS::AccountId}:bucket/${TableBucketName}/*'
KeySpec: SYMMETRIC_DEFAULT
KeyUsage: ENCRYPT_DECRYPT
MultiRegion: false
Origin: AWS_KMS
PendingWindowInDays: 30
RotationPeriodInDays: 365
特筆する点はキーポリシーのプリンシパルです。公式ドキュメントによると、テーブルを直接操作する場合のIAMプリンシパルのほか、以下のプリンシパルにもKMSキーへの権限を付与する必要があります。
- 自動テーブルメンテナンスのために
maintenance.s3tables.amazonaws.com
のサービスプリンシパル - メタデータテーブルの更新とメンテナンスのために
metadata.s3.amazonaws.com
とmaintenance.s3tables.amazonaws.com
のサービスプリンシパル - 統合されたAWS分析サービスでテーブルを操作するために
S3TablesRoleForLakeFormation
のサービスロール
これらの権限をまとめて一つのステートメントで記述したのが、上記サンプルの以下部分です。
- Sid: Allow Service Principals
Effect: Allow
Principal:
Service:
- 'maintenance.s3tables.amazonaws.com'
- 'metadata.s3.amazonaws.com'
AWS:
- !Sub 'arn:aws:iam::${AWS::AccountId}:role/service-role/S3TablesRoleForLakeFormation'
Action:
- 'kms:GenerateDataKey'
- 'kms:Decrypt'
Resource: '*'
Condition:
StringLike:
kms:EncryptionContext:aws:s3:arn: !Sub 'arn:aws:s3tables:${AWS::Region}:${AWS::AccountId}:bucket/${TableBucketName}/*'
あとは通常通りにCloudFormationスタックを作成できます。
テーブルの作成とデータの挿入・取得
今回はAthenaでテーブルの作成とデータの挿入・取得を試してみます。
AthenaからS3 Tablesをクエリする手順は、以下の公式ドキュメントで説明されています。
また、S3のコンソールからAthenaでのテーブル作成に遷移するリンクも用意されており、ダイアログでテーブルの名前空間を作成・指定できて、Athenaのクエリエディタにサンプルのクエリを入力してくれます。こちらのリンクを利用した様子が以下のスクリーンショットです。
データの取得まで成功すると、Athenaのクエリエディタに以下のようなクエリ結果が出力されます。
S3のコンソールに戻ると、作成したテーブルの存在を確認できます。
SSE-KMSで暗号化されていることの確認
KMSキーへの権限が無いロールからテーブルの中身を参照できないことを確認します。
まずは、CloudFormationテンプレートのキーポリシーに以下の拒否ポリシーを追加してみました。
- Sid: Deny Role
Effect: Deny
Principal:
AWS: <コンソール上でS3とAthenaにアクセスしているIAM Role>
Action:
- 'kms:GenerateDataKey'
- 'kms:Decrypt'
Resource: '*'
Condition:
StringLike:
kms:EncryptionContext:aws:s3:arn: !Sub 'arn:aws:s3tables:${AWS::Region}:${AWS::AccountId}:bucket/${TableBucketName}/*'
結果はテーブルの存在確認もデータの挿入・取得も成功。この理由は、統合されたAWS分析サービスでテーブルを操作するときにはS3TablesRoleForLakeFormation
のサービスロールが使われており、KMSキーへのアクセスもこのロールの権限が用いられているためと考えられます。
では先ほど追加した拒否ポリシーを削除して、以下のようにS3TablesRoleForLakeFormation
の許可ポリシーをコメントアウトしてみました。
- Sid: Allow Service Principals
Effect: Allow
Principal:
Service:
- 'maintenance.s3tables.amazonaws.com'
- 'metadata.s3.amazonaws.com'
# AWS:
# - !Sub 'arn:aws:iam::${AWS::AccountId}:role/service-role/S3TablesRoleForLakeFormation'
Action:
- 'kms:GenerateDataKey'
- 'kms:Decrypt'
Resource: '*'
Condition:
StringLike:
kms:EncryptionContext:aws:s3:arn: !Sub 'arn:aws:s3tables:${AWS::Region}:${AWS::AccountId}:bucket/${TableBucketName}/*'
結果はテーブルの存在確認は成功してデータの挿入・取得は失敗。これにより、テーブルの中身がSSE-KMSで暗号化されていることを確認できました。
おわりに
今回はシンプルなシナリオだったため容易に動作確認できましたが、社内横断のデータ基盤といった実務レベルの利用においては、マルチアカウントでのデータ共有やLake Formationの権限設定などについて、より深く検証・設計する必要があると感じました。
とはいえ、Apache Iceberg準拠のフルマネージドなテーブルを扱えるS3 Tablesは、レイクハウスの構築者にとって非常に強力なサービスでしょう。同様に、Google Cloud Next 2025でも取り上げられた、Apache Iceberg用のBigQueryテーブルも選択肢の一つになると思います。
この記事がどこかの誰かの一助になりましたら幸いです。
Discussion