はじめに
AWS CloudFormationを使って、Amazon SNSの一つのトピックへ複数のメールアドレスをサブスクリプションとして登録したいケースがありました。
具体的には、新規アカウント発行後に、アカウントへの初期設定として、複数の担当者へ通知を送るためのSNSトピックを作成するCloudFormationテンプレートが必要でした。
このテンプレートは、各アカウントによって担当者や人数は変わることから、サブスクリプションするメールアドレスを動的に変更できる設定が求められました。
例えば、担当者が5名の場合、作成するSNSトピックは、以下のイメージです。
これを実現するためのテンプレートについて解説します。
ForEach関数を利用したテンプレート
複数のメールアドレスをSNSトピックに登録するためのテンプレートは以下のようになります
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
Description: SNS Sample Stack
Parameters:
SnsTopicName:
Description: Topic name
Type: String
Default: notify-mail-sns
MailAddressDomain:
Description: Domain name of mail address
Type: String
Default: example.com
AddressUserList:
Description: User name of mail address
Type: List<String>
Default: test1,test2,test3,test4,test5
Resources:
SnsTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Ref SnsTopicName
Fn::ForEach::UserName:
- MailAddressUserName
- !Ref AddressUserList
- Topic${MailAddressUserName}:
Type: AWS::SNS::Subscription
Properties:
Endpoint: !Sub ${MailAddressUserName}@${MailAddressDomain}
Protocol: email
TopicArn: !Ref SnsTopic
例として、以下のメールアドレスを1つのサブスクリプションに登録するSNSトピックを作成します。
- test1@example.com
- test2@example.com
- test3@example.com
- test4@example.com
- test5@example.com
メールアドレスというのは、ユーザー名と、@、ドメイン名で構成されています。(ユーザー名
@ドメイン名
)
それぞれに対応するパラメータは以下のとおりです
AddressUserList
:メールアドレスのユーザー名をカンマ区切りで入力します。MailAddressDomain
:ドメイン名SnsTopicName
:作成するSNSトピックの名前
この設定でスタックを作成すると、5つのメールアドレスに対して通知するSNSのトピックが作成されます。
パラメータのAddressUserList
に担当者のメールアドレスのユーザー名を入力するだけで、テンプレートのForEach関数がそれぞれのアドレスを1つのSNSトピックにサブスクライブします。
ドメインが異なるメールアドレス
ただし、上記テンプレートの例では、ドメインが異なるメールアドレスを登録することができません。
原因は、CloudFormationの論理IDには、英数字のみが有効であるためです。
論理IDとは、CloudFormationテンプレート内でリソースを一意に識別するための名前です。特殊文字(「@」「:」「-」など)を含めることはできません。
そのため、下記のように、メールアドレスをパラメータに入れてForEach関数を利用すると、23行目のOutputKeyは、論理IDになりますので、Topictest1@example.com
やTopictest2@example.com
が論理IDとなり、エラーになります。
したがって、メールアドレス全体をパラメータとしてForEach関数を利用すると、23行目のOutputKeyが、論理IDになりますので、Topictest1@example.com
やTopictest2@example.com
が許可されない形式となり、エラーが発生します。
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
Description: SNS Sample Stack
Parameters:
SnsTopicName:
Description: Topic name
Type: String
Default: notify-mail-sns
MailAddressList:
Description: User name of mail address
Type: List<String>
Default: test1@example.com,test2@example.org,test3@example.net
Resources:
SnsTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Ref SnsTopicName
Fn::ForEach::UserName:
- MailAddress<img src="https://d1tlzifd8jdoy4.cloudfront.net/wp-content/uploads/2023/08/b89a5dca19b12db09ba8e0bde4ee33ef-640x239.png" alt="" width="640" height="239" class="alignnone size-medium wp-image-1130213" />
- !Ref MailAddressList
- Topic${MailAddress}:
Type: AWS::SNS::Subscription
Properties:
Endpoint: !Ref MailAddress
Protocol: email
TopicArn: !Ref SnsTopic
以下が実際のエラー内容です。OutputKeyは、英数字のみにするよう怒られています。
Transform AWS::LanguageExtensions failed with: OutputKey 'Topictest1@example.com' should be alphanumeric.
Rollback requested by user.
回避方法があれば教えていただきたいです。。
Conditionsを利用したテンプレート
不格好ですが、Conditionsセクションを利用してドメインが異なるメールアドレスを登録することが可能です
AWSTemplateFormatVersion: 2010-09-09
Description: SNS Sample Stack
Parameters:
SnsTopicName:
Description: Topic name
Type: String
Default: notify-mail-sns
MailAddress1:
Description: Email address to add to SNS
Type: String
Default: test1@example.org
MailAddress2:
Description: Email address to add to SNS
Type: String
Default: test2@example.com
MailAddress3:
Description: Email address to add to SNS
Type: String
Conditions:
IsMail1Set: !Not [!Equals [!Ref MailAddress1, '']]
IsMail2Set: !Not [!Equals [!Ref MailAddress2, '']]
IsMail3Set: !Not [!Equals [!Ref MailAddress3, '']]
Resources:
SnsTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Ref SnsTopicName
Mail1Subscription:
Type: AWS::SNS::Subscription
Condition: IsMail1Set
Properties:
Endpoint: !Ref MailAddress1
Protocol: email
TopicArn: !Ref SnsTopic
Mail2Subscription:
Type: AWS::SNS::Subscription
Condition: IsMail2Set
Properties:
Endpoint: !Ref MailAddress2
Protocol: email
TopicArn: !Ref SnsTopic
Mail3Subscription:
Type: AWS::SNS::Subscription
Condition: IsMail3Set
Properties:
Endpoint: !Ref MailAddress3
Protocol: email
TopicArn: !Ref SnsTopic
例として、以下のメールアドレスを1つのサブスクリプションに登録するSNSトピックを作成します。
- test1@example.org
- test2@example.com
- test3@example.net
各メールアドレスに対応するパラメータは以下の通りです
MailAddress1
、MailAddress2
、MailAddres3
:登録するメールアドレスSnsTopicName
: 作成するSNSトピックの名前
この設定でスタックを作成すると、3つのメールアドレスが通知対象とするSNSのトピックが作成されます。
パラメータMailAddress1
, MailAddress2
, MailAddress3
には通知を受け取りたいメールアドレスを記載します。
もし、2つだけが必要な場合には、MailAddress3
を空白にしておけばOKです。
4人以上のメールアドレスが必要な場合は、テンプレートのConditionsセクションとResourcesセクションを適宜増やすだけです。
必要になるメールアドレス上限数分をテンプレートに作成しておくとよいでしょう。