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,
}),
);
}