5
4

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

Last updated at Posted at 2019-01-17

はじめに

自分は昔、たろっとさんという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をトリガーとしてReply 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というプラグインを使ってください(今回は未使用)

追記

Slackの審査通しました。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4