Shibboleth IdPのログをPostgreSQLに格納する

Shibbolethのログ保存の問題

Shibboleth IdPのログは通常、サーバ上のテキストファイルとして記録され続けますが、この形式では次のような問題があります。

  • 複数サーバでロードバランスしている場合にログが分散してしまう(Shibbolethのロードバランサ配下での利用に関してはこちら)。
  • ログを様々な条件で検索したい場合に不便。

特に、Shibbolethは標準ではログイン履歴的な情報を参照することが困難なため、監査ログ(idp-audit.log)の検索ができると特に便利です。

先行事例の検討

検索していたところ、いくつかの先行事例が見つかりました。例えば次のようなものがあります。

時間がたっぷりあれば、後者のほうが魅力的ではありますが、安易にやるならば前者のほうが実に簡単そうです。そこで、まずはsyslogベースで実現してみることにしましたが、やはりsyslogメッセージのパースは実現したいと思います。対象は監査ログということにしました。

(もちろん、信頼性やその他の問題から、Shibboleth IdPから直でDBに入れたほうが良いことはわかっているので、今後時間がある時に、そちらも試してみようかと思います) 続きを読む

Shibbolethのログインページをブックマーク可能にする

一般論として、Shibbolethのログインページはブックマークできません。もちろんブラウザからブックマーク操作をすることは可能ですが、再度そのブックマーク経由でログインしようとした場合、ログイン対象のアプリが識別できず、ユーザにとっては謎のエラーが出てしまいログインできません。

そこで、次のような方法を取れば、仮にブックマークしてしまった場合であっても、ポータルアプリなど、一番良く使われるであろうアプリケーションのログイン画面にリダイレクトが可能です。この手法は、ポータルのようなアプリがあることが前提となります。学認で専ら外部のアプリのみを利用している場合は、ローカルアプリとして学認ポータル的なものを作ると良いかもしれません。学認IdPにおけるローカルアプリの作り方に関してはこちらをご覧ください。

手法は超簡単です。Shibboleth IdPのlogin.jsp内で、ログイン対象アプリは <idpui:serviceName/> で表示されます。この部分を囲むタグ(なければ<span>を作れば良い)の中身をJavaScriptからDOMで読み取り、それが”Unspecified Service Provider”という文字列であれば、JavaScriptでポータルアプリのログインURLに飛ばしてやればよいのです。

こうすれば、IdPのログイン画面をブックマークしても、ユーザに表示されるのはUnspecified Service Providerへの謎のログイン画面ではなく、無事にポータルアプリ用のIdPログイン画面が瞬時に表示されます。

Tips的ですが、Shibbolethのユーザビリティで初心者が一番引っかかりやすいだろう部分を、これで解決できます。

Shibboleth関連サーバをロードバランサの下に置く場合の注意

ShibbolethのIdPやSP等のサーバを、SSLのオフローディングや冗長化のためにロードバランサの下に置く場合の注意点をまとめてみます。

Shibboleth IdPのロードバランサー利用

RNAT or client-IP

サーバをロードバランサー配下に置く場合、クライアントのIPアドレスをソースに持ったままサーバに届く設定と、特定のHTTPヘッダにクライアントのソースIPアドレスを入れて、ソースアドレスはロードバランサー自身となるタイプの2種類の構成が考えられます。前者はデフォルトルートをロードバランサーにする必要があるため、ロードバランサーで一種のNATを行います。

個人的には後者のほうがネットワーク構成に対する制約が少なくて好きなのですが、Shibbolethをロードバランサーの下に入れる場合は圧倒的に前者がお勧めです。後者だと、Apache, mod_proxy_ajp, Tomcat, Shibboleth IdPの各段階で色々設定してソースアドレスをShibboleth IdPに届けないと、ShibbolethのログにソースIPアドレスが記録されません。しかもいろいろな制約条件があります。

一回挑戦してみたのですが、あまりに複雑になるので諦めました。普通にNATするほうが良いと思います(諸事情で、NAT構成にするためにサーバにNICを足す羽目になりましたが…)。

