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 test-glonavi-s3-01 --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 の利用方法は、下記の記事を参照ください。

AWS, S3

Posted by takaaki