laravel8からs3へ画像アップロードしてみる。署名付きURL(期限付きURL)を生成して、S3に一時的に読み取り可能にする。

laravel8からs3へ画像アップロードしてみる。署名付きURL(期限付きURL)を生成して、S3に一時的に読み取り可能にする。

参考URL
https://qiita.com/nobu0717/items/51dfcecda90d3c5958b8

前回つくったのを改造する

laravel8で画像掲示板を作ってみる。

やる事リスト
1, S3へのIAMユーザ作成
2, S3バケット作成
3, S3ポリシー設定(IAMユーザの許可)
4, laravelの.envに、IAMユーザのアクセスキーID・シークレットアクセスキー・S3バケット名を設定する。
5, 署名付きURL(期限付きURL)を生成して、非公開S3にアップロードしたファイルを一時的に読み取り可能にする

1, IAMで、s3アクセス権限のあるユーザを作成(このユーザのアクセスキーを使ってlaravelから操作する)
1-a, s3_fullaccess_userとか適当なユーザ名にして、プログラムによるアクセスにチェック
1-b, AmazonS3FullAccessポリシーを付与
1-c, このユーザのアクセスキーIDとシークレットアクセスキーは、この時にしか取得できないので、CSVダウンロードしておく(もしくはどこかにメモしておく)
1-d, IAMユーザの管理画面から、s3_fullaccess_userの認証情報タブのコンソールのパスワードの管理リンクをクリック。有効化するとパスワードを取得できる。
1-e, 一旦ログアウトして、AmazonS3FullAccessと取得したパスワードでログインできるか確認する。

2, S3バケット作成
2-a, バケット名は全世界でユニークだから、image-uploader-英数乱数 みたいな感じで、乱数のプレフィックかサーフィックスを付与して作成する
2-b, すべてブロックしちゃうとlaravelからアクセスできないので、最初の2つはオフにする
新しいアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
任意のアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
2-c, バケット作成ボタンを押して完了

3, S3パケットポリシーで、s3_fullaccess_userをアスセス許可する
3-a, s3_fullaccess_userユーザーのARN(Amazon Resource Name)をIAM管理画面から取得
3-b, s3バケット(image-uploader-英数乱数)を開いて、プロパティタブからS3バケットのARNを取得
3-c,アクセス許可タブからパケットポリシーの編集ボタンを押す
3-d, 「ポリシージェネレータ」ボタンを押して、以下の値に設定。
「Select Type of Policy」: S3 Bucket Policy
「Effect」: Allow
「Principal」: コピーしたユーザのARN
「AWS Service」: Amazon S3
「Actions」:All Actions(‘*’)
「Amazon Resource Name(ARN)」:コピーしたバケットのARN
3-e, 「Add Statement」ボタンを押してから「Generate Policy」ボタンを押す。ポリシーのテキストが表示されるのでコピー
3-f, 元画面のパケットポリシーを編集のテキストエリアにコピペ。変更の保存ボタンを押してポリシー設定完了

4, laravelの.envに、IAMユーザのアクセスキーID・シークレットアクセスキー・S3バケット名を設定する。
AWS_ACCESS_KEY_ID= csvの認証情報に記載されているAccess key ID
AWS_SECRET_ACCESS_KEY= csvの認証情報に記載されているSecret access key
AWS_DEFAULT_REGION=ap-northeast-1 (リージョンをアジアパシフィック東京で作成したため)
AWS_BUCKET= 作成したバケット名

5, laravelからs3にアクセスするパッケージをcomposerでインストール

最初にlaravel用のawsパッケージをインストールする。
composer.jsonに追加して、composer updateする

S3のパッケージをインストールする

6, /config/filesystems.phpを編集 laravel8では不要だった。

7, 画像ファイルのアップロード先をWebサーバからS3に変更する。
app/Http/Controllers/ImageController.phpを修正

8, アップロードされた画像一覧を表示する部分を、S3のURLにする。
resources/views/image/index.blade.php

※ただし、S3ポリシーの問題で、ブラウザからS3オブジェクト(画像ファイル)へのURLを記述してもAccessDenyされる(画像が表示されない)
S3にアップロードされたファイルを、ネットに全公開する設定なら、ここまででOK。

9, 署名付きURL(期限付きURL)を生成して、非公開S3にアップロードしたファイルを一時的に読み取り可能にする。

S3は非公開がデフォなので、単純にアップロードしてもURLへアクセスできない。
なので、ただのURLではなく署名付きURL(期限付きURL)を生成してviewに渡す。

9-a, S3にアップロードした時に、URLではなく、S3キー(ファイルパス)をDBに保存するように変更
app/Http/Controllers/ImageController.phpを修正

9-b, S3キー(ファイルパス)から、期限付きURLを取得する

ブラウザの見た目は、何も変わってないけど、S3に保存できるようになった。
非公開S3から画像ファイルを取得するのに、署名付きURL(期限付きURL)を使ったのが、意外とサンプルがなくて苦労した。
ドットインストールの動画とかも、この方法で実装しているっぽい。
有効期限1分でもリロードすれば再発行されるので、問題ないはず…。と思ったけど、クリックして別タブで表示する時に有効期限が切れている可能性があるな…。
ログインのタイムアウトと同じにすべき?