SSLオフローディングに関する問題

ここでは、ロードバランサーでSSLオフローディングを行い、Apacheのmod_proxy_ajpとTomcat上のShibboleth IdPを単純に組み合わせて、80/tcpでロードバランサ経由のリクエストを受ける場合を考えます。

この場合、ShibbolethはSSLが必須のため、ブラウザが認証画面に移った際に、”Error Message: Message did not meet security requirements”というエラーが出て利用できません。

また、Tomcatはセキュアな通信の場合CookieにSecure属性を付けるようですが、この機能も働かなくなります。

これは、tomcatのserver.xmlで、AJPコネクタの設定を次のように変更すれば解決します(前者に対応するのがproxyPortとscheme、後者に対応するのがsecure)。

変更前:

変更後:

これで、エラーメッセージは発生しなくなり、またJSESSIONIDのCookieだけではなく、_idp_authn_ic_keyのCookieにもSecure属性が付くようになります。

続きを読む

Shibboleth SPとしてTomcatを用いた場合の属性受け渡し

ShibbolethはApacheからの環境変数として属性を受け渡すため、多くの環境では非常に簡単にアプリケーションから属性を取得することができますが、Tomcatはその例外の一つです(Tomcatのアプリにすんなりと環境変数を渡す方法が無いため)。今回実験環境でテストしたので、そのメモを残しておきます。

システム構成

Tomcat単体ではShibbolethのSPとなることはできないため、Shibboleth SPをApacheで構築し、そこからAJP経由で接続するのがもっとも簡単なように思えます。

たとえばCentOSであれば、/etc/httpd/conf.d/proxy_ajp.confみたいな感じでファイルを作成し、その中でTomcatのアプリケーション(ここでは/myapp/とする)を、

のようにAJPで繋ぎます。そして/etc/httpd/conf.d/shib.confの最後辺りに、

みたいな感じで/myapp/をShibboleth認証します(実際の環境では、ログインに必要なロケーションのみをShibboleth認証するほうがおすすめだと思います)。CentOSにおけるSPの構築は、学認の技術ガイドに詳しく解説されています。FreeBSD上での構築はこのサイトの昔の記事にあります。

以上の環境を仮定して、TomcatにShibboleth属性を渡す設定について紹介します。IdP側の設定は通常のSPと同じなので省略します。渡す属性はeduPersonPrincipalName(以下ePPN)を仮定します。 続きを読む

OpenLDAP back-sqlにおけるPostgreSQLのtext型の利用

先日、OpenLDAPのback-sqlの使い方について解説してみたのですが、その際にちょっと気になっていたことがありました。OpenLDAPのサンプルのSQLに引きづられて文字列型にvarchar型を利用していたのですが、実際のところ互換性の話を考えなければ、PostgreSQLでvarchar型を使う理由はあまりありません。むしろ効率などの面でもPostgreSQLではtext型の方がオススメです。

というわけで、back-sqlのテーブルのvarchar型を全てtext型に変更してみました。たとえば、edupersonのテーブルは次のようになります。

さらに、back-sqlが内部的に用いるテーブルであるldap_attr_mappings, ldap_entries, ldap_entry_objclasses, ldap_oc_mappings内のvarchar型もtext型に直してみました。たとえば、ldap_attr_mappingsは次のようになります。

これでデータベースを作りなおしてみたところ、問題なく動作しました。もし、現用の環境をそのまま変更したいのであれば、バックアップ(もしくはVMのスナップショット)を取った上で、slapdを停止すれば、alter tableで型の変更が可能です。たとえば、

のように実行すれば(この例はedupersonのuidを変更する場合)、データは保ったままtext型に変更可能です。なお、edupersonのuidにはNOT NULLの制約がありますが、これはそのままtext型に変更しても受け継がれます。

これで、根拠の無いvarcharの文字数指定がなくなってすっきりしました。

