【アップデート】S3でACLを無効化できるようになりました #reinvent

ちょっとACL捨ててくる
2021.12.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

re:Invent 2021 の期間中に登場した以下アップデートを紹介します。

どんなアップデート?

S3バケットに 『ACL無効』 の設定を付与できます。 この設定は新規バケット作成時にも設定可能、既存バケットに対しても追加で設定可能です。

img

何が嬉しいの?

ひとことで言うと

「ACLを捨てて、全部ポリシーで管理したいなああぁ…」 を叶えてくれます

詳しく

S3 は歴史あるサービスです。 当初は S3バケットに対するアクセス制御の手段は ACL のみでした。 S3バケットはデフォルトでプライベートです。 そのため 他アカウント(もしくはパブリック)からのアクセス許可は ACL で実現しました。

その後 IAM が提供されて、アクセス制御の手段として ポリシー(IAMユーザーポリシーやバケットポリシーなど) が追加されました。

つまり現在、 S3バケットに対するアクセス制御は ACL と ポリシーを両方考慮 する必要があります。

img

– 画像: アクセス管理の概要 - Amazon Simple Storage Service

これが結構大変です。 『ポリシーではパブリックにしていないけど、ACLでパブリック設定になっていた…』 ケース※ がよく出てきます。

さらにいうと、ポリシーのほうがより柔軟です。 ACLではできない粒度のアクセス制御を実現できます。

こういった背景から 「ACLを捨てて、全部ポリシーで管理したいなああぁ…」 と願う人たちが出てきました。 その願いを叶える機能が今回のアップデート 『ACL無効の設定』 です。

※『意図しない公開』を防ぐために パブリックアクセスブロック機能 も 2018年に追加されています。これも ACL の制限を行うために役立ちます。

仕組み

ひとことで言うと

オブジェクトオーナーシップ設定値BucketOwnerEnforced を定めることで、 全てのオブジェクトを 『バケットを所有しているアカウント』のもの とできます。

『詳しく』の前に

ここから先は ACL が前提知識となってきます。 もし『ACL ってそもそも何だっけ?』となっている方がいらっしゃったら、以下ブログを参照ください。

(『そもそも ACL を知る必要が無くなる、素晴らしいアップデート』という捉え方もできますね)

詳しく

もともと S3バケットに対して オブジェクトオーナーシップ設定 を付与できていました。 (この設定自体は比較的新しく、2020年に実装されています)

この設定はバケットにアップロードされたオブジェクトの所有権を制御するための設定です。 今までは以下 2つの設定値が選択できていました。

  • オブジェクトライター(ObjectWriter)
    • 従来どおりの挙動です
    • 『オブジェクトライター(アップロードしたアカウント)』がオブジェクト所有者となります
  • バケット所有者優先(BucketOwnerPreferred)
    • bucket-owner-full-control 既定ACLを指定した場合、 『バケットを所有しているアカウント』がオブジェクト所有者です
    • それ以外の場合、 『オブジェクトライター』がオブジェクト所有者です

img

※ 上図キャプチャ(2021/12/02時点)では『希望するバケット所有者』となっていますが、 正しい解釈としては『バケット所有者優先』だと思います

この設定値に BucketOwnerEnforced を新たに定められるようになりました。 これが今回のアップデートです

img

※前提として 『バケットACLはデフォルトである』必要があります。バケットACLを付与している状態ではこの設定は適用できません。

BucketOwnerEnforced を定めることで、 全てのオブジェクトは 『バケットを所有しているアカウント』 のものとなります。

今までは ACL次第で オブジェクトの所有者を他アカウントにすることができていました。 BucketOwnerEnforced によって、それができなくなります。

つまり ACLによるアクセス制御(例えば他アカウントに意図せず公開されてないか) を意識する必要がなくなります。 これによって、バケットとオブジェクトへのアクセス制御を ポリシー(IAMユーザーポリシーやバケットポリシーなど)で集中管理 できます。

試してみる

試したこと

img

3つのバケット(図の右側)を作成します。 それぞれオーナーシップの設定を ObjectWriter, BucketOwnerPreferred, BucketOwnerEnforced としています。

そしてそれぞれのバケットに対して 2つの操作(操作1, 操作2) でオブジェクトをアップロードします。

  • 操作1: ACLはデフォルトの設定でオブジェクトアップロード
  • 操作2: ACLは bucket-owner-full-control の設定でオブジェクトアップロード

『それぞれのバケット』にある『それぞれのオブジェクト』の ACL上の所有者を確認します。

結果

以下のような結果になりました。

オブジェクト(操作1) オブジェクト(操作2)
S3バケット#1(ObjectWriter) Writer 所有 Writer と Owner 所有
S3バケット#2(BucketOwnerPreferred) Writer 所有 Owner 所有
S3バケット#3(BucketOwnerEnforced) Owner 所有 Owner 所有

今回アップデートで追加された設定値 BucketOwnerEnforced の結果から、 『特別なACLを付ける/付けない』に関わらず 他アカウントからアップロードされたオブジェクトは 全て バケットのオーナー所有になる ことを再確認できました。

おわりに

以上、S3アクセス制御周りの新機能の紹介でした。 これから新規に作成するS3バケットには必ず設定したい機能だと感じました。

既存バケットにも適用できますがワークロードへの影響を考慮しましょう。 事前に ACL は使わずに ポリシーで運用できていることを確認した上で、 移行すると良いと思います。

参考

補足

ライターアカウントから『オーナーアカウントのS3バケット』へアクセスするために設定したバケットポリシー

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Statement1",
      "Principal": {"AWS": "${ライターアカウントのAWSアカウントID}"},
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::${バケット名}/*"
    }
  ]
}

操作1(ACLはデフォルトでオブジェクトアップロード)のコマンド

profile_writer="${ライターアカウントのプロファイル}"
bucket="${オーナーアカウントにあるバケット}"
file_path="./test.txt"
key="test-from-write-account-default.txt"

aws s3api put-object --profile "${profile_writer}" --output yaml \
  --bucket "${bucket}" --key "${key}" --body "${file_path}"

操作2(ACLは bucket-owner-full-control でオブジェクトアップロード)のコマンド

profile_writer="${ライターアカウントのプロファイル}"
bucket="${オーナーアカウントにあるバケット}"
file_path="./test.txt"
key="test-from-write-account-with-acl.txt"

aws s3api put-object --profile "${profile_writer}" --output yaml \
  --bucket "${bucket}" --key "${key}" --body "${file_path}" \
  --acl bucket-owner-full-control

結果の確認コマンド

profile_writer="${ライターアカウントのプロファイル}"
profile_owner="${オーナーアカウントのプロファイル}"
bucket="${オーナーアカウントにあるバケット}"

key="test-from-write-account-default.txt"
# key="test-from-write-account-with-acl.txt"

# オーナーアカウントからオブジェクトの ACL設定をチェック
echo "## check from bucket owner account"

aws s3api get-object-acl --profile "${profile_owner}" --output yaml \
--bucket "${bucket}" --key "${key}"

# ライターアカウントからオブジェクトの ACL設定をチェック
echo "## check from object writer account"

aws s3api get-object-acl --profile "${profile_writer}" --output yaml \
--bucket "${bucket}" --key "${key}"