S3 の ListBuckets API のレスポンスの CreationDate は(その名前に反して)変更されうる

タイトルのまんまです(2024/11/08 時点の情報です)。意外な仕様!

どういうこと?

AWS アカウント内の S3 バケットを列挙したりするのに、aws s3api list-buckets のようなコマンドを利用することがあると思います。そのレスポンスに含まれる CreationDate は、実際の作成日時とは異なるものを返す場合があるようです。 ドキュメント list-buckets — AWS CLI 2.19.3 Command Reference いわく、

CreationDate -> (timestamp)

Date the bucket was created. This date can change when making changes to your bucket, such as editing its bucket policy.

バケットへの変更(バケットポリシーの変更など)により、CreationDate の値は変更される可能性がある、とのこと。

具体的には、対象のバケットに変更を加えたうえで、us-east-1 でないサービスエンドポイントからコマンドを実行すると、実際の作成日時とは異なるものを返すようです。というわけで、実際のバケット作成日時を知りたいときは --region us-east-1 を指定しておく のが良さそうです。なお、マネジメントコンソールでは us-east-1 サービスエンドポイントから実行しているので、コンソール上で見るときは正しい値を見ているようです。

再現手順

creationdate-is-mutable という S3 バケットを作成し、適当なバケットポリシーを設定します。その前後で aws s3api list-buckets を実行して、CreationDate の変化を見てみます。

手元で試すときは、creationdate-is-mutable だとか 123456789012 は適当に変更してください。

CreationDate が変更されることの確認

// ap-northeast-1 にバケット作成
$ aws s3 mb s3://creationdate-is-mutable --region ap-northeast-1
make_bucket: creationdate-is-mutable

// CreationDate は "2024-11-08T01:18:36+00:00"
$ aws s3api list-buckets --query "Buckets[?Name=='creationdate-is-mutable']" --region ap-northeast-1
[
    {
        "Name": "creationdate-is-mutable",
        "CreationDate": "2024-11-08T01:18:36+00:00"
    }
]

// バケットポリシーを作成(なんでもいいです)
$ echo '{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789012:root"
                ]
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::creationdate-is-mutable/*"
        }
    ]
}' > example-policy.json

// バケットポリシーを put
$ aws s3api put-bucket-policy --bucket creationdate-is-mutable --policy file://example-policy.json

// 再度、CreationDate を確認すると、"2024-11-08T01:18:36+00:00" …… ではなく、put した時間に更新されている!
$ aws s3api list-buckets --query "Buckets[?Name=='creationdate-is-mutable']" --region ap-northeast-1
[
    {
        "Name": "creationdate-is-mutable",
        "CreationDate": "2024-11-08T01:19:16+00:00"
    }
]

// ポリシーを delete したりしても変更されていた
$ aws s3api delete-bucket-policy --bucket creationdate-is-mutable

$ aws s3api list-buckets --query "Buckets[?Name=='creationdate-is-mutable']" --region ap-northeast-1
[
    {
        "Name": "creationdate-is-mutable",
        "CreationDate": "2024-11-08T01:20:04+00:00"
    }
]

us-east-1 サービスエンドポイントと、それ以外の挙動

みなさんご存知の通り S3 バケット名前空間はグローバルに共有されています。creationdate-is-mutable バケットap-northeast-1 に作成したので、us-east-1 では作成できません。

$ aws s3 mb s3://creationdate-is-mutable --region us-east-1
make_bucket failed: s3://creationdate-is-mutable An error occurred (BucketAlreadyOwnedByYou) when calling the CreateBucket operation:
Your previous request to create the named bucket succeeded and you already own it.

だから aws s3api list-buckets コマンドも、--region us-east-1 で実行しても --region ap-northeast-1 で実行しても、同じ結果が帰ってきてほしいですよね。あるいは正しいリージョンからの実行でないと返ってきてほしくない。しかし実際の挙動はというと、us-east-1 ではバケットの作成時刻 "2024-11-08T01:18:35+00:00" が返っていますが、その他のリージョンではバケットの最終更新時刻が返ってきています。

$ aws s3api list-buckets --query "Buckets[?Name=='creationdate-is-mutable']" --region us-east-1
[
    {
        "Name": "creationdate-is-mutable",
        "CreationDate": "2024-11-08T01:18:35+00:00"
    }
]

$ aws s3api list-buckets --query "Buckets[?Name=='creationdate-is-mutable']" --region ap-northeast-1
[
    {
        "Name": "creationdate-is-mutable",
        "CreationDate": "2024-11-08T01:20:04+00:00"
    }
]

$ aws s3api list-buckets --query "Buckets[?Name=='creationdate-is-mutable']" --region ca-central-1
[
    {
        "Name": "creationdate-is-mutable",
        "CreationDate": "2024-11-08T01:20:04+00:00"
    }
]

余談

大量の S3 バケットを棚卸しすべく ListBuckets API を利用するスクリプトを組んでいたところ、そのレスポンスの CreationDate と、Management Console 上の「作成日時」の表記が異なることに気づいて調べました。(AWS サポートさんにも確認 & フィードバック済みです。)そんな仕様だったとは……、ハマる人居そうだな〜、と調べていたところ、まさにこの仕様の裏側を説明するような Issue が出てきました。

github.com

All bucket creations are mastered in us-east-1, then replicated on a global scale - the resulting difference is that there are no "replication" events to the us-east-1 region. The Date Created field displayed in the web console is according to the actual creation date registered in us-east-1, while the AWS CLI and SDKs will display the creation date depending on the specified region (or the default region set in your configuration).

When using an endpoint other than us-east-1, the CreationDate you receive is actually the last modified time according to the bucket's last replication time in this region. This date can change when making changes to your bucket, such as editing its bucket policy. This experienced behavior is result of how S3's architecture has been designed and implemented, making it difficult to change without affecting customers that already expect this behavior.

なるほどな〜。しかし S3 という歴史あるサービスだし、知っている人は知っているもんなんだろうか。面白いですね。