以前、802.1X用のFreeRadiusのバックエンドにPostgreSQLを用いた際も、サンプルのSQLをほぼそのまま使ったらセッションIDをしまう部分がvarchar(32)型で、新しく導入したCiscoのAPが返すセッションID(33文字)を格納しきれずにvarchar(64)型にalter tableしたことを思い出します(本当はtext型にalter tableしたかったのだけれども、動いているシステムにそれを行うのは怖いので、varchar型の文字数を変えるにとどめました)。

こういうソフトのバックエンドにPostgreSQLを使われる開発者の方は、開発の段階でvarchar型ではなくtext型を使ってほしい…と個人的には思ってます。

FreeBSD pkg (pkgng)でのカスタマイズ環境アップグレード

FreeBSD 10から標準になったパッケージ管理システムのpkg(旧称pkgng)ですが、何しろ新しい機能でどのように使いこなせばいいのかわかりません。pkgだけで全て済むのであればいいのですが、カスタマイズしてportsをコンパイルした場合との共存はまだそれほどうまくいっていないように感じます。

とりあえず以前構築に関して紹介した本サーバのpkgをアップグレードしようと思ったのですが、次のような問題があります。

  • ja-wordpressはWordpress自体のアップグレード機能を使うので、pkgから管理する必要はない。
  • apache22は標準のprefork MPMではなくてworker MPMを使っているが、mod_php5のpkgの依存性はprefork MPMのpkgに向いている。そのためこれをpkgで更新しようとすると、新規にapache22のprefork MPMなpkgをインストールしようとしてしまい、衝突する。
  • worker MPMでmod_phpを利用するにはphpをZTSでスレッドセーフにビルドしなければならないが、標準のpkgはそうではない。
  • ja-wordpressのpkgの依存性は、上記の標準php5なpkgに向いている。
  • 以上のような事情で、php5およびphp5-extension系とja-wordpressはportsからインストールした。

なので、そのままpkg upgradeすると、悲惨なことになってしまうのです。もう少しpkgさんには頑張って欲しいところです。

続きを読む

VMware vSphereにおけるFreeBSDのP2V(dump/restoreを使う方法)

前回紹介したFreeBSDのP2V方法は、手順はそれなりに簡単ですが、イメージの取得と貼り付けにddを使うため、パーティションの切り直しなどが不可能で、シンプロビジョニングも活用できないという欠点がありました。

これを解決する方法として、dump/restoreを用いてP2Vを行う方法があります。

手順概要

基本的な手順は前回と同じため、手順が重なる部分は省略して解説します。おおまかな前提は次のとおりです。

  • FreeBSDの物理サーバからvSphere上の仮想ゲストマシンにP2Vを行う
  • それぞれのマシンは直接通信できるネットワーク上にない(直接通信できる場合は、この手順より少し楽ができる)が、双方に対してsshでアクセスできる、物理サーバのディスクイメージを格納できる十分なディスクを持ったマシン(以後、仲介マシン)がある
  • 物理サーバには起動用のCD-ROMなどは必要ない
  • ディスクやパーティションのサイズを変更できる
  • シンプロビジョニングが活用できる

前回と異なる部分は後半3項目です。

ddの代わりにdump/restoreを用いるわけですが、FreeBSDのdumpはUFS2のスナップショット機能を利用してくれるので、DBサーバやWebサーバなど、テンポラリな不整合を発生しがちなプログラムさえ止めておけば、物理サーバを起動した状態で十分健全なdumpを取得できます(もちろん、Live CDブートして作業を行えばより安全です)。

また、dumpしたパーティションと異なるサイズにrestoreできるため、リッチに使っていた物理マシンのディスクを、必要最小限的に領域を確保した仮想マシンに縮めることが可能です。

さらに、restoreの書き込みはイメージ書き込みとは異なるため、シンプロビジョニングも活かすことが可能です。

