【Auth0】Auth0+Apache(mod_auth_openidc)でシングルサインオンしてみる

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは植木和樹@上越妙高オフィスです。いろいろなユースケースでAuth0を使ってみています。前回はWordPressにAuth0プラグインをインストールして、ユーザー認証を行ってみました。

今回はApacheからAuth0を扱ってみたいと思います。ApacheとAuth0を組み合わせることで、たとえば社内システムを外部アクセスから保護するためのBasic認証の代わりにAuth0を使ったアクセス制限として利用するということが可能になります。またApacheをリバースプロキシ−として用いれば、Auth0を扱うことが(アプリの改修コストなどで)難しい場合にも最低限のアクセス制限をかけることが可能になるかと思います。

20170103_mod_auth_openidc008

mod_auth_openidcのインストール

Auth0のドキュメントによるとApacheからAuth0を扱うにはmod_auth_openidcというOpenID Connectモジュールリが必要なようです。なお似たような名前でmod_auth_openidというモジュールがありますが別物なのでご注意ください。

Ubuntu/RHEL/CentOSであれば Github pingidentity/mod_auth_openidcからdebやRPMファイルを入手して簡単にインストールすることができるようです。ただ今回はAmazon Linux(2016.09)を利用するため、依存ライブラリの関係でRPMがインストールできませんでした。

とういわけでソースを落としてきてコンパイルしてみることにします。

インストールを簡素化したり今後ライブラリのアップデートした時の保守性をよくするためにも、ソースからのビルド・インストールはお勧めしません! ちゃんとRPMファイルを作成して保守するようにしましょう。

必要パッケージをインストールする

mod_auth_openidc のINSTALLマニュアルによると下記ライブラリが必要になります。Redisサポートは不要なのでhiredisは使いません。

  • Apache (>=2.0)
  • cjose (>=0.4.1)
  • OpenSSL (>=0.9.8) (>=1.0.1 for Elliptic Curve support)
  • Curl (>=?)
  • Jansson (>=2.0) (JSON parser for C)
  • pcre3 (>=?) (Regular Expressions support)
  • pkg-config

mod_auth_openidc/INSTALL at master · pingidentity/mod_auth_openidc

コンパイルするために、gccやautoconf、automakeといったコマンドもインストールしておきましょう。janssonはepelリポジトリにありました。またcjoseはこの後にソースからコンパイルします。 (今回は動作検証を行うためにPHPもインストールしていますが mod_auth_openidc の動作には不要です)

sudo yum install autoconf automake gcc httpd24 httpd24-devel libcurl-devel openssl-devel pcre-devel -y
sudo yum install php56 -y
sudo yum install --enablerepo=epel jansson jansson-devel -y

インストールされたバージョンは下記の通りです。

  • Apache 2.4.23
  • openssl-1.0.1k
  • curl-7.47.1
  • jansson-2.9-1
  • pcre-8.21
  • pkgconfig-0.27.1

cjose をコンパイルする

からcjose-0.4.1.tar.gzをダウンロードしてコンパイルします。ライブラリは/usr/lib64にインストールしてpkg-configから見つけられるようにしています。

$ curl -OL https://github.com/pingidentity/mod_auth_openidc/releases/download/v2.1.3/cjose-0.4.1.tar.gz
$ tar xvzf cjose-0.4.1.tar.gz
$ cd cjose-0.4.1
$ ./configure --prefix=/usr --libdir=/usr/lib64
$ make
$ sudo make install

mod_auth_openidc をコンパイルする

cjoseと同様 Releases · pingidentity/mod_auth_openidc からSource code (tar.gz)v2.1.3.tar.gz)をダウンロードしてコンパイルします。

$ curl -OL https://github.com/pingidentity/mod_auth_openidc/archive/v2.1.3.tar.gz
$ tar xvzf v2.1.3.tar.gz
$ cd mod_auth_openidc-2.1.3
$ ./autogen.sh
$ ./configure --prefix=/usr
$ make
$ sudo make install

Auth0 Client設定

mod_auth_openidcモジュール設定の前に、ApacheからAuth0へ接続するためのClient設定を行います。

Auth0のダッシュボードからClients - CREATE CLIENTをクリックすると新規クライアント作成画面が開くので、クライアント名を入力し、Client TypeとしてNon Interactive Clientsを選択してCREATEします。

20170103_mod_auth_openidc001

Clientが作成できたらSettingsタブからClient ID, Client Secretをメモしておきましょう。またAllowed Callback URLsには、Auth0での認証完了後に戻したい先のURLを記入します。

20170103_mod_auth_openidc002

認証ソース(Connections)は前回同様Google Apps認証のみを利用することにします。

20170103_mod_auth_openidc003

mod_auth_openidcの設定

最後にmod_auth_openidcモジュールの設定を行います。サンプルの設定は下記ページからコピーできます。

/etc/httpd/conf.d/openidc.conf

LoadModule auth_openidc_module modules/mod_auth_openidc.so

