AWS CDKで、SNS経由でメール通知を飛ばすLambdaを作る

この記事では、AWS CDKを使用してSNSトピックを作成するLambda関数や、SNSトピックおよびEmailのサブスクリプションを作成する方法が紹介されています。CDKを使うことで、手組みの構成を忘れることなくリソースを管理できます。具体的なコードやLambda関数の実装方法も紹介されており、EventBridgeを介してSNSに情報を送信するプロセスも紹介されています。dotenvなどの追加の設定も必要です。

広告ここから
広告ここまで

目次

    この記事では、AWS CDKを使ってSNSトピックを作成するLambdaと、それを受信するSNSトピックおよびEmailのサブスクリプションを作成するコードを紹介します。

    背景: 手組みは構成をすぐ忘れる

    個人開発では、どうも手組みした構成を忘れてしまうことが多く、半年か1年くらいしてから「あれ、これどんな構成だっけ・・・?」となりがちです。そのため、ここ最近は余程のことがない限りCDKを使ってリソースを作成・管理しています。

    今回はエラーや実行結果などをSNSトピックに公開するLambda関数と、通知先の例としてEmailのサブスクリプションをCDKでまとめて定義します。

    SNSトピックとサブスクリプションを作る

    まずはSNSまわりを定義します。トピックの作成もサブスクリプション作成もかなりシンプルな実装で行えます。通知先のメールアドレスは、環境変数から設定するようにしました。必要に応じてdotenvなども追加しましょう。

        // SNSトピックの作成
        const snsTopic = new aws_sns.Topic(this, `MiscNotification-${props?.environment}`, {
          topicName: `misc-notification-${props?.environment}`,
        });
        new aws_sns.Subscription(this, 'Hidetaka', {
          topic: snsTopic,
          protocol: aws_sns.SubscriptionProtocol.EMAIL,
          endpoint: process.env.ADMIN_EMAIL_ADDRESS as string,
        })

    SNSへのアクセス権を持つLambdaをつくる

    あとはLambdaを作成するだけです。aws_lambda_nodejsを使っていますが、普通のlambda.Functionでも同じように定義できるはずです。追加の設定として、sns:Publishを作成したSNSトピックに対して実行する権限も追加しています。

        const lambdaFunction = new aws_lambda_nodejs.NodejsFunction(this, `LambdaToSNS`, {
          entry: join(__dirname, '../lambda/lambda.ts'),
          handler: 'handler',
          environment: {
            SNS_TOPIC_ARN: snsTopic.topicArn,
          }
        });
    
        lambdaFunction.addToRolePolicy(new aws_iam.PolicyStatement({
          actions: ['sns:Publish'],
          resources: [snsTopic.topicArn],
        }));

    CDK定義全体図

    import * as cdk from 'aws-cdk-lib';
    import { Construct } from 'constructs';
    import { aws_lambda_nodejs, aws_sns, aws_iam } from 'aws-cdk-lib';
    import { join } from 'path'
    
    export class AppBackendStack extends cdk.Stack {
      constructor(scope: Construct, id: string, props?: cdk.StackProps & {
        environment: string
      }) {
        super(scope, id, props);
    
        // SNSトピックの作成
        const snsTopic = new aws_sns.Topic(this, `MiscNotification-${props?.environment}`, {
          topicName: `misc-notification-${props?.environment}`,
        });
        new aws_sns.Subscription(this, 'Hidetaka', {
          topic: snsTopic,
          protocol: aws_sns.SubscriptionProtocol.EMAIL,
          endpoint: process.env.ADMIN_EMAIL_ADDRESS as string,
        })
    
        const lambdaFunction = new aws_lambda_nodejs.NodejsFunction(this, `LambdaToSNS`, {
          entry: join(__dirname, '../lambda/lambda.ts'),
          handler: 'handler',
          environment: {
            SNS_TOPIC_ARN: snsTopic.topicArn,
          }
        });
    
        lambdaFunction.addToRolePolicy(new aws_iam.PolicyStatement({
          actions: ['sns:Publish'],
          resources: [snsTopic.topicArn],
        }));
      }
    }
    

    ちなみにLambda関数はこのような実装にしています。EventBridgeで受け取った値をそのままSNSに投げるようなイメージですね。実際のコードでは、この中でStripeなどのAPIを呼び出して追加の情報を収集しています。もし受け取った値をそのままSNSに送信するだけであれば、EventBridgeから直接SNSをよびだせますので、そちらも検討しましょう。

    import { EventBridgeHandler } from 'aws-lambda';
    import { SNSClient, PublishCommand } from "@aws-sdk/client-sns";
    
    export const handler: EventBridgeHandler = async (event) => {
        console.log(JSON.stringify(event,null,2))
        const snsTopicArn = process.env.SNS_TOPIC_ARN as string
        const snsClient = new SNSClient();
        await snsClient.send(
          new PublishCommand({
            Message: JSON.stringify({ message: 'Hello' }, null, 2),
            TopicArn: snsTopicArn,
          }),
        );
    }

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark