AWS LambdaからAmazon SNSへメッセージを発行する方法(Serverless Framework)

AWS

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

タイトルとURLをコピーしました