S3からのファイルコピーでHTTP 403が表示されたとき
概要
はじめに
- 今回は、S3バケットからクロスアカウントでファイルをコピーする際に、HTTP 403のエラーが発生した事例をご紹介します。
症状
- 1つの案件の中に、システム毎にアカウント:A、アカウント:B、アカウント:C、アカウント:Dの環境があるとします。各アカウントにはCloudWatch Logs にログを集めており、定期的にS3バケットへログをエクスポートしています。
- アカウント:A のEC2から各アカウントB~Dに対して、AWS CLI を使用してファイルをコピーしたところ下記のHTTP 403 エラーが出力されました。バケット内のオブジェクトをlistすることはできたためコピーも成功すると思ったのですが、どうやらアクセス拒否されている様子…。
- fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
- 以下、AWS CLIで実行したコマンドと出力されたエラーです。
C:\Users\niikawa\Desktop>aws s3 cp s3://bucket-name/exportedlogs/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/000000.gz .
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
S3のクロスアカウントコピー
- 先ず、他のAWSアカウントからS3オブジェクトをコピーする場合に、S3のバケットポリシーの変更やIAMのポリシー追加が必要となります。他アカウントからのS3アクセスを許可する方法は、下記記事を参照ください。
- しかし‼、今回は他アカウントからのアクセスを許可するため、S3のバケットポリシーの変更、IAMのポリシー追加を実施していますが、HTTP 403 エラーが発生しました。どうやら正常にコピーできるオブジェクトもあり、特定のオブジェクトのみHTTP 403 エラーが起きることが分かりました。
原因、"logs+prod-nrt"は誰?
- 原因はオブジェクトの所有者にあります。
- 通常、アカウント内のEC2やLambdaからS3バケットへアップロードされたオブジェクトは、S3バケットの所有者であるアカウントのrootがオブジェクトの所有者となります。また、クロスアカウントが許可された環境であれば、他アカウントからS3バケットへアップロードされたオブジェクトは、アップロードした他アカウントがオブジェクトの所有者となります。
- 今回コピーしたいオブジェクトは、CloudWatch Logs から定期的にエクスポートされたログであり、CloudWatch Logs からエクスポートされた場合のオブジェクト所有者は、“logs+prod-nrt" となることが分かりました。そのためオブジェクト所有者がバケットの所有者と異なり、各アカウント内からはCloudWatch Logs からエクスポートされたオブジェクトにアクセスできますが、クロスアカウントを許可した他アカウントからのアクセスがエラーとなりました。
- AWS CLI は、下記aws s3api list-objects-v2 コマンドを使い、オブジェクトの所有者を確認します。Ownerが“logs+prod-nrt"になっていることが分かると思います。
C:\Users\niikawa\Desktop> aws s3api list-objects-v2 --fetch-owner --bucket bucket-name --prefix exportedlogs/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
{
"Contents": [
{
"Key": "exportedlogs/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/000000.gz",
"LastModified": "2019-11-27T16:42:57.000Z",
"ETag": "\"88888888888888888888888888888888\"",
"Size": 362,
"StorageClass": "STANDARD",
"Owner": {
"DisplayName": "logs+prod-nrt",
"ID": "9999999999999999999999999999999999999999999999999999999999999999"
}
}
]
}
対処方法
Assume Roleを利用する
- aws s3api put-object-aclコマンドも利用できますが、recursiveオプションがないなど、まだいくつもハマるポイントがありそうですので、ここはAssume Role を使って、アクセスを許可を委任する方法を取ります。
- 例えば、各アカウントB~DでS3バケットをアクセスできるポリシーを作成し、アカウントAにアクセスを許可するロールを作成します。アカウントAのEC2からAssume Roleを利用して、アカウントB~Dのロールを委任してもらい、各S3バケットのオブジェクトにアクセスします。
- Assume Role の利用方法は、下記の記事を参照ください。
S3にバケット所有者としてオブジェクトをUpload する (2021/1/11更新)
- 2020年10月の Amazon S3 Updateの機能追加によって、S3バケットの"Object ownership" 設定がカスタマイズできるようになっております。
- この"Object ownership" 設定を変更することで、オブジェクトの所有者を“logs+prod-nrt" ではなく、バケット所有者としてログエクスポートが可能となりました!
- 詳細は、下記の記事を参照ください。