mod_auth_mellon を使ってみた

# はじめに
Apache を SAML SP として動作させる mod_auth_mellon について紹介します。
なかなか日本語の記事が見当たらなかったので、インストールや初期設定手順について解説します。


# mod_auth_mellonとは
mod_auth_mellon は 認証連携プロトコルの SAML をしゃべってくれるApacheのモジュールです。導入するとSAMLのIdPで認証済みのユーザーのみApache配下のコンテンツにアクセス可能な環境を構築できます。
標準の認証連携プロトコル SAML で連携可能なため、IdPはSAMLをしゃべることができれば製品は問いません。OpenAMやADFS等 SAML に準拠した IdP と連携可能です。Keycloakのドキュメントではアプリケーションを保護するためにSAMLで連携すると SP としてmod_auth_mellon が登場しています。

Apache にはBASIC認証やForm認証を行うモジュールが用意されておりますが、これの代わりに使うことで`SAML IdP で認証したユーザーのみ Apache 配下のコンテンツにアクセス可能`というシステム構成を取ることができます。
mod_auth_mellon には認可の機能も備わっており、`IdPから受け取ったデータが○○だったらコンテンツにアクセス許可する`というアクセス制御も実現出来ます。

IdPから受け取ったデータは、`Apache環境変数`にセットされます。mod_headers を使ってIdPから受け取ったデータを`リクエストHTTPヘッダー`にセットすることができます。
アプリケーションでは`リクエストHTTPヘッダー`や`Apache環境変数`からIdPから渡ってきたデータを取得し利用することが可能です。

割と手軽にシステムを SAML SP 対応出来るため、`システムをSAML SP化したい!`と考えた場合は選択肢の一つとして検討に値すると思います。

今回は mod_auth_mellon のインストールから設定方法、アプリケーションでデータを取得するうえでの注意事項を踏まえて紹介したいと思います。



# mod_auth_mellon のインストール
## 前提事項
1. CentOS７でApacheがインストール&設定済み
2. SAML IdP が構築済み

CentOS7 で Apache httpd Server がインストール & アプリケーションが利用可能なよう設定済みであることを前提とします。
本記事では `https://sp.example.com/` でアクセスされるとコンテンツが返るApacheが構築済みであるとして設定例を示します。
mod_auth_mellon を試すには連携する SAML IdP が必要です。製品は問いませんので何かしらのIdPは構築済みであることを前提とします。

## mod_auth_mellonのインストール
 CentOS7の標準パッケージにmod_auth_mellonが含まれているため、yumコマンドでインストールすることが可能です。

``` console
# yum install mod_auth_mellon
```

インストールを行うとモジュールの設定ファイルと

``` /etc/httpd/conf.modules.d/10-auth_mellon.conf
LoadModule auth_mellon_module modules/mod_auth_mellon.so
```


設定ファイルが保存されています。

``` /etc/httpd/conf.d/auth_mellon.conf
MellonCacheSize 100
MellonLockFile "/run/mod_auth_mellon/lock"
```

このあと auth_mellon.conf に設定を追加していきます。

# mod_auth_mellon の設定
auth_mellon.confに追加する内容を説明します。
## 事前準備
mod_auth_mellon を設定するために事前に決めておくことがあります。

### EntityIDの決定
SAML SP として動作する際の識別子(EntityID)を決めます。
EntityID は他のサービスと重ならないユニークな値とする必要が有るため、サーバーのFQDN を利用することが多いです。

- 本記事ではSPのEntityIDを `https://sp.example.com/sp` とします。

### mellon動作用URLパスの決定
mod_auth_mellon 用に動作するURLのパスを決めます。
mod_auth_mellonはここで決めたURLパスでSAMLのレスポンスを受け取ったりするため、
アプリケーションで使用しないURLパスを用意します。

 - 本記事では `/mellon` をmod_auth_mellonで使用するURLパスとします。


### 保護対象とするURLのパス 
mod_auth_mellon を導入するサーバーで、IdPで認証を行った場合のみコンテンツにアクセス可能とする保護対象のURLパスを決めます。

 - 本記事では `/cgi-bin/配下`をmod_auth_mellonの保護対象の URLパスとします。


