AWSのS3で本番環境の画像を保存する①AWSの設定

# はじめに
　　
AWSS3のクラウド環境に画像を保存する方法をまとめます。チームメンバーが既にまとめてくれていてそれを参考に進めたのでほぼ一緒の内容ですｗ
自分なりに疑問に思った点を深掘りできたらと思います。

https://qiita.com/iijima-naoya-45b/items/0bdf75bde960787c9c04


# 環境
　　
・Ruby　3.2.2
・Rails 7.0.7
・Docker
・render

・CarrierWave　導入済み
・AWS　IAM　設定済み

・AWS画像は2023.11のものです


# 導入経緯
　　
チーム開発でrenderを使いアプリをデプロイした際、デプロイし直すたびにプロフィール画像が表示されなくなるエラーが発生しました。
原因としては、renderは画像のクラウド保存の機能がないこと、CarrierWaveでアプリ内の`public/uploads`ディレクトリに保存される設定の為、デプロイする度にローカルのまっさらな`public/uploads`が上書きされてしまい、画像のデータが消失してしまいました。

そこでS3を導入し、AWSのクラウドに画像を保存することでこの問題を解決します。

 　　
# バケットの作成
　　
まず、AWSでバケットを作成していきましょう。バケットとはAmazon S3における基本的なデータ格納用のコンテナです。画像を保存する特定のアプリ専用バケツのイメージです。

