カスタムリソースで複数エンドポイントをSNSトピックに設定する
目次
はじめに
こんにちは、スカイアーチHRソリューションズのharaです。
今回はAWS公式ドキュメントを参考に、SAMでCloudFormation カスタムリソースを使用して
複数のメールエンドポイントをSNSトピックに登録していきたいと思います。
前提
カスタムリソースとは
CloudFormationのリソースタイプに提供されていないリソースを作成することができます。
作成時は他リソースと同じテンプレート内に定義をすることが可能です。
カスタムリソースの作成にはカスタムリソースプロバイダ (CloudFormationからのリクエストを処理/応答するサービストークン) が必要となります。
カスタムリソースは以下の流れで作成されます。
1.CloudFormationファイル作成
テンプレート内にカスタムリソース含む作成するリソースの定義とサービストークンを指定します。
2.サービストークンへのリクエスト実行
CloudFormationを実行し、指定したサービストークンへリクエストを行います。
サービストークンはリクエストを処理し、事前署名されたURLへSUCCESSまたはFAILEDの応答を返します。
3.CloudFormationへの応答返却
応答がSUCCESSの場合はStackが完了、応答がないまたはFAILEDの場合はStackは失敗します。
なお、応答がない場合はCREATE_IN_PROGRESSからステータスが1時間動かないため注意が必要です。
※その後削除を試行した場合もDELETE_IN_PROGRESSからステータスが1時間動かず、
最終的にStackの削除は失敗しますので注意してください。
SAMとは
AWS SAM CLIを利用し、CloudFormationの拡張テンプレートでサーバレスアプリケーションを作成できます。
今回はCloud9の環境でSAMを使用してカスタムリソースを作成していきたいと思います。
作成手順
Cloud9環境作成
※必要に応じて、事前にVPC関連の環境を作成しておきます。
AWS Management ConsoleのCloud9ページから、環境を作成していきます。
[ 環境を作成 ] 画面にて、必須項目を入力して画面下部の [ 作成 ] を押下します。
作成が完了するとCloud9の画面が自動的に立ち上がります。
※立ち上がらない場合はCloud9 IDEのリンクを開きます。
事前準備
念のためインストールされている AWS SAM CLI をアップデートしておきます。
$ sam --version
SAM CLI, version 1.72.0
$ wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip
$ unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
$ sudo ./sam-installation/install --update
$ /usr/local/bin/sam --version
SAM CLI, version 1.97.0
※2023年9月時点の最新バージョンです。
また、テンプレートファイルを以下AWS公式ドキュメントから取得します。
$ wget https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/patterns/samples/p-attach/ba49dc99-c3e1-4c33-a40d-30ef48191720/attachments/attachment.zip
$ unzip attachment.zip
$ unzip custom-resource-sns-endpoints.zip
解凍したcustom-resource-sns-endopointsディレクトリ配下のtemplate.yamlを編集します。
変更箇所は以下となります。
・7行目のメールアドレス
・11行目のRuntime
・64行目以降のSNSトピック名
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Parameters:
pSNSNotificationsEmail:
Description: "Email address for SNS notifications"
Type: CommaDelimitedList
Default: "xxxx@gmail.com,yyyy@gmail.com"
Globals:
Function:
Runtime: python3.9
Handler: lambda_function.lambda_handler
Resources:
######## LAMBDA #########
rSNSTopicSubscriptionLambda:
Type: "AWS::Serverless::Function"
Properties:
CodeUri: ./lambda/topic/src
FunctionName: !Join ['-', ["cr", "sns", "topic", "endpoints", "subscription"]]
Description: "Subscribes multiple endpoints to an SNS topic."
Role: !GetAtt rSNSTopicSubscriptionRole.Arn
######## IAM #########
rSNSTopicSubscriptionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Version: '2012-10-17'
Path: /
Policies:
-
PolicyName: root
PolicyDocument:
Statement:
- Action:
- logs:CreateLogGroup
- logs:DescribeLogGroups
- logs:CreateLogStream
- logs:DescribeLogStreams
- logs:PutLogEvents
Effect: Allow
Resource:
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:*'
Sid: LogAccessPolicy
- Action:
- sns:Unsubscribe
- sns:Subscribe
Effect: Allow
Resource: '*'
Sid: SNSSubscription
Version: '2012-10-17'
######## SNS #########
rSNSTopic:
Type: 'AWS::SNS::Topic'
Properties:
TopicName: 'hara-custom-topic'
rSNSTopicPolicy:
Type: 'AWS::SNS::TopicPolicy'
Properties:
PolicyDocument:
Id: 'hara-custom-topic'
Version: '2012-10-17'
Statement:
- Sid: 'hara-custom-topic-notifications'
Effect: Allow
Principal:
Service:
- 'cloudwatch.amazonaws.com'
- 'cloudtrail.amazonaws.com'
Action: 'sns:Publish'
Resource: !Ref rSNSTopic
Topics:
- !Ref rSNSTopic
rSNSTopicSubscription:
Type: Custom::SNSSubscription
Properties:
ServiceToken: !GetAtt rSNSTopicSubscriptionLambda.Arn
TopicArn: !Ref rSNSTopic
SubscriptionEndpoints: !Ref pSNSNotificationsEmail
SubscriptionProtocol: 'email'
lambda用に、必要なPythonパッケージを一括でインストールするファイルを作成します。
$ touch ./custom-resource-sns-endpoints/lambda/topic/src/requirements.txt
requirements.txtには以下を記載して保存しておきます。
boto3
requests
SAM環境の構築 ( sam build )
custom-resource-sns-endpointsディレクトリに移動し、sam buildします。
sam buildする際はオプションの–use-containerを付与して実行すると、
指定のランタイム (今回だとpython 3.9) のコンテナ環境が立ち上がるため、
ローカルの環境 (Cloud9) にPython3.9が入っていなくても sam build の実行が可能です。
$ cd custom-resource-sns-endpoints/
$ sam build --use-container
SAM CLI now collects telemetry to better understand customer needs.
You can OPT OUT and disable telemetry collection by setting the
environment variable SAM_CLI_TELEMETRY=0 in your shell.
Thanks for your help!
Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
Starting Build inside a container
Building codeuri: /home/ec2-user/environment/custom-resource-sns-endpoints/lambda/topic/src runtime: python3.9 metadata: {} architecture: x86_64 functions: rSNSTopicSubscriptionLambda
Fetching public.ecr.aws/sam/build-python3.9:latest-x86_64 Docker container image........................................................................................................
Mounting /home/ec2-user/environment/custom-resource-sns-endpoints/lambda/topic/src as /tmp/samcli/source:ro,delegated, inside runtime container
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
SAM環境のデプロイ ( sam deploy )
対話形式でデプロイしていきます。
$ sam deploy --guided
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Not found
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: hara-sam-teststack
AWS Region [ap-northeast-1]:
Parameter pSNSNotificationsEmail [xxxx@gmail.com,yyyy@gmail.com]:
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]:
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]:
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]:
Save arguments to configuration file [Y/n]:
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
Looking for resources needed for deployment:
Creating the required resources...
Error: Failed to create managed resources: An error occurred (InvalidClientTokenId) when calling the CreateChangeSet operation: The security token included in the request is invalid
デプロイしようとしたらErrorになりました。AWS CLIの認証で弾かれたようです。
以下の方法でCloud9 の認証情報を修正します。
1.Cloud9 の設定 > AWS Settings >Credentials をオフ
2.実行ユーザアカウント (AdministoratorsAccess権限所持) のアクセスキー/シークレットキーをaws configure に設定
再実行してみます。
sam deploy --guided
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Not found
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: hara-sam-teststack
AWS Region [ap-northeast-1]:
Parameter pSNSNotificationsEmail [xxxx@gmail.com,yyyy@gmail.com]:
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]:
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]:
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]:
Save arguments to configuration file [Y/n]:
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
Looking for resources needed for deployment:
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-**********
A different default S3 bucket can be set in samconfig.toml and auto resolution of buckets turned off by setting resolve_s3=False
Saved arguments to config file
Running 'sam deploy' for future deployments will use the parameters saved above.
The above parameters can be changed by modifying samconfig.toml
Learn more about samconfig.toml syntax at
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
Uploading to hara-sam-teststack/e9f4e5ce66f1c4943082047d9b6ea205 12289766 / 12289766 (100.00%)
Deploying with following values
===============================
Stack name : hara-sam-teststack
Region : ap-northeast-1
Confirm changeset : False
Disable rollback : False
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-***********
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {"pSNSNotificationsEmail": "xxxx@gmail.com,yyyy@gmail.com"}
Signing Profiles : {}
Initiating deployment
=====================
Uploading to hara-sam-teststack/59088f31845286ffa2f7f02d21f829e4.template 2934 / 2934 (100.00%)
Waiting for changeset to be created..
CloudFormation stack changeset
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add rSNSTopicPolicy AWS::SNS::TopicPolicy N/A
+ Add rSNSTopicSubscriptionLambda AWS::Lambda::Function N/A
+ Add rSNSTopicSubscriptionRole AWS::IAM::Role N/A
+ Add rSNSTopicSubscription Custom::SNSSubscription N/A
+ Add rSNSTopic AWS::SNS::Topic N/A
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:**********:changeSet/samcli-deploy1694275489/e195c545-e468-407d-94f0-1932f2fe2c6f
2023-09-09 16:05:00 - Waiting for stack create/update to complete
CloudFormation events from stack operations (refresh every 5.0 seconds)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS AWS::IAM::Role rSNSTopicSubscriptionRole -
CREATE_IN_PROGRESS AWS::SNS::Topic rSNSTopic -
CREATE_IN_PROGRESS AWS::IAM::Role rSNSTopicSubscriptionRole Resource creation Initiated
CREATE_IN_PROGRESS AWS::SNS::Topic rSNSTopic Resource creation Initiated
CREATE_COMPLETE AWS::SNS::Topic rSNSTopic -
CREATE_IN_PROGRESS AWS::SNS::TopicPolicy rSNSTopicPolicy -
CREATE_IN_PROGRESS AWS::SNS::TopicPolicy rSNSTopicPolicy Resource creation Initiated
CREATE_COMPLETE AWS::SNS::TopicPolicy rSNSTopicPolicy -
CREATE_COMPLETE AWS::IAM::Role rSNSTopicSubscriptionRole -
CREATE_IN_PROGRESS AWS::Lambda::Function rSNSTopicSubscriptionLambda -
CREATE_IN_PROGRESS AWS::Lambda::Function rSNSTopicSubscriptionLambda Resource creation Initiated
CREATE_COMPLETE AWS::Lambda::Function rSNSTopicSubscriptionLambda -
CREATE_IN_PROGRESS Custom::SNSSubscription rSNSTopicSubscription -
CREATE_IN_PROGRESS Custom::SNSSubscription rSNSTopicSubscription Resource creation Initiated
CREATE_COMPLETE Custom::SNSSubscription rSNSTopicSubscription -
CREATE_COMPLETE AWS::CloudFormation::Stack hara-sam-teststack -
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - hara-sam-teststack in ap-northeast-1
うまくいきました。
実行結果
CloudFormationを見ると、作成したStackがCREATE_COMPLETEのステータスで表示されています。
リソースの中に、カスタムリソースプロバイダとして作成したLambdaが存在しています。
LambdaのCloudWatchLogsを見ると、サービストークンが発行されています。
また、SNSにはTemplate.yamlに記載したメールアドレスが登録されました。
おわりに
今回はAWSドキュメントから提供されているファイルを基にカスタムリソースを作成しました。
今回はSAMを使用しましたが、提供されているファイルの中にはより簡単に作成ができるような
スクリプト (deploy.sh) もあるので、そちらを利用しても良いと思います。
本記事が何かの参考になりましたら幸いです。