Laravel の Storage で disk として S3 を指定したときに deleteDirectory できない
LaravelにはStorageというファサードがあり、ローカルだろうがS3だろうが簡単ファイル操作を簡単に行うことができ、とても便利です。
例えば、localにファイルを設置したい場合は、
Storage::disk('local')->putFile('', $file);
などとすることができ、localの特定のディレクトリを丸々削除したい場合は、
Storage::disk('local')->deleteDirectory('target_dir');
と書けます。
上記はlocalでしたが、S3を対象にしたい場合には、
Storage::disk('s3')->putFile('', $file); Storage::disk('s3')->deleteDirectory('target_dir');
と local
→ s3
にするだけで良いです。
もちろん、S3上の操作なので、S3側で権限の設定は必要です。
putFile
のために s3:PutObject
の権限が必要だということは感覚的にわかりますが、 deleteDirectory
のためにはどんな権限が必要なのでしょう?
deleteに関することなので s3:DeleteObject
のような気がするのですが、これで実行すると、以下のようなエラーが発生します。
Error executing "ListObjects" on "https://〜〜"; AWS HTTP error: Client error: `GET https://〜` resulted in a `403 Forbidden` response: <?xml version="1.0" encoding="UTF-8"?> <Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>〜 (truncated...) AccessDenied (client): Access Denied - <?xml version="1.0" encoding="UTF-8"?> <Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>〜</RequestId><HostId>〜</HostId></Error>
正解は、対象バケットに対して s3:ListBucket
の権限が必要です。
deleteDirectory
の内部では、S3ClientInterface::deleteMatchingObjectsAsync() が呼ばれており、そこで ListObjects
らしきことが行われています。
S3には s3:ListObjects
といった権限がなく、結局どうすれば良いかわからなかったのですが、PHPもLaravelも関係ない、以下の記事に助けられました。
dev.classmethod.jp
まとめ。
Laravel の Storage(S3) で deleteDirectory する場合には、 S3 の対象バケットの s3:ListBucket
の権限が必要。