S3にアップした画像が「403 (Forbidden)」エラーで表示されない


目的

LaravelでS3にアップした画像をサイトで表示する。

画像アップ処理

パッケージをComposerでインストール

"aws/aws-sdk-php": "~3.0",
"league/flysystem-aws-s3-v3": "~1.0",

パフォーマンスを上げるため、絶対に必要なのはキャッシュアダプタ
"league/flysystem-cached-adapter": "~1.0",

S3ドライバ設定

S3ドライバの設定情報は、config/filesystems.php設定ファイルに設定

// Default Filesystem Disk
'default' => env('FILESYSTEM_DRIVER', 'local'),

// Default Cloud Filesystem Disk
'cloud' => env('FILESYSTEM_CLOUD', 's3'),

// Filesystem Disks
'disks' => [

    'local' => [
        'driver' => 'local',
        'root' => storage_path('app'),
    ],

    'public' => [
        'driver' => 'local',
        'root' => storage_path('app/public'),
        'url' => env('APP_URL') . '/storage',
        'visibility' => 'public',
    ],

    's3' => [
        'driver' => 's3',
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION'),
        'bucket' => env('AWS_BUCKET'),
        'url' => env('AWS_URL'),
    ],
]

envファイル

AWS_ACCESS_KEY_ID=アクセスキーID
AWS_SECRET_ACCESS_KEY=シークレットアクセスキー
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=バケット名
AWS_URL=https://s3-ap-northeast-1.amazonaws.com/バケット名/
FILESYSTEM_DRIVER=s3

LaravelのController

// ディスクインスタンス取得
use Illuminate\Support\Facades\Storage;

// 画像アップロード
保存したいファイルのパスを指定し、storeメソッドでアップロード
$path = request()->file('file')->store('tmp');
アップロードした画像を一時領域('tmp')に保存

// urlメソッドを使い、指定したファイルのURLを取得
'url' => Storage::url($path),
s3ドライバを使用している場合、完全なリモートURLを返す

その他ファイル関連メソッド

// ファイル取得
$contents = Storage::get('file.jpg');

// ファイルが存在しているかを判定
$exists = Storage::disk('s3')->exists('file.jpg');

// ファイルのダウンロード
return Storage::download('file.jpg', $name, $headers);

画像表示

下記のURLで画像表示

img src="https://app-develop.s3.ap-northeast-1.amazonaws.com/Image/H5o2hmClZdGfH5s0d8DNxlkZs6Y8L1xUL0.jpeg

バケット名(app-develop )
Amazon リソースネーム (ARN) (arn:aws:s3:::app-develop)

画像表示で「403 (Forbidden)」エラーで表示されない
原因はバケットポリシーが公開状態になってない為

バケットポリシー公開設定

下記のPolicy Generatorを使用し、jsonフォーマットのポリシー定義を記述する
http://awspolicygen.s3.amazonaws.com/policygen.html

入力内容は下記である

・Principal : *
特定のアカウントに対して参照可能にする場合は下記:
・Principal : 権限付与するAWSアカウントID

・AWS Service: Amazon S3

・Actions: s3:GetObject

・ARN:  arn:aws:s3:::app-develop/*

とし、Add Statementを押下。続けて

・Principal : *
特定のアカウントに対して参照可能にする場合は下記:
・Principal : 権限付与するAWSアカウントID

・AWS Service: Amazon S3

・Actions: s3:ListBucket

・ARN:  arn:aws:s3:::app-develop

Statementが2つあるのは、GetObjectはバケット配下のオブジェクトに対する定義であり、ListBucketはバケットそのものに対する定義となるため

{
  "Id": "Policy1604544585920",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1604544465312",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::app-develop/*",
      "Principal": "*"
    },
    {
      "Sid": "Stmt1604544535477",
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::app-develop",
      "Principal": "*"
    }
  ]
}

Generate Policyを押下すると、ポリシー定義したjson記述が表示されるのでコピーする。

S3の画面にて、バケットのプロパティを表示し Permissions-> Edit bucket policyで上記jsonを貼り付けて saveする

画像表示確認

下記のURLで画像確認

img src="https://app-develop.s3.ap-northeast-1.amazonaws.com/Image/H5o2hmClZdGfH5s0d8DNxlkZs6Y8L1xUL0.jpeg

エラーなく無事画像表示される〜〜