こんにちは、システムエンジニアの kouki です。
この記事では WordPress のアップデートをした時に遭遇した LDAP のトラブルとその対処法について紹介します。今回は端的にまとめていますので、調査経緯に興味がある方は気づくまでに至った「調査ログ」も見ていただけると幸いです。
トラブルに遭遇した環境
- WordPress 内で miniOrange が提供している「LDAP Login for Intranet Sites」というプラグインを導入していた
上記のプラグインに限定されず、PHP の LDAP extension を利用しているコードが存在するならば今回のトラブルに遭遇するはずです。
経緯
- bitnami/wordpress docker image を 5.9.3 から 6.0.0 にアップデートした
- アップデートを行った時に、WordPress から OpenLDAP に接続できない事象が発症した
- ログには
Can't contact LDAP server
というログが出力されていた
- ログには
原因と対処
bitnami/wordpress
の 5.9.3 では存在していた /etc/ldap/ldap.conf
というファイルが 6.0.0 では削除されていました。そのため、PHP LDAP extension において「TLS_CACERT」のファイルパスが見つからず、証明書の検証に失敗し、TLS 接続時にエラーが出ていることが分かりました。
対処として wordpress container 起動時に環境変数として TLS_CACERT=/etc/ssl/certs/ca-certificates.crt
を指定することで PHP LDAP extension が LDAP サーバに接続できるようになりました。
2022/09/08 時点の 5.9.3 image でも /etc/ldap/ldap.conf
が存在しないようです。(社内の bitnami/wordpress:5.9.3 をカスタムしたイメージには含まれていました) 5.9.2 のイメージでは /etc/ldap/ldap.conf
があることが確認できますので、確認してみたい方は 5.9.2 でお試しいただけるかと思います。
調査ログ
ここからはデバッグを行った調査ログを残しておきます。
LDAP サーバに openssl コマンドで接続するも、問題無し (ドメインは example.com で置換済)
# echo | openssl s_client -connect example.com:636 | openssl x509 -noout -text
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = *.example.com
verify return:1
DONE
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Let's Encrypt, CN = R3
Validity
Not Before: May 31 14:55:53 2022 GMT
Not After : Aug 29 14:55:52 2022 GMT
Subject: CN = *.example.com
WordPress plugin から通信があった際の LDAP サーバ側のログは下記の通り
62cfd66c conn=3662245 fd=26 ACCEPT from IP=XXX.XXX.XXX.XXX:33692 (IP=0.0.0.0:636)
62cfd66c conn=3662245 fd=26 TLS established tls_ssf=256 ssf=256
62cfd66c conn=3662245 fd=26 closed (connection lost)
connection lost
というログしか出ないため、「接続時に何らかのトラブルが起きているんだろう」ということしかわからず。
ここで一旦調査に行き詰まる。
LDAP Login for Intranet Sites
plugin のソースコードを改変して、デバッグ作業の開始
/opt/bitnami/wordpress/wp-content/plugins/ldap-login-for-intranet-sites/class-mo-ldap-config.php
(GitHub へのリンク) のファイルに下記のコードを仕込み、container のログを確認する
# stdout に変数の内容を出力するコード ($err, $error_no は ldap_bind 関数から取得したもの
$fp = fopen('php://stdout', 'w');
fwrite($fp, $err . "\n");
fwrite($fp, $error_no . "\n");
fclose($fp);
ldap_bind
関数にて Can't contact LDAP server
というメッセージが出力されていることを確認
再度調査が行き詰まる
その後、ldap_set_option
という関数があることが分かり、そのコードを仕込む
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
コード適用後、下記のようなログが出力される
ldap_ndelay_off: 12
ldap_pvt_connect: 0
TLS: peer cert untrusted or revoked (0x42)
TLS: can't connect: (unknown error code).
「証明書周りで問題がありそうだ」というところまで特定
putenv('LDAPTLS_REQCERT=never')
というコードを plugin に書き加えて、接続ができることを確認 (あくまで仮の対処法)
しかし、LDAPTLS_REQCERT=never
という workaround は筋が悪い。セキュリティ的にも問題がある
その後、調査を進めると ssl - Can not connect to server via ldaps using Let's Encrypt certificates - Stack Overflow という記事を他のメンバーが発見
bitnami/wordpress 5.9.3 時点では /etc/ldap/ldap.conf
ファイルが存在し、6.0.0 では存在しないことが分かる
### 5.9.3 image
$ docker run -it --rm bitnami/wordpress:5.9.3 --entrypoint /bin/bash -c 'cat /etc/ldap/ldap.conf'
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
#BASE dc=example,dc=com
#URI ldap://ldap.example.com ldap://ldap-master.example.com:666
#SIZELIMIT 12
#TIMELIMIT 15
#DEREF never
# TLS certificates (needed for GnuTLS)
TLS_CACERT /etc/ssl/certs/ca-certificates.crt
### 6.0.0 image
$ docker run -it --rm --entrypoint /bin/bash bitnami/wordpress:6.0.0 -c 'cat /etc/ldap/ldap.conf'
cat: /etc/ldap/ldap.conf: No such file or directory
image 起動時の環境変数に TLS_CACERT=/etc/ssl/certs/ca-certificates.crt
を指定
上記の LDAPTLS_REQCERT=never
は削除し、TLS_CACERT
にて対応完了
最後に
今回は他の docker image でも応用が利きそうなトラブルシューティングを紹介しました。
NextCloud なども PHP で作られているのでこの問題に該当しているならば、同じような対処を行うことで意図した挙動になると思います。