[アップデート] その S3 バケット、本当に意図したアカウントのものですか? S3 API 実行時にバケット所有者を検証する条件を追加できるようになりました!

これだけで万事OK、とはなりませんが、リスク回避の選択肢が増えたのは嬉しいですね。

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

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

S3 API 実行時に、バケットの所有者を検証する条件を含めることができるようになりました!

バケットポリシーや IAM ポリシーで権限制御を行うのとはまたの別のアプローチで、意図せぬ対象に API を実行しないようにするための予防策が取れるようになりました。

目次

何が変わったのか

API 実行時に、バケット所有者の検証を行うパラメータを含めることができるようになりました。

例えば AWS CLI であれば、以下のようなオプションが追加されています。

  • --expected-bucket-owner(多くの aws s3api コマンド)
  • --expected-source-bucket-owner(aws s3api copy-object など)

一般的に、 API 実行時に対象となるバケットを指定する際には、バケット名のみを指定することになります。ARN にアカウント番号が含まれないこともあり、取り違えにより意図せぬ対象を指定しまうリスクが存在します。

API 実行元の IAM エンティティの IAM ポリシーや、実行先の S3 バケットのバケットポリシー・ACL での許可を最小化することでもリスクを抑えられます。それに加えて、新たなレイヤーでの防御策を提供してくれるのが今回のアップデートの内容です。

想定されるケース

例えばドキュメントで例示されているのは以下のようなケースです。

S3 を使用するアプリケーションを開発しており、開発環境においては専用の S3 バケットを使用していました。

アプリケーションを本番適用する際に使用するバケットの向き先を変更するのを忘れ、本番環境で使用する情報が開発環境のバケットに書き込まれてしまった、という事象がありました。

ここで、アプリケーションによる API 実行の条件として環境に応じたアカウント番号を指定するようにしておけば、意図せぬ対象へのアクションを行うリスクを減らせるというものです。

でも所有者条件もアプリケーションに埋め込んでいたら同じだよね?

上記の例を見た際に、「所有者条件を指定する部分もアプリケーションに埋め込んでいたら同じことじゃないか?」と疑問が生じました。イメージとしては以下です。

なので、ここで想定されているのは、所有者条件の指定は別出しされていて、実行時に手動で指定するようなケースかと捉えました。

もしくは、アプリケーションの実行を行うアカウントがそれぞれ分かれている前提で、変数を用いて「自身が所属するアカウント」を所有者条件を指定するようなこともできますね。

いずれにしても、アプリケーションが使用する IAM や各環境の S3 のバケットポリシーを適切に設定していれば防げる事象ではありますが、API 実行時の条件、という新たなレイヤーでの防御策が加わったことで、より柔軟にリスクを減らせるようになりました。

適切に組み合わせて使っていきましょう。

考慮事項

  • 指定できるのは 12桁のアカウント番号のみであり、カノニカル ID などは指定できません
  • 以下の S3 API には対応していません
  • パラメータで指定したアカウントがバケットを所有しているかどうかの検証のみ行います
    • バケットの設定状態は確認しません
    • 過去の状態と一致していることを保証するものではありません

やってみた

今回は以下のようなケースで、やってみます。

  • クロスアカウントで aws s3api copy-objectを実行する
  • 送信元バケットが存在するのはアカウントxxxxxxxxxxxx
    • AWS CLI を実行するのは AdministratorAccess を持つ IAM ユーザー
  • 宛先バケットが存在するのはアカウントyyyyyyyyyyyy
    • 宛先バケットのバケットポリシーでクロスアカウントを許可している

宛先バケットのバケットポリシーの内訳は以下です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::xxxxxxxxxxxx:root"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::chiba-dest-20200913",
                "arn:aws:s3:::chiba-dest-20200913/*"
            ]
        }
    ]
}

AWS CLI のバージョンは最新のものにアップデートしました。

% aws --version
aws-cli/2.0.48 Python/3.7.4 Darwin/19.6.0 exe/x86_64

条件を指定しないで実行

まずは条件を指定しないで実行します。クロスアカウントでの S3 API 実行に必要な条件が設定済みのため、問題なく成功します。

% aws s3api copy-object --copy-source chiba-source-20200913/test.text \
                            --bucket chiba-dest-20200913 --key test.text_copy \
                            --acl bucket-owner-full-control
{
    "CopyObjectResult": {
        "ETag": "\"b1946ac92492d2347c6235b4d2611184\"",
        "LastModified": "2020-09-13T12:07:00+00:00"
    }
}

ソースバケットの条件を満たさないで実行

オプション--expected-source-bucket-ownerで存在しないアカウント(ドキュメントのサンプルに載っているもの)を指定して実行したところ、エラーが発生します。

% aws s3api copy-object --copy-source chiba-source-20200913/test.text \
                            --bucket chiba-dest-20200913 --key test.text_copy1 \
                            --acl bucket-owner-full-control \
                            --expected-source-bucket-owner 111122223333

An error occurred (AccessDenied) when calling the CopyObject operation: Access Denied

バケット所有者条件を満たさないためにエラーが発生した、とは読み取れないメッセージなのはちょっと残念ですね。(バケットポリシーや IAM ポリシーで拒否されている場合にも同じメッセージが出る)

宛先バケットの条件を満たさないで実行

オプション--expected-bucket-ownerでも同じようにダミーのアカウントを指定して実行してみました。結果は、エラーメッセージも含めて同じですね。

% aws s3api copy-object --copy-source chiba-source-20200913/test.text \
                            --bucket chiba-dest-20200913 --key test.text_copy2 \
                            --acl bucket-owner-full-control \
                            --expected-bucket-owner 444455556666

An error occurred (AccessDenied) when calling the CopyObject operation: Access Denied

条件を満たす形で実行

ソースバケット、宛先バケット共に適切な値を指定して実行したところ、問題なくオペレーションが成功しました。

% aws s3api copy-object --copy-source chiba-source-20200913/test.text \
                            --bucket chiba-dest-20200913 --key test.text_copy3 \
                            --acl bucket-owner-full-control \
                            --expected-source-bucket-owner xxxxxxxxxxxx \
                            --expected-bucket-owner yyyyyyyyyyyy
{
    "CopyObjectResult": {
        "ETag": "\"b1946ac92492d2347c6235b4d2611184\"",
        "LastModified": "2020-09-13T12:11:01+00:00"
    }
}

明示的に指定することで、意図しないアカウントのバケットに対する誤操作を抑止することができますね。

これで所有者バケット条件の挙動について確認できました!

終わりに

S3 の新たな条件、バケット所有者条件について確認しました。

実行する S3 API が条件指定に対応していて、かつ実行先の S3 バケットの所有アカウントを把握しているのであれば、常にこの条件を使用することを勧める、とドキュメントには記載があります。

誤操作によるリスクを回避する手段が増えたのは嬉しいですね。そもそもの権限を最小化する、という大前提を踏まえつつ、新たな手法を積極的に活用していきましょう。

以上、千葉(幸)がお送りしました。