## SPメタデータの生成
SP のSAMLメタデータを準備します。
yum でmod_auth_mellonをインストールするとメタデータ生成スクリプトが配置されるので、このスクリプトを使ってSPのメタデータとアサーション署名・暗号化用のサーバー証明書/秘密鍵を生成します。
スクリプトの引数には事前準備で決めた SP の EntityID、mellon動作用URLパスを含めたURLを指定します。


``` console
# mkdir /etc/httpd/saml
# cd /etc/httpd/saml
# /usr/libexec/mod_auth_mellon/mellon_create_metadata.sh https://sp.example.com/sp https://sp.example.com/mellon
```

実行結果は以下のとおりです。

```
Output files:
Private key:                              https_sp.example.com_sp.key
Certificate:                              https_sp.example.com_sp.cert
Metadata:                                 https_sp.example.com_sp.xml
Host:                                     sp.example.com

Endpoints:
SingleLogoutService (SOAP):               https://sp.example.com/mellon/logout
SingleLogoutService (HTTP-Redirect):      https://sp.example.com/mellon/logout
AssertionConsumerService (HTTP-POST):     https://sp.example.com/mellon/postResponse
AssertionConsumerService (HTTP-Artifact): https://sp.example.com/mellon/artifactResponse
AssertionConsumerService (PAOS):          https://sp.example.com/mellon/paosResponse
```

スクリプトを実行したディレクトリに`サーバー証明書` `秘密鍵` `SPメタデータ` が生成されます。上記手順では `/etc/httpd/saml` というディレクトリを作成して、そこでスクリプトを実行しています。

`https_sp.example.com_sp.xml`が SP のメタデータです。このメタデータを連携するIdPで信頼するSPとしての登録を行ってください。


## 基本設定

これまで入手した情報や事前準備で決まった値を設定ファイル(auth_mellon.conf)に記載します。

```
<Location />
  MellonEndpointPath "/mellon"
  MellonIdPMetadataFile /etc/httpd/saml/idp-metadata.xml
  MellonSPPrivateKeyFile /etc/httpd/saml/https_sp.example.com_sp.key
  MellonSPCertFile /etc/httpd/saml/https_sp.example.com_sp.cert
  MellonSPMetadataFile /etc/httpd/saml/https_sp.example.com_sp.xml
</Location>

<Location /cgi-bin>
  AuthType "Mellon"
  Require valid-user
  MellonEnable "auth"
</Location>
```
`/etc/httpd/saml/idp-metadata.xml` はIdPのメタデータです。mod_auth_mellonと連携するIdPからメタデータを入手してこのファイル名で配置してください。

これで設定は完了です。Apacheを再起動し`https://sp.example.com/cgi-bin/配下`にアクセスすると、IdPに遷移するようになります。
IdP側での認証が完了すれば`https://sp.example.com/cgi-bin/配下`のコンテンツにアクセスできます。


## 属性情報の取得
IdPから応答されるSAMLアサーションの属性(AttributeStatement)は、mod_auth_mellonで特に設定しなくても Apache環境変数にセットされます。
Apache環境変数名はAttributeStatementの属性名に接頭語"MELLON_"が付きます。
属性が複数存在したケースを想定していて、「環境変数名_[数字]」の形式でもセットされます。(「環境変数名_[数字]」は属性値が一つの場合もセットされます。)

* 例： AttributeStatementでuidが送られてきた際にセットされるApache環境変数

```
MELLON_uid=testuser01
MELLON_uid_0=testuser01
```


### CGIで環境変数を扱う場合の注意

CGIで環境変数を扱う場合の注意について説明します。
Linuxの環境変数名に扱える文字列は`アルファベット`，`数字`，`アンダースコア`です。
そのためApacheがCGIプロセスの環境変数にセットする際の名前は、以下のルールで変更されます。

* 最初の1文字がアルファベット以外であれば`アンダースコア`にする。
* 以降の文字がアルファベット/数字以外であれば`アンダースコア`にする。


