Serverless Frameworkでタロットカードを引くSlack botを作った

Serverless Frameworkでタロットカードを引くSlack botを作った:


はじめに

自分は昔、たろっとさんというTwitter Botを作っていました。このたろっとさんを復活させたいなぁと思ったのですが、TwitterのAPI申請がめんどくさそうなので、まずはSlack Bot化してみました。


作ったもの

まだ公式アプリではありません。

実際動いているコードから機密情報や、タロットカードを引くロジック(門外不出)を除いたものをGitHubに置いています。


システム構成

以下の図のような構成で作りました。



slack-tarot3-構成.png


  • AWS Lambdaで4つ関数を作成

    • 認可エンドポイントへのリダイレクタ
    • OAuth 2.0のコールバックエンドポイント
    • Event Subscriber
    • Reply
  • アクセストークン保存用にDynamoDBを使用
  • Event SubscriberでAmazon SNSにpublishし、Replyをトリガーで呼び出し
  • API GatewayとRoute 53でURLを独自ドメインに紐づけ
リダイレクタを作ったのは、クライアントIDやscopeが変わってもURLを変更する必要がなく管理が楽だからです。注意点として、リダイレクトする際はHTTPステータスコードは302にする必要があります。

All your server needs to do is build the same URL to slack.com/oauth/authorize you would build for your on-site "Add to Slack" URL and instead of presenting it in a button, send a HTTP 302 redirect to it instead.
Event Subscriberとリプライを分けたのは、SlackのEvents APIには、3秒以内で応答する必要があるためです。Event Subscriberとリプライを分けることで、リプライ側の処理が複雑になっても安心です。

Your app should respond to the event request with an HTTP 2xx within three seconds.


処理の流れ

処理の流れは以下のようになります。



slack-tarot3-フロー.png


詳細は以下のとおりです。1〜6までがOAuth 2.0による認可コードフロー、7〜12がタロットを引くところです。

  1. リダイレクタにアクセス
  2. Authorizeエンドポイントにリダイレクト
  3. Slack上でユーザが認証 & 認可
  4. コールバックエンドポイントにリダイレクト(アプリ管理画面のOAuth & Permissions → Redirect URLsに登録する必要あり)

  5. oauth.accessでcodeとアクセストークンを交換
  6. 取得したアクセストークンをDynamoDBに保存
  7. ユーザが @tarot3 と呼ぶ
  8. イベントが発生し、Events Subscriberが呼ばれる(アプリ管理画面のEvent Subscriptionsに登録する必要あり)
  9. Amazon SNSに通知を投げる
  10. Amazon SNSをトリガーとしてReplay Lambda関数が呼び出される
  11. DynamoDBからアクセストークンを取得
  12. タロットカードを引いてリプライを送る


ポイント


まず画面で操作してみる

最終的にはServerless Frameworkを使いましたが、開発の最初はLambdaの管理コンソールで直接コードを書き、API Gatewayを手動で設定していました。ある程度コンソールで慣れてからServerless Frameworkを使うことで、設定ファイルの書き方がスムーズに理解できました。


scope=bot

scopeはいろいろ定義されているようですが、botだけで良さそうです。

注意しないといけないのは、scope=botの場合はボット専用のアクセストークンが含まれることです。


DNS設定

DNS設定にはserverless-domain-managerというプラグインを使ったのですが、証明書の指定でエラーになりました。

原因は、ACM証明書を東京リージョンで作ったためです。この場合は endpointType: regional の設定を付ける必要があります。


Events APIの署名検証

Events APIを使う場合、Slackから来たメッセージであることの検証を行う必要があります。その方法は以下にかかれています。

概要を書くと、以下のようになります。

  1. 署名用のシークレットキーを取得(アプリ管理画面の "Basic Information" にある "Signing Secret")
  2. HTTPヘッダ X-Slack-Request-Timestamp からリクエストした時刻を取得し、現時刻と大きくずれてないことを検証(例では5分以内の誤差はOK)。これはリプレイアタックを防止するためです。
  3. 署名のベースとなる文字列を sig_basestring = 'v0:' + timestamp + ':' + request_body のようにタイムスタンプとリクエストボディから作成します。
  4. この文字列とシークレットキーより、 HMAC-SHA256 の値を計算します。
  5. 4で計算した文字列の最初に v0= を付けた文字列が HTTPヘッダ X-Slack-Signature と一致することを確認します。


Serverless Frameworkが要求するメモリ

serverless.ymlのリファレンスによれば、メモリサイズ(memorySize)のデフォルトは1024です。もったいないので変更しましょう。最小の128MBで十分でした。


ロールは一括で定義(個別定義はプラグイン)

Serverless Frameworkでは、IAMのロールは一括で定義します。関数ごとに個別に定義したい場合は、serverless-iam-roles-per-functionというプラグインを使ってください(今回は未使用)

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)