AWS S3/SQS/Lambda/SNSにCloud9を連携し、メール通知を行ってみる[04]

こんにちは。
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

今回はAWS S3,SQS,Lambda,SNS環境にCloud9をベースとしたDjango環境を追加して、Django経由でS3に何らかのデータがアップロードされた際にメールが通知される環境を構築していきたいと思います。
今回が想定では最後となります。

前回の記事は以下となります。

https://qiita.com/ohtsuka-shota/items/59821498db47ecbeed7d

また、DjangoからS3にデータを送るために以前私が作った以下の記事も軽く見てます。

https://qiita.com/ohtsuka-shota/items/cdb365fe164fbc48b528

全体の流れは以下にまとめています。

https://qiita.com/ohtsuka-shota/items/db74a418dabc261d9126

# 最終的な構築イメージ
以下環境を作っていきます。今回はCloud9/Djangoを実装していきます。
![aws-django01-ページ6.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/426843a2-5d28-7283-96dc-22fb1cbe3e34.png)

# DjangoのPJ
DjangoのProjectは以下GitHubをご覧ください

https://github.com/ohtsuka-shota/cloud9-sqs-lambda-sns/tree/main

# 構築
## Cloud9でサーバ立ち上げ、環境セットアップ

以下のパラメータでCloud9環境をデプロイします。
![1000003045.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/39baa3f8-12db-e2fa-b3fb-51c4400873d2.png)

Cloud9に入って以下のコマンドを実行します
```
pip3 install django boto3
django-admin startproject qiita
cd qiita/
mkdir static 
mkdir templates
```
作成したstaticとtemplatesディレクトリにそれぞれcssとhtmlを作成し以下の状態にします。
![1000003053.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/6f11cd55-ce42-1255-fecf-813da0ce3ad1.png)

## S3設定
Cloud9/Djangoの受皿となるS3のCORS設定に以下を追加します。
```
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]
```

![1000003064.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/fe94973d-42ea-990d-9ee9-ad520fe28d5e.png)
![1000003068.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/2daf1443-d814-d962-144a-1edaec35a9c3.png)

## ACCESSキーとSECRET ACCESSキーを用意する
IAMを開きユーザを作成します。
ユーザの作成を押下します。
![2024050801.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/49216d53-aec1-38ea-b08d-8ad2bdf524b0.png)
名前はなんでも大丈夫です。
![2024050802.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/e038b49c-0b4d-2b6f-a09b-dec7228e5fb3.png)
ポリシーを直接アタッチを選択します。
許可ポリシーのところでEC2とS3を検索し、それぞれのFullAccessポリシーにチェックを入れます。
![2024050803.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/ad0e1de3-ad49-3af6-7d37-0b484fcd5df0.png)
![2024050804.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/dfe5ed61-2161-3c6d-1a09-567416f6ff0d.png)
ユーザの作成が出来たら、右上にあるアクセスキーを作成を押下します。
![2024050805.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/c0bc0c35-2991-0a48-a8c5-9ee39962319d.png)
以下を選択し、次に進みます。
![2024050806.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/e6115d8d-6b76-16a1-6b13-84f49e9761aa.png)
アクセスキーとシークレットアクセスキーが確認できるようになりますので控えます。控えたら完了を押下します。
![2024050807.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/332a5a14-1de8-304e-cf74-11845a72931a.png)

## Cloud9/Djangoの作り込み
settings.pyやurls.py,views.py,各種html/cssはGutHubを参考に設定してください。
settings.pyはimport os等をしていたり、クロスサイトリクエストフォージェリ関係の設定をコメントアウトして無効化してます。他にもこまごまと設定を修正しています。
またviews.pyでアップロード先のＳ３バケットを名前で指定してあげてください（Arnではありません。）

その後、ACCESS KEYとSECRET ACCESS KEYを.bashrcに記載し、永続的に登録します。
```
ec2-user:~/environment $ cd ../..
ec2-user:~ $ ls -a
.   .aws           .bash_logout   .bashrc  .cache      .gitconfig  .local   .npm  .profile  .ssh     .zshrc       go            package-lock.json
..  .bash_history  .bash_profile  .c9      .codeintel  .gnupg      .mkshrc  .nvm  .rvm      .zlogin  environment  node_modules  package.json

ec2-user:~ $ vi .zshrc

# Add RVM to PATH for scripting. Make sure this is the last PATH variable change.
export PATH="$PATH:$HOME/.rvm/bin"
export AWS_ACCESS_KEY_ID="IAMのアクセスキー"
export AWS_SECRET_ACCESS_KEY="IAMのシークレットアクセスキー"

ec2-user:~ $ source ~/.zshrc
```

## Lambdaの関数修正
以下のように修正し、アップロードされたファイル名、アップロード先のS3バケット名を通知メールに記載するようにします。
```
import boto3
import json

client = boto3.client('sns')

def lambda_handler(event, context):
    # SQS メッセージをパース
    for record in event['Records']:
        # SQS メッセージの body を JSON として読み込む
        message = json.loads(record['body'])
        # S3 イベント通知データを取得
        s3_info = message['Records'][0]['s3']
        # バケット名を取得
        bucket_name = s3_info['bucket']['name']
        # オブジェクトのキーを取得
        object_key = s3_info['object']['key']

        # SNS に送るメッセージを作成
        subject = 'File Uploaded to S3'
        message = f'A file has been uploaded to S3: {object_key} in bucket {bucket_name}'

        # SNS トピックにメッセージを公開
        params = {
            'TopicArn': 'arn:aws:sns:ap-northeast-1:310016072763:qiita-sns',
            'Subject': subject,
            'Message': message
        }
        client.publish(**params)
```

# テスト
Cloud9のターミナルでpython3 manage.py runserver 0.0.0.0:8080と入力します。するとターミナルの右上に"Your code is running～"とURLが表示されていると思います。このURLをクリックします。
![2024050808.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/df1fbfc4-e71b-a4fb-1ef8-62e5dc0bd4ca.png)
するとDjangoにWebブラウザでアクセスることが出来ます。
ファイルを選択します。
![2024050809.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/0b986e0d-c72c-2155-bd60-5ef62a1a9a53.png)
![2024050810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/4efa05d0-e2ac-8a66-7615-2170a3f11cf4.png)
ファイルが表示されていることを確認し、アップロードします。
![2024050811.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/42fe1f99-36d0-a303-c47c-0950eb817246.png)
S3の画面に移動し、Djangoの画面で選択したファイルがアップロードされていることを確認します。
![2024050812.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/d3ae52ab-5fd1-d68c-cbbf-0401191e93e4.png)
また、SNSで登録したメールアドレスにメッセージが届ていることを確認します。Lambdaを修正したことでファイル名とS3バケット名が表示されていますね。
![2024050813.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/5a163d4d-14c0-5962-8a91-75d5aef56368.png)