この変更処理はApache本体においてCGI実行時の環境変数セット時に行われます。
Apache動作内でのApache環境変数はこれまでどおりのためCGI実行時のみ意識すべき点であり、RequestHeadersディレクティブや php で属性名を扱うときはこのルールは適用されないことに注意してください。


| 項目                            | 属性名                           |
|:-------------------------------|:--------------------------------|
| アサーション内のAttributeStatement | urn:oid:0.9.2342.19200300.100.1.3     |
| phpで取得時に指定する名前 | MELLON_urn:oid:0.9.2342.19200300.100.1.3   |
| CGIで取得時に指定する名前 | MELLON_urn_oid_0_9_2342_19200300_100_1_3   |

## アクセス制御
MellonCond ディレクティブを使うことでSAMLアサーションで受け取ったAttribute Statementの属性値を条件にアクセス制御を行うことができます。
条件には正規表現を指定でき、複数の条件を OR 条件や AND 条件とすることができます。


```
MellonCond <Attribute Statementの属性名> <条件> [<オプション>]
```

設定例を示します。`<Location /cgi-bin>`内に定義を追加しています。

```
<Location /cgi-bin>
  AuthType "Mellon"
  Require valid-user
  MellonEnable "auth"
  MellonCond "description" "admin"
  MellonCond "mail" "@example\.net$" [OR,REG]
  MellonCond "mail" "@example\.com$" [OR,REG]
  MellonCond "mail" "@example\.co.jp$" [REG]
</Location>
```

上記の設定では、IdPから送られてくる属性名description の値が "admin" であり、かつ 属性名mailの@以降が「example.net」または「example.com」または「example.co.jp」である場合、ユーザーのアクセスが許可されます。
条件を満たさないユーザーは、ステータスコード403の応答となります。
正規表現(REGオプション)と `AND`  `OR` を組み合わせることで柔軟なアクセス制御を行えます。


## その他の設定
インストール後のconfファイルに書かれている設定について、解説します。

### MellonCacheSize
mod_auth_mellon は、IdPの認証に成功しアサーションの検証が完了すると以降のアクセスで SP で認証OKと扱うためセッションを発行します。このセッションは shardメモリに保存され、`MellonCacheSize` は保存可能なセッション数を指定する設定です。
初期値の`100`であれば、100セッションまで同時に作成可能となります。
アクセス数が多く、SPが発行するセッションが100を超えた場合はLRUアルゴリズムで動作します。新規の認証はOKとなり、最後に使われてから最も長い時間経過したセッションが一つ破棄されます。
セッションにはタイムアウトがあり、`MellonSessionLength`ディレクティブで設定可能です。
ただし、セッションのタイムアウトはIdPからのアサーションのAuthnStatement にSessionNotOnOrAfter属性が含まれている場合は設定値より SessionNotOnOrAfter属性値を優先します。


### MellonLockFile
`MellonLockFile` は、セッションの排他処理に利用するロックファイルの指定です。
CentOS7 のバンドルApache は、排他処理の実装に SySV 形式のセマフォを使うため lockファイル名は使用しません。そのためこのディレクティブは気にする必要はありません。

## シングルログアウト
`セッション` のところで mod_auth_mellonがセッションを発行すると説明しました。
mod_auth_mellonのセッションを終わらせるログアウトURLが用意されています。
このURLへアクセスするとSAMLのシングルログアウトが実行され、IdPへシングルログアウト要求が行われます。すなわちSPのログアウトとIdPのログアウトが実行されます。
SPのログアウトURLは、`[mellon動作用URLパス]/logout`です。
本記事のURL構成だと以下のURLとなります。

```
https://sp.example.com/mellon/logout
```

mod_auth_mellonはIdP起点のシングルログアウトにも対応しています。IdPからシングルログアウト要求が来てもセッションは破棄されます。


# 終わりに
mod_auth_mellon は設定がシンプルであり構築するのが簡単に出来ると思います。
多くの人が`アプリケーションをSAML SP化したい`となったときにやりたいことは`SAML IdP で認証した人だけに使わせたい`という単純なことなので、そのような用途であれば mod_auth_mellon は手軽に出来るのでオススメです。