S3にファイルがアップされたらLambdaでメール通知する設定


S3にファイルがアップされたらLambdaでメール通知する設定

この手の設定記事も何番煎じか分かりませんが、今回はついにAWS Lambdaに手を出していこうと思います。PythonとかRubyとか全然できないので敬遠してたんですけど、諸事情あり勉強がてらの記事投稿です。

今回のゴール

S3の特定バケットに特定の拡張子ファイル(今回はテキストファイル)をアップロードしたら、Lambdaでpythonコードが実行されからAmazon SNS経由でメール通知が届く。

以下イメージです。

設定項目

①テキストファイルを格納するS3バケットとサブフォルダを作成
②Lambda関数を作成
③LambdaにIAMロールを設定
④Lambda関数のトリガーを設定
⑤SNSのトピック、サブスクリプションを作成、設定
⑥Lambda関数にpythonコードを記述

実際にやってみた

まず①ですがLambdaを設定するリージョンと同じリージョンを選択して、S3バケットを作成します。基本的にデフォルトの設定のままでOKです。

続いて②のLambda関数を作成ですが、AWSが用意したテンプレートを使うこともできますが今回は「一から作成」で進めていきます。

「関数名」は任意の名前を、「ランタイム」はPython3.7を選択します。
実行ロールは「基本的なLambdaアクセス権限で新しいロールを作成」を選択します。

これでいったんLambda関数の作成は完了です。

次に③のLambdaにIAMロールを設定を行います。
Lambdaは作成された時点の状態では以下の図のようにCloudWatch Logs以外のアクセス権がついていない状態となります。

今回のゴールが「Amazon SNS でメール通知する」のため、LambdaからSNSを呼びさせるようにアクセス権を設定する必要があります。

アクセス権の設定方法については色々なやり方があると思いますが今回は単純に「新しく作成されたロール」にSNSのアクセス権をアタッチするやり方で進めます。
「リソースの概要」の上部に「実行ロール」の表示があり、LambdaにアタッチされたIAMロールが表示されています。このロールにSNSの権限を以下のようにアタッチします。※別にFullAccessでなくてもOKです

これでIAMロールの設定はOKです。

次に④Lambda関数のトリガーを設定をしていきます。トリガーとは、Lambdaが実行されるきっかけとなるアクションのことです。今回の場合、「トリガー」はS3バケットへのデータアップロードになります。
トリガーの設定は下図の赤丸の「トリガーを追加」をクリックして、以下のように選択していきます。

  • トリガーはS3
  • バケットは①で作成したバケットを指定
  • イベントタイプはとりあえず今回は「全てのオブジェクト作成イベント」を選択
  • プレフィックスはサブフォルダを指定   ※「サブフォルダ/」 という形で最後の”/”も記載する
  • サフィックスは今回はテキストファイルなので、「.txt」を選択

これでトリガーの設定は完了です。S3の指定バケットのテキストファイルがアップロードされたらLamdba関数が実行されるようになります。

続いて⑤Amazon SNSのトピック、サブスクリプションを作成、設定をしていきます。Lambdaが呼び出すSNSを設定し、通知ができるように有効化しておきます。
下図の赤い丸の「トピック」をクリックし、まずトピックを作成します。

「名前」、「表示オプション」は任意のものでOKです。
トピックが作成されるとARNが発行されますので、ARNをメモしておいてください。Pythonコードに後ほど埋め込んで使います。

次にサブスクリプションを設定していきます。下図の赤い丸の「サブスクリプションの作成」をクリックします。

プロトコルは「Eメール」を選択し、エンドポイントに「通知したいメールアドレス」を設定します。

サブスクリプションを作成するとエンドポイントで設定したメールアドレスに確認依頼のようなメールが届きます。そのメールの「Confirm subscription」をクリックすると確認OKになり、以下ような画面が表示されます。

これでSNSの準備が整いました。
最後にいよいよ⑥のLambda関数にコード記載していきます。lambda_function.py となっているファイルをダブルクリックして、既存コードを削除して以下のコードを記述してください。コードを書く場所やlambda_function.py の場所は下図参照。

import boto3

def lambda_handler(event, context):
client = boto3.client('sns')

TOPIC_ARN = 'Amazon SNSのトピックのARNを記載'     
msg = 'Pythonからのテストメール\nS3バケットにファイルがアップロードされました'
subject = 'S3バケットを確認してください!!!!'

response = client.publish(
    TopicArn = TOPIC_ARN,
    Message = msg,
    Subject = subject
)

return response

エラー表示がでなければ、「Deploy」をクリックして、コードを保存してください。

もし、Lambda関数に適切なアクセス権が設定されていない場合はテスト実行すると以下のようなResponse結果になります。IAMロールにアタッチしているポリシーを見直しましょう。

あとは該当のS3バケットのサブフォルダにテキストファイルをアップロードしてみましょう。
こんな感じでメール通知が出ると思います。

注意点

  • トリガーを追加する画面の右側に「送信先を追加」というものがあり、ここにAmazon SNSを設定するのかな?...と思って設定すると通知は来るのですが、タイムスタンプやリクエストIDなどの情報が羅列されたものが通知されるだけでした。
  • トリガーの設定で、プレフィックスにサブフォルダを記載しますが、サブフォルダ名の最後に"/"をつけ忘れると上手く動作しなくなります。 またサブフォルダを作成せず、バケット直下を指定してしてもなぜか上手く動作しませんので、適当にバケット下にサブフォルダを作成してください。

参考にしたサイト

https://qiita.com/tsumita7
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-s3-example.html
https://blog.smtps.jp/entry/2019/10/04/171230
https://recipe.kc-cloud.jp/archives/10035
https://dev.classmethod.jp/articles/lambda-my-first-step/
https://nopipi.hatenablog.com/entry/2019/01/11/224201

終わりに

Lambda が使えるようになると一気にAWSで構築できる内容が広がります。何より楽しくなってきます(笑)
pythonをそこそこ書けるようになったら、さぞ楽しいことでしょう...精進しますm(_ _)m