2024.12.10
“放置系”なのにサイバー攻撃を監視・検知、「統合ログ管理ツール」とは 最先端のログ管理体制を実現する方法
認証認可とGoの話@knwoop(全1記事)
リンクをコピー
記事をブックマーク
高橋建太氏(以下:高橋):「認証認可とGo」について説明します。まず自己紹介です。現在Showcase GigのPlatformチームに所属しています。主に認証認可の機能を担当しています。高橋建太です。
週1回会社でGoの知見を共有したり、ドキュメントを読んだり、Goについてみんなで話す緩い勉強会を主催で開催しています。もし合同で勉強会やりたい方がいれば、気軽に連絡してください。ぜひやりましょう。
まず前提知識として、「O:derとは?」について、あらためて説明します。ちょっと内部寄りな説明となり、実際のものは若干スライドの図と異なったりはしますが、「O:der」は、OMO(Online Merges with Offline)とも呼ばれるオンラインとオフラインの融合を実現して、次世代の店舗体験を提供することをミッションとした次世代店舗創出プラットフォームです。
機能としてはおおまかに、テイクアウトや店内飲食、店頭端末決済などを飲食・小売店に提供しています。
図にもあるように、O:der にはさまざまなクライアントの皆さんに導入いただいています。ひとえに導入と言っても、かなり多くのものを店舗で動かすのですが、お客さまが実際にご自身のスマホで操作するプロダクトのみならず、ホールの店員さんが操作する管理画面や注文情報をキッチンに通知して調理状況を管理するキッチン用の管理画面などがあります。
そして、プラットフォーム内部にもたくさんのサービスが存在しています。あくまで一例ですが、キッチンサービスやレストランサービス、メニューサービスなどです。
今日話すところです。今ちょうど僕がスライドの青い部分のO:der ID Serviceを担当しているので、説明します。
そもそも「O:der IDとは?」ですが、O:der IDはO:der におけるDegital Identityというところでやっています。O:der ID Serviceが担っている役割が、大きく分けて3つあります。
まず1つ目は、生産性の向上です。先ほどたくさんのクライアントがいるとお伝えしたと思いますが、登録やログインなど、アカウント関連の機能を汎用的に提供することで、開発の効率化を図るためにやっています。
2つ目は、お客さまとO:der のRelationshipのところです。お客さまは、さまざまなクライアントからO:derにアクセスなどをしてきます。そういったユーザーのデータを1ヶ所に一元管理するためのIdentityを定義しています。
将来的にはメニューのレコメンデーションだったり、アレルギー検知だったり、あと不正利用などもできたらなと考えています。
3つ目は、リソースに対するアクセス制限です。
先ほどのプラットフォームの図の中ですが、例えば管理画面が決済サービスを呼ぼうとする流れがあったとして、これはもちろんやってはいけないので、ちゃんとアクセス制限するのも役割として担っています。
Degital Identityなどについてはけっこう長く語れちゃうので、またどこかの機会で共有できたらと思っています。
マイクロサービスセキュリティの難しいところは、大きく7つあると感じました。
まず1つ目です。攻撃対象の領域が広いほど、攻撃のリスクが高くなるところです。マイクロサービスといえどAPI群ではあるので、いろいろなエントリポイントがあり、エントリポイントの数だけセキュリティホールが存在している感じになっています。そのため、マイクロサービスが増えていけば増えていくほど、その管理がすごく大変だと感じています。
2つ目は、外部リクエストの検証によるパフォーマンスの低下です。よくあるサービスで、セッションサービスみたいなものがあって。そこでユーザーのログインを管理しており、ログイン済みのユーザーが会計を行います。その時のサービスのリクエストのフローは、Payment Serviceからの、Ordering Serviceからの、Delivery Serviceと。
あくまで例ですが、こうなった時に、各マイクロサービスがリクエストごとにセッションを問い合わせなければいけないことで、ネットワークをまたいだリクエストになってしまいます。その分、負荷も上がるし、速度もパフォーマンスも落ちてしまうということで、問題点としてあります。
マイクロサービス間の信頼性の構築です。単純にマイクロサービス同士で認証を行う時は、お互いに鍵を管理したりすると思いますが、マイクロサービスが増えるたびに鍵管理を増やしたりするのが、ちょっとつらいなというところで。
例えばローテーションだったり、有効期限切れだったりは、けっこうつらみではあるかなと考えています。
複数のマイクロサービスにまたがるリクエストの追跡を先ほどのフローを例にたとえると、Payment ServiceからOrdering Serviceのリクエストをした時に、データの欠損や、どのリクエストで失敗したのかが、なにも決めずにやってしまうと、やはりすごく大変だったりします。
サービス認証情報やアクセス制御のポリシーの維持です。というのも、マイクロサービスは、基本的にコンテナでやるのが一般的になっているのかなと思います。
コンテナはイミュータブルなサーバーなので、変更を途中で加えたりはけっこう難しかったりします。そのため、鍵の更新だったり、例えばアクセス制御が変更になった時に、再度デプロイが必要になったりとか。マイクロサービスが増えていけば増えていくほど、デプロイ忘れが出てきたりするのかなと思っています。
分散性によるユーザーコンテキストの共有です。こちらも先ほどの例を使うと、ログイン済みとなっているけれど、管理者などがユーザーをBANしたりロックした時などにも、ちゃんと各リクエストごとにユーザーのステータスを管理しなければいけないのが、やはりすごく大変だったりします。
最後ですが、実装レベルのセキュリティです。マイクロサービスというのは、基本的にはどの言語、技術スタックを使ってもいいとなっているとは思います。ただそれ相応に、ちゃんと同様のセキュリティレベルをちゃんと担保しなければいけないところが、けっこうつらいところではあります。ということで、弊社ではバックエンドにGoを採用しています。
これら問題を踏まえ、僕たちがどうやって認証認可を行っているのかというところで、今やっていることが大きく2つあります。Open ID Connectの実装とSDKの実装です。
Open ID Connectについての説明はちょっと割愛しますが、おおまかには認証と認可と、プラスProfile APIの機能を実装しています。
認証と認可について軽く触れます。認証は、ユーザーやシステムが、“本当にその人なんですよ”という本人性を検証するものです。
認可は、ユーザー、システムに対して、リソースのアクセス権限を与えること。“誰”というのはあまり重要ではないです。
先ほどの例で挙げると、先ほど言った管理画面のユーザーが、Payment Service 使って決済することができないとかが認可にあたります。
どうやっているのかですが、まず各クライアントがOpen ID Connectを利用して、O:der ID Serviceに問い合わせます。O:der ID Serviceは認証画面を提供して、そこでユーザー認証を行い、認可、アクセストークンを返却します。クライアントが受け取ったアクセストークンを使ってマイクロサービスにリクエストを行う流れになっています。
そのアクセストークンですが、中身が署名済みのJWT形式になっています。その中にスコープの値も入っていて、各マイクロサービスはそのスコープを見てアクセスの可否を判断したりしています。各マイクロサービスがアクセストークンの検証を自分自身で行い、都度セッションのチェックなどをしなくていいようになっています。
アクセストークン自体の有効期限はすごく短く、同時にリフレッシュトークンを渡しているので、そこでリフレッシュをしてもらい、また新しいトークンを発行するような流れになっています。署名のためのキーローテーションはここで必須です。
実際のフローです。まずO:der ID Serviceが、各マイクロサービスに対して公開鍵を配布します。
各マイクロサービスはその公開鍵をメモリなどにキャッシュして、アクセストークンが渡ってきたら、各マイクロサービスはアクセストークンを先ほど配布された公開鍵を使って、自身で検証を行うような流れになっています。
SDKの実装です。ここで実装しているのが、キーローテンション機能とアクセストークン検証の機能です。
キーローテーションはけっこう重要だと思っていて、サービスが増えていくことで、やはり鍵の管理がすごく大変になったりします。どのサービスに配布しているのか(の把握)もすごく大変だったり、ローテーションした時に、管理しきれないところがあって、もうすでにつらい状態になっていたり。
署名に使っているトークンの鍵が漏れたりすると、なりすましなど、トークン自体を改ざんすることが可能になってしまいます。そこで、退職した時などの鍵ローテーションでつらみが出てきたりします。
鍵ローテーションの実装を軽く紹介しようと思います。まず、O:der ID Serviceが定期的に鍵をストレージに保存します。Kitchen ServiceやPayment Serviceは、定期的に公開鍵を問い合わせに行きます。
実際のクライアント側の実装ですが、ちょっと見づらいですかね。すごくシンプルですが、main関数などでKey Rotatorを初期化して、その時にアプリケーション起動時に有効な鍵をO:der ID Serviceから取得してきます。
例えば、クライアントがgRPCを使っているのであれば、SDKでgRPCのミドルウェアを提供しているので、gRPCのミドルウェアにKey Rotatorを渡してあげます。最後、下のRun関数の中で、O:der IDにRun関数を実行すると、定期的にO:der ID Serviceに鍵を取得しにいっく実装になっています。
ここでけっこうポイントなのが、errgroupを使って、サーバーと Key Rotator を 並行実行を並行実装をしています。ちょっと書くのは忘れましたが、WithContextを使っているのもちょっとポイントです。
先ほどRotator側のローテートクライアントを初期化したと思いますが、その中にKeyStorageというものがあります。これは単なるmapで、実際のインターフェースはわかりやすいように書いているだけですが、Key valueでPublicKeyを持っていて、Mutexを使って書き込み、読み込みの時にロックを取得するようにしています。
Runの中がどうなっているのかというと、time.NewTickerを使っています。main関数ではerrgroupを使っていたと思いますが、そこでWithContextを呼ぶと、contextのキャンセルを受け取れるようになるので、Runの中で受け取れるようにしています。
for と select を組み合わせて無限ループを行っています。そこで、context と ticker の結果を非同期で受信しています。time.Ticker を使うと、将来の任意のタイミングで処理を実行できます。context を使ってキャンセルを待ちつつも、一定の時間で処理を行うようになっています。
time.NewTickerを使って定期的にintervalTimeを設けて、そこでfetchして鍵を取得していくような実装になっています。
まだいろいろ課題はあります。キャッシュされた古い鍵問題だったり、鍵の取得リクエストが失敗した時のリトライ処理などです。
スライド47今はエラーになっていますが、実際はログに出したり、処理は止めずにログを出したりしています。リファレンスはスライドのとおりになります。
まとめます。マイクロサービスセキュリティはすごく難しくて、やることとが無限にある。まだまだやれてないことがたくさんあります。
認証認可については、Open ID Connectを利用して認証認可を提供しています。各マイクロサービスにSDKの実装を提供して、なるべくセキュリティを担保したものを作ろうと思っています。
ご清聴ありがとうございました。
関連タグ:
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
2024.12.09
10点満点中7点の部下に言うべきこと 部下を育成できない上司の特徴トップ5
2024.12.09
国内の有名ホテルでは、マグロ丼がなんと1杯「24,000円」 「良いものをより安く」を追いすぎた日本にとって値上げが重要な理由
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.12.10
職場であえて「不機嫌」を出したほうがいいタイプ NOと言えない人のための人間関係をラクにするヒント
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.06
嫌いな相手の行動が気になって仕方ない… 臨床心理士が教える、人間関係のストレスを軽くする知恵
PR | 2024.11.26
なぜ電話営業はなくならない?その要因は「属人化」 通話内容をデータ化するZoomのクラウドサービス活用術
2024.12.11
大企業への転職前に感じた、「なんか違うかも」の違和感の正体 「親が喜ぶ」「モテそう」ではない、自分の判断基準を持つカギ
PR | 2024.11.22
「闇雲なAI導入」から脱却せよ Zoom・パーソル・THE GUILD幹部が語る、従業員と顧客体験を高めるAI戦略の要諦