複数のホストをoauth2_proxyを用いてOAuth認証してリバースプロキシする
2018/02/19
累計閲覧数 1190 PV
oauth2-proxy(旧名 oauth2_proxy)を複数のリバースプロキシ先に対応させた、 サンプル(Himenon/oauth2_proxy)を作成した紹介です。
たとえば、
などなど、対外向けのサービスで使うというより、内部向けのアプリや、情報を保護するための用途で使えます。
(読み飛ばして大丈夫です。)
Cookpad Tech Conf 2018でChallenges for Global Service from a Perspective of SREの発表で、 認証周りの業務が増えてがつらく、それをnginx側でoauthをproxyさせること脱Basic認証をし、管理するアプリケーションが増えても柔軟に対応できるようにした、 と聞いた際に自分でもやってみようと思ったことが発端です。
Coockpadさんの記事もありますので、これ以上はそちらを読んで下さい。
僕自身もBasic認証つれぇ、モダンにやりたい、って思ってたのでちょうどいいと思ってたところだったので、 その辺のツール落ちていないか、というところから探してみました。
そして、出会ったのがoauth2_proxy。 色んな人がメンテナスしている + スター数が3k超えってところで使ってみようと思いました。
日本語の記事を調べたところ、割と最近(今が2018/2なので)の記事も発見できました。
他にも次のコードも発見しました。
ただ、欲しかった情報が
だったので、どれも満たしていなかったので自分で作ることにしました。
難しいことはしてませんが、以下の2点が他と異なるので、ここで取り上げます。
また、以下では冒頭のアーキテクチャ図にある名称で説明します。
Providerのredirect_urlsを複数指定すること。 コード風にかくと、
redirect_urls = [
'server-a.example.com',
'server-b.example.com'
]
と言った具合です。
Providerによっては複数の入力欄があったり、カンマ区切りで入力したりさまざまなので、
そこは個々の入力方法を確認して下さい。
実行ファイル、google_auth_proxy
がとる引数で--cookie-domain
があるのですが(この部分)、
ここをサブドメインを含めずに書きます。
つまり、--cookie-domain=example.com
とし、server-aでもserver-bでも同じCookieを利用するようにします。
このようにすることで、CORSがコケることなく、複数のサブドメインで認証できます。
無論、この手は普通やらないと思いますし、何が起こるかわからないので、
実際のサービスとしては使ってはいけません。
これは、内部向けだったり、用途が限られた空間内でBasic認証などによる不必要な認証管理をするための1手段としては有効なので、
このProxyを噛ませるアプリケーションの公開範囲をキチンと管理できた上で利用するならば有効な手だと思います。
Cookie Domainを明確に単一にすることが現状の課題です。 これは2つのことを解決します。
1つ目は先に上げたCORSの問題です。
例えばproxy.example.com
のように、現状の*.example.com
よりも狭い範囲でCookieが利用されている方が
サブドメインで分けられた、他のアプリケーションが不必要なCookieをロードする必要がなくなります。
2つ目は、redirect_urlsの問題です。 一見、問題がなささそうに見えますがそうではありません。 redirect_urlsはどこに・誰が登録しますか? リバースプロキシする対象が増減たびに、Providerのredirect_urlsを更新する必要があります。
これはオペレーションミスの可能性を含んでいますし、 実装者はnginxの調整以外に、Providerの管理者に更新依頼をするというプロセスが増えてしまいます。
理想のフローは次のような手順です(ざっくり)
<div className="mermaid"> sequenceDiagram Browser->>Nginx: request(a.example.com) Nginx->>oauth2_proxy: proxy(proxy.example.com/oauth2/auth) oauth2_proxy->>Provider: request Provider->>Nginx: response(redirect: proxy.example.com) Nginx->>Backend: Reverse Proxy (a.example.com) </div>これが解決できたらまた更新しようと思います。