OIDCProviderIssuer https://<your-auth0-account>.auth0.com
OIDCProviderAuthorizationEndpoint https://<your-auth0-account>.auth0.com/authorize
OIDCProviderTokenEndpoint https://<your-auth0-account>.auth0.com/oauth/token
OIDCProviderTokenEndpointAuth client_secret_post
OIDCProviderUserInfoEndpoint https://<your-auth0-account>.auth0.com/userinfo

OIDCClientID < your-client-id >
OIDCClientSecret < your-client-secret >
OIDCProviderJwksUri https://<your-auth0-account>.auth0.com/.well-known/jwks.json

OIDCScope "openid name email"
OIDCRedirectURI https://example.com/protect/redirect/
OIDCCryptoPassphrase hogehoge
OIDCCookiePath /

#SSLはELBでTerminationするのでコメントアウトします
#SSLEngine on
#SSLCertificateFile /home/your_cert.crt
#SSLCertificateKeyFile /home/your_key.key

<Location /protect/>
   AuthType openid-connect
   Require valid-user
   LogLevel debug
</Location>

OIDCClientID, OIDCClientSecretにはAuth0のSettingsページでメモしておいた文字列を書きます。またOIDCRedirectURIにはAllowed Callback URLsで記入したURLを入れましょう。

設定ファイルを保存したらhttpdをリスタートしておきましょう。

$ httpd -t
Syntax OK
$ sudo service httpd restart

動作確認

ブラウザでサーバーにアクセスしてみます。が、その前にどんなリクエストがやりとりされているのか見てみたいのでphpinfo()を出力するページを用意します。

$ sudo -s
# echo '<?php phpinfo() ?>' | tee -a /var/www/html/index.php
# mkdir -p /var/www/html/protect/redirect
# cp -p /var/www/html/index.php /var/www/html/protect/
# cp -p /var/www/html/index.php /var/www/html/protect/redirect/

ブラウザでサーバーにアクセスしましょう。 https://example.com/ トップページはアクセス制限をかけていないので認証なしで表示することができます。

20170103_mod_auth_openidc004

次に保護されたURLにアクセスしてみます。 https://example.com/protect/ するとAuth0のログインぺージにリダイレクトされます。Google Appsによる認証を選択します。

20170103_mod_auth_openidc005

20170103_mod_auth_openidc006

認証が完了すると元々アクセスしていたパス /protect/ を表示することができました! Apacheの変数にOIDCで始まる値が設定されていることが分かりますね。

なおブラウザからは分かりませんがGoogle Appsによる認証選択後に、ApacheのCallback URL(https://example.com/protect/redirect/)へのリダイレクトが行われ、Apache→Auth0へアクセスするための認証情報が渡されていることがわかりました(Apacheのアクセスログで確認できます)。

またこの認証情報を用いてApache(mod_auth_oidc)からAuth0へアクセスされていました。(Auth0のログ参照画面で確認できます)

補足情報

1: OIDCRedirectURI について

OIDCRedirectURIはAuth0側の認証が完了するとブラウザがリダイレクトされる先になります。リダイレクト時のURLパラメータとしてApacheがAuth0へアクセスするための認証情報が渡されてきます。 このURL自体はApacheがリクエストを受けた際にmod_auth_openidcがトラップして処理するので、特にファイル等を用意する必要はありません。

ただしOIDCRedirectURIのパスはアクセス制限されたパス以下でないといけないようです。例えば今回は<Location>タグで/protect/にアクセス制限をかけています。その場合在OIDCRedirectURIはそのパス配下/protect/redirect/にする必要があります。

またAuth0のCallback URLsと合わせておかないと認証後にエラーが表示されます。

20170103_mod_auth_openidc007

2: OIDCCryptoPassphrase について

OIDCCryptoPassphraseに設定するパスフレーズはAuth0とは関係なく任意のもので良いようです。このパスワードはCookie等を暗号化するために使われるようです。

3. 認証セッションの有効期限について

一度認証が通るとAuth0で設定したJWT Expiration (seconds)(初期値: 36000秒 = 10時間)は再認証なしでページが表示できます。ただしApacheを再起動するとサーバー側の認証情報が消去されてしまうため再度認証が必要になります。

簡易的にApacheを再起動してもセッションを継続したい場合は設定ファイルでCacheTypeFileにすればOKです。

OIDCCacheType file

またローカルファイルだと、複数のサーバーでApacheを冗長化させた時に情報が共有されません。スケールアウトする環境で使う場合はMemcached/Redisなどを検討した方が良さそうです。

まとめ

今回はApacheを使ってAuth0での認証をやってみました。Amazon LinuxだとRPMが提供されていないため準備がやや複雑になってしまいましたが、Ubuntuを採用して認証専用サーバーとして分離させてあげればより簡単に導入ができるかと思います。

また認証セッションの共有についても、AWSならElastiCacheを使ってRedisも簡単に導入できるので今後試してみたいと思います。