freeeの開発情報ポータルサイト

これってもしかして……認証基盤が入れ替わってる〜?

こんにちは、DevBrandingのellyです。9月2日に配信した「これってもしかして……認証基盤が入れ替わってる〜?」の様子をご紹介します。

今年に入ってfreeeの認証基盤が新しい基盤に入れ替わりました。リリースされるまでの1454日間の取り組み、今後の開発にどう活かされていくのかを担当したエンジニアに根掘り葉掘り聞いてみました。

登壇者集合写真
登壇者集合写真

mura:写真左。2020年freeeに中途入社。エンジニアリングマネージャー。趣味はプチ旅行、サウナ。

cat:写真中央。2020年新卒入社。猫が大好き。好きなものはゲームと作曲。

terara:写真右。本日の司会。普段は認証認可基盤エンジニア。好きなものはホラー映画と人参。

認証認可基盤リプレイスの背景

―リプレイス前の認証認可基盤はどういう状態だったのでしょうか?

mura:はい、最初にfreeeの歴史を紐解いていきたいと思います。

freeeは2012年に会計のアプリケーションを開発する会社としてスタートしました。その際は会計しかアプリケーションはありませんので、ログイン画面やパスワードといった認証認可の情報自体が会計のデータベースにありました。そのあとに給与計算freee(現freee人事労務)のプロダクトがリリースされるときに、同じID/PWで使いたいよねという話があり、そこでログイン画面と共通で使えるバックエンドの部分を切り出したというのがこれまでのアーキテクチャになります。

―これまではfreee会計の部分にログイン情報が入っていて、次のプロダクトが出てくると、freee会計の方にアクセスしてログインするというイメージですか?

mura:そうですね、もちろんユーザーさんからするとアカウント管理のログイン画面からログインして利用するという形だったんですけど、実際のデータ自体は会計のデータベースにあったというところになりますね。

それが3年ほど続いたんですが、やはりいくつかの問題が出てきました。会計・人事労務以外にも様々なプロダクトが増えて、複数のプロダクトから同じ会計のDBに一緒にアクセスするような状況になり、高負荷な状況となっていました。

手段としてとれるのは、シャーディングだったりとか、データベースにあるので、Auroraへ移行もしました。データモデルも初期に急いで作ったということももちろんあるので、改善がしづらいようなデータモデルになっていたりとか、セッション管理自体が認証ライブラリの方から直接KVSの方にアクセスするような形になっていたので、こちらの改修もしづらい状況でした。

旧認証認可基盤アーキテクチャ概念図
旧認証認可基盤アーキテクチャ

リプレイスプロジェクトの行程

―そこから、1454日という約4年間の大規模プロジェクトがどのように進んでいったのか教えてください。

cat:大きくやったことが4つあります。まず、さっきあったように、急いで最初作ったので、中々メンテがしづらくなってしまってるドメインモデル、ロジックがあったのでそれを整理し直して、新しく今の理想の形に作り直しました。

そのあと、実際作り直したモデルを使って作っていくんですけど、readのAPIとwriteのAPIに分け、readから先に実装しました。readが一通り実装が終わった段階でwriteを実装しました。readとwriteは旧認証認可基盤システムと中身のロジックは違うんですけど、とても多くのプロダクトで使われているので同じように動いてもらわないとリプレイスが出来なくて、これ何とか担保しなきゃいけないということになりました。

それでread/writeを新旧両方のシステムに対して実施して、結果に違いがあったときに開発者に通知してくれるみたいなデバック用の機能を作って、実際の環境に入れて行きながら、テストしていきました。

これをread/write両方実装出来た後に、システムを順々にonにしていって、最後の1年くらいはその差分があるぞっていうエラーをひたすら頑張って直していました。それで落ち着いてきたので、めでたく最後の入れ替えをやって交換完了となりました。

新認証認可基盤アーキテクチャの概念図
新認証認可基盤アーキテクチャ

―freee会計のDBから新サーバーの新DBに徐々に移し替える段階で、readとwriteに分けて、まずはwriteの部分から旧DBに書き込んでいったのでしょうか?

cat:最初は、新システムのwrite機能を段々onにしていきまして、その場合もwriteも両方に書き込んで、書き込んだ後にDBから両方もう一回読んで、同じかどうかをちゃんと見るというのをやっていました。

―最初は旧DBに書き込みつつ、新しいDBにも書き込む、その際に差分を検知しておいて、新DBへの読み取りを行うときも再度差分をチェックして、旧DBのデータが影響なくユーザーさんに返るようにしたってことですかね?

