webhook開発は大変だったので話を聞いて欲しい

こんにちは、Public APIチームでエンジニアをしているまっつーです。

趣味は飲酒、特技は多量飲酒、苦手なことは酒に飲まれないことです。

freee Developers Advent Calendar の 5 日目を気合入れて書いていきます。

突然ですがfreeeは今年Webhook機能をリリースしました。

prtimes.jp

現在は会計freee上での経費精算と各種申請の作成、更新をhookに通知を受け取ることができるようになっています。

今までは自分の申請した経費申請が承認されたかどうかをわざわざブラウザを開いて会計freeeにログインして確認しないといけない世界でした

しかし、Webhookの登場により自分の申請が承認されたらそれを通知で受け取れる世界になりました。

これがコロナ時代の会計ソフト、ニューノーマルってやつです。たぶん。

WebhookはPublic APIチームで開発したんですが、リリースまでにあちこちでつまづいたのでそんな話をしようと思います。

つまづきその1: Webhookを知らなかった

そんなエンジニアおらんやろって言われるかもしれませんが、います。私です。

私は1月に今のチームに移動してきたのですが、そのときチームのOKRにWebhookのリリースがありました。

OKRというのは目標とそれに対する進捗管理のフレームワークで、ざっくりと四半期の目標だと思ってください。

「ほお、Webhookとは?」

OKRを見たときの感想はこんな感じでした。

ちなみにWebhookというのは、ざっくりといえばWebアプリケーションでのイベント発生をトリガーに、あらかじめ登録してあるURLへHTTPリクエストを送信する仕組みです。

具体例を出すと、SlackのWebhook urlを登録しておくことで会計freeeで経費申請が承認された (イベント発生)タイミングで通知をうけとることができます。

つまりは通知機能ですね。

皆さんもWebhookを開発する前に、まずWebhookって何かを調べる必要があることを覚えておきましょう。

つまづきその2: freeeにはプロダクトがありすぎて設定画面をどこにおくべきかわからなかった

freeeには現在たくさんのプロダクトがあります。

  • 会計freee
  • 人事労務freee
  • 申告freee
  • 開業freee
  • 会社設立freee
  • プロジェクト管理freee
  • etc...

ファーストスコープでは会計freeeのWebhook機能を開発しようと決まったのですが、後々は人事労務freeeや他のプロダクトのイベントも通知できるようにしたいと思っていました。

そこで1つの問題が発生、「設定画面はどこにおくべきだろう?」

案1 会計freeeにWebhook設定を用意する

会計freeeのイベントを通知するんだから会計freee内に設定画面があるのはわかりやすいですね。 ただこれだと他サービスへの展開がしづらい。 たとえば人事労務freeeにも展開したい時には

  • 人事労務freeeにも設定画面を用意 => 画面実装が増えるし、ユーザー的にも使っているプロダクトごとに設定が必要になり面倒
  • 会計freeeの設定画面で人事労務freeeのWebhook設定もできるようにする => 人事労務freeeだけ使ってるユーザーが使えないしわかりにくい

と、いろいろ苦しそうだなあという話がでてきて結果ボツになりました

案2 アカウント管理画面にWebhookを用意する

freeeのアカウント管理画面のキャプチャ
freeeで共通で使えるアカウントの管理画面

freeeには様々なプロダクトがありますが、アカウントは共通で使うことができます

アカウントの管理画面は全プロダクトで共通なのでここにWebhook設定をおけばいいのでは?という話になりました。

ただアカウントの管理画面はユーザーが日常的にアクセスするものではない、アカウント管理のプロダクト内のdbにあまり認証情報以外のデータを保存したくないといった理由でボツになりました。

案3 ユーザーにアプリを作成してもらい、アプリ設定にWebhookを用意する

freeeのプロダクトの中に、freee アプリストアというものがあります。

app.secure.freee.co.jp

ここでは開発者がfreeeの公開しているPublic APIを利用したアプリを作成し、他のfreeeユーザーに向けて公開することができます。

アプリの設定画面にWebhook設定を追加するのはどうかという話になりました。

ユーザー的にはどうか? => Webhookの設定のためにアプリを作るという手間はあるが、アプリの作成自体はすぐできる。また、今後複数のプロダクトのWebhookが提供されても同じ画面で設定できる。

開発者的にはどうか? => イベントが発生したら会計freeeからfreee アプリストアのAPIをcallするような仕組みにする。

今後、他プロダクトに展開する時はpayloadだけ揃えてもらえば、同じAPIを叩いてもらうだけでWebhook送信側のロジックは変わらないし、画面の改修も一部で済む。

良さそうだねということでアプリ設定に用意する案が採用されました。

アプリ詳細ページのWebhookタブが開かれているキャプチャ
アプリの設定ページにWebhook設定が追加されました

具体的な設定方法は以下のリンク先に書いてあります。

developer.freee.co.jp

つまづきその3: 性善説で機能を作ってた

いざ開発の段階になり、インフラは基本的にAWSを利用することになりました。

流れとしては

アプリストア => Amazon SNS => Amazon SQS => Lambda とつながり

lambdaが登録してあるURLへ通知を送信します。

開発当初はhttpsでないURLは登録時に弾くくらいの制御しか考えておらず、ユーザーが入力したURLをそのままlambdaからpostしようとしていました。

しかし一度社内でsecurity観点のレビューをしてもらったところ

  • lambdaがどこへpostするかわからないので通信を監視した方がよいのではないか?
  • lambdaからvpc内のaws resourceにアクセス出来たりしないか?(監視のためにlambdaをvpc内にいれるという話が出ていた)
  • 悪意あるユーザーによってfreeeのプロダクト内部のAPIを叩かれないか?

出るわ出るわ、いろんなヤバそうポイントが出てきました。

この時に初めて、自社のサービスからのリクエスト先をユーザーが決定できるWebhookという機能って怖いんだなということに気付きました。

普段自分たちが作るサービスでは意図したサーバーに意図した方法でアクセスしますが、Webhookはユーザーが入力したURLにアクセスするので、普段とは違った視点でセキュリティを考える必要がありました。

完全に性善説で開発すすめていましたがセキュリティはそれではいけませんね。

  • lambda用の新たなvpcを作成する
  • internetに出ていく部分のroute tableを編集することでroutingを制御する
  • lambdaのpost先を監視する

上記の対応をとることでセキュリティ面にも対応しました。

最後に

いろいろつまづきながら開発したWebhook機能なのでぜひ使ってみてください。

使っていただけると私がログを見てニヤニヤしながら旨い酒を飲みます。

明日はPublic APIチームでもお世話になっているQAのすごい人、コヤマンさんの記事です。お楽しみに〜