Kerberosを使ったsingle sign on

Kerberos keytab を取得する

Kerberos認証を行うためには、 "HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET" のようなHTTP用のservice principalを作成する必要があります。 Kerberos標準のkadminを使って addprinc、 ktadd の順で作成することもできますが、 Active Directory相手ならSamba付属の net command もしくは adcli を利用するとLinux host側だけで作業を完結できるので簡単です。

Samba net commandを使う例

Samba の net command を使うと、Windows client を domain参加させる権限のあるuserでservice principalを作成できます。

/etc/samba/smb.conf

...
  security = ads
  workgroup = WORK.HANABUSA.NET
  realm = WORK.HANABUSA.NET
  password server = dc1.work.hanabusa.net
  kerberos method = secrets and keytab

設定fileを用意したら、以下のcommandでActive Directoryに参加 & service principalの作成を行います。

# net ads dns register -U some_domain_user
# net ads join -U some_domain_user
# net ads keytab create -U some_domain_user
# net ads keytab add HTTP -U some_domain_user

adcliを使う例

RHEL>=7 では、Samba以外にadcliをつかってActive Directoryに Linux hostを参加させることができます。 設定fileは不要で、command lineでdomain, domain controller, host名などを指定してadcliを走らせます。 実行すると、/etc/krb5.keytabにservice principalが書き込まれます。 また、computer accountのpasswordが表示されるので保管しておきます。

# adcli join -v --show-password --os-name=Linux --os-version=RHEL7 \
  -K /etc/krb5.keytab --service-name=host --service-name=HTTP \
  -D work.hanabusa.net -R WORK.HANABUSA.NET -S dc1.work.hanabusa.net \
  -H webapp.work.hanabusa.net -N webapp -U some_domain_user

DNSへの登録は別途bind-utilsに含まれるnsupdateを使って実施します。

# nsupdate
> server dc1.work.hanabusa.net
> update add webapp.work.hanabusa.net. 86400 A 192.168.100.200
> update add 200.100.168.192.in-addr.arpa. 86400 PTR webapp.work.hanabusa.net.
> send
> ^D

Kerberos principalの確認

上記の手順で正しくprincipalを作成できているか確認します。 "klist -k"で/etc/krb5.keytabにservice principal表示し、 HTTP/webappなどが入っていれば正しく設定できています。 同じ行が複数出てきますが、暗号の種類につき1行でてくるためです。 "klist -k -e " すると暗号種類まで表示できます。

# klist -k
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
   2 webapp$@WORK.HANABUSA.NET
   2 webapp$@WORK.HANABUSA.NET
   2 webapp$@WORK.HANABUSA.NET
   2 host/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   2 host/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   2 host/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   2 host/webapp@WORK.HANABUSA.NET
   2 host/webapp@WORK.HANABUSA.NET
   2 host/webapp@WORK.HANABUSA.NET
   2 HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   2 HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   2 HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   2 HTTP/webapp@WORK.HANABUSA.NET
   2 HTTP/webapp@WORK.HANABUSA.NET
   2 HTTP/webapp@WORK.HANABUSA.NET

HTTP用のservice principalだけ分ける

このあとApacheからkeytabを使うように設定しますが、 HTTP/webappだけを別のfileに分けて、 そのfileだけをApacheから使わせる方が安全面から好ましいです。

ktutilを使って/etc/httpd/httpd.keytabを作成します。 手順としては、rktで既存のkrb5.keytabを読み込み、 delentで不要なものを削除し、 wktで残ったHTTP/webapp... をhttpd.keytabに書き込むという手順になります。 やってみるとわかりますが、delentすると1行削除されて、slot番号が詰められます。 ですので、例のようなkeytabの場合、9回 "delent 1"を行なえば良いことになります。

最後にchownでApacheに読み取り権限をつけてください。 忘れるとApacheから読取できずにうまく動きません。

# rm /etc/httpd/httpd.keytab
# ktutil
ktutil: rkt /etc/krb5.keytab
ktutil: list
slot KVNO Principal
---- ---- ---------------------------------------
   1    2 webapp$@WORK.HANABUSA.NET
...
  10    2 HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET
..
  15    2 HTTP/webapp@WORK.HANABUSA.NET
ktutil: delent 1
ktutil: delent 1
ktutil: delent 1
ktutil: delent 1
ktutil: delent 1
ktutil: delent 1
ktutil: delent 1
ktutil: delent 1
ktutil: delent 1
ktutil: list
slot KVNO Principal
---- ---- ---------------------------------------
   1    2 HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   2    2 HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   3    2 HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET
   4    2 HTTP/webapp@WORK.HANABUSA.NET
   5    2 HTTP/webapp@WORK.HANABUSA.NET
   6    2 HTTP/webapp@WORK.HANABUSA.NET