cat:そうですね。しばらくはread、write両方onにした状態にしていて、差分がないようにしつつ、もし差分があれば、新しい方のデータが間違っている可能性があるので古い方を返す実装をしていて、それがある程度落ち着いてきたところから、順々にチェックをoffにしていって、offにしたけどちゃんと運用出来ているってことは、新システムがちゃんと動いてるってことだよね、すごい!って言って毎月みんなで盛り上がっていました。プロダクトごとにもon/off出来たので、ついに会計のこれがoffに出来たぞ!すごい!動いてる!って。会計が一番リクエストが多かったので感無量でした。

プロジェクトの中で特に大変だったこと

―このプロジェクトの中で一番大変だった、一番時間がかかったタスクはどこですか?

cat:やはり最後の差分のエラーの修正ですね。差分があるぞってだけ出てくるんですけど、何がどうなって差分があったのかっていうのは教えてくれないんですね。だからDBを調査しに行ったりしなきゃいけないし、特にユーザーを増やす処理とか減らす処理、権限を与える処理とか外す処理、物凄い分岐していて、一体何したらこんなデータ出来たんだ?というのを調査するのにとても時間がかかりました。

後は最初期のデータを今入れようとしてもバリデーションに引っかかって入らないんですけど、昔はバリデーションがなかったようで、それがデータ不整合になってうまく同期がとれずに落ちてしまって、これを色んな方法で解決する必要があったのもチャレンジングでした。

―途方もないタスクですね...。それはエッジケースですか?

cat:エッジケースですね。普通にローカルでやってると今後再現しないやつばっかりでしたね。検知されてエラーとして出るけど、それを再現するやり方がまず分からないみたいな状況に陥ってました。

―お疲れ様でした。本当に大変でしたね。

cat:はい、muraさんのおかげです。大体分からないときはmuraさんどうしたらいいんですか?って言うと「うーん」って言ってヒントをくれたんで、それで助かったことは何回もあります。

―すべてを知る男、muraさんが(笑)

freeeの認証認可基盤のすべてを知る男、muraさん
freeeの認証認可基盤のすべてを知る男、muraさん

無事にリリースするための工夫

―壮大なプロジェクトで、リリースする際のプレッシャーも大きかったと思いますが、リリースする際に工夫したことってありますかね?

mura:そうですね、新しい基盤も古い基盤も、落ちてしまえばfreeeの全プロダクトが使えなくなります。会計締めたいのに...と言われても落ちてしまったらどうしようもないので、これはかなりのプレッシャーですよね。そういった中なので、石橋を叩いて渡っていました。

旧認証認可基盤と新認証認可基盤で差分があれば旧認証認可基盤の結果を返せるようにすることで、新しい方はやっぱり開発途中で落ちやすいところもあるので、それを避けるような形にはなっていましたし、手順を踏むというのが一つ重要なポイントだったんじゃないかと思ってます。

もちろん移行の際に何度も何度も停止するようでしたらユーザーさんに大きく影響を及ぼしてしまうので、環境変数の切り替えも無停止で出来るような形をとっていました。会計DBにあったオートインクリメントの最適化を新DBの方で行うという部分は、最後深夜のメンテナンスで切り替えをしたんですが、それ以外は基本無停止やっていました。

―凄いプレッシャーあると言っておきながら、無停止を選ぶという。(笑)ユーザーさんにとってはログインできない状況はかなり困りますからね。環境変数の切り替えも何か対応が必要だったんですか?

mura:基本的にライブラリのところで切り替えるということをしていたので、プロダクトに環境変数を配布するようにしていましたね。基本的にfreeeのサービスはその時点でEKS移行されていたので、環境変数の配布自体はすんなりできますし、何か問題があったとき、エラー数が多すぎて通知があまりにも溜まりすぎるみたいな状況になれば切り戻すってことはすぐにやってましたね。

―呼び出し側は特に意識をせずに開発を進められるし、認証基盤側は自分たちのタイミングで切り替えが出来たということですね。最後のメンテで切り替えというのは、旧DBと新DBのユーザーIDのフォーマットが違うから必要だったのでしょうか?

mura:フォーマットは違わなかったんですけど、基本的に書き込むときに、両方とも同じIDじゃなければいけないという問題があります。元々は旧DBでIDを発番したあとに、その結果を新DBの方にも書き込むという状態で、その順序だと切り替えがちゃんと出来ていない状況なので、新DBで発番して、それを旧DBに書き込んで、両方同期が出来るような状況にしておくというのがオートインクリメントの付け替えの対応ですね。入れ違いみたいになると非常に問題ですので、さすがにそこはメンテナンスを入れました。

モノリスな状態からマイクロサービスへ移行する上で重要なこと

