[アップデート] CloudWatch Logs エクスポート機能が出力先として SSE-KMS 暗号化 S3 バケットをサポートしました

カスタマー管理の KMS キーを指定した SSE-KMS デフォルト暗号化のバケットが対象です。

コンバンハ、千葉(幸)です。

CloudWatch Logs のログエクスポートを行う際、AWS KMS によって暗号化された S3 バケットを宛先に指定できるようになりました。

「AWS KMS によって暗号化された S3 バケット」とは、デフォルト暗号化が有効で、使用するキーがSSE-KMSであるバケットのことです。 *1

制約がひとつ取り払われたので、要件に応じてより幅広く選択できるようになりました。

先にまとめ

  • デフォルト暗号化がSSE-KMSの S3 バケットも CloudWatch Logs ログエクスポートの宛先に指定できる
    • ただしSSE-KMSのキーを AWS 管理キーaws/s3にしてはならない
    • 出力先 S3 バケット、KMS キーの双方でlogsへの許可が必要

CloudWatch Logs ログエクスポート機能とは

標準で使用できる機能で、CloudWatch Logs ロググループ上のログを S3 バケットにエクスポートできるものです。エクスポート対象のログは開始時刻と終了時刻を指定できるほか、特定のログストリームのみを対象とする、ということもできます。

これまでエクスポート先の S3 バケットは以下のいずれかである必要がありました。

  • デフォルト暗号化が無効
  • デフォルト暗号化で使用するキーがSSE-S3

今回のアップデートでデフォルト暗号化がSSE-KMSであるバケットもサポートされています。

SSE-KMS暗号化されたバケットを出力先に指定する場合、S3 バケットポリシーに加え、KMS キーのキーポリシーも意識する必要があります。

それぞれのポリシーで、プリンシパルをlogs.{region}.amazonaws.comとする許可を与えてあげる必要があります。(リージョンを指定しないこともできますが、なるべく絞った方がよいでしょう。)

キーポリシーで許可が与えてあげる必要があるということは、AWS 管理キーaws/s3は指定できなく、カスタマー管理の KMS キーを指定してあげる必要があるということですので注意してください。

SSE-KMS 暗号化バケットへのログエクスポートやってみた

今回は以下のイメージで実行していきます。

1. KMS キーの準備

以下設定で KMS キーを作成します。

  • キーのタイプ:対称
  • キーの使用:暗号化および復号化 *2
  • エイリアス:chibayuki-key

キーポリシーはドキュメントの記述を参考に以下を指定しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow CWL Service Principal usage",
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "kms:GenerateDataKey",
            "Resource": "*"
        },
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::012345678910:root"
            },
            "Action": [
                "kms:GetKeyPolicy*",
                "kms:PutKeyPolicy*",
                "kms:DescribeKey*",
                "kms:CreateAlias*",
                "kms:ScheduleKeyDeletion*",
                "kms:Decrypt"
            ],
            "Resource": "*"
        }
    ]
}

2. S3 バケットの準備

以下設定で S3 バケットを作成しました。

  • バケット名:chibayuki-destination
  • デフォルト暗号化:SSE-KMS
    • 先ほど作成した KMS キーを指定
  • オブジェクト所有者:ACL 無効
  • ブロックバブリックアクセス:すべてブロック
  • バージョニング:無効

作成後、S3 バケットポリシーを以下の通り編集します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::chibayuki-destination"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::chibayuki-destination/*",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "012345678910",
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}

ちなみに

今回は「ACL 無効」にしたので、もしかしてバケットポリシーでs3:GetBucketAclの Allow は要らないのか?と思い削ってみたところ、エクスポート実行時に以下のエラーが発生しました。

エクスポートタスクを作成できませんでした。 GetBucketAcl call on the given bucket failed. Please check if CloudWatch Logs has been granted permission to perform this operation.

改めて考えると「ACL 無効」は無効というよりは「ACL の固定・強制」なので、s3:GetBucketAclが不要になるわけではありませんでした。 *3

ちなみに 2

SSE-KMSで使用するキーに AWS 管理のaws/s3を使用した際にはエクスポート実行時に以下のエラーが発生します。

エクスポートタスクを作成できませんでした。 PutObject call on the given bucket failed. Please check if CloudWatch Logs has been granted permission to perform this operation. This may be a result of a KMS key or bucket encryption misconfiguration.

aws/s3は logs からのアクセスを許可していないしそれを変えることもできないので、カスタマーが作ったキーを指定する必要があるということですね。


3. エクスポートタスクの実行

準備が整ったのでエクスポートを実行していきます。今回はたまたま環境にあった、Lambda 関数の実行ログをエクスポートしてみます。

CloudWatch Logs ロググループの画面から「アクション」→「データを Amazon S3 にエクスポート」を押下します。

CloudWatch_export_CloudWatch_Management_Console

エクスポートの設定画面で各種指定を行い、「エクスポート」を実行します。指定できるパラメータは以下の通りです。

  • エクスポートするデータの期間
    • 開始
    • 終了
  • 特定のログストリームのみエクスポートする場合はそのプレフィックス
  • 出力先 S3 バケット
  • 出力先プレフィックス(省略した場合はexportedlogsになる)

