Apache2.4によるLDAP認証の設定

# はじめに

LDAPサーバーを準備したので、とりあえずApache HTTP Serverを使って、独自のグループ設定まで使えているか確認してみます。

# 構成例

1. httpd.confを利用してサイト全体の設定を行なう方法
2. .htaccessなどのユーザーが準備したファイルの中で、グループ設定を行なう方法

## 環境

* Ubuntu 18.04 LTS (64bit) on VMWare Workstation14
* apache2 deb package (2.4.29-1ubuntu4.3)

## 事前準備

必要なモジュールを有効にします。mod_ldap(ldap)や、mod_auth_basic(auth_basic)も必要ですが、デフォルトの環境からは次の手順で環境を構築できます。

```bash
$ sudo apt-get install libapache2-mod-webauthldap

$ ls /etc/apache2/mods-enabled/
access_compat.load  authn_file.load  autoindex.load  env.load        mpm_event.load    status.conf
alias.conf          authz_core.load  deflate.conf    filter.load     negotiation.conf  status.load
alias.load          authz_host.load  deflate.load    mime.conf       negotiation.load
auth_basic.load     authz_user.load  dir.conf        mime.load       setenvif.conf
authn_core.load     autoindex.conf   dir.load        mpm_event.conf  setenvif.load

$ sudo a2enmod authnz_ldap
Considering dependency ldap for authnz_ldap:
Enabling module ldap.
Enabling module authnz_ldap.
To activate the new configuration, you need to run:
  service apache2 restart

$ ls /etc/apache2/mods-enabled/
access_compat.load  authn_file.load   autoindex.conf  dir.load     mime.conf         negotiation.load
alias.conf          authnz_ldap.load  autoindex.load  env.load     mime.load         setenvif.conf
alias.load          authz_core.load   deflate.conf    filter.load  mpm_event.conf    setenvif.load
auth_basic.load     authz_host.load   deflate.load    ldap.conf    mpm_event.load    status.conf
authn_core.load     authz_user.load   dir.conf        ldap.load    negotiation.conf  status.load
```

### TLS(ldaps://)を利用する場合

必ず **ca-certificates** を追加で導入してください。

```bash:ca-certificatesの導入例
$ sudo apt-get update
$ sudo apt-get install ca-certificates
```

特にDockerのhttpd公式コンテナでldaps://...を利用する場合は、ca-certificates の導入が必要です。

## httpd.confを利用したサイト全体に影響させる場合の課題

LocationやDirectoryディレクティブの中で指定をすると、Basic認証をパスしたユーザー全員が閲覧できます。

以下の例では、LDAP Cache Informationを表示するldap-statusハンドラを有効にしています。

Apache 2.2を対象としている古い記事では、公式ドキュメントから採った"Satisfy any"を指定する例が多いですが、2.4以降はRequireAll,RequireAny,RequireNoneなどをネストしながら意図した指定をすることができるので、その点は書き換えています。（デフォルト値はRequireAny）

```apache
<Location /ldap-status>
    SetHandler ldap-status

    AuthType Basic
    AuthName "LDAP Protected by LDAP-ID"
    AuthBasicProvider ldap
    AuthLDAPURL ldap://localhost/ou=people,ou=proxy,dc=example,dc=com?uid?one
  <RequireAll>
    Require valid-user
    Require host localdomain  ## "localdomain" は適切なアクセス元のFQDNかドメインを指定する
  </RequireAll>
</Location>
```

