carrierwaveとfog-awsを使用してファイルをアップロードしようとしたところ以下のエラーが発生しました。
Excon::Error::Forbidden: Expected(200) <=> Actual(403 Forbidden)
このエラーの原因と対処法を整理しましたので同様のことでお悩みの方はぜひ参考にしてみてください。
エラーの原因
AWS S3のバケットには「ブロックパブリックアクセス」について設定する項目があります。 ブロックパブリックアクセスとは、リソースへのアクセスについてセキュリティ高めることができる設定です。 説明すると長くなるので、この記事では説明は省略します。
ブロックパブリックアクセスについてはこのの記事が参考になると思います。 aws s3のパブリックアクセスについてまとめる - Qiita
デフォルトではブロックパブリックアクセスは全てオンになっています。
ブロックパブリックアクセスが全てオンなのにも関わらず、carrierwave.rbにはfog_public = true
が設定されています。
fog_publicとはリソースを公開する場合はtrue、公開しない場合はfalseを設定します。(デフォルトはtrueが設定されます)
S3バケットのブロックパブリックアクセスとcarrierwaveの設定内容が矛盾しているためエラーが発生しています。
require 'carrierwave/storage/abstract' require 'carrierwave/storage/file' require 'carrierwave/storage/fog' CarrierWave.configure do |config| config.storage :fog config.fog_provider = 'fog/aws' config.fog_directory = ENV['S3_BUDGET_NAME'] # アップロードしたリソースを公開する場合はtrue config.fog_public = true config.fog_credentials = { provider: 'AWS', aws_access_key_id: ENV['S3_BUDGET_ACCESS_KEY'], aws_secret_access_key: ENV['S3_BUDGET_SECRET_ACCESS_KEY'], region: 'ap-northeast-1', path_style: true } end
対処方法
対処方法は2つあります。いずれかの方法を採ると良いでしょう。
fog_public = falseにする
fog_public = false
にすることで、リソースを非公開状態でアップロードできます。
ブロックパブリックアクセスは有効なままですのでバケット内のセキュリティが保たれます。
デメリットとしては、S3上のリソースをブラウザ等からURLを指定して直接ダウンロードすることが出来ないことです。 そのため、ダウンロード用のアクションを配置するなどして、サーバー上でダウンロードしてからクライアントに返却する必要があります。
しかしながら、fog-awsではfog_publicがfalseの場合、fog_authenticated_url_expirationというオプションが自動で有効になります。 600秒間有効な署名付きURLを自動で発行するという機能です。
これを活用することで「URLを指定して直接ダウンロードできない」というデメリットがほとんど解決されるのではないかと思います。
ブロックパブリックアクセスをオフにする(非推奨)
もう一つの方法はブロックパブリックアクセスをオフに変更することです。
オフにすることで、fog_public = true
との矛盾がなくなり、エラーが発生しなくなります。
しかし、セキュリティホールが発生してしまうリスクが伴いますので個人的にはオススメしません。 セキュリティ要件に応じて、アップロードリソース毎にパブリックアクセスの可否を設定する必要が生じるので管理コストも増えてしまいます。
参考
carrierwave/fog.rb at master · carrierwaveuploader/carrierwave · GitHub