CloudWatch_export_logs_CloudWatch_Management_Console

実行すると、画面上部にエクスポートタスクが正常に作成された旨のメッセージと、その詳細画面へ遷移できるボタンが表示されます。

CloudWatch_export_CloudWatch_Management_Console-8237870

エクスポートタスクの詳細画面です。ここから出力先の S3 バケットに遷移できます。

CloudWatch_export_CloudWatch_Management_Console-8237912


(なお、CloudWatch コンソールの左ペインから上記の画面に遷移できる導線はありませんでした。東京リージョンであれば以下リンクから遷移できそうです。)

https://ap-northeast-1.console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#logsV2:export-tasks

出力先の S3 バケットに遷移しました。

CloudWatch_logs_export_chibayuki-destination_-_S3_bucket

オブジェクトは.gzで圧縮されています。S3 バケットの設定に従い、指定した KMS キーで暗号化されています。

CloudWatch_Logs_export

ダウンロード・解凍し中身を確認するとこのような感じ。冒頭で述べた通り今回エクスポートしたログは Lambda 関数の実行ログなので、このような内容になっています。

2022-11-11T01:10:28.255Z START RequestId: a7679120-0a7d-4ca2-9b4c-3dd23567b670 Version: $LATEST

2022-11-11T01:10:30.491Z 200

2022-11-11T01:10:30.531Z END RequestId: a7679120-0a7d-4ca2-9b4c-3dd23567b670

2022-11-11T01:10:30.531Z REPORT RequestId: a7679120-0a7d-4ca2-9b4c-3dd23567b670	Duration: 2275.75 ms	Billed Duration: 2276 ms	Memory Size: 128 MB	Max Memory Used: 69 MB	Init Duration: 515.05 ms

SSE-KMS で暗号化された S3 バケットへの CloudWatch Logs ログのエクスポートが確認できました。

おまけ:エクスポートされたオブジェクトの命名規則

アップデートとは関係ありませんが、今回やってみたことで学んだので書いておきます。

今回エクスポートされたオブジェクトの S3 URI は以下の通りです。

s3://chibayuki-destination/exportedlogs/d8fdd9b6-9bb8-4e13-8df1-7f41e8610d8c/2022-11-11-[$LATEST]cb2c7d0c04344d1d820adffe7ae8a506/000000.gz

これは以下の規則になっています。

s3://バケット名/プレフィックス名/エクスポートタスクID/ログストリーム名/000000.gz

プレフィックス名

エクスポート時に S3 バケットのプレフィックスを指定すると上記の例のexportedlogsの部分がそのプレフィックスに置き換わります。

エクスポートタスク ID

エクスポートタスク ID は実行直後以外はマネジメントコンソールからは確認できませんが、例えば AWS CLI を使用すれば後からでも確認できます。

% aws logs describe-export-tasks\
 --query 'exportTasks[].{taskID:taskId,completionTime:executionInfo.completionTime}'\
 --output table
------------------------------------------------------------
|                    DescribeExportTasks                   |
+-----------------+----------------------------------------+
| completionTime  |                taskID                  |
+-----------------+----------------------------------------+
|  1668238248915  |  75cfe91e-2f6c-4e42-91f7-dfb6d31dc1df  |
|  1668238157538  |  081b0127-b7fd-4447-a152-612d16d8e20d  |
|  1668237746082  |  d8fdd9b6-9bb8-4e13-8df1-7f41e8610d8c  |
+-----------------+----------------------------------------+

ログストリーム名

エクスポート対象のログストリームが複数あった場合、s3://バケット名/プレフィックス名/エクスポートタスクID/配下にそれぞれのストリーム名に応じたプレフィックスが作成されます。

まとめ(再掲)

  • デフォルト暗号化がSSE-KMSの S3 バケットも CloudWatch Logs ログエクスポートの宛先に指定できる
    • ただしSSE-KMSのキーを AWS 管理キーaws/s3にしてはならない
    • 出力先 S3 バケット、KMS キーの双方でlogsへの許可が必要

終わりに

CloudWatch Logs ロググループのエクスポートで出力先のバケットにSSE-KMS暗号化バケットが指定できるようになった、というアップデートでした。

SSE-KMSを標準的に使っているが、これまでサポートされていなかったのでエクスポート先のバケットのみSSE-S3にしていた、といったワークロードに刺さりそうです。

こういった暗号化方針はある程度大規模な環境では細かく定められていることも多いと思います。機能の仕様により例外的な対応をとる、というのがなるべく少なくなり、幅広い選択肢の中から選択できる、となっていくのは望ましいことだと思います。

以上、 チバユキ (@batchicchi) がお送りしました。

脚注

  1. 公式ドキュメントの表現を借りて「AWS KMS によって暗号化された S3 バケット」という書き方をしてみましたが、個人的にはあまりしっくりきてないです。「暗号化の指定が特に何もない状態で PutObject された際にそのオブジェクトに対して特定のキーでサーバーサイド暗号化を施す設定が入ったバケット」な訳で、暗号化されるのはバケットではなくオブジェクトだろう、という考え方からです。でもね、そんなところも好きなんですよ
  2. 個人的には「復号」派ですが、コンソールの表記に倣って「復号化」としました
  3. このあたりはまた別途整理したい、、、