notebook

都内でWEB系エンジニアやってます。

S3のPresigned URLで直接アップロードするときのAccessDenied対応

S3へフロントからPresigned URLを使って直接アップロードする記事は色々出ているので参考にすればサクッとできるかなと思っていたが権限周りでつまずいた

今回はその備忘録

想定ケース

  • Presigned URLをRubyのサーバ側で生成
  • フロント側でPresigned URLの発行リクエスト
  • レスポンスの情報を使ってPresigned URLへファイルをアップロード

という流れ

ざっくり作ったサンプルコードで確認する

Presigned URL生成側(Ruby)

      id = SecureRandom.hex
      bucket = Aws::S3::Resource.new.bucket(ENV['AWS_BUCKET'])
      key = "hoge/#{id}.#{request.params['extension']}"
      expires = Time.now
      presigned_object = bucket.presigned_post(
        key: key,
        success_action_status: '201',
        acl: 'public-read',
        content_type: extensions[request.params['extension'].to_sym],
        expires: expires
      )
      { url: presigned_object.url, fields: presigned_object.fields }.to_json

コードは下記

s3-direct-upload-with-presigned-url/rack.ru at master · swfz/s3-direct-upload-with-presigned-url

フロント側のアップロード処理

  <script type="text/javascript">
  function upload() {
    const extension = document.querySelector("#image").value.split(".").slice(-1)[0];
    console.log(extension);
    // presigned_urlの発行
    fetch(`/presigned_post_url?extension=${extension}`)
      .then(res => res.json())
      .then(json => {
        console.log(json)
        const file = document.querySelector("#image").files[0];
        const formData = new FormData();

        for (const key in json.fields) {
          formData.append(key, json.fields[key])
        }
        formData.append('file', file);

        const headers = {
          'accept': 'multipart/form-data'
        };
        // アップロード
        fetch(json.url,{method: 'POST', headers, body: formData}).then((res) => {
          console.log('fetch');
          console.log(res);
        });
      });
  }
  </script>
  <body>
    <input type="file" name="sample" accept="image/png,image/jpeg,image/gif,video/mp4" id="image" onchange="upload()">
  </body>

コードは下記

s3-direct-upload-with-presigned-url/index.html at master · swfz/s3-direct-upload-with-presigned-url

こんなかんじで楽勝!と思ってたら全然うまくいかなかった

AccessDenied

この手のパターンがよくあるのかトラブルシューティング用のページが存在する

とりあえずはこの項目をチェックしていくのが近道なのではと思う

Amazon S3 から HTTP 403: Access Denied エラーをトラブルシューティングする

aws.amazon.com

このページにも存在したがPresigned URLを発行するユーザーのIAMにs3:PutObjectAclが必要

今回はそれで結構時間を使ってしまった

今回のサンプル

swfz/s3-direct-upload-with-presigned-url

github.com