[アップデート] S3 Express One Zone が S3 インベントリに対応したので試してみた

[アップデート] S3 Express One Zone が S3 インベントリに対応したので試してみた

2026.04.25

はじめに

2026 年 4 月、Amazon S3 Express One Zone(ディレクトリバケット)が S3 インベントリに対応しました。これまでディレクトリバケット内のオブジェクト棚卸しは、ListObjectsV2 による全件走査しかありませんでした。大規模なバケットではコストと時間が無視できません。今回のアップデートで、汎用バケットと同様に定期的なインベントリレポートを取得できるようになりました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/04/s3-express-one-zone-supports-s3-inventory/

設定は API / CLI / SDK のみで、マネジメントコンソールは非対応です。AWS CLI で設定からレポート出力、Athena から確認までを一通り試した内容を紹介します。

確認結果

  • S3 Express One Zone のディレクトリバケットに S3 インベントリを設定できるようになった
  • 設定は CLI / SDK のみ。マネジメントコンソールのディレクトリバケット画面にインベントリタブは存在しない
  • IAM アクションは s3express:PutInventoryConfiguration / s3express:GetInventoryConfigurations3: ではない)
  • 出力先バケットポリシーの Principal は s3express.amazonaws.coms3.amazonaws.com ではない)
  • 初回レポートの配信まで最大 48 時間かかる(S3 インベントリ共通仕様)

これまで

S3 Express One Zone はミリ秒オーダーの低レイテンシを持つディレクトリバケットを提供しますが、S3 インベントリは長らく未対応でした。オブジェクト数が数百万件を超えると ListObjectsV2 の走査コストと時間が無視できなくなります。

https://dev.classmethod.jp/articles/new-amazon-s3-express-one-zone-high-performance-storage-class/

アップデートのポイント

ディレクトリバケットの S3 インベントリを汎用バケットへ書き出せるようになるアップデートです。制限事項を以下に整理します。

項目 内容
設定方法 API / CLI / SDK のみ(マネジメントコンソール非対応)
出力先バケット 同一リージョンの汎用バケット(クロスリージョン不可)
暗号化 SSE-S3 / SSE-KMS(カスタマー管理キーのみ。AWS マネージドキー aws/s3 は不可。これは S3 インベントリ全般の制約)
出力形式 CSV / ORC / Parquet
スケジュール Daily / Weekly

やってみた

検証環境は ap-northeast-1 リージョン、AZ ID apne1-az4 です。AZ ID はアカウントやリージョンにより異なるため、aws ec2 describe-availability-zones --region ap-northeast-1 で事前に確認してください。

検証で使う変数を定義します。

SRC_BUCKET=devio-express-inv-src--apne1-az4--x-s3
DST_BUCKET=devio-express-inv-dst-20260421
ACCOUNT_ID=123456789012

ディレクトリバケットを作成する

ディレクトリバケットを作成しました。

aws s3api create-bucket \
  --bucket "$SRC_BUCKET" \
  --region ap-northeast-1 \
  --create-bucket-configuration \
    'Location={Type=AvailabilityZone,Name=apne1-az4},Bucket={Type=Directory,DataRedundancy=SingleAvailabilityZone}'

出力先の汎用バケットを作成する

受け取り先には同一リージョンの汎用バケットを使います。クロスリージョンは非対応です。

aws s3 mb s3://$DST_BUCKET --region ap-northeast-1

出力先バケットにポリシーを設定する

S3 インベントリのサービスが DST_BUCKET にレポートを書き込めるよう、バケットポリシーを設定します。Principal には s3express.amazonaws.com を指定します。s3.amazonaws.com を指定すると PutObject が拒否されます。

aws:SourceARNarn:aws:s3express:<region>:<account>:bucket/<name--azid--x-s3> の形式で指定します。末尾の --azid--x-s3 サフィックスまで含める必要があります。