ktutil: wkt /etc/httpd/httpd.keytab
ktutil: q
# chown apache /etc/httpd/httpd.keytab

ApacheでKerberos認証を行う設定

ApacheでKerberos認証を行うためには、mod_auth_kerbが必要です。 RHEL/CentOS系なら、yum install mod_auth_kerb だけでinstallできます。 mod_auth_kerbの設定として Apacheのhttpd.confに以下の例のように書きます。

<Location "/myapp/">
  require valid-user
  AuthName "My Application Login"
  AuthType Kerberos
  KrbMethodNegotiate on
  KrbMethodK5Passwd on
  KrbMethodK4Passwd off
  KrbAuthRealms WORK.HANABUSA.NET
  Krb5Keytab /etc/httpd/httpd.keytab
</Location>

mod_auth_kerbをmod_proxyと共に使用する場合

Apache&mod_auth_kerbで認証を行って、 mod_proxy経由でbackendのapplication server (例えばUnicorn & Ruby on Rails) に認証情報を渡す方法です。

基本的には、httpd.confの中で REMOTE_USER環境変数の内容を RequestHeaderを使ってHTTP headerとして appliation serverに送ってやればokです。 Basic認証の場合は、 "RequestHeader set X-Forwarded-User %{REMOTE_USER}e" のように書けば良いのですが(最後のeに注意)、 mod_auth_kerbではなぜかうまく動きません。 その代わりに、mod_sslを有効にした上で、 "RequestHeader set X-Forwarded-User %{REMOTE_USER}s" とすると(最後のsに注意)、正しくREMOTE_USERを送れるようになります。

httpd.confの例

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
...
<Location "/myapp/">
  require valid-user
  AuthName "My Application Login"
  AuthType Kerberos
  KrbMethodNegotiate on
  KrbMethodK5Passwd on
  KrbMethodK4Passwd off
  KrbAuthRealms WORK.HANABUSA.NET
  Krb5Keytab /etc/httpd/httpd.keytab

  ProxyRequests     Off
  ProxyPreserveHost On
  ProxyPass http://localhost:3000/myapp
  ProxyPassReverse http://localhost:3000/myapp
  RequestHeader set X-Forwarded-User %{REMOTE_USER}s
  RequestHeader set X-Forwarded-SSL  on
</Location>

ClientがFirefoxの場合の設定追加

FirefoxからKerberos認証するには、 about:config で設定を変更する必要があります。 変更する必要のある設定名は "network.negotiate-auth.trusted-uris" と "network.negotiate-auth.delegation-uris" で、Kerberos認証するdomainをcomma区切りで書きます。 例として、 ".work.hanabusa.net,.bobby.hanabusa.net" という設定値を上記の両方に設定します。 そうすると、 http://webapp.work.hanabusa.net や http://robot.hobby.hanabusa.net のようなURLに対してKerberos認証するようになります。

うまく認証できない場合の対処方法

上記の設定を順番に行なえばKerberos認証できるようになるはずですが、 うまく動かない場合はまずはApache側の問題なのか それ以外なのか問題を切り分けてみましょう。 まず、 http://webapp.work.hanabusa.net/myapp にaccessしてみます。 その後に、client側でklistを走らせて、 ticketを取得しているか確認します。 klistはWindows clientの場合でもcommand promptから実行できます。

$ kinit
Password for some_domain_user@WORK.HANABUSA.NET: mypassword
$ curl --negotiate --user : http://webapp.work.hanabusa.net/myapp
...
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: some_domain_user@WORK.HANABUSA.NET

Valid starting     Expires            Service principal
12/23/14 11:22:33  12/23/14 21:22:33  krbtgt/WORK.HANABUSA.NET@WORK.HANABUSA.NET
12/23/14 11:22:44  12/23/14 21:22:44  HTTP/webapp.work.hanabusa.net@WORK.HANABUSA.NET

Ticketを取得できているなら HTTP/webapp....の行があるはずです。 もしこの行が無い場合はticket取得に失敗しています。 その場合には以下のような原因が考えられます。

一方、HTTP/webapp....の行があってclientがHTTP用のticketを取得できているなら 基本的にはmod_auth_kerb周りの不具合です。 Apacheのerror logを読めば原因は特定できるはずです。

Ticketを取得に失敗している場合の対処

Ticket取得に失敗している場合にはclient側でlogを出させるのが有効です。 KRB5_TRACEという環境変数にfile名を書くと そこにKerberosのlogを出力するのでlogを確認してみてください。

$ export KRB5_TRACE=/tmp/krbclient.log
$ curl --negotiate --user : http://webapp.work.hanabusa.net/myapp
...
$ cat /tmp/krbclient.log

更新 : 2014-08-23
ご意見、ご感想は、花房 真広 <webmaster@hanabusa.net>まで。メールする前にtop pageの注意書を読んでください。