OIDC連携を設定したALBの背後で動かすWebアプリをローカルPC上で開発するためにOAuth2 Proxyで環境構築してみた

ALBのOIDC連携は便利な機能ですが、バックエンドのアプリをどうやってローカル環境で開発すべきか?という課題が残ります。ローカル環境の開発向けにOAuth2 ProxyがALBの代替として利用できないか調査してみました
2021.09.04

CX事業本部@大阪の岩田です。ALBの認証機能はアプリケーションを簡単にOIDC準拠のIdPと連携できる非常に便利な機能です。

単に認証機能を付与できるだけでなく、ALBはバックエンドのターゲットに

  • x-amzn-oidc-accesstoken
  • x-amzn-oidc-identity
  • x-amzn-oidc-data

といったカスタムヘッダでIdPから取得した諸々の情報を送信するため、バックエンドのアプリケーションはこれらのヘッダを参照して様々な処理を実装することができます。ここで課題になるのが、ローカル環境でのアプリケーションの開発です。本番環境と同等の条件でテストをするためには、アプリケーションに上記のカスタムヘッダを渡してやる必要があります。ローカル環境での開発時にALBの代替えとして利用できるツールが無いか探していたところ、社内でOAuth2 Proxyというツールを紹介してもらいました。今回はこのOAuth2 Proxyについて簡単に紹介させて頂きます。

OAuth2 Proxyとは

OAuth2 ProxyはGoogle、GitHub、FaceBookといった外部のIdPと連携して認証機能を提供するGo言語製のリバースプロキシです。GitHubのリポジトリはこちらです。

https://github.com/oauth2-proxy/oauth2-proxy/

元々はhttps://github.com/bitly/oauth2_proxyで開発されていたものを2018/11/27にフォークし、以後も継続的に開発されています

※現在こちらのリポジトリはアーカイブ済みです

現在の最新バージョンは7.1.3で、以下のIdPがサポートされています

  • Google(デフォルト)
  • Azure
  • Facebook
  • GitHub
  • Keycloak
  • GitLab
  • LinkedIn
  • Microsoft Azure AD
  • OpenID Connect
  • login.gov
  • Nextcloud
  • DigitalOcean
  • Bitbucket
  • Gitea

現時点ではα版という位置づけではありますが、アップストリームにリクエストをプロキシする際にリクエストヘッダー/レスポンスヘッダーを加工する機能も持っているため、ローカル環境でALBの代替えとして利用できそうな雰囲気を感じます。

https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/alpha-config

OAuth2 Proxyを使ってローカル開発環境を構築してみる

ここからは実際にOAuth2 Proxyを使ってローカルの開発環境を構築していきます。

今回は

  • ローカルマシンの80ポートでOAuth2 Proxyを稼働させる
  • OAuth2 Proxyは公開されているDockerイメージを利用する
  • アップストリームとして設定するWebアプリはローカルマシンの8080ポートで稼働させる
  • OAuth2 ProxyはGoogleとの連携を設定し、Google認証済みの場合だけアップストリームにプロキシする
  • OAuth2 ProxyからアップストリームのWebアプリにプロキシする際にX-AMZN-OIDC*系のリクエストヘッダを追加で付与する

という環境を作ります

Googleの認証情報を準備

まずは以下のURLからGoogleの認証情報を作成します。

https://console.cloud.google.com/apis/credentials

「認証情報」から「認証情報を作成」をクリックし、「OAuthクライアントID」を選択します

続いて以下のように入力します

  • 「アプリケーションの種類」に「ウェブアプリケーション」を
  • 「名前」は適当にわかりやすいように名前を設定
  • 「承認済みのリダイレクトURI」はhttp://127.0.0.1/oauth2/callback
    • ※今回OAuth2 Proxyをローカルマシンの80ポートで起動するため

作成できたらクライアントIDとクライアントシークレットが発行されるため、これらの情報を控えて下さい。後ほどOAuth2 Proxyの設定に利用します。

OAuth2 Proxyの設定ファイルを準備

Googleの認証情報が準備できたので、今度はローカル環境でOAuth2 Proxyを起動する準備をしていきます。前述の通り今回はDockerを使って環境を構築していきます。

OAuth2のリポジトリで公開されているサンプルの設定を加工しつつ設定を作っていきます。

https://github.com/oauth2-proxy/oauth2-proxy/tree/master/contrib/local-environment

まずはdocker-compose.yamlです

version: '3.0'
services:
  oauth2-proxy:
    command: --config /oauth2-proxy.cfg --alpha-config /oauth2-proxy-alpha-config.yaml
    volumes:
      - "./oauth2-proxy-alpha-config.cfg:/oauth2-proxy.cfg"
      - "./oauth2-proxy-alpha-config.yaml:/oauth2-proxy-alpha-config.yaml"
    image: quay.io/oauth2-proxy/oauth2-proxy:v7.1.3-arm64
    ports:
      - "80:80"

imageにはquay.io/oauth2-proxy/oauth2-proxy:v7.1.3-arm64を指定しています。前述の通りアップストリームにリクエストを転送する際にリクエストヘッダを加工する機能は現在α版という位置付けで、設定の書き方も現在進行系でどんどん変わっています。今回紹介する設定はバージョン7.1.3でしか動作しない可能性が高いので、イメージのタグでv7.1.3までしっかり指定しましょう。

