どうする?マイクロサービスでの認可と認証 後編
2019-10-25
azblob://2022/11/11/eyecatch/2019-10-25-microservice-authorization-part-two-000.jpg

はじめに

以前のブログにおいて、マイクロサービスにおける認証や認可の仕組みの実装の難しさについて説明しました。

モノリシックなアーキテクチャのサービスとは違い、マイクロサービスアーキテクチャではサービスが複数になるので、ユーザー情報や認証情報をどのように持つのかが問題になっていました。

認証に関する同じデータを全部のサービスに持たせると、どれか一つで情報に変更が加えられると残りのすべてのサービスに反映させなければならないのでデータベースの時と同じようにデータの整合性の問題が起きます。

これをどのように解決していけばいいのかについて、今回は解説したいと思います。

David Borsosによる4つのパターン

Javaアプリケーション開発で8年の経験があるDavid Borsosという方が、「Authentication in Microservice Systems」というタイトルでマイクロサービスにおける認証について挙げている4つの方法がこちらの記事で解説されています。

それぞれの方法とメリット、デメリットについて説明したいと思います。

SSOを使う方法

この方法では、内部、または外部のSSOサービスを利用します。

サービスごとにSSOサービスとやり取りし、そのユーザーがログインしているのか、また、どのユーザーなのかといった情報を受け取って認証を行います。

ユーザーがどれかのサービスを使用する際にSSOを通してログインしていれば、残りのサービスにおいても自動的に認証されるため、サービスごとに個別に認証する必要がありません。

O'Reilly本のマイクロサービスアーキテクチャ(以後O'Reilly本と呼びます。)においては、この方法が推奨されています。

しかし、もしもサービスごとにSSOサービスと通信した場合、個々のサービスとSSOサービスがそれぞれで通信を行うことになるので、通信トラフィックがかなり大きくなってしまいます。

一つの対策として、O'Reilly本においてはフロントとサービスの間にAPIゲートウェイを設置し、そこで認証を行う方法が挙げられています。

APIゲートウェイを使用する方法はDavid Borsosも提案していますが(後述)こちらでは認証の仕組みをトークンではなくSSOで持っている点が違いになります。

ただ、そのようにしたとしても、今度はAPIゲートウェイの後ろのサービス群の間でどのように認証や認可を行うかという問題が起きます。

Basic認証やSAML、証明書などを用いる方法などを挙げていますが、どうしても実装する仕組みが複雑になってしまう、ということがO'Reilly本の方では指摘されています。

共有データストアに保存する方法

二つ目の方法は、ユーザ認証に関わるデータを全サービスで共有するデータストアに保存し、マイクロサービスを使用する際はそこから認証情報を引き出すという方法です。

この方法であれば、一つのサービスでログインしていれば、その認証情報を全サービスで使いまわせるので、サービスごとにログインしなければならないこともなくなります。

また、ユーザーのログイン状態が不透明であるという点もメリットとして挙げられています。

しかし、それぞれのサービスはその共有のデータストアにアクセスする必要があります。

そんな状況ででデータストアを不正なアクセスから保護するためには、サービスとデータストアの間のアクセスはセキュアな通信を通して行わなければならなくなります。

これを実装するには、再び証明書の設定等のために実装が複雑になるという問題点があります。

トークンを使用する方法

三つ目の方法は、ユーザー認証にクライアント側で作成されるトークンを使用することです。

認証サービスで認証を行った際に署名されてトークンの作成を行います。

このトークンには認証に必要な情報が含まれており、各サービスにおいては、トークンからユーザー情報を読み出せるか、そのトークンの署名は有効かといったことをチェックして認証を行います。

実装においては標準であり、実装がシンプルでライブラリのサポートが充実しているなどの理由から、JWT(JSON Web Token)を使用することが推奨されています。

一方で、この方法においてはログアウトが難しいといわれています。

特に何もしなかった場合、そのトークンは署名の期限が切れるまでずっと有効になってしまうため、ずっとログインが行えることになってしまいます。

対策としては、署名を失効させる、トークンを短命にするといった方法が挙げられています。

加えて、失効させたトークンをブラックリストに登録し、そのトークンではアクセスできないようにするのも方法として有効です。

トークンとAPIゲートウェイを使用する方法

トークンを使用する方法に加え、APIゲートウェイを実装する方法も挙げられています。

この方法においては、フロントエンドからサービスに接続する間にAPIゲートウェイを通し、そこで認証や認可などの本来個々のサービスで行うはずだった処理を集約して行うようにします。

メリットとして、フロントエンドがサービス群と直接やり取りしないのでサービスが隠蔽されることが挙げられていますが、実装はいくらか複雑になります。

まとめ

今回は、前回のマイクロサービスにおける認証と認可の問題に答える形として、David Borsosが挙げた4つの解決策を解説しました。

ちなみに、Borsosはこの中ではトークンとAPIゲートウェイを使用する方法を推しています。

トークンを用いた実装の容易さと、APIゲートウェイを用いたサービス群の隠蔽を合わせることが、モノリシックアーキテクチャと違って各サービスが分立しているマイクロサービスアーキテクチャにおいて有効であるようです。

今回は認証と認可の問題を扱いましたが、マイクロサービスアーキテクチャを実装するにあたってはモノリシックなアーキテクチャでは起きなかった様々な問題に突き当ります。

しかし、既知のそれぞれの問題にはすでにいくつかの解決策が示されているので、その中から最適な解決策を検討して自分たちのサービスに実装できるようにしましょう。

謝辞

今回も、記事を書くにあたって、「WindowsでNFCタグを扱うには? (Windows nfcpy FeliCa)」の合田さんに執筆のサポートいただきました。

本当にありがとうございました!