―最初にできたプロダクトに機能が積み込まれ、それを呼び出す機能がどんどん追加されていき、最初のプロダクトに高負荷がかかっていくみたいな流れはスタートアップや新規開発においてありがちなパターンだと思います。いわゆるモノリスな状態からマイクロサービスへの移行で最初にやったほうがいいことはありますか?

mura:今回結構長い期間かかっていてそこの反省点でいうと、物凄いデータのズレが発生したので、古い良くないデータっていうのをちゃんと最初に整理すべきだったなと一つ感じています。

機能も同じですね。機能も移行するにしても、複雑なロジックを新しい方で同じく実装すると工数もかかりますし、古いほうからキレイにするしかないということを考えると、やはりリファクタ、そして正常な状態にしておくことっていうのは、最初に大切になるんじゃないかなと思います。

どうしてもスタートアップだとすぐにプロダクトを出さなくてはいけないというところもあるので、今回の古いアーキテクチャも最初の選択肢としては非常によかったんじゃないかなと思っていて、そのあとにどうやって吸収するかを順序だててやる必要があるんじゃないかと思ってます。基本的に切り分けるということであれば、そのまま切り分けたらそりゃ複雑なのは変わらないので、そこは新しくする前に整理をしておきましょう、というところですね。

プロジェクトを通して経験、成長したこと

―今回の大規模プロジェクトをやり遂げたことでお二人の中で特に成長したと感じる部分はありますか?

cat:私は実は新卒で2020年にfreeeに入社しているんですが、そこで初めてアサインされたプロジェクトがこのプロジェクトでした。

入社する前まではWindowsのローカルで動くゲームとかアプリとか、WindowsAPIを叩いて作るみたいなことをずっと一人でやっていて、サーバーも作ったことはあるんですが、入社してからは一気にリクエストの単位から何から全然違いました。

後は、これまで一人で作ってたけど、会社に入るとチームで同じ大きなコードベースをいじるので、エンジニアとして仕事をしていくにあたって、基礎的な部分は物凄い学びが多い3年間だったなと思っていて、これマイグレーション入れようかと思ったら、そんなマイグレーション入れたらロックで使えなくなるからダメだよ、とか、そういう感覚を養えたり、自分で作ったものが今認証で使われているんだと感じられるのは凄くよかったと思います。

入れ替えがほぼほぼ終わった後に、認証に関わる新機能の開発っていうのも設計から実装からリリースまで担当することが出来たので、それも集大成として、とてもいい経験になったと思います。

今年個人でまたオンラインで遊べるカードゲームみたいなのを作ったんですけど、それもやっぱりそのノウハウが活きてて、テストがちゃんと書いてあるとか、モジュールの責務分離とか、一家言あるっていう状態になったことでほんとにバグが減りましたし、改修したいときにここ変えればいいやってのがすぐ分かるし、デプロイとか修正の差分を見るとかも凄いよくなってて、今とてもいい気分です。

日本史・世界史は怪しいが、メタルギア史なら全部分かるcatさん
日本史・世界史は怪しいが、メタルギア史なら全部分かるcatさん

―すごいいい経験ですね。企業に入ってチーム開発、かつ認証の重要な開発を行ったことで、個人開発にもいい影響があったと。

mura:やっぱり結構長いプロジェクトですし、色んなチームの関わりだったり、チームメンバーも結構多かったので、チーム一丸となってちゃんとリリースできたということ自体がかなりいい経験になったんじゃないかと思っています。

技術的にも、ドメイン駆動開発みたいなところを採用しつつだったので、しっかりと堅牢なサービスを作る能力も高まりましたし、結構そういったリクエスト数も多い状況でしたので、インフラ周りに関する知識もかなりついてきたと思っています。

あとは途中からプロジェクトマネジメントも任せてもらって、そういった意味ではよきメンバーに恵まれて、しっかりサポートしつつ、いかにしてリリースするかの調整だったりとか、他のチームとコミュニケーションをとる力がついたと思います。

―プロジェクトをしっかりやりきって、そのあともちゃんとチームとしていい状態を保ち続けている、しかも実装やりながら。本当にすごいです。

視聴者からの質問

―「旧サーバーと新サーバー両方に読み込み、書き込みをしていて負荷への問題はなかったんですか?何か対策をしていたんですか?」

cat:新システムの方をGo言語で実装していて、gRPCを使っていたというのもあり、パフォーマンスにはかなり気を配って設計していました。

処理時間には気を配っていたので、新システムへのアクセスが普段の利用での追加で増えたからと言って、そこまで重くなるってことは基本ありませんでしたが、何か起きたときのため、例えば事業所の数が増えれば増えるほど重くなりそうなクエリがあるので、1秒経っても新システムが返ってこなかったら途中でやめるっていうのをしてました。なので何か新システムにバグがあって、書けなかったとか読めなかったとか時間がかかってしまった場合でもうまく復旧するようなシステムを中に入れてました。

―なるほど、かなりユーザーさんにとって安全なやり方をとっていたんですね。

cat:はい、かなりバックアッププランを用意していたと思います。

―「もっと早く開発出来た改善点や反省点はありますか?」

mura:小さく出すというのが大事ですね。すべてのプロダクトに対してreadとwriteとセッション基盤の移行をやっていたんですけど、その一通りって言う部分を一部のプロダクトで一通りやる形にしたのが実は大切だったんじゃないかなと思っていて、大きくやっていくと手戻りが発生したりするので、小さくやって、ゴールを小さく持っていく、そしてフィードバックサイクルを回していくっていうところは重要なポイントだったと思います。

―readとwriteを分けて順々に進めていったけど、更にもっと細かくゴールを設定して行った方がよかったんじゃないかなと。具体的な例みたいなのってありますか?

mura:そうですね、基本的に先ほどはAPIの部分でしたけど、データモデルの再返却も実は切り出しとは別であるべきだったというのもあるでしょうね。先に切り出しだけやっておいて、DBが別になったタイミングでデータモデルを解消するというのでもよかったと思います。やっぱり同期する処理が非常に複雑になっていきますし、更に不正なデータを吸収しなければいけなかったので、そこは結構難しいところでした。

―「catさんは新卒で入社して、認証認可のような広範囲に影響範囲がある機能を把握する上で、大変だったポイントなどありますか?」

cat:これは…、大変でした。(笑)新システムのところに2要素認証の機能を入れるというのが一番最初のタスクだったので、そのときはまだそこまで旧システムのロジックを読んでなかったんですね。両方に書き込みを実施することになり、一気にロジックをインプットしたんですけど、自分でまず読んで、とりあえず分からないことがいっぱい出てくるのでそれをメモに書いて、「これはこうなっててこうだと思うんですけど実際のところはどうなんですか?」みたいなことを聞くしかないってことが結構多かったです。このときはGo言語も書いたことはなかったです。

―機能を開発する前に旧サーバーの仕様も知らなければいけない…コミュニケーション力も必要ですね。

cat:はい、多分かなり。最初は特に、どうしても調べないと分からないことが多くて、それでかなり開発スピードが上がらなくて、フィードバックでも何度か指摘してもらって段々意識を変えていって、「これは聞いた方が早いな」とか「これは調べたほうが早いな」と見極められるようになってきてから、ちょっと自信がついてきたかなって感じはあります。

―「ユーザーへのネガティブな影響がないようにするために意識した取り組みはありますか?」

mura:もちろんテストを書くことや、さっきの切り戻しの部分もそうですし、後はQAですね。弊社にはQAの専門チームがいます。認証認可を使用する機能は山のようにあるわけですが、そういったところのシステムテストをちゃんとQAチームの人が色々とヒヤリングして網羅してくれて、当時14プロダクトぐらいあったんですけど、一緒にコミュニケーションとりながらスケジュールをとってすべてテストして、そこで見つかったものもいっぱいあったので、協力して解消するのも大事なところです。

認証認可チームとして今後やりたいこと

―今回の移行が終わって、今後認証基盤としてやりたいことを教えてください。

mura:そうですね、新機能の開発でいえば直近だとメールアドレスがIDとして必須だったのが、メールアドレスのないユーザーさんにも提供することが出来る機能を開発しました。

後はセキュリティ面ですね。認証要素を増やすためにFIDO2を導入したりとか、認証周りの改善を今後ガンガンやっていければいいなと思っています。やはりfreeeはスモールビジネスをやっている方だったり、そうじゃなくて大きな会社のところにも提供しているものですので、広いユーザー層に対していかにセキュリティの高い状況を提供できるか、そしてユーザーさん皆さんに利用していただけるかはユーザビリティの観点で非常に重要となってくるんじゃないかなと思ってます。そういった開発をこのメンバーでしっかりとやっていければいいなと思ってます。

―セキュリティはちゃんと保ちつつ、ユーザビリティもどんどん高めて行くと。

mura:やっていきましょう!

▶今回のイベントのアーカイブ(録画)

www.youtube.com

▶おまけ

今回はfreeeの新オフィスから初めての配信となりました!配信スペースもかなり広くなって機材も一新しており、これからより質の高い配信を目指して頑張っていきます。

freee Tech Night 運営チーム集合写真
freee Tech Night 運営チーム