# AWS のS3にactive storageの画像を保存させるようにする！

# AWS のS3にactive storageの画像を保存させるようにする！

今回、自作アプリ内でactive storageによって画像を投稿させる機能を作っていたのですが、

すっかり保存先について何にも考えておらずローカルに保存する状態のままで、講師さんからの指摘をいただき、S3に保存するようにしました….。

## ＜まず、S3ってなんぞや？＞

S3（Simple Storage Service）とは、AWSのサービスの中の一つで、オンラインストレージサービスのことである。インターネット上でファイルを保存、管理、公開することができます。つまり、アプリ内で、ユーザーがアップロードした画像等のファイルを、保存させることができるサービスです！デフォルトだと、ローカル（自分のpc）のままなので、アプリ開発者以外のユーザーが画像等をアップロードできなくなってしまいます。

**それでは、S3の使い方について説明します！！**

### 1.AWSのアカウントを作る

ここは、割愛します。

### **2.S3のバケットを作る**

アカウント作成後、AWSのコンソールにアクセスして、検索欄から、S#を検索し、S3に飛んでください。

飛んだら、バケットの作成をクリック。

<a href="https://gyazo.com/89b7f2fa5bd2832a6fce2cecf6e753c8"><img src="https://i.gyazo.com/89b7f2fa5bd2832a6fce2cecf6e753c8.png" alt="Image from Gyazo" width="424"/></a>
- バケットの名前と、リージョンを決めます。

***<リージョンて何？>***

AWSのリージョンっていうのは、AWSがデータセンターを設置している場所のこと。リージョンは世界中に多く設置してある。

**私は日本人なので、東京を選択でOK**

- ACL有効をONにする。

<a href="https://gyazo.com/e0d34ec722e969ac373307a9aca76218"><img src="https://i.gyazo.com/e0d34ec722e969ac373307a9aca76218.png" alt="Image from Gyazo" width="589"/></a>
ACLってなんですか？って思いましたよね？

ACLとは、バケットに保存されるファイル等へのアクセス権を制御（設定）する機能のことだそうです。

ACLを使うことで、誰がそのバケットやオブジェクトに対して読み取りや書き込みができるかを細かく制御できるようになります。

ACLの設定を調整することで、アプリにアップされた画像の読み取り権限を一般のユーザーに許可しておくこともでき、アプリ閲覧者がそのコンテンツにアクセスできるようになります。デフォルトはプライベート（見れない）です。

バケットのパブリックアクセスの設定を行います。

以下の画像のようにしてください

<a href="https://gyazo.com/52c3a411bfb1ff989ddbc148a8fcb700"><img src="https://i.gyazo.com/52c3a411bfb1ff989ddbc148a8fcb700.png" alt="Image from Gyazo" width="607"/></a>
バケット作成をクリック。バケットが作成されたことを確認してください。

### **3.IAMポリシーを作成する**

また知らん単語出てきたよ…。

## ＜IAMとは？＞

IAMというのは、ざっくりいうとAWSのサービス（S3や、EC２など）へのアクセス権限の管理を行える機能のことです。（みんながアクセスできたらやばいよね。誰がどのサービスにアクセスできるか、iMAで定義付けちゃおう！ということです。)

この機能によってAWSのアクセス権の管理が効率的に行えます。

 **IAMポリシーとは？
IAMの機能の一つで、AWSのリソースへのアクセス権限を定義する文書のことです。**

**「どのAWSサービスの」、「どのリソースに対して」、「どんな操作を」、「許可するか(許可しないか)」という具体的なアクセス権の設定を書く文書のことを指します。**

＜IMAポリシーの作り方＞

コンソールから、IAMに飛んで、ダッシュボードから、ポリシーをクリックします。

サービスをS3に選択します。

アクセスレベルのトグルリストから該当する項目をチェックします。

Railsガイドを参考の下結果以下のようにします。

五つの項目にチェックを入れます。

リスト：ListBucker

読み取り：GetObject

書き込み：DeleteObject、PutObject

許可の管理：PutObjectAcl

今回作るポリシーは、さっき作ったバケットにのみ適応させるので、リソースは特定にします。

アクセスレベルの選択をしたら、下の方に、

ARNを追加とか出ていますので、bucketだけ、ARNを追加をクリックして、バケット名を作成します。

リリースARNの項目は自動で記載されていますのでそのままでOK。

<a href="https://gyazo.com/c7c8c29192c77b19797286a844ba681b"><img src="https://i.gyazo.com/c7c8c29192c77b19797286a844ba681b.png" alt="Image from Gyazo" width="653"/></a>
<a href="https://gyazo.com/170be2f4f93302daf3475bf1f1e82f87"><img src="https://i.gyazo.com/170be2f4f93302daf3475bf1f1e82f87.png" alt="Image from Gyazo" width="885"/></a>


バケット名前を追加したら、次へを押して、

ポリシーの詳細について設定します。今回は説明は不要なのでポリシー名だけ記載します。

ポリシーの作成をクリックし、ポリシーが作成されたことを確認します。

### **4.IAMユーザーの作成**

IAMのダッシュボードから、ユーザーに飛びます。

ユーザーの作成クリック。

ユーザー名を作成。次へをクリック。

許可の設定を行います。許可のオプションから、

「ポリシーを直接アタッチする」を選択します。

選択したら、下の方に、許可するポリシーの選択画面が表示されるので、さっき作ったポリシーを選択します。

つまり、今回作るユーザーはさっき作ったiAMポリシーの設定に従って、アクセスの許可や、未許可を行いますという設定づけです。

次へを押して、詳細や、許可の概要を確認して、ユーザーの作成をクリックします。

### 5.IAMユーザーのアクセスキーを作成します。

iAMのダッシュボードから、ユーザーをクリック。

