Serverless Frameworkを使ってAWS LambdaからAmazon SNSへメッセージを発行する処理を書いてみました。
AWS Lambdaの処理(test.js)
Amazon SNSへメッセージを発行する関数です。
発行先のTopicArnは環境変数から取得します。
'use strict';
const AWS = require('aws-sdk');
const sns = new AWS.SNS({apiVersion: '2010-03-31'});
const TOPIC_ARN = process.env.TOPIC_ARN;
module.exports.handler = async function(event, context) {
const params = {
Message: 'message',
Subject: 'subject',
TopicArn: TOPIC_ARN
};
return await sns.publish(params).promise();
};
serverless.ymlの定義
resourcesでAmazon SNSを定義しておくと、serverless deploy時にトピックやサブスクリプションを自動生成してくれます。
自動生成されたトピックのARNをprovider.environmentの環境変数(TOPIC_ARN)に格納していて、AWS LambdaはこのARNに対してメッセージを発行します。
Amazon SNSへメッセージが発行されると、サブスクリプションの宛先へメールが送信されます。
service: my-service
provider:
name: aws
runtime: nodejs12.x
region: us-east-1
stage: ${opt:stage, self:custom.defaultStage}
profile: ${self:custom.profiles.${self:provider.stage}}
iamRoleStatements:
- Effect: Allow
Action:
- sns:Publish
Resource: !Ref SNSTopic
environment:
TOPIC_ARN: !Ref SNSTopic
custom:
defaultStage: dev
profiles:
dev: serverless-dev
prod: serverless-prod
functions:
test:
handler: test.handler
memorySize: 128
timeout: 3
resources:
Resources:
SNSTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: SNS Topic
TopicName: ${self:service}-${self:provider.stage}-topic
SNSSubscription:
Type: AWS::SNS::Subscription
Properties:
Endpoint: test@example.com
Protocol: email
TopicArn: !Ref SNSTopic
動作確認
deploy、invokeしてメールが受信できたら成功です。
> serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (378 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.......
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: us-east-1
stack: my-service-dev
resources: 8
api keys:
None
endpoints:
None
functions:
test: my-service-dev-test
layers:
None
Serverless: Removing old service artifacts from S3...
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
> serverless invoke -f test -l
null
--------------------------------------------------------------------
START RequestId: 7f5506a1-e3a0-4c48-b3e5-34a6b6e1f1de Version: $LATEST
END RequestId: 7f5506a1-e3a0-4c48-b3e5-34a6b6e1f1de
REPORT RequestId: 7f5506a1-e3a0-4c48-b3e5-34a6b6e1f1de Duration: 768.61 ms Billed Duration: 800 ms Memory Size: 128 MB Max Memory Used: 90 MB Init Duration: 382.09 ms
AuthorizationError
AWS LambdaにAmazon SNSへのアクセス権がないと下記のようなエラーが発生します。
serverless.ymlでiamRoleStatementsを追加してアクセスを許すと実行できるようになりました。
> serverless invoke -f test -l
{
"errorType": "AuthorizationError",
"errorMessage": "User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic",
"trace": [
"AuthorizationError: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic",
" at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/query.js:50:29)",
" at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)",
" at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)",
" at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)",
" at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)",
" at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)",
" at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10",
" at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)",
" at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)",
" at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)"
]
}
--------------------------------------------------------------------
START RequestId: 0338236e-835c-4160-be21-e5d3aec07734 Version: $LATEST
2020-03-22 11:14:46.076 (+09:00) 0338236e-835c-4160-be21-e5d3aec07734 ERROR Invoke Error {"errorType":"AuthorizationError","errorMessage":"User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic","code":"AuthorizationError","message":"User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic","time":"2020-03-22T02:14:46.075Z","requestId":"fce7bca4-e69c-525c-bee1-ea630b4a00d5","statusCode":403,"retryable":false,"retryDelay":14.81009541751066,"stack":["AuthorizationError: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/my-service-dev-us-east-1-lambdaRole/my-service-dev-test is not authorized to perform: SNS:Publish on resource: arn:aws:sns:us-east-1:XXXXXXXXXXXX:my-service-dev-topic"," at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/query.js:50:29)"," at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)"," at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)"," at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)"," at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)"," at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)"," at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10"," at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)"," at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)"," at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)"]}
END RequestId: 0338236e-835c-4160-be21-e5d3aec07734
REPORT RequestId: 0338236e-835c-4160-be21-e5d3aec07734 Duration: 377.61 ms Billed Duration: 400 ms Memory Size: 128 MB Max Memory Used: 90 MB
Error --------------------------------------------------
Error: Invoked function failed
at AwsInvoke.log (C:\snapshot\serverless\lib\plugins\aws\invoke\index.js:105:31)
at AwsInvoke.tryCatcher (C:\snapshot\serverless\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:547:31)
at Promise._settlePromise (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:604:18)
at Promise._settlePromise0 (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:649:10)
at Promise._settlePromises (C:\snapshot\serverless\node_modules\bluebird\js\release\promise.js:729:18)
at _drainQueueStep (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:93:12)
at _drainQueue (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:86:9)
at Async._drainQueues (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:102:5)
at Immediate._onImmediate (C:\snapshot\serverless\node_modules\bluebird\js\release\async.js:15:14)
at processImmediate (internal/timers.js:439:21)
at process.topLevelDomainCallback (domain.js:130:23)
For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
Get Support --------------------------------------------
Docs: docs.serverless.com
Bugs: github.com/serverless/serverless/issues
Issues: forum.serverless.com
Your Environment Information ---------------------------
Operating System: win32
Node Version: 12.13.1
Framework Version: 1.63.0 (standalone)
Plugin Version: 3.3.0
SDK Version: 2.3.0
Components Core Version: 1.1.2
Components CLI Version: 1.4.0

