OAuth
OpenID
oauth2
openid_connect
dex

はじめに

Go製の OAuth2.0 / OpenID Connect Provider実装である coreos/dex を使ってみたメモです。

基本的に公式ドキュメントのチュートリアル+αの補足説明レベルです。

dexはOpenID ConnectでいうところのOPに相当するサーバですが、IdPの部分は持っていない認証proxy的なものです。
ちなみに同じようにOAuth2.0 / OpenID Connect Provider実装である ory/hydraを使ってみたメモは以下。

ory/hydraで OAuth2.0 / OpenID Connect Provider を立ててみる

インストール

以下の公式チュートリアルに従って、作業します。
https://github.com/coreos/dex/blob/master/Documentation/getting-started.md

go getしてきて自分でmakeします。Goの開発環境の設定などは割愛。

$ go get github.com/coreos/dex
$ cd $GOPATH/src/github.com/coreos/dex
$ make
[dex@master]$ ./bin/dex version
dex Version: fe1516332c4a41aee1dcab66164660676527a36c
Go Version: go1.9
Go OS/ARCH: darwin amd64

dexのバージョン番号がコミットIDになってますが、これを書いてる時点で最新のリリースはdex v2.7.1です。
ちなみにdexはv1とv2でいろいろ変わってるようですが、masterブランチで作業しているのでv2の認識。
v1とv2の違いは以下のドキュメントを参照。

https://github.com/coreos/dex/blob/master/Documentation/v2.md

大きなところで「Local user management」を削除していて、IdPの機能をなくして完全に認証proxyになった印象。ory/hydra よりも bitly/oauth2_proxy のイメージに近くなった気がする。ちなみにoauth2_proxyにも最近OpenID Connect対応が入ったよう。ただ、dexの方はLDAPとかSAML2.0もサポートしているので、もっと守備範囲の広い認証proxy。

起動

デモ用のサンプルのファイルが提供されているので、これを使ってサーバを起動します。

[dex@master]$ bin/dex serve examples/config-dev.yaml
time="2017-10-03T03:22:32Z" level=info msg="config issuer: http://127.0.0.1:5556/dex"
time="2017-10-03T03:22:32Z" level=info msg="config storage: sqlite3"
time="2017-10-03T03:22:32Z" level=info msg="config static client: example-app"
time="2017-10-03T03:22:32Z" level=info msg="config connector: mock"
time="2017-10-03T03:22:32Z" level=info msg="config connector: local passwords enabled"
time="2017-10-03T03:22:32Z" level=info msg="keys expired, rotating"
time="2017-10-03T03:22:33Z" level=info msg="keys rotated, next rotation: 2017-10-03 09:22:33.136007551 +0000 UTC"
time="2017-10-03T03:22:33Z" level=info msg="listening (http) on 0.0.0.0:5556"

デモ用のクライアントアプリを起動します。

[dex@master]$ ./bin/example-app
2017/10/03 14:14:32 listening on http://127.0.0.1:5555

ブラウザでクライアントアプリ http://127.0.0.1:5555 にアクセスします。

image.png

「Login」ボタンを押すとdexサーバにリダイレクトされます。

image.png

「Login with Email」ボタンを押します。

image.png

Usernameに admin@example.com をPasswordに password を入力して 「Login」ボタンを押します。

image.png

認可の同意画面がでてきました。

image.png

「Grant Access」を押します。

image.png

OpenID ConnectのID TokenとClaimsとRefresh Tokenが返ってきた。

Token:

eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyYmQwYThmMjlhZTlhOGQzZmY4ZWNkY2RkZWJlZjA5MjEyYzZhNTAifQ.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjU1NTYvZGV4Iiwic3ViIjoiQ2lRd09HRTROamcwWWkxa1lqZzRMVFJpTnpNdE9UQmhPUzB6WTJReE5qWXhaalUwTmpZU0JXeHZZMkZzIiwiYXVkIjoiZXhhbXBsZS1hcHAiLCJleHAiOjE1MDcwOTQ0NzksImlhdCI6MTUwNzAwODA3OSwiYXRfaGFzaCI6ImNQNEdEYkc0b3M5LVExd2ZEYnVzQ2ciLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJhZG1pbiJ9.Kvtrz_i17jyeAXG9I1q_w1e2d_9zQHxRkY4EYhnD8-VVYVG0UPpOuwKvJ49HzRVE-o4lGwXRUbmkMf5Y_F10wMiIHeUOjYX9A9DwU0qEBtDnH4vJAQs7d1ZQ57Fiwx5wIYee16SvA4f5c980R1AHFjOnnnT8cG90Ab6ZY6pp2co1ogEeKjH0LP9QyP7lYWWwLYZNFoT94SvdazZ151I4_MjkQ6tiLkY3lZeDCOJ5tnHeB-MOV8NtjF1tJwqqJ5PpjB7hRynGSxtCSSQCCTywBfStRbg66Jm66afLxLRsHO9WRhYc46jIjKqq_OQOoljxfHwvcYaPkLynurVsq_8X9A
Claims:

{
  "iss": "http://127.0.0.1:5556/dex",
  "sub": "CiQwOGE4Njg0Yi1kYjg4LTRiNzMtOTBhOS0zY2QxNjYxZjU0NjYSBWxvY2Fs",
  "aud": "example-app",
  "exp": 1507094479,
  "iat": 1507008079,
  "at_hash": "cP4GDbG4os9-Q1wfDbusCg",
  "email": "admin@example.com",
  "email_verified": true,
  "name": "admin"
}
Refresh Token:

ChlmYXZrZDN1Z3lyZTJpeWVlajNod2hlc2h0EhlxZXV5Ymcydnl6Zmw3bWJ6aGxjdjVscW53

dexのv2なのになんでuser/passwordでログインできるんだろう?と思ったら
先ほど使った、 examples/config-dev.yaml に以下のような設定があって、mockでローカルDBで認証してたっぽい。

connectors:
- type: mockCallback
  id: mock
  name: Example

# Let dex keep a list of passwords which can be used to login to dex.
enablePasswordDB: true

所感

  • oauth2_proxy的な使い方にはよさそう
  • OpenID Connect以外にもSAMLとかLDAPとかいろいろ連携した時に前段に挟んでおくと、OpenID ConnectとしてIDトークン発行できるので、APIサーバ側からは統一的に検証できてよさそう。
  • ドキュメントがあんまりないので、分からないことあればコード読むしかない
  • ログイン画面にCoreOSのロゴが出てるんだけど、コードみたかんじWebConfigって言うので差し替えできるように見えるものの、カスタマイズするのはオススメしないというコードコメントがあったりして、社内用ならいいけど、エンドユーザに見せる画面作るつもりならいろいろ制約がありそうで厳しい印象。