🔐

S3 TablesのテーブルバケットをSSE-KMSで暗号化する(CloudFormation)

に公開

はじめに

東急株式会社のURBAN HACKSでサーバーサイドエンジニアをしています、一杉です。

昨年末はAWS re:Invent 2024に参加してきましたが、そこで発表されたS3 TablesにSSE-KMSでの暗号化が最近サポートされたということで実際に試してみました。

Apache Iceberg準拠のフルマネージドなテーブルを使いたく、かつセキュリティ・コンプライアンスの要件で独自のキーによるデータ暗号化が必要、という方の参考になればと思います。
https://aws.amazon.com/jp/about-aws/whats-new/2025/04/amazon-s3-tables-server-side-encryption-aws-kms-customer-managed-keys/
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/s3-tables-kms-encryption.html

今回のシナリオ

  • S3のコンソールでAWS分析サービスとの統合を有効化しておく。
  • テーブルバケット内のすべての新しいテーブルにデフォルトのカスタマーマネージドキーを設定する。(テーブルごとの専用キーの設定については本記事では扱わない。)
  • テーブルバケットとカスタマーマネージドキーの作成・管理にはCloudFormationを用いる。
  • Athenaでテーブルの作成とデータの挿入・取得を試す。

AWS分析サービスとの統合

テーブルバケットを作成するリージョンにおいて、事前にAWS分析サービスとの統合を有効化しておきます。S3のコンソールで「統合を有効にする」を押下していくだけで終わります。

統合の仕組みなどについては、以下の公式ドキュメントをご参照ください。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/s3-tables-integrating-aws.html

テーブルバケットとカスタマーマネージドキーの作成

今回はCloudFormationでテーブルバケットとカスタマーマネージドキーを作成します。

公式ドキュメントにAWS::S3Tables::TableBucketのリソースタイプが公開されていますので、こちらを基にCloudFormationテンプレートを記述できます。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-s3tables-tablebucket.html

また、本記事では使用しませんが、AWS::S3Tables::TableBucketPolicyのリソースタイプも公開されていますので、テーブルバケットポリシーでより細かいアクセス制御を行いたい場合にはこちらも利用するとよいでしょう。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-s3tables-tablebucketpolicy.html

作成してみた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.commaintenance.s3tables.amazonaws.comのサービスプリンシパル
  • 統合されたAWS分析サービスでテーブルを操作するためにS3TablesRoleForLakeFormationのサービスロール

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/s3-tables-kms-permissions.html

これらの権限をまとめて一つのステートメントで記述したのが、上記サンプルの以下部分です。

          - 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をクエリする手順は、以下の公式ドキュメントで説明されています。
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/gdc-register-s3-table-bucket-cat.html

また、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テーブルも選択肢の一つになると思います。
https://cloud.google.com/bigquery/docs/iceberg-tables?hl=ja

この記事がどこかの誰かの一助になりましたら幸いです。

東急URBAN HACKS

Discussion