いいことばかりのように思えますが、手順は幾分複雑になります。

  1. 物理サーバを掃除して、仮想マシンに必要なパーティションサイズ計画を検討する
  2. 物理サーバからssh経由のdumpで仲介マシン上に各パーティションのバックアップを取得
  3. 仮想ゲストマシンでP2Vしたい対象と同じFreeBSDのバージョンを、計画したパーティションサイズで最小インストールする
  4. 仮想ゲストマシンをLive CDで起動し、インストールしたファイルをすべて消す
  5. 仲介マシンから仮想ゲストマシンにdumpイメージをssh経由でrestoreする
  6. 仮想ゲストマシンに対応する設定を修正する
  7. VMware Toolsをインストールする

続きを読む

VMware vSphereにおけるFreeBSDのP2V(ddを使う方法)

VMware vCenter Converterを利用すれば、物理サーバを仮想化するいわゆるP2Vは比較的簡単に行うことができますが、対応しているOSは限られています。具体的には次のようなOSです。

  • Windows XP Professional SP3 (32-bit and 64-bit)
  • Windows Server 2003 SP2, R2 (32-bit and 64-bit)
  • Windows Vista SP2 (32-bit and 64-bit)
  • Windows Server 2008 SP2 (32-bit and 64-bit)
  • Windows Server 2008 R2 (64-bit)
  • Windows 7 (32-bit and 64-bit)
  • Red Hat Enterprise Linux 2.x (32-bit and 64-bit)
  • Red Hat Enterprise Linux 3.x (32-bit and 64-bit)
  • Red Hat Enterprise Linux 4.x (32-bit and 64-bit)
  • Red Hat Enterprise Linux 5.x (32-bit and 64-bit)
  • SUSE Linux Enterprise Server 8.x (32-bit and 64-bit)
  • SUSE Linux Enterprise Server 9.x (32-bit and 64-bit)
  • SUSE Linux Enterprise Server 10.x (32-bit and 64-bit)
  • SUSE Linux Enterprise Server 11.x (32-bit and 64-bit)
  • Ubuntu 8.x (32-bit and 64-bit)
  • Ubuntu 9.x (32-bit and 64-bit)
  • Ubuntu 10.x (32-bit and 64-bit)

要するにWindowsとLinuxの一部以外無理ということですね。まあ上記以外にももちろんCentOSとかはOKのようですが。

そうは言ってもFreeBSDのサーバとかも入れたい場合があるのです。特にもう再構築するのが果てしなく面倒くさいくらい作りこんだサーバなどが典型例でしょうか。というわけで、FreeBSDのサーバをP2Vする方法をまとめてみましょう。今回はddを使う方法です。

手順概要

今回の作業手順の前提は次のようなものです。なお、最後の2項目であるディスク・パーティションサイズの変更やシンプロビジョニングへの対応に関しては、もう少し面倒な別の方法を後日紹介します

  • FreeBSDの物理サーバからvSphere上の仮想ゲストマシンにP2Vを行う
  • それぞれのマシンは直接通信できるネットワーク上にない(直接通信できる場合は、この手順より少し楽ができる)が、双方に対してsshでアクセスできる、物理サーバのディスクイメージを格納できる十分なディスクを持ったマシン(以後、仲介マシン)がある
  • 物理サーバには起動できるCD-ROMが付いている
  • ディスクやパーティションのサイズは変更しない
  • シックプロビジョニングになる(シンプロビジョニングにしても意味がない)

なお、仲介マシン上に置かれるディスクイメージはセキュリティ上重要な情報を含むため、容易に外からアクセスされるマシンや、持ち出されることのあるノートPCなどは適しません。ファイルを削除した後もデータは残るので、特に重要なデータの場合は、消去後に空き領域を/dev/randomで埋めるなど、データを慎重に消してください。仮想システム上に使い捨ての仲介マシンを構築するのが一番お勧めです。普段利用されているマシンを使う場合は、別途安全な場所に保管や、ランダム書き込み初期化、廃棄処分が可能な外付けUSBディスクなどを使うのも良い手でしょう。

続きを読む

プロビジョニングの道具としてのOpenLDAP back-sql

OpenLDAPのバックエンドのおすすめはBDBなのですが、多くの場所から認証データを収集し、適切な形に編集してLDAP形式で公開する、いわばアカウント・プロビジョニング的な用途には、SQLのバックエンド機能(back-sql)も魅力的に見えます。

巨大なデータをトランザクションで全件更新しつつ、パスワードの更新は可能な限りリアルタイムで別テーブルに収集し、より新しいパスワードをクライアントに渡す…ような仕組みは、(単なるイメージなのかもしれませんが)やはりSQL系のデータベースに一日の長があるのではないかと考えます。

そんな魅力的に見えるOpenLDAPのback-sqlですが、実際に試してみると次のような欠点があります。

  • パフォーマンスが悪い
  • 設定が複雑すぎてわけがわからない

まずは性能面です。小規模なデータの場合はそれほどでもないのですが、大規模なデータを食わせると途端に悲惨な性能になってしまいます。実際に数万件のデータを食わせたところ、1秒に5件ほどしか検索ができないという悲惨な状況になりました。これではいくらなんでも実用的ではありません。

設定が複雑なのは、LDAPのスキーマを、SQLのスキーマとデータ(メタデータと呼ぶ)の双方を使って表現するからです。テーブル構造は難しくありませんが、メタデータの方はたしかに難解です。その分、さまざまなカスタマイズも可能と言えますが、そのメリットがあるかどうかはケースによりますが微妙でしょう。

これら2つの論点について、軽く解説します。なお、ここで用いたバックエンドのSQLデータベースはPostgreSQLです。

OpenLDAP back-sqlの性能問題

大規模なデータを入れると悲惨な性能になると評判のback-sqlですが、実はサンプルなどを見てスキーマをこさえて、何も考えずに大量のデータを入れると性能が悪化するのは当たり前で、PostgreSQL用のサンプルもMySQL用のサンプルも、インデックスの定義が含まれていません。

続きを読む

Shibbolethで複数のIDを同一人物としてログインさせる

(こちらの内容は、学認メーリングリストで国立情報学研究所の西村様、京都大学の針木様から頂いたアドバイスの内容を含んでいます)

Shibbolethにおいては、認証システムにおける「ユーザ名」に相当する概念が、uid(ログイン名)、ePPN(フェデレーション内で一意なユーザ名)、ePTID(IdP:SPのペアで一意なユーザ名)の3つがあります。

この仕組を利用して、他のID体系からShibbolethにユーザアカウントのプロビジョニングを行うにあたって、学内に複数のID体系が存在して、同一ユーザが複数のIDを持っている場合に、次のようなID管理を実現可能です。

  • ユーザはどのID体系でもIdPにログインできる
  • ログイン後は、どのID体系でログインしてもSPからは同一人物として見える

複数uidで同一ePPNのLDAPを用意する

まず、パスワードはuidに紐付いています。LDAP上にuidの異なる複数のエントリを設けることで、その双方でログインすることは可能となります。Shibbolethのuidはフリーフォーマットですので、「@ドメイン名」などのスコープを付けた形でuidを定義するなどの方法で、複数ID体系の衝突を防ぐことは可能でしょう。

そして、ePPNは一番広いアカウント体系のuidを採用するか、Trusted DBにあるユーザ識別可能な何らかの属性から生成して、LDAP上で同一人物は同一のePPNを持つようにすることで、ePPNを要求するSPからはどのuidでログインしても同一人物に見えるようにすることができます。

ePTIDは基本的にePPNとSPのentityIDから生成されるようにすれば、これもSPから見ればどのuidでログインしても同一人物に見えるようにすることができます。

これだけ読むと、LDAP上のデータを適切に用意することだけで実現できそうに思えるのですが、それほど簡単な話ではありません。

ePPNとePTIDをLDAPのePPN値ソースに変更する

まず、学認の標準テンプレートのattribute-resolver.xmlでは、ePPNをLDAPのePPNのエントリではなく、uidを流用するようになっています(2行目のsourceAttributeID=”uid”の部分)。

続きを読む