ようへいの日々精進XP

よかろうもん

(やらかした) aws s3api copy-object したら、権限のことを忘れてしまって (略

これは

やらかしの記録であります。今後、自分が同じ過ちを繰り返さないよう、公開出来る範囲で記事にしたいと思います。

何が起きたか

S3 バケット上で意図的に Public Read 権限を付与して公開しているオブジェクトのメタデータ (content-type) をカジュアルに変更した後、オブジェクトにアクセスしたら HTTP ステータスコード 403 (Forbidden) を返すようになった結果、サイト上の画像の一部が表示されない状態を発生させてしまいました orz

オブジェクトのメタデータは、以下のように AWS CLI で一括変更しました。

aws s3api copy-object \
  --bucket $BUCKET_NAME \
  --copy-source $BUCKET_NAME/$KEY \
  --key $KEY \
  --metadata-directive "REPLACE" \
  --content-type "image/png" | jq -r .CopyObjectResult.LastModified

何が原因だったか

AWS CLIメタデータを変更する際、aws s3api の copy-object を利用するしかないようなのですが、この copy-object はソースオブジェクトをコピーはするものの、権限まではコピーしてくれないようです。

例えば、以下のように、my-sandbox バケットの sample.txt オブジェクトには Public Read 権限が付与されています。

$ aws s3api get-object-acl --bucket=my-sandbox --key=sample.txt
{
    "Owner": {
        "DisplayName": "test-user",
        "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    },
    "Grants": [
        {
            "Grantee": {
                "DisplayName": "test-user",
                "ID": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
                "Type": "CanonicalUser"
            },
            "Permission": "FULL_CONTROL"
        },
        {
            "Grantee": {
                "Type": "Group",
                "URI": "http://acs.amazonaws.com/groups/global/AllUsers"
            },
            "Permission": "READ"
        }
    ]
}

sample.txt を copy-object してみます。

$ aws s3api copy-object \
  --bucket my-sandbox \
  --copy-source my-sandbox/sample.txt \
  --key sample.txt \
  --metadata-directive "REPLACE" \
  --content-type "text/plain""

copy-object では content-type を付与しています。そして、権限を確認してみましょう。

$ aws s3api get-object-acl --bucket=inokara-sandbox --key=sample.txt
{
    "Owner": {
        "DisplayName": "test-user",
        "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    },
    "Grants": [
        {
            "Grantee": {
                "DisplayName": "test-user",
                "ID": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
                "Type": "CanonicalUser"
            },
            "Permission": "FULL_CONTROL"
        }
    ]
}

うおー、見事に public-read 権限が無くなっていますね。copy-object は権限まではコピーしてくれないようです。

ドキュメントにもはっきりと書かれております。

docs.aws.amazon.com

When copying an object, you can preserve all metadata (default) or specify new metadata. However, the ACL is not preserved and is set to private for the user making the request. To override the default ACL setting, specify a new ACL when generating a copy request. For more information, see Using ACLs .

そもそも

S3 上のオブジェクトを Public Read 権限で付与して公開してしまっている構成がイケていないのでは...と突っ込まれても仕方ないと思いますが、歴史的な経緯で、泣く泣く Public Read 権限を付与しておりました。本来であれば、CloudFront を挟んで OAI 設定が定石なのかもしれません。

ということで

今回、以下のような知見を得ました。

  • オブジェクトのメタデータを更新したい場合には aws s3api copy-object 一択
  • コピーしたオブジェクトの ACL はコピーされないので注意が必要

ご迷惑をおかけしてしまい申し訳ございませんでした。そして、ドキュメントをしっかりと読みましょう。