→ユーザー一覧から、さっき作ったユーザーをクリック。

セキュリティ認証タブを選択。→下スクロール、アクセスキーの作成をクリック。

<a href="https://gyazo.com/f7c5092f3a297a7c742e1a9eb1cf241b"><img src="https://i.gyazo.com/f7c5092f3a297a7c742e1a9eb1cf241b.png" alt="Image from Gyazo" width="582"/></a>
主要なベストプラクティスと代替案にアクセスするとかいう設定を定義づけます。

「AWS の外部で実行されるアプリケーション」を選択してください。

<a href="https://gyazo.com/c257389bc5f1da5ad667bbeaadad6c33"><img src="https://i.gyazo.com/c257389bc5f1da5ad667bbeaadad6c33.png" alt="Image from Gyazo" width="736"/></a>
次へをクリックし、説明タグの設定が出ますが、今回はいらないので、空白のまま、「アクセスキーの作成」をクリックしてください。

### *＜ここが重要ポイント＞*

アクセスキーを作成した直後、今回作成したアクセスキーの

**access_key_id:と、secret_access_keyが表示されます！**

これらは今後見ることができないので、後から使うため、どこかにメモしておいてください！！！！

### 6.バケットポリシーを編集

S3のページに戻り、先ほど作ったバケットに移動し、

アクセス許可タブをクリック。

バケットポリシーの編集をクリックします。

以下のように記載します。

```ruby
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "AIDAVVZOOTVWOPWLUDHNC"
            },
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::style-love",
                "arn:aws:s3:::style-love/*"
            ]
        }
    ]
}
```

⭐️ユーザーのARN確認方法

IAMのダッシュボードから、ユーザーをクリック。

今回使うIAMユーザー名に飛ぶ。詳細ページにて、ARNが表示されているのでコピペする。

<a href="https://gyazo.com/038f4d9e47403bb4f460a1fc845c85ef"><img src="https://i.gyazo.com/038f4d9e47403bb4f460a1fc845c85ef.png" alt="Image from Gyazo" width="385"/></a>

### **7.gem  ‘aws-sdk-s3'の追加**

S3を使いたいアプリに**gem  ‘aws-sdk-s3’を追加しておきます。**

やり方はいつものgemと同じです。割愛します！

### **8.config/credentials.yml.enc の編集**

アプリ内の、config/credentials.yml.enc の内容を編集します！このファイルは隠しファイルなので、直接記載ができないので、ターミナル上で編集を行う必要があります。

***＜編集方法＞***

1.コンテナに入り込みます。

```ruby
 docker-compose exec web bash
```

2.ファイルを指定し`vim`で開く

```ruby
$ EDITOR="vim" rails credentials:edit
```

そしたら、以下のような記述のファイル内容が出てくる。

```ruby
# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: ・・・・・・・・・・・・・・・・・・・省略・・・・・・・・・・・・・・・・・・・
```

２でやったコマンドにより編集が可能になっているので、以下のコードを参考に追記してください。

```ruby
# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: ・・・・・・・・・・・・・・・・・・・省略・・・・・・・・・・・・・・・・・・・

aws:
  access_key_id: アクセスキー（さっきメモしとけって言ったやつ）
  secret_access_key: シークレットアクセスキー（さっきメモしとけって言ったやつ）
  region: リージョン（自分で作ったバケットのリージョンを指定）
  bucket: バケット名
```

編集を終了するときは、英数字に切り替えて、escキーを押した後に、『:wq』を入力すると（エンターも最後に）、終了できます。

### **9.config/storage.yml の編集**

さっきのconfig/credentials.yml.encの内容に合わせるため、

config/storage.ymlを編集します。以下のようにしてください。（インデントと改行に気をつけてください。）

```ruby
config/storage.yml
local:
  service: S3
  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  region: <%= ENV['AWS_REGION'] %>
  bucket: <%= ENV['AWS_BUCKET'] %>

amazon:
  service: S3
  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  region: <%= ENV['AWS_REGION'] %>
  bucket: <%= ENV['AWS_BUCKET'] %>
```

セキュリティ対策のため、アクセスキーや、リージョンなどは直接記載せず、上記のように、config/credentials.yml.encに自動的に合わせられるように書いておきます。

### **10.config/environments/development.rbと、config/environments/production.rbの編集**

双方のファイルの以下の部分を書き換えます。

```ruby
-    config.active_storage.service = :local
+    config.active_storage.service = :amazon
```

### 11.**CORSを設定する**

***CORSって何？***

私もあんまり詳しく説明できないのでざっくりいうto,

CORSとは、「どのサイトがどのデータにアクセスできるかを決めるルール」です。例えば、ユーザーが、自分のアプリ外からの画像（例えばLINEやインスタ）を自分のアプリに表示させたいってなった時にデフォルトのままだと、

外部からの情報は受け付けない状態なので、CORSを設定し、S3に保存された画像をweb上に表示させるようにする必要があります。

### **＜設定方法＞**

１.バケットにアクセス。アクセス許可タブをクリック。

２.`Cross-Origin Resource Sharing (CORS)`の`編集`をクリックします。

今回私は以下のようにました。

```ruby
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT"
        ],
        "AllowedOrigins": [
            "http://http://127.0.0.1:3000"
        ],
        "ExposeHeaders": [
            "Origin",
            "Content-Type",
            "Content-MD5",
            "Content-Disposition"
        ],
        "MaxAgeSeconds": 3600
    }
]
```

書き終えたら、編集を完了します！

以上でS3が使えるようになるはずです！

アプリを再起動して、エラーがないことを確認し、

画像をアップロードしてみてください。バケットに画像

の保存・削除ができていたら成功です！！

参考になればありがたいです。
AWS素人ですので間違っていたらすみません💦