[![Image from Gyazo](https://i.gyazo.com/552f923742bb11d8f77f2f60123e8206.png)](https://gyazo.com/552f923742bb11d8f77f2f60123e8206)

S3のページに飛んだら、オレンジの**バケットを作成**をクリックします。
　　
**【一般的な設定】**
[![Image from Gyazo](https://i.gyazo.com/3868c520b1434fe0fe5dbce7eaecc3c5.png)](https://gyazo.com/3868c520b1434fe0fe5dbce7eaecc3c5)

・バケット名を入力
・AWSリージョンをアジア・パシフィック（東京）で設定
　　
**【オブジェクト所有者】**
[![Image from Gyazo](https://i.gyazo.com/4b7f78f511761931219fe8fd758a2691.png)](https://gyazo.com/4b7f78f511761931219fe8fd758a2691)
・ACL　有効
・オブジェクトライター選択
　　
**【ブロックパブリック・アクセス設定】**
[![Image from Gyazo](https://i.gyazo.com/f05e86b65cafbe0f12fcfdc756a3509c.png)](https://gyazo.com/f05e86b65cafbe0f12fcfdc756a3509c)

今回はバケットポリシーというものを使用して、S3のセキュリティ対策を行います。
まずは、パブリックアクセスをすべてブロックのチェックを外し、画像のように3つのチェックボックスにチェックを入れます。

　　
変更は以上です。**バケットを作成**を押し完了させます。
　　

[![Image from Gyazo](https://i.gyazo.com/cc707f239d5ceceda447f87818b0492f.png)](https://gyazo.com/cc707f239d5ceceda447f87818b0492f)

バケットが完成しました〜👏


**【Amazon　リソースネーム(ARN)】** 
[![Image from Gyazo](https://i.gyazo.com/99913d64a8576ddb62dab232007c5512.png)](https://gyazo.com/99913d64a8576ddb62dab232007c5512)
Amazon　リソースネーム(ARN)は後ほど使用するのでメモに控えておきます。

　　
**【補足事項】**
Amazon　リソースネーム(ARN)はarn:aws:s3:::バケット名と形が決まっています。その為バケット名がバレてしまったら簡単に推測されてしまいます。セキュリティの観点から、バケット名を複雑なものにしておいたほうが良かったかな？とあとから疑問になりました。

https://chat.openai.com/share/2360137c-3e00-4ca3-a4d0-2ee17fa4670e

結論としては、ARNが露出しても、適切なアクセス許可とセキュリティ対策が施されていれば、直接的なセキュリティ侵害にはつながらないことが多いです。しかしながら、セキュリティのベストプラクティスとしては、必要ない場合はARNを公開しないようにするべきです。

ということで、使用した画像は念のため塗りつぶしました笑


# バケットポリシーの設定
　　
バケットポリシーとは、Amazon S3バケットに適用されるアクセス制御ポリシーで、バケットへのアクセスを細かく制御し特定のユーザーやグループ、または一般のインターネットユーザーへの権限を設定することができます。

IAMユーザーのみバケットにアクセスできるよう設定していきます。

　　
**【バケットポリシーの設定】**

[![Image from Gyazo](https://i.gyazo.com/96dbe42bbf21764665ddffa16442f6fb.png)](https://gyazo.com/96dbe42bbf21764665ddffa16442f6fb)

・先ほど作成したバケット名をクリックし、画面中央のアクセス許可をクリックします。
・バケットポリシーを編集します。

　　
**【バケットポリシーを作成】**

https://awspolicygen.s3.amazonaws.com/policygen.html

AWS Policy Generatorを使い自作できます。[【参考記事】](https://qiita.com/libra_lt/items/284b2723eaae26c5a39b
)

```
{
    "Version": "2012-10-17",
    "Id": "Policy1699409320136",
    "Statement": [
        {
            "Sid": "Stmt1699409298149",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::◯◯◯◯◯:user/××××××"　# IAMユーザーARN
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::バケット名" # バケットARN
        }
    ]
}
```
IAMで作成したユーザーのARNと、先ほど作成したバケットのARNをそれぞれ入力します。

<table>
  <caption>Statement: ポリシーの具体的な権限設定を記述する部分</caption>
  <thead>
    <tr>
      <th>要素</th> 
      <th>説明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sid (Statement ID)</td> 
      <td>ステートメントの一意の識別子です。ここでは "Stmt1699409298149" となっています。このIDは任意の値です。</td>
    </tr>
    <tr>
      <td>Effect</td> 
      <td>ステートメントの効果を示します。"Allow" は許可、"Deny" は拒否を意味します。この例では "Allow" が指定されています。</td>
    </tr>
    <tr>
      <td>Principal</td> 
      <td>ポリシーが適用される主体（ユーザー、グループ、ロール）を指定します。特定のIAMユーザー（ARNで指定）がここに該当します。</td>
    </tr>
    <tr>
      <td>Action</td> 
      <td>許可または拒否するアクションを指定します。"s3:*" が指定されており、S3に関連するすべての操作を許可することを意味します。</td>
    </tr>
    <tr>
      <td>Resource</td> 
      <td>ポリシーが適用されるリソースを指定します。特定のS3バケット（バケット名で指定）がここに該当します。</td>
    </tr>
  </tbody>
</table>

  　　
**【バケットポリシーを自作】**

https://qiita.com/iijima-naoya-45b/items/0bdf75bde960787c9c04

https://qiita.com/libra_lt/items/284b2723eaae26c5a39b

今回この記事を見ながらバケットポリシーを自作する過程で疑問点が出たのでまとめます。(飛ばしてOK)

　　
上の記事ではバケットポリシーのActionの部分が`"s3:*"`になっていますが、下の記事内ではGetObjectとPutObjectのみ許可されていて`"s3:PutObject","s3:DeleteObject"`になっています。

　　
**【ふたつの違い】**
  
AWS IAM（Identity and Access Management）ポリシーにおいて、ワイルドカード "s3:*" は、指定されたS3リソースに対して全てのS3アクションを許可します。この場合、"Resource": "arn:aws:s3:::test" は特定のバケット（この例では test バケット）に対するすべてのアクションを許可します。

一方で、"Resource": "arn:aws:s3:::test/*" とすると、このポリシーは test バケット内の全てのオブジェクト（バケット内のアイテム）に対して全てのアクションを許可しますが、バケット自体（例えばバケットの削除やバケットポリシーの設定など）に対するアクションは許可しません。

　　
要約すると、違いは以下の通りです：
　　
"Resource": "arn:aws:s3:::test": この設定は、test バケットに対する全てのアクション（バケットレベルとオブジェクトレベルの両方）を許可します。

"Resource": "arn:aws:s3:::test/*": この設定は、test バケット内の全てのオブジェクトに対する全てのアクションを許可しますが、バケットレベルのアクション（例えばバケットの削除や設定変更）は許可しません。
　　

https://chat.openai.com/share/efb96f29-f88f-49e2-812f-d4ada4443b6e

　　
セキュリティの観点からは、必要最小限の権限必要なリソースとアクションにのみアクセスを許可することが推奨されます。


今回の場合、少人数のチーム開発でS3の担当になったので私に対する権限はとくに制限しなくてもいいんじゃないか？となり、現在のコードを採用しました。

また個人開発でもこちらでいいかも？と考えています。
　　

この部分に関しては是非ご意見が頂きたいです。マサカリお待ちしております✨


# 参考記事

https://qiita.com/iijima-naoya-45b/items/0bdf75bde960787c9c04

https://qiita.com/libra_lt/items/284b2723eaae26c5a39b

https://awspolicygen.s3.amazonaws.com/policygen.html

https://chat.openai.com/share/efb96f29-f88f-49e2-812f-d4ada4443b6e


# 関連記事

https://qiita.com/joinus_ibuki/items/774a79e9c828ecdc57b3