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

#きっかけ
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`となっています。

```ruby: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`下に作らなければなりません。

```ruby: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
```
```ruby

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](https://qiita-image-store.s3.amazonaws.com/0/321520/5138f0ae-de05-f649-8bcf-d68fde0b2690.png)
ユーザー名は任意のものでよいです。今回はプログラムによるアクセスのみチェックをつけてください。![スクリーンショット 2018-12-01 16.45.34.png](https://qiita-image-store.s3.amazonaws.com/0/321520/691fdd41-28c9-f606-e469-31cbebb7dd37.png)
次のページで既存のポリシーを直接アタッチから`AmazonS3FullAccess`にチェックし、次に進んでください。次のステップのタグは何も触らずに次に進んで良いです。
その後ユーザーの作成をしたらアクセスキーとシークレットキーが表示されます。これらは.csvでダウンロードできますので必ずダウンロードしてください。シークレットキーはこの時しか手に入れることができません。このアクセスキーとシークレットキーを環境変数に設定することになります。
#AWSS3
次は(AWS)S3に飛んでください。バケットを作成するボタンがあると思うのでそこをクリックします。
![スクリーンショット 2018-12-01 16.58.41.png](https://qiita-image-store.s3.amazonaws.com/0/321520/7598be03-ccd9-d238-1b7a-2ef52a451b26.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](https://qiita-image-store.s3.amazonaws.com/0/321520/92068517-c266-d69a-e4c5-ea82171e2fda.png)

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

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<あなたのAWS１２桁のID>:user/<あなたのIAMユーザー名>"
            },
            "Action": "*",
            "Resource": "arn:aws:s3:::<あなたのバケット名>/*"
        }
    ]
}
```
日本語で書いたところを自分のものに変更してからバケットポリシーを変更してください。（<>はいりませんよ）設定を、保存してください。この設定はあなたのIAMユーザーのみに許可をするものです。
以上で本番環境でもs３にアップロードができるようになります。


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