volumesではoauth2-proxy-alpha-config.cfgoauth2-proxy-alpha-config.yamlという2つの設定ファイルを指定し、コンテナ内にマウントします。commnadに指定した--command--alpha-configでこれらの設定ファイルが読み込まれます。

続いて設定ファイルoauth2-proxy-alpha-config.cfgです。こちらはtoml形式です

email_domains="<適当なドメイン もしくは*>"
cookie_secret="<適当なシークレット>"
redirect_url="http://127.0.0.1/oauth2/callback"

設定内容は以下の通りです

  • email_domains
    • ここで指定したドメインに一致するメールアドレスのみOAuth2 Proxyの認証を通過できます。例えば、email_domainsexample.comが指定されていた場合、hoge@gmail.comというメールアドレスはGoogle認証済みでもOAuth2 Proxy側で403エラーが返却されます
  • cookie_secret
  • redirect_url
    • IdPの認証後にリダイレクトさせるURLです。OAuth2 Proxyのデフォルト設定だと/oauth2/callbackといるURLが利用されます。今回はローカルPCの80ポート上でOAuth2 Proxyを起動するのでhttp://127.0.0.1/oauth2/callbackを設定します。

続いて設定ファイルoauth2-proxy-alpha-config.yamlです。こちらはYAML形式になります

injectRequestHeaders:
- name: x-amzn-oidc-identity
  values:
  - claim: user
- name: x-amzn-oidc-data
  values:
  - claim: id_token
- name: x-amzn-oidc-accesstoken
  values:
  - claim: access_token
providers:
- approvalPrompt: force
  clientID: <Google側で発行したクライアントID>
  clientSecret: <Google側で発行したクライアントシークレット>
  id: google
  oidcConfig:
    emailClaim: email
    groupsClaim: groups
    insecureSkipNonce: true
    userIDClaim: email
  provider: google
server:
  BindAddress: :80
  SecureBindAddress: ""
  TLS: null
upstreams:
- flushInterval: 1s
  id: /
  passHostHeader: true
  path: /
  proxyWebSockets: true
  uri: http://host.docker.internal:8080/

設定箇所のいくつかを抜粋して紹介します

injectRequestHeaders

ここで追加するリクエストヘッダが設定可能です。ALB環境をシミュレーションするためにX-AMZN-OIDC*系のヘッダを定義しています。

  • x-amzn-oidc-identity
    • ALBがUserInfoエンドポイントから取得した subを設定するヘッダです。OAuth2 Proxyでの設定はsubではなくuserを指定します。
  • x-amzn-oidc-data
    • ALBがJWT形式でユーザークレームを設定するヘッダです。JWT形式ですが、IDトークンではありません
    • 現状OAuth2 Proxyでの設定ではALBと同様のクレームを設定できないので、IDトークンを設定することで代替えとしています。ALB環境と完全に同等にはなりませんが、これである程度互換性を担保できます。
  • x-amzn-oidc-accesstoken
    • ALBがトークンエンドポイントから取得したアクセストークンを設定するヘッダです。OAuth2 Proxyでもaccess_tokenを指定することで、リクエストヘッダに追加可能です。

OAuth2 Proxyが管理するセッション情報からどういった値が設定できるか(claim:xxxxのxxxx部分)の詳細はパっと見る限りドキュメントに記述されていなさそうだったので、ソースコードを確認しながら設定してみました。恐らくこの当たりを見れば詳細が分かりそうです。

https://github.com/oauth2-proxy/oauth2-proxy/blob/16a9893a19dfe832a1acc72af70b27d0150caa7f/pkg/apis/sessions/session_state.go#L127

providers

ここにはIdPとの連携に関わる項目を設定します。clientIDclientSecretにそれぞれGoogle側で発行したクライアントID、クライアントシークレットを設定します

upstreams

uriにはアップストリームのURIを指定します。今回はOAuth2 Proxyをコンテナとして起動して、ローカルPCの8080ポート上で動作するアプリケーションにプロキシする構成なので、host.docker.internalの8080ポートを指定しています。

ローカル環境でOAuth2 Proxyを起動してみる

準備ができたので、実際にOAuth2 Proxyのコンテナを起動して動作確認してみます。

docker-compose -f docker-compose-alpha-config.yaml up

まずはトップページにアクセス

「Sign in with Google」と表示され、Google認証で保護されていることが分かります。

「Sign in with Google」をクリックしてGoogleにログインします

ログイン完了すると、数回のリダイレクトを経たのちにアップストリームから返却されたコンテンツが表示されます。

今回アップストリームのアプリケーションとしてPHPでprint_r($_SERVER)するだけの簡単ものを利用しています。画面にHTTP_X_AMZN_OIDC*のヘッダが表示されており、ALBと同等の環境がシミュレーションできていることが分かります。

まとめ

OAuth2 Proxyを利用してOIDC連携を設定したALBの環境をシミュレーションしてみました。リクエストヘッダのx-amzn-oidc-dataに関してはALBがユーザークレームを設定しているところをIDトークンで代替しているため完全な再現とは言えませんが、ローカル環境でアプリケーションを開発する上では支障の無いレベルでシミュレーション出来ているのではないでしょうか?

OIDC連携を設定したALBの背後で動かすWebアプリをどうやってローカルPC上で開発しよう?とお悩みの方は一度OAuth2 Proxyの利用をご検討下さい。