以下を dst-policy.json として保存します。

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "InventoryDeliveryFromExpress",
    "Effect": "Allow",
    "Principal": { "Service": "s3express.amazonaws.com" },
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::devio-express-inv-dst-20260421/*",
    "Condition": {
      "ArnLike": {
        "aws:SourceARN": "arn:aws:s3express:ap-northeast-1:123456789012:bucket/devio-express-inv-src--apne1-az4--x-s3"
      },
      "StringEquals": {
        "aws:SourceAccount": "123456789012",
        "s3:x-amz-acl": "bucket-owner-full-control"
      }
    }
  }]
}

ポリシーを適用します。

aws s3api put-bucket-policy --bucket "$DST_BUCKET" --policy file://dst-policy.json

適用後の状態はコンソールのアクセス許可タブから確認できます。

devio-express-inv-dst-2026042…3_バケット___S3___ap-northeast-1.png

テスト用オブジェクトをアップロードする

レポートに何件か表示されるよう、サイズの異なるオブジェクトを 2 つアップロードします。

dd if=/dev/urandom of=/tmp/small.bin bs=1024 count=10
dd if=/dev/urandom of=/tmp/large.bin bs=1048576 count=20
aws s3 cp /tmp/small.bin s3://$SRC_BUCKET/small.bin
aws s3 cp /tmp/large.bin s3://$SRC_BUCKET/large.bin

アップロードしたオブジェクトはディレクトリバケットの画面で確認できました。

devio-express-inv-src--apne1-…S3_バケット___S3___ap-northeast-1.png

インベントリ設定を投入する

以下を inv.json として保存します。フォーマットは Parquet、スケジュールは Daily を選択しました。LifecycleExpirationDate は OptionalFields から除外しています(ライフサイクルルール未設定のため空欄になります)。

バケット名、アカウント名は環境に合わせて修正してください。

{
  "Id": "daily-full-report",
  "IsEnabled": true,
  "Destination": {
    "S3BucketDestination": {
      "AccountId": "123456789012",
      "Bucket": "arn:aws:s3:::devio-express-inv-dst-20260421",
      "Format": "Parquet",
      "Prefix": "inventory"
    }
  },
  "Schedule": { "Frequency": "Daily" },
  "IncludedObjectVersions": "Current",
  "OptionalFields": [
    "Size", "LastModifiedDate", "StorageClass", "ETag",
    "IsMultipartUploaded", "EncryptionStatus", "BucketKeyStatus",
    "ChecksumAlgorithm"
  ]
}

設定を投入します。

aws s3api put-bucket-inventory-configuration \
  --bucket "$SRC_BUCKET" \
  --id daily-full-report \
  --inventory-configuration file://inv.json

成功すると空レスポンスが返ります。

$ aws s3api put-bucket-inventory-configuration \
>   --bucket "$SRC_BUCKET" \
>   --id daily-full-report \
>   --inventory-configuration file://inv.json
$

設定を確認する

投入した設定を取得して内容を確認します。

aws s3api get-bucket-inventory-configuration \
  --bucket "$SRC_BUCKET" \
  --id daily-full-report

IsEnabled: trueSchedule.Frequency: Daily などが返ってきます。

実行結果
{
    "InventoryConfiguration": {
        "Destination": {
            "S3BucketDestination": {
                "AccountId": "123456789012",
                "Bucket": "arn:aws:s3:::devio-express-inv-dst-20260421",
                "Format": "Parquet",
                "Prefix": "inventory"
            }
        },
        "IsEnabled": true,
        "Id": "daily-full-report",
        "IncludedObjectVersions": "Current",
        "OptionalFields": [
            "Size",
            "LastModifiedDate",
            "StorageClass",
            "ETag",
            "IsMultipartUploaded",
            "EncryptionStatus",
            "BucketKeyStatus",
            "ChecksumAlgorithm"
        ],
        "Schedule": {
            "Frequency": "Daily"
        }
    }
}

翌日以降にレポートの配信を確認する

devio-express-inv-dst-2026042…3_バケット___S3___ap-northeast-1-2.png

私の検証では設定を投入してから約 33 時間後(2026-04-23 22:20 JST)に初回レポートが配信されました。丸 2 日待つつもりで計画しておくと安全です。

DST_BUCKET の中身を再帰的に確認します。

aws s3 ls "s3://$DST_BUCKET/inventory/" --recursive --human-readable

実行結果は以下のとおりです。

2026-04-23 22:20:25   33 Bytes inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/2026-04-23T00-00Z/manifest.checksum
2026-04-23 22:20:25  904 Bytes inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/2026-04-23T00-00Z/manifest.json
2026-04-23 22:20:17    0 Bytes inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/data/
2026-04-23 22:20:24    3.5 KiB inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/data/5bc79653-697b-400a-b851-52678a86704b.parquet
2026-04-23 22:20:25  152 Bytes inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/hive/dt=2026-04-23-00-00/symlink.txt

配置されたオブジェクトの内容は以下のとおりです。

パス 内容
<inventory-id>/<snapshot-date>/manifest.json レポートのメタデータ。data ファイルへのパスとスキーマを保持
<inventory-id>/<snapshot-date>/manifest.checksum manifest.json の MD5 チェックサム
<inventory-id>/data/<uuid>.parquet レポート本体。スナップショット時点のオブジェクト一覧
<inventory-id>/hive/dt=<snapshot-date>/symlink.txt Hive 互換のパーティション用 symlink。Athena から日付パーティションでクエリする際に利用

manifest.json をダウンロードして中身を確認します。

aws s3 cp \
  "s3://$DST_BUCKET/inventory/$SRC_BUCKET/daily-full-report/2026-04-23T00-00Z/manifest.json" \
  ./manifest.json
cat manifest.json

中身は次のとおりでした。

{
  "sourceBucket" : "devio-express-inv-src--apne1-az4--x-s3",
  "destinationBucket" : "arn:aws:s3:::devio-express-inv-dst-20260421",
  "version" : "2016-11-30",
  "creationTimestamp" : "1776902400001",
  "fileFormat" : "Parquet",
  "fileSchema" : "message s3.inventory {  required binary bucket (STRING);  required binary key (STRING);  optional int64 size;  optional int64 last_modified_date (TIMESTAMP(MILLIS,true));  optional binary e_tag (STRING);  optional binary storage_class (STRING);  optional boolean is_multipart_uploaded;  optional binary encryption_status (STRING);  optional binary bucket_key_status (STRING);  optional binary checksum_algorithm (STRING);}",
  "files" : [ {
    "key" : "inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/data/5bc79653-697b-400a-b851-52678a86704b.parquet",
    "size" : 3614,
    "MD5checksum" : "7835c2a989a416983fc72004841e59e2"
  } ]
}

Parquet 本体の中身も確認します。ローカルマシンの duckdb で覗いてみます。

$ aws s3 cp s3://devio-express-inv-dst-20260421/inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/data/5bc79653-697b-400a-b851-52678a86704b.parquet .

$ duckdb -c "SELECT key, size, storage_class, is_multipart_uploaded, encryption_status, checksum_algorithm FROM read_parquet('/tmp/5bc79653-697b-400a-b851-52678a86704b.parquet');"
実行結果
┌───────────┬──────────┬─────────────────┬───────────────────────┬───────────────────┬────────────────────┐
    key   size  storage_class is_multipart_uploaded encryption_status checksum_algorithm
  varchar  int64     varchar        boolean      varchar      varchar
├───────────┼──────────┼─────────────────┼───────────────────────┼───────────────────┼────────────────────┤
 small.bin    10240 EXPRESS_ONEZONE false SSE-S3 CRC64NVME
 large.bin 20971520 EXPRESS_ONEZONE true SSE-S3 CRC64NVME
└───────────┴──────────┴─────────────────┴───────────────────────┴───────────────────┴────────────────────┘

アップロードした 2 オブジェクトが想定どおり記録されていました。

large.bin は 20 MiB のファイルで、aws s3 cp のマルチパートしきい値を超えます。そのため自動でマルチパートに切り替わり、is_multipart_uploadedtrue として記録されています。small.bin は 10 KiB なので false です。

storage_class はディレクトリバケットなので EXPRESS_ONEZONE で固定です。checksum_algorithm は今回 aws s3 cp でアップロードしたため CRC64NVME が記録されていました。AWS CLI v2 の既定では新しいオブジェクトに対して CRC64NVME が選択されます。チェックサムアルゴリズムに興味があれば、こちらの記事も参照してください。

https://dev.classmethod.jp/articles/s3-new-checksum-algorithms-ec2-benchmark/

Athena でクエリを試す

Parquet 形式で出力しているため、Athena で CREATE EXTERNAL TABLE を実行すればそのままクエリできます。公式手順の Parquet 向けテンプレートをベースに、今回の OptionalFields(8 項目)に合わせて列を絞ったものが以下です。

インベントリレポートを Athena でクエリする手順全般は公式ドキュメントにまとまっています。

https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-inventory-athena-query.html

CREATE EXTERNAL TABLE express_inventory_report (
    bucket string,
    key string,
    size bigint,
    last_modified_date timestamp,
    e_tag string,
    storage_class string,
    is_multipart_uploaded boolean,
    encryption_status string,
    bucket_key_status string,
    checksum_algorithm string
) PARTITIONED BY (
    dt string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.SymlinkTextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat'
LOCATION 's3://devio-express-inv-dst-20260421/inventory/devio-express-inv-src--apne1-az4--x-s3/daily-full-report/hive/'
TBLPROPERTIES (
    "projection.enabled" = "true",
    "projection.dt.type" = "date",
    "projection.dt.format" = "yyyy-MM-dd-HH-mm",
    "projection.dt.range" = "2026-04-23-00-00,NOW",
    "projection.dt.interval" = "1",
    "projection.dt.interval.unit" = "HOURS"
);

テーブル作成後、マルチパートアップロードだけ絞り込むクエリを投げてみます。

SELECT key, size, last_modified_date
FROM express_inventory_report
WHERE dt = '2026-04-23-00-00'
  AND is_multipart_uploaded = true;

Athena クエリエディタで実行すると、マルチパート対象の large.bin だけが結果に返ってきました。

クエリエディタ___Athena___ap-northeast-1-2.png

さいごに

S3 Express One Zone が S3 インベントリに対応したことで、ディレクトリバケットの棚卸しが格段に楽になりました。とくに次のユースケースで役立つのではないでしょうか。

  • コンプライアンス棚卸し: 定期的なオブジェクト一覧を S3 に保持し、監査証跡とする
  • 暗号化状態の監査: EncryptionStatus / BucketKeyStatus で全オブジェクトの暗号化状況を確認する
  • ライフサイクル期限の可視化: LifecycleExpirationDate を OptionalFields に追加し、削除タイミングを事前に把握する(ライフサイクルルール未設定のバケットでは空欄)

参考

この記事をシェアする

関連記事