余談ですが、[Upgrading to 2.4 from 2.2](https://httpd.apache.org/docs/2.4/en/upgrading.html)の日本語版がちゃんと提供されていないので、Order,Deny,Allow,Satisfyを使う記述がまだ見受けられますが、基本的には従来のアクセス制御の記法は2.4では書き換えるべきでしょう。

## .htaccessを利用した設定の例

.htaccessを利用するためには、サーバー全体の設定の中で、特定のディレクトリ以下で、```AllowOverride AuthConfig```を有効にする必要があります。

```apache:/etc/apache2/conf-available/sitewide-auth.conf
<Directory /var/www/html>
    AllowOverride AuthConfig
</Directory>
```
conf-availableに配置したファイルは、```a2enconf```コマンドで有効に(conf-enabledからのシンボリックリンクが作成)されます。一緒にプロセスを再起動します。

```bash
$ sudo a2enconf sitewide-auth
Enabling conf sitewide-auth.
To activate the new configuration, you need to run:
  service apache2 reload
## 

## プロセスの再起動
$ sudo systemctl restart apache2
```

下記の例はhttpd.confを利用する例から少し変更して、cn=ml01グループに所属するメンバーだけに限定する例を載せています。

```apache:.htaccess
AuthName "LDAP Authentication Gateway"
AuthType Basic
AuthBasicProvider ldap
AuthLDAPUrl "ldap://localhost/ou=people,ou=proxy,dc=example,dc=com?uid"
AuthLDAPGroupAttribute member
Require ldap-group cn=ml01,ou=maillist,ou=proxy,dc=example,dc=com
```

# Docker上でのLDAP認証の有効化

Kubernetesでの稼動も想定してDockerコンテナを作成する方法についてまとめます。

## サンプルコンテンツ・.htaccessファイルの準備

次のようにhtdocsディレクトリを作成し、中にコンテンツと.htaccessを配置します。

```bash:作業手順
$ mkdir htdocs

$ cat <<EOF  > htdocs/.htaccess
AuthName "LDAP Authentication Gateway"
AuthType Basic
AuthBasicProvider ldap
AuthLDAPUrl "ldaps://ldap.example.com/ou=people,ou=proxy,dc=example,dc=com?uid"
<RequireAll>
  Require valid-user
</RequireAll>
EOF

$ cat <<EOF > htdocs/index.html
<h1>Hello world!</h1>
EOF
```

## Dockerfile

次のようなDockerfileファイルを準備します。

```:Dockerfile
FROM httpd:2.4

RUN sed -i \
        -e 's!^#\(LoadModule authnz_ldap_module modules/mod_authnz_ldap.so\)!\1!' \
        -e 's!^#\(LoadModule ldap_module modules/mod_ldap.so\)!\1!' \
        -e 's!AllowOverride None!AllowOverride AuthConfig!' \
        -e 's!LogLevel warn!LogLevel info!' \
        conf/httpd.conf

RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates libldap-common

ADD htdocs /usr/local/apache2/htdocs
```

``docker build`` などでコンテナを構築してください。

```bash:ビルド&実行
$ sudo docker build . --tag httpd-ldapauth
$ sudo docker run --rm --name httpd-ldapauth -p 8080:80 -v "`pwd`/htdocs:/usr/local/apache2/htdocs" -dit httpd-ldapauth
```

# LDAP関連のトピック

## LDAPグループの指定方法

現在使っているopenldapサーバーには、translucentモジュールを有効にして属性(attribute)を追加したエントリを作ったり、独自ディレクトリを追加していたり、metaモジュールを使って、それらを束ねていたりします。

前述の例で利用しているou=maillistディレクトリは次のようなエントリになっています。

```ldap
$ldapsearch -x -h localhost -b ou=maillist,ou=proxy,dc=example,dc=com cn=ml01
# extended LDIF
#
# LDAPv3
# base <ou=mailgroup,ou=proxy,dc=example,dc=com> with scope subtree
# filter: cn=ml01
# requesting: ALL
#

dn: cn=ml01,ou=MailGroup,ou=proxy,dc=example,dc=com
member: uid=user01,ou=people,ou=proxy,dc=example,dc=com
member: uid=user02,ou=people,ou=proxy,dc=example,dc=com
objectClass: groupOfNames
cn: ml01
...
```

OSのGroupに対応するou=groupの状況は以下のようになっています。

```ldap
$ ldapsearch -x -h localhost -b ou=group,ou=proxy,dc=example,dc=com cn=staff
# extended LDIF
#
# LDAPv3
# base <ou=group,ou=proxy,dc=example,dc=com> with scope subtree
# filter: cn=staff
# requesting: ALL
#

dn: cn=staff,ou=Group,ou=proxy,dc=example,dc=com
objectClass: posixGroup
objectClass: top
cn: staff
gidNumber: xxxx
memberUid: user01
memberUid: user02
...
```
属性(Attribute)のmemberUidにドメインが指定されていないので、これにマッチさせるためには、
次のように[AuthLDAPGroupAttributeIsDN](http://httpd.apache.org/docs/2.4/ja/mod/mod_authnz_ldap.html#authldapgroupattributeisdn)(デフォルト値on)を使用します。

```apache
AuthLDAPGroupAttribute memberUid
AuthLDAPGroupAttributeIsDN off
Require ldap-group cn=staff,ou=group,ou=proxy,dc=example,dc=com
```

# 参考文献

* [Apache Module mod_ldap](https://httpd.apache.org/docs/2.4/mod/mod_ldap.html)
* [Apache Module mod_authnz_ldap](https://httpd.apache.org/docs/2.4/mod/mod_authnz_ldap.html)

# 2021/12/14 追記 - ldapsプロトコルがエラーになる

Dockerコンテナ docker.io/library/httpd:2.4.51 では、ldaps接続を行なうためにlibldap-commonパッケージの導入が必要です。GitHub上でissuesに登録し対応応してもらっていますが、独自にコンテナを構築する場合には気をつけてください。

詳細は以下のリンク先を確認してください。

* [Failed to access LDAP server over TLS](https://github.com/docker-library/httpd/issues/209#issuecomment-993128957)

現在、この問題は明示的に libldap-common を指定することで解決済みです。

以上