BASEプロダクトチームブログ

ネットショップ作成サービス「BASE ( https://thebase.in )」、ショッピングアプリ「BASE ( https://thebase.in/sp )」のプロダクトチームによるブログです。

OIDCって何なんだー?から、実際に使うまで

ごあいさつ

はじめましての人ははじめまして、こんにちは!BASE BANK Divisionのフロントエンドエンジニアのがっちゃん( @gatchan0807 )です。

今回は、ここ数ヶ月の間にOIDC(OpenID Connect)という技術を使った開発を複数行い、この技術の概観を理解することができたので、OIDCの技術概要に触れつつBASE BANKの中でどのように使ったのかをご紹介しようと思います。

OIDCとは何なのか

このパートでは、まずOIDCという技術について概要を紹介します。いくつかのWebページに記載されていた内容を参考にしてまとめさせて頂いているので、記事の最後に参照元のリンクを記載しておきます。

また、OIDCをはじめとした認証・認可の仕組みには様々な用語があり、自分自身も「調べれば調べるほど知らない用語が増えて、どんどんわからなくなってきた…」という経験をしたので、それらを具体例を交えて箇条書きなども用いながらまとめています。もし、明らかに間違ったことを書いている場合はX(旧Twitter)などで適宜ご指摘いただけますと幸いです!

OIDC(OpenID Connect)とは?

OIDC(OpenID Connect)はOpenID Foundationが策定をしている、アイデンティティ情報を連携するためのプロトコルの一種です。

このプロトコルは、Webアプリケーション等で利用する場合はOAuth 2.0(Googleログインなどで使われている「認可」プロトコル)をベースに、アイデンティティ情報を持つサーバー(IDプロバイダ)とサービスを提供するアプリやWebサーバー(サービスプロバイダ)でやり取りする値の中身まで定義しており、「認証」に使えるプロトコルとして定義されています。

この「認証」プロトコルを使ってSSO(シングルサインオン)の機能を実現することが多く、2024年現在では様々なところでOIDCプロトコルに対応した認証機構が用意されています。

ここまでで「認証と認可」や「SSO(シングルサインオン)」など、いくつか専門用語が出てきているので、これらがどういうものなのかおさらいしていきましょう。

認証と認可の違い

  • 認可: ユーザーまたはサービスに、データへのアクセスまたは特定の処理の実行を許可すること
  • 認証: 誰かまたは何かが、主張する通りの人物または物であるかどうかを検証し、特定すること

出典: https://www.onelogin.com/learn/authentication-vs-authorization

OAuth2.0では「認可」を行うための仕組み(認証を実装しようと思えば出来るが、技術仕様上は担保出来ないので非推奨)を定義しています。

例えば、OAuth2.0を使ったGoogleログインなどでは「Googleの画面でログイン→Googleの認可サーバーからアクセストークン発行→Googleのリソースサーバーにアクセストークンを渡してデータを取得」というフローでデータのやり取りが行われています。

ただ、発行されたアクセストークンには「誰のリソースにアクセスしていいか?」という情報しかない(そのアクセストークンを送ってきたのが誰なのかはわからない)ため、何らかの方法でアクセストークンを盗まれると、認可サーバー側で認可した人以外にリソースを奪取されてしまうことになります。

OIDCではこれを防ぐために、「IDトークン」という形の(暗号化・復号化の仕様まで定義された)トークンをやり取りすることで「やり取りをしている相手が誰(何)であるか」を識別し、それを元に適切な権限付与を行えるように技術仕様を定義しています。

OAuth2.0とOIDCの差分を図で説明した画像

[追記: 2024-05-02]

後日、X上にて @pinzolo 様よりご連絡をいただき、図の中の誤っていた部分(「⑤ IDトークンを送信」と記載していた部分)を「⑤ アクセストークンを送信」という形に修正しました! ご指摘いただき誠にありがとうございました!

要求された End-User の Claim を取得するため, Clientは OpenID Connect Authentication を通して得られた Access Token を用いて UserInfo Endpoint に要求する.

引用元: https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#UserInfo

SSOとは

SSO(シングルサインオン)とは「1つのアカウントにログインすることで複数のサービスのログインが可能になる機能」のことです。この機能を実現するために、OIDCやSAML(後述)という技術・プロトコルを利用するという関係性です。

BASE内ではOneLogin(クラウド型ID管理サービスの一つ)を使ったSSO環境を利用しており、Google Wokrspaceなど各種アカウントへのログインをセキュアに便利に利用できるように環境が構築されています。

SAMLとは

SAML(Security Assertion Markup Language)は、XMLベースの認証情報を表現する方法の規格のことです。現在では、そのSAML(XML情報)を送受信して認証を行うルール・プロトコルまで含めてSAMLと表現されることが多いです。

SAML認証では、サービスプロバイダ側からIDプロバイダに対してSAML形式のXMLファイルをあらかじめ登録し、ID情報を「どこから入手するのか・どこに提供するのか」の連携を事前に取っておく形で認証が実現されています

現在主流のSAML 2.0は2005年に仕様が策定され、SSOの機能を作る際のデファクトスタンダードな仕様として使い続けられてきたため、世の中に非常に多くの文献・利用事例などがあります。

しかし、そもそもXMLのパースやそのパース後のデータを利用した通信フローの作成、XML自体の脆弱性の対応が必要だったりして、全体として難解になりがちで、仕様を理想通り実装できれば全く問題ない認証方式だが、現実は実装に問題があって脆弱になってしまうということが起こりがちなものでした。

そのため、SAMLを代替できるようにOIDCが生まれ、利活用されてきている。という背景があります。

SAMLとOIDCの差分を図で説明した画像

SAMLとOIDCの違うところ

以上のように、SAMLとOIDCはどちらもSSOに使われる技術であり、認証を実現するための技術であり、どちらもIDプロバイダとサービスプロバイダとクライアント(ユーザーの端末)が決められた手順で通信を行って認証する技術です。

逆に、差分として以下の2点があり、今回BASE BANKでは「サービスプロバイダ側の実装が簡単になる」というメリットを享受するためにOIDCを使った認証・連携処理を作成しました

  • OIDCはHTTPS通信でデータをやり取りし、JWTという(XMLよりも)単純な文字列をやり取りするため、サービスプロバイダ側の実装が簡単になりやすい
  • OIDCでは、サービスプロバイダ側からIDプロバイダに対して希望するデータのスコープ(範囲)をリクエストできることが仕様として存在しており、クライアント(ユーザーの端末)に対してサービスプロバイダにどのデータが与えられるかを伝えることが容易に実現できる

今回BASE BANKで使ったところ

ここまで、OIDCとそれに関連する技術・キーワードについて紹介をしてきましたが、ここからはその技術を実際どこで使ったの?というところを紹介していきます。

GitHub ActionsからAWSリソースにアクセスし、デプロイする

1つ目のユースケースは、GitHub Actionsを使って、AWS上にある開発環境(ステージング環境とは別に、非エンジニアが動作確認する際やQAを行う時に利用する環境)に対してアプリケーションをデプロイするワークフローを作成する際にOIDCでの認証を利用しました。

BASE BANKチームが主に開発を行っている YELL BANK (BASEのショップオーナーさん向けの資金調達機能)のバックエンドには、APIとして利用するアプリケーションが複数あります。 ざっくりとした技術構成に関しては、BASE BANKチームの紹介資料をご覧ください。

これまではステージング環境での確認で事足りていたため開発環境を使う機会が少なく、本番へのデプロイと同時に(本番との差分をなくすためのデプロイを)CI上で行うだけで問題なかったのですが、この環境をもっと活用していくために開発環境へのデプロイを自由なタイミングでもっと手軽に行えるようにしたい!というモチベーションからこの対応を行いました。

全体の作業の流れとしては、以下のように大きく3つのステップで実現できました。

  1. AWS IAMでOIDC Providerを作成する(このProviderにロールを指定し、AWS リソースへのアクセス許可を行う)
    1. https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_create_oidc.html
  2. GitHub Actionsのステップで aws-actions/configure-aws-credentials を使い、上記で作成したOIDC Providerを指定する
    1. https://github.com/aws-actions/configure-aws-credentials?tab=readme-ov-file#oidc
  3. GitHub Actionsのワークフローを workflow_dispatch から利用できるようにし、GitHub上のActionsタブから利用する(完成!)

より詳しい解説はGitHub Actions公式の解説ページをご覧ください。

docs.github.com

AWS IAMでOIDC Providerを作成する

今回はマネージメントコンソールからOIDC Provider作成する方法を解説します。(AWS CLI経由など他の作成方法はAWS公式ドキュメントをご確認ください)

以下のように、GitHub公式の解説ページに記載されているプロバイダのURL(AWS ⇒ GitHubへのリクエスト先なので、基本的にここはユーザー個別ではない)を設定し、サムプリントの取得の上ID Providerを作成してください。

OIDCのIDプロバイダをAWS IAM上で作成するときの画面のキャプチャ

ID Providerの作成後、IAMロールを割り当てることでAWSリソースにアクセス可能なOIDC Providerが出来上がります。

注意点としては、AWS IAMの管理単位として上述の「プロバイダのURL」に設定したURL単位で1つのIAMユーザーとして扱うため、1つのAWS環境に対してのGitHub ActionsからのOIDC経由アクセスは1つに集約されてしまい、GitHub Actionsのワークフロー / リポジトリごとに「このリソースへのアクセス権限だけ与える」ということは出来ない点だけご注意ください。

作成したIDプロバイダにIAM Roleを設定する時に表示されるポップアップのキャプチャ

GitHub Actionsのワークフローの作成

今回は将来的な拡張も見据えて、以下のような形で workflow_dispatch の input として環境名を受け取れるようにしていますが、基本的にはGitHub公式の解説ページのGitHub Actionsのワークフロー設定を踏襲して実装しています

env:
  dev_id: 123456789012
on:
  workflow_dispatch:
    inputs:
      env:
        description: "deploy env(現時点は dev のみ)"
        required: true
        type: choice
        default: "dev"
        options:
          - "dev"
jobs:
  deploy:
    name: deploy
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
      actions: read
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          # 作成したIAM Role名を指定する
          # see: https://github.com/aws-actions/configure-aws-credentials
          # 例) dev指定のときに env[format('{0}_id', inputs.env)] => dev_idを取り出す
          role-to-assume: arn:aws:iam::${{ env[format('{0}_id', inputs.env)] }}:role/${{ inputs.env }}-oidc-provider
          aws-region: ap-northeast-1

(以降は、各ステップでデプロイに必要なAWS ECRへのコンテナのPushやAWS ECSクラスターへのプロビジョニングコマンドをaws cli経由で実行している)

GitHub上のActionsタブから利用出来るように

上述のYAMLファイルをデフォルトブランチにマージすることで、Actionsタブから以下のように実行することが可能になります。

画面右上のRun workflowから実行時に利用するブランチと環境情報を選択できるので、これでデフォルトブランチ以外のブランチを開発環境に適用することもGUIからかんたんにできるようになりました。

手動デプロイが行えるようになった後のGitHub Actionsの画面のキャプチャ

社内向け管理画面でNextAuthを利用し、OneLoginを使ったSSOを実装する

2つ目のユースケースは、新たに作成する社内向け管理画面のログイン機構にOneLoginを使ったSSOでの認証機構を用意するために、NextAuthでOIDCを利用しました。

NextAuthとは、複雑な認証・認可の処理をラップして提供してくれるJavaScript向けライブラリのAuth.jsの派生ライブラリで、中でもNext.js用にチューニングされたものの名前です。

このNextAuthを使った社内向け管理画面自体はまだ完成していない状態ではありますが、PoCの段階でOIDCでのOneLoginとNext.js製アプリケーションとの連携が問題なく行えることを確認できて、このまま本番投入を行う予定のため、主になぜこの意思決定をしたかをご紹介します。

今回のOneLoginと社内向け管理画面のログイン機構では、OneLoginが提供しているAppの「OpenID Connect (OIDC) Custom Connector」を利用してClient ID / Client Secrets / Issuer情報を発行し、それらの情報をNextAuthのOneLogin Providerの形式に合わせて利用する形を取っています。

このアーキテクチャでの実装(IDaaSやフレームワーク選定)をなぜ選択したのか?をまとめたADR(Architecture Decision Records)があるので、そこから内容をサマライズし箇条書きしたものを以下に記載しておきます

  • なぜクラウド型ID管理サービス(認証IDaaS)はOneLoginを利用するのか?
    • BASE内のSSO環境でOneLoginを使っている事例が複数あるため、それと合わせたSSO環境を利用すると認証、認可情報の管理を効率的に行えると考えたため
  • なぜOIDCの実装でNextAuthを利用するのか?
    • 今回、管理画面を作成するプロダクトのプロダクションコード側は既にNext.jsで実装されており、(フロントエンドメンバーの人数がチームに少ない事もあって)学習すべき技術を分散させないためにNext.jsを利用することにしたため
    • Next.jsを利用する場合、ブラウザ上での実行なのかサーバー上での実行なのかがコード上から判別しづらく、OAuth 2.0(OIDC)の通信ステップをある程度隠蔽して、NextAuthのAPI経由で認証データを取得する方が全体像の理解がしやすいと考えたため
  • なぜOneLoginとの接続方法はSAMLではなく、OIDCを利用するのか?
    • 前述の解説パートの通り、OIDCはSAMLの代替になるようOAuth 2.0の仕様を拡張して定義された認証方法。SAMLに比べるとまだまだ導入事例は少ないが、直近はAWS、GitHub、Azure、GCP等様々な箇所の認証方式として利用されていて、2024年時点でSAMLではなくOIDCでの導入に踏み切っても、問題ないと判断できたため
    • OneLoginからOIDC認証経由で取得できるデータ(claim)の種類も必要十分であることがわかり、取得可能なデータと言う面でもOIDCで問題ないと判断できたため
      • このURL から確認できるJSONの claims_supported の値
  • その他、検討したが選択しなかったこと
    • SDKにAuth0を使うパターン
      • OneLoginと併用する場合、認証IDaaS(SSO提供サービス)が二重( Auth0 → OneLogin )になり、Auth0とOneLoginをSAMLで連携させないといけないため
        • 社内でのAuth0の利用事例はなくゼロから探索をする形になる。そのコストを払うよりもOneLoginを使う方が効率的だと考えたため
      • Auth0のSDKにNext.jsとExpress以外のものはなく、アプリケーションの実装フレームワークをNext.jsにする選択肢(Next.jsへのロックインを避ける方向)としても、特にNextAuthと比べた差分がなかったため
    • NextAuthを使わず、OIDCの通信ステップをフルスクラッチするパターン
      • Next.js上でフルスクラッチでOIDC(OAuth 2.0 + IDトークン)の認証フローを実装するのは、Next.jsがSSRとCSRどちらも活用してアプリケーションを作成するフレームワークである以上、コードの複雑性が高まりやすい。そのため、フルスクラッチ実装 + そのメンテナンスと、NextAuthライブラリのバージョンアップ等のメンテナンスコストを比較したときに後者のほうがコストが低いと考えたため
    • 認証をID/Passwordでフルスクラッチするパターン
      • 入退職者管理、セキュリティ脆弱性を産まない実装、適切なアクセスコントロールを実現するために、OneLoginのSSO基盤の上に乗せる形に比べてコストがかかりすぎると判断したため

おわりに

ここまで、OIDCという技術について関連キーワードも含めた紹介とBASE BANKチームの中でどのように利用したのかを紹介させていただきました。

今回ゼロからOIDCという技術を学びつつ、導入のメリット・デメリットなどを整理していましたが、非常に便利な技術で適宜活用していきたいなと思いました。

このように、新機能開発や新規事業などはもちろんのこと、フルサイクルエンジニアとして計測基盤を盤石にするための開発や開発体験の向上のための開発などなど…様々な開発が少人数で活発に行われているが故に、適切に調査・言語化することで技術選定を任せてもらうチャンスも多いBASE BANKチームにもし興味が湧いた方はぜひカジュアル面談などにご応募いただけると嬉しいです!

gatchan0807としては、一緒にBASE BANKチームのフロントエンドを盛り上げてくれる方をとっても求めています!X(旧 Twitter)のDMやリプライなどでも問題ないので、お気軽にお声がけください〜!

参照したWebページ

最後に、この記事を書くにあたって参照させて頂いたページを紹介してこの記事を締めくくろうと思います。知識を公開情報にしてくださった先人たちに最大限の感謝をこの場でお伝え出来ればと思います。ありがとうございました!