【Laravel】Amazon S3へのアップロードが「403 Access Denied」で失敗する原因と対処方法

はじめに

LaravelでAmazon S3へ画像アップロードする処理を実装し、いざアップロードしようとしたところ、以下のエラーが出て失敗しました。

Error executing "PutObject" on "https://minna-no-houteishiki.s3.ap-northeast-1.amazonaws.com/r1oJ01mYWVeol0m7jUTji7uef5lyG7MATNOqzl1A.png"; AWS HTTP error: Client error: `PUT https://minna-no-houteishiki.s3.ap-northeast-1.amazonaws.com/r1oJ01mYWVeol0m7jUTji7uef5lyG7MATNOqzl1A.png` resulted in a `403 Forbidden` response:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>ABBC2D (truncated...)
AccessDenied (client): Access Denied - <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>ABBC2D1C8E07A319</RequestId><HostId>ZvHZ5rneZGsSstZLX2jIoixQFaaFnRxFdtoiNE1Hd+0n17a09y4JKDckdlYsZOC/nMhiQuBb3fA=</HostId></Error>

PutObjectというコマンドを実行したところ、アクセスが拒否されてしまったようです。

原因

S3のバケットにパブリックアクセス設定機能が設定されているためです。パブリックアクセス設定機能とは、バケット内のファイルをパブリックアクセスできないようにする設定のことです。

Amazon S3のセキュリティについては、以下の記事が大変よくまとまっているため参照してください。

S3で誤ったデータの公開を防ぐパブリックアクセス設定機能が追加されました | Developers.IO

つまり、Amazon S3にパブリックアクセス設定機能が追加されたことにより、デフォルトでパブリックアクセスができなくなったということです。

ちなみに、Laravelの実装は以下のようになっています。

$image = $request->file('image');
$path = Storage::disk('s3')->put('/', $image, 'public');
$post->image = Storage::disk('s3')->url($path);

putメソッドの第3引数にpublicを指定しており、ファイルをパブリックファイルとしてアップロードしようとしています。publicを指定せずにアップロードしても、アップロードはできても参照ができないため、意味がありません。

対処方法

AWS管理コンソールにサインインし、Amazon S3のバケット管理画面にアクセスします。

パブリックアクセス設定機能を以下のように変更します。

  • パブリックアクセスをすべてブロック:オフ
    • 新しいアクセスコントロールリスト (ACL) を介して許可されたバケットとオブジェクトへのパブリックアクセスをブロックする:オフ
    • 任意のアクセスコントロールリスト (ACL) を介して許可されたバケットとオブジェクトへのパブリックアクセスをブロックする:オフ
    • 新規のパブリックバケットポリシーまたはアクセスポイントポリシーを介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする:オン
    • 任意のパブリックバケットポリシーまたはアクセスポイントポリシーを介したバケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする:オン

正直、日本語がわかりにくいのでどれをオフにしたらいいかよくわかりません…😅

パブリックアクセス設定機能はセキュリティを高める設定のため、オフにするのは最小限にとどめたほうがいいです。

私の場合は上記のような設定でアップロードできるようになりました。

まとめ

LaravelでAmazon S3へアップロードする方法を解説している記事はたくさんありますが、いずれもAWSのセキュリティ設定が変更される前の記事のため、手順通り設定しているのにアップロードできないという事態に陥ることが多いと思います。

Amazon S3へのアップロードができないという人は参考にしていただければと思います。

関連記事

開発環境(ローカルストレージ)と本番環境(Amazon S3)にトリミング+リサイズした画像を保存する方法
# はじめに 以前、以下の記事を書きました。 - [開発環境と本番環境で画像のアップロード先を分岐する方法 \- AUTOVICE](https://www.autovice.jp/articles/68) - [ローカルやAmazon [...]
2020年3月7日 11:56
Laravel Mixの仕組みをわかりやすく解説:CSSをSASS/SCSSで記述する方法
# はじめに Laravel Mixの仕組みをわかりやすく解説します。Laravel Mixを使ってアセットコンパイルを行うことで、SASS/SCSSでCSSを記述できるようになります。 # Laravel Mixの仕組み まずはじめに、 [...]
2020年3月6日 9:25
【Laravel 6.x】Laravelプロジェクトの名称を変更する方法
# はじめに あまりないケースではありますが、一度作成したLaravelプロジェクトの名称を変更する方法を解説します。ここで言うLaravelプロジェクトの名称とは、以下のコマンドの`Sample`のことを指します。 ```terminal [...]
2020年3月4日 16:24
【Laravel】ローカルディスクやAmazon S3にアップロードした画像をビューで表示する方法
# はじめに 本記事では、ローカルディスクやAmazon S3にアップロードした画像をビューで表示する方法について説明しています。 なお、本記事では画像のアップロードする方法については説明していません。本記事は既に実装済みの画像アップロード [...]
2020年3月4日 15:44
開発環境と本番環境で画像のアップロード先を分岐する方法
# はじめに この記事では、以下の方針で画像のアップロード先を分岐する方法について解説しています。 - 開発環境:ローカル(storage/app/public/) - 本番環境:Amazon S3 # 事前準備 AWSに未登録の [...]
2020年3月4日 12:52
独自ポリシーの導入手順と注意点(ハマリポイント)を解説
# はじめに ユーザーと記事を関連付けておいて、編集や削除は記事の作成者のみ許可したいときにはポリシーを作成します。今回はポリシーの導入手順と注意点(ハマリポイント)を解説します。 # 導入手順 ## ポリシー作成 ターミナルで以下 [...]
2020年3月1日 10:32
ユーザー認証機能の導入手順と生成されたフォームを日本語化する方法を解説
# はじめに Laravelではユーザー認証機能の導入が簡単にできてしまいます。この記事ではLaravelプロジェクトにユーザー認証機能を追加する手順と、生成されたフォーム(デフォルトでは英語)を日本語化する方法を解説します。 # 前提 [...]
2020年2月29日 13:54
【Laravel 6.x】ネスト構造になっているRESTfulルーティングの定義方法
# はじめに RESTfulルーティングを定義するときは`Route::resource`を使いますが、ネスト構造になっているRESTfulルーティングの定義方法を調べたので記事にします。 # 前提 おそらく、Laravel 6.xのみ対 [...]
2020年2月28日 20:06