SAMLを使ったSSOログインの設定と問題
SAMLを使ったログインをOpenStackで実現する場合は、mellon
または shibboleth
といったモジュールを使用することになります。参考資料
今回はmellonとは、mod_auth_mellon のことで、それを検証してみたのでその中で気が付いた問題をまとめました。
セットアップについては下記のリンクを参考にセットアップできるかと思います。
OpenStackのドキュメントはわりとあてになりませんが、OpenStackが公開している設定のリンクをまとめます。
- OpenStack Docs: Federated keystone
- Setup Mellon (mod_auth_mellon) — keystone 9.3.0 documentation
- OpenStack Docs: Setup Web Single Sign-On (SSO)
- OpenStack Docs: Configuring Keystone for Federation
SSOログインの一連の流れについてもまとめました。
opt1はSAML AuthnRequestに関わる処理のところを囲んでいます。
SAML AuthnRequestというものは、IdentityProvider (idP)に認証要求を投げる時にcookieに入れられるもので、idPからのレスポンスが自分で送ったものか確認するために使われます。
- ログインリクエストを投げると、redirectで、mellonのメソッドが叩かれます
- そこで、SAML AuthRequestが作成されます
- identityProvider(idP)に認証をするため、認証リクエストのパスをたたき、idPにリクエストします
- idPで認証をし、結果をmellonに返します
- SAML AuthRequestのチェックを行い、ユーザ情報をkeystoneに渡します。
- keystone上にユーザがいなかったら、401エラーで、ユーザが入ればログインです。
一番大事なのはidPにすべての認証を一任することが一つのポイントです。
勘違いしやすいのですが、SSOのログアウトは該当サービス(OpenStackならhorizon)のログアウトであって、idPの認証はログアウトしないということです。
そして、ログインはidPの認証情報であって該当サービスの認証はidPに一任していることです。
UMLでも認証したユーザ情報が該当サービス上に存在するか最後に確認し、そのユーザに対してログインを許可しています。
また、OpenStackでSSOログインした時はUnscoped Tokenが発行されます。 Unscoped Tokenはpolicyで一概には言えませんが、project情報やuser情報を見ることは可能ですが、
追加や更新、削除といった操作はできません。
あくまで、Unscoped Tokenは Project Scoped Tokenに交換するためのTokenです。交換方法はHorizonでプロジェクトを選択すれば、Project Scoped Tokenが発行されます。
Tokenについては、 以下記事にまとめています。
requestが飛んたサーバに認証結果が返らなければならない
1つ問題になるのが、複数Apacheを置いている場合です。Apacheごとに発行しているので最初にユーザがログインしたい!とrequestしたときにrequestが届いたサーバと、SPから認証が帰ってくるサーバが同じでないと SAML AuthnRequestが一致しないのです。
一つの解決方法として、HAproxyを使っている場合は sticky sessionを張る方法があります。sticky sessionでは、requestが毎回同じホストへ行くようにcookieにサーバネームもしくはどのサーバにrequestを飛ばせば良いか判断できるような名前を登録し、毎回同じサーバにrequestが届くようにする仕組みです。
ドキュメントにも書かれているので、haproxyを使う場合はこの設定が基本的な解決方法かと思います。ドキュメント
ハードウェアのロードバランサでしたら、sticky sessionでもソースIPなバランシングでもいくらでも解決方法はありそうなため、考えてません。
実際の設定は、
・・・ cookie SERVERID insert indirect nocache maxidle 20s maxlife 30s server KEYSTONE_HOST_NAME KEYSTONE_API_ENDPOINT check inter 2000 rise 2 fall 5 cookie KEYSTONE_HOST_NAME ・・・
と設定します。
各設定については、haproxyのドキュメントを見るのが早いでしょう。
設定中の2行だけ切り抜きましたが、cookieをセットするとsticky sessionで設定されます。また、maxlifeにより30秒でcookieの有効期限がきれるため、仮に接続するサーバが死んだとしてもアクセスできないという事故はほぼ解消されるかと思います。
また、maxidleを20sにしているのは、mellon側の設定でMellonSessionLength
を20sに設定しているためです。
本来mellon上で何かしらの情報を持つのはよくないなーと思っているのでより良い方法があれば、別の方法で解決したいと考えています。
idP上にユーザがいて、SP側にユーザがいなかった時はjsonが返る
ブラウザに直接結果が返ってしまうため、ユーザがSP(OpenStackの場合ならKeystone)に登録されてなかった場合は、残念ながらブラウザに401のjsonが表示されます。
この問題については、wsgi_middlewareをkeystoneに追加し、responseを返す時にhtmlに置き換える方法で対応可能です。
-
OPTを本来の用途ではなく囲むために使ってます。↩