MICINのID基盤の取り組み
この記事は MICIN Advent Calendar 2023 の 20 日目の記事です。
昨日は小野さんの「SREチームの今までとこれから」でした。
はじめに
プラットフォームチームに所属している酒井です。
プラットフォームチームでは、プロダクト横断的に利用される機能の開発・運用をしており、私が担当する「ID基盤」は、 MICIN のプロダクトを利用していただいているユーザーのアカウント情報の管理や認証機能を提供しています。
ID基盤のプロジェクトは、2021年の終わり頃に、プラットフォームチームの立ち上げと共に始まりました。
気がついたら二年くらい経っていたので、これまでの変遷や、プロジェクトを進めるに当たって考えたこと、うまくいったこと、いかなかったことなどを思い出しながら書いています。
具体的な技術の話は少なめで、抽象的な話が多くなってしまいそうですが、ご一読いただければ幸いです。
MICIN におけるID基盤
ID基盤は、 MICIN のプロダクトの中では、オンライン診療クロン、クロンお薬サポート、クロンスマートパスで利用されています。
オンライン診療クロンでログインをしようとすると、次のような id.curon.co
ドメインのサイトが表示されるようになっていて、これがID基盤のサイトです。
1つのユーザーアカウントで MICIN が提供する複数のプロダクトが利用できます。例えば、クロンスマートパスを利用する時に作成したユーザーアカウントは、オンライン診療クロンを使う際にも同じようにログインに使えます。
MICIN のプロダクトは、基本的に患者と医療機関の双方にアプリケーションを提供します。それぞれで独立したアカウント管理をしており、ID基盤も、患者向けID基盤と医療者向けID基盤が存在します。
アカウント管理の課題とID基盤の立ち上がり
2021年にプロジェクトを開始するまでは、プロダクトチームがそれぞれユーザーアカウント関連の機能を作っていて、そこには3つの課題がありました。
1つ目は、開発効率です。ユーザーアカウントに関連する機能としては、ログインはもちろん、ユーザーアカウントの登録、プロフィール情報の変更、メールアドレスの変更、アカウントリカバリーなど意外と様々あります。これらの機能をそれぞれのプロダクトチームで開発・運用するのは、単純に効率がよくありません。例えば、UXやセキュリティの向上のために新しい認証方法を追加したいとなった場合に、同じ実装をそれぞれのプロダクトに展開して回る必要があります。
2つ目は、セキュリティです。機微な情報を扱うプロダクトを開発する立場として、認証関連の機能の実装が分散するのは、管理の上であまり望ましくないように感じていました。専門の知見を持ったチームが注意深く設計し、堅牢な実装を提供するべきです。
3つ目は、データの一元管理です。MICIN のプロダクト群のユーザーのアカウントをプロダクトごとにバラバラに管理するのでなく、1つのエンティティとして正しく管理できる基盤を作り上げたいと考えています。その基盤のもとに、 MICIN のプロダクトがプラットフォームとして拡がりをみせ、ユーザーの方にシームレスな体験を作っていきたいと思っています。
これがまさに課題となったのが、クロンスマートパスのプロダクトの立ち上げのときです。クロンスマートパスは対面診療の際に利用できる決済サービスですが、オンライン診療クロンやクロンお薬サポートのユーザーアカウントを使ってサービスを利用できるようにしたいというのが、プロダクトとして重要な要求事項でした。
そういった経緯の元、クロンスマートパスの開発とともに、プラットフォームチームを立ち上げ「ID基盤」という概念を作っていくこととなります。
ID基盤の設計
私はそれまでID基盤と呼ばれるものの開発をしたことはなく、どのように作ったら良いのか、そもそもID基盤とはどういうものなのかというイメージもあまり湧いていませんでした。
幸いチームの PdM が以前の会社でID基盤に深く携わっていたこともあり、彼と議論をする中で、ID基盤というもののイメージが少しずつ明瞭になっていきます。また、各企業の事例や、認証関連技術のブログを読み漁ることで、理解も深まりました。
ちょうど Digital Identity技術勉強会のAdvent Calendar に「デジタルアイデンティティの仕事をはじめたらやるべき7つのこと」という記事が上がっていたのですが、この中に名前が上がっている方々のブログ記事などはとても参考にした記憶があります。
特に初期の設計では、次のようなことを意識していました。
二種類のログイン連携
異なるサービス間で認証情報を連携するプロトコルとしては、 OpenID Connect (以降 OIDC )が一般的でしょう。
私たちのID基盤では、 OIDC に準拠したログイン連携も提供していますが、 UX 上の要求から OIDC とは異なる独自の「Cookie によるログイン連携」の方式も提供しています。特に初期は後者の方式のみを提供していました。
私たちのプロダクトでは、プロダクトをまたいでシームレスな UX を実現したいケースがあります。例えば、クロンスマートパスで医療機関での決済をして、そのままクロンお薬サポートを使い、薬局でお薬を受け取る、といったことが行えます。その際に、プロダクトごとに再認証が必要になってしまうのは、あまり望ましくありません。
そのため、そのような場合は Cookie を用いて、同一のドメインの元では認証情報を共有できるようにしています。
まとめると次のような使い分けをしています。
- OIDC によるログイン連携: ネイティブアプリや、
curon.co
以外のドメインで提供されるプロダクト - Cookie によるログイン連携:
curon.co
ドメインで提供されるプロダクト
基盤とプロダクトの境界を意識する
Cookie によるログイン連携でも、 OIDC のフローやそのインターフェースはとても参考になりました。
OIDC では、 IdP/RP といった異なるロールがあります。 Cookie によるログイン連携の方式でも同様に、ID基盤が IdP として振る舞い、プロダクトが RP として振る舞うようなモデルを意識しています。
ID基盤とプロダクトとでは、明確にアプリケーション(サイト)を分離しています。プロダクトでは、ユーザーにログインを行なって欲しい場合は、ID基盤の決められた認証エンドポイントにパラメータを付与して遷移させます。ID基盤の上でユーザーがログインを完了すると、ユーザーはプロダクトのサイトに戻ってきます。これは OIDC のフローと同じ形をとっています。
認証エンドポイントの URL とパラメータの組み合わせをID基盤とプロダクトの間の取り決めとするシンプルで疎な形になっています。
具体的には、プロダクトは次のような形式の URL にユーザーを遷移させるだけで、ログイン処理がID基盤に委譲されます。
/signin?client_id=[プロダクト固有のID]&redirect_uri=[ログイン完了後の遷移先]
開発を進めるにあたっては、はじめに Design Doc を手厚目に書き、なるべく設計意図を言語化するようにしました。ID基盤でのとプロダクトの間にはどのようなインターフェース持つのかといったことについても詳細に定義し、ドキュメントに書き起こしました。これは、チームやチーム外への共有の意図もありますが、自身が実装を進めていく中で迷った時も立ち戻る場所ができ、なるべく一貫した実装を行う助けになったのかなと感じています。
プラットフォームチームとプロダクトチームの距離は近く、お互いに密にコミュケーションをとりながら進められる関係性ではあるのですが、仕様や実装の上では、どこが境界線となるのかを意識しています。
移行の戦略
前項の通り、ID基盤のフロントエンドアプリケーション(サイト)はプロダクトと分離されています。一方、バックエンドはオンライン診療クロンやクロンお薬サポートと同じモノリシックな Rails アプリケーションに実装されています。
バックエンドも含めて、初めから綺麗に分離しようと考えたこともあったのですが、既に多くのユーザーデータと、それを参照する既存のプロダクトのコードがあります。それらを短期間で安全にAPI呼び出しに書き換えるのは困難なことや、開発環境も複雑になり、短期的な開発の生産性は落ちてしまうのではないかと考え、それは行わない方針としました。
まずは、ID基盤のフロントエンドさえ分離され利用できるようになっていれば、プロダクト側は認証機能をID基盤を使うように移行してもらうことは可能です。
プロダクト側の移行作業を進めつつ、バックエンド内部については、リファクタリングという形でID基盤とプロダクトのデータや機能の境界を徐々に明確にしていく作業をしました。
いわゆるモジュラモノリスと呼ばれるような形に作り変えています。
初めは、エンドポイントとネームスペースを分けるところから始まり、直近では packwerk を導入しました。プロダクト側からは、決められたインターフェースを通してのみID基盤のデータや機能にアクセスできるような制約を加えようとしています。
現在、ID基盤は3つのプロダクトから利用されていますが、他の MICIN のプロダクトや、さらには社外のプロダクトから利用される未来も想像しています。
いずれは、今よりレベルの高いセキュリティ要件や SLO が求められることもあるのではないかと考えています。そうなった場合は、モノリスから分離した方が良いという判断になるかもしれないですが、決められたインターフェースを通してID基盤が利用されるような形に整理しておくと、その分離も安全に行えるのではないかと目論んでいます。
これから
プロダクトチームの協力もあり、当面の目標であった3つのプロダクト(オンライン診療クロン、クロンお薬サポート、クロンスマートパス)にID基盤を統合ほぼ完了したと言える状況までくることができました。
これからは、次のような取り組みを進めていきたいと考えています。
PassKeys
ユーザーの方には、セキュアでありながらも、シンプルでわかりやすいログインの体験を届けたいと考えています。
それを実現するための一つの強力な手段が PassKeys であり、世の中のプロダクトでも採用されるケースが増えてきていると思いますが、 MICIN のID基盤でも導入に向けて検討を進めています。
これまでは、なんかごちゃごちゃしたものを何とか整理していく、というところに多くのエネルギーを割いてきましたが、より先進的な技術の取り組みも行えるチームとなっていけると良いなと考えています。
医療機関アカウントの基盤を作る
これまで、患者の方や医療者の方といった「個人」の管理をする基盤としてID基盤の話を書かせていただきました。私たちのチームのもう一つのターゲットとして、「医療機関」というエンティティを正しく管理できるようにしたいと考えています。
「患者アカウント」「医療者アカウント」「医療機関アカウント」という3つのエンティティを扱う基盤を提供するチームとして、社内では、ID基盤チームではなく「アカウント基盤チーム」という名称を使っています。
例えば、ある医療機関で複数の MICIN のプロダクトをご利用いただくとなった場合でも、利用料の請求が一元的に管理されており、所属する医療者の方の権限も一つの画面で設定できるような世界を作りたいと思っています。
現在は、そういった機能がそれぞれのプロダクトごとに実装されているケースも多いのですが、これを基盤として提供できるようにしていきたいと考えています。
「組織管理」「請求管理」といった機能群を提供することになると思うのですが、例えば認可処理をどのように実現するかなど技術的にも面白いトピックになるのではないかと思っています。
取り組みから感じたこと
最後に、ID基盤のエンジニアとしてこれまで取り組んできて、個人的に感じていることを瑣末ですが書いておきます。
プラットフォームチームに所属する以前は、一つのプロダクトのアプリケーションエンジニアであったわけですが、個々のプロダクトだけではなく、会社としてどういった世界を作りたいのか、どういった「構造」を作りたいのか、といったことを頭の片隅におきながら開発するというのは良い経験となりました。
あまり確実な未来もない中で、中長期の技術的な判断をしなければならないこともあり、不安も結構あるのですが、そのような中で助けとなるのはチームで議論し合える土壌があることです。プラットフォームチームでは、定期的にオフサイトを開催しており、その中でお互いが思い描いているものを擦り合わせることができていて、これは良いカルチャーだなと感じています。
一足飛びに先に進むことはできず、一つずつ確実に変えていくしかなく、一方でそういったところも現実のプロダクトに向き合っている気がしていて、個人的には結構好きです。
また、技術観点では、それまでは認証関連の技術を深く学ぶ機会は多くなかったのですが、 OIDC をはじめ様々な Web の技術に触れることができ、エンジニアとしての好奇心も満たされています。
まだまだやるべきこと・やりたいことは多くありますが、来年も頑張っていこうと思います。
MICINではメンバーを大募集しています。
「とりあえず話を聞いてみたい」でも大歓迎ですので、お気軽にご応募ください!
Discussion