Help us understand the problem. What is going on with this article?

エラー<Message>Access Denied</Message> 〜Rails + Carrierwave + HerokuでAWS S3に画像を保存〜

More than 1 year has passed since last update.

きっかけ

railsでwebアプリを作成後、AmazonS3に画像を保存するべく、IAMユーザーを作成。S3への権限を持たせていざアップロード!としようとしたところ,エラー....

heroku logs

で確認してみると。

<Message>Access Denied</Message>

との文字が... あれ?権限持たせているつもりなんだけどなと試行錯誤...
他の記事を参考にしてもうまくいかず、解決方法を模索しました。同じところで詰まった人への解決策として役立てばいいなと思い記事にしました。簡単にセットアップから説明します。
AWS(Amazon Web Service)について全く知らない状態から、調べたので間違いなどがあったら指摘をお願いします。 ここではcarrierwaveでのアップロードを前提とします。(herokuへのデプロイも)

uploaderの設定

carrierwaveを使っている人ならapp/uploadersに自分で作ったuploaderがあると思います。自分の場合はimage_uploader.rbとなっています。

image_uploader.rb
            .
            .
            .
  if Rails.env.production?
    storage :fog
  else
    storage :file
  end
           .
           .  
           .

本番環境でのみ、S3に保存します。
ただ最初はfogが入っていないと思うので、gemfileにfogを追記します。

Gemfile
  gem 'fog',  '1.42'

bundle installも忘れずに。

carrier_waveの設定

次はcarrier_wave.rbを設定します。carrier_wave.rbは自分でconfig/initialzers下に作らなければなりません。

carrier_wave.rb
if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_provider = 'fog/aws' 
    config.fog_credentials = {
      # Amazon S3用の設定
      :provider              => 'AWS',
      :region                => ENV['S3_REGION'], 
      :aws_access_key_id     => ENV['S3_ACCESS_KEY'],
      :aws_secret_access_key => ENV['S3_SECRET_KEY']
    }
    config.fog_directory     =  ENV['S3_BUCKET']
    config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" } 
  end

  # 日本語ファイル名の設定
  CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/ 
end
ENV[hoge]

となっているのは環境変数のことです。自分のパソコンのみにコードを保存していれば良いのですが、大抵の人はGithubなどにコードをあげていると思います。それが公開されていると他者からコードが確認できてしまいます。s3のアクセスキーやシークレットキーなどが他者にバレてしまうと、悪用されてしまう恐れがあるので、コードに直接書き込むのは危険な行為となります。
のちにherokuでの環境変数の設定を説明します。
ここまででrailsのコードの書き換えは終了です。あとはAWS(Amazon Web service)S3とIAMユーザーの設定のみとなります。

AWS(Amazon Web Service)

今回はアカウントを作成されておりクレジットカードも登録されている前提とします。一年間はある基準まで無料で使えます。個人サービス程度であったら無料の範囲内で収まると思います。
まずはIAMユーザーを作成します。

IAMユーザーの作成

AWSにログイン後、 IAM Management Consoleに移動し、左端にあるユーザーボタンを押し、ユーザーを追加します。スクリーンショット 2018-12-01 16.40.48.png
ユーザー名は任意のものでよいです。今回はプログラムによるアクセスのみチェックをつけてください。スクリーンショット 2018-12-01 16.45.34.png
次のページで既存のポリシーを直接アタッチからAmazonS3FullAccessにチェックし、次に進んでください。次のステップのタグは何も触らずに次に進んで良いです。
その後ユーザーの作成をしたらアクセスキーとシークレットキーが表示されます。これらは.csvでダウンロードできますので必ずダウンロードしてください。シークレットキーはこの時しか手に入れることができません。このアクセスキーとシークレットキーを環境変数に設定することになります。

AWSS3

次は(AWS)S3に飛んでください。バケットを作成するボタンがあると思うのでそこをクリックします。
スクリーンショット 2018-12-01 16.58.41.png
バケット名とリージョンを決めます。その後左下の作成ボタンを押してとりあえずのバケットを作成します。バケット名は後で使うので覚えていてください。

herokuの環境変数を設定する

ターミナルで以下のようにうってください。

$ heroku config:set S3_ACCESS_KEY="ココに先ほどメモしたアクセスキーを入力"
$ heroku config:set S3_SECRET_KEY="同様に、シークレットキーを入力"
$ heroku config:set S3_BUCKET="バケットの名前を入力"
$ heroku config:set S3_REGION="リージョンの名前を入力"

これでherokuの環境変数が設定できました。

他の記事はここまでしか書いていませんでした。(自分の調べた限り)ここまでやると、本番環境で画像をアップできるとほとんどが書いてあります。しかしながら自分はs3に保存できず、heroku logsで見てみると<Message>Access Denied</Message>の文字が...
ここからはS3の新機能が働いてしまっているようです。
2018/11/15に発表されたパブリックアクセス設定機能のおかげでデフォルトでは管理者しかアクセスできず、IAMユーザーのアクセスがブロックされているという結論に至りました。

タイトルのエラーの解決方法

まずは使うバケットを選択します。アクセス権限からパブリックアクセス設定を選択します。スクリーンショット 2018-12-01 17.28.11.png

以上のように設定を変更します。その後バケットポリシーを選択します。
バケットポリシーを次のようにします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<あなたのAWS12桁のID>:user/<あなたのIAMユーザー名>"
            },
            "Action": "*",
            "Resource": "arn:aws:s3:::<あなたのバケット名>/*"
        }
    ]
}

日本語で書いたところを自分のものに変更してからバケットポリシーを変更してください。(<>はいりませんよ)設定を、保存してください。この設定はあなたのIAMユーザーのみに許可をするものです。
以上で本番環境でもs3にアップロードができるようになります。

まとめ

自分がこのエラーに悩まされたのはこの新機能が発表されてすぐのことだったので参考の記事が全く見つからず、自分で一つ一つ調べ、試行錯誤していきながらこの結論に至りました。このエラーだけでだいぶ時間を使ったと思います笑。まあでもエラーが出なかったらAWSについて何も知らずに(考えずに)使う羽目になっていたと思うのでいい機会だったとは思います。長かった.....
この記事にご意見や、ミス報告などがあったらぜひコメントよろしくお願いします。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away