OpenLDAP 2.5のlloadd機能
2022-06-09 - 下窪 聖人
はじめに
OpenLDAP 2.5の新機能となるlloaddの機能について紹介します。
lloaddは、LDAP用のロードバランサーとして実装されたOpenLDAPのモジュールで、受け取ったLDAPリクエストを複数のLDAPサーバーに振り分けて、LDAPサーバーの負荷分散を行うことが可能です。
lloaddとマルチマスターのLDAP2台を組み合わせた場合の処理の流れは下図のようになります。
lloaddの設定
今回は1号機をロードバランサー、2号機と3号機でマルチマスター構成にします。
OpenLDAPの1号機はlloadd機能のみを利用するために、 1号機のslapd.confに下記のパラメーターを設定します。
本記事ではbackend-serverに2号機と3号機の2台のLDAPサーバーを指定していますので、 1号機のロードバランサーは2号機と3号機にリクエストを振り分けるようになります。
slapd.conf
moduleload lloadd.la
backend lload
# The Load Balancer manages its own sockets, so they have to be separate
# from the ones slapd manages (as specified with the -h "URLS" option at
# startup).
listen "ldap://:1389"
# Enable authorization tracking
feature proxyauthz
# Specify the number of threads to use for the connection manager. The default is 1 and this is typically adequate for up to 16 CPU cores.
# The value should be set to a power of 2:
io-threads 2
# If TLS is configured above, use the same context for the Load Balancer
# If using cn=config, this can be set to false and different settings
# can be used for the Load Balancer
TLSShareSlapdCTX false
# Authentication and other options (timeouts) shared between backends.
#bindconf bindmethod=simple
# binddn=cn=Manager,dc=example,dc=com credentials=secret
# network-timeout=5
# tls_cacert="/opt/osstech/etc/openldap/certs/ldap.example.com.crt"
# tls_cert="/opt/osstech/etc/openldap/certs/ldap.example.com.crt"
# tls_key="/opt/osstech/etc/openldap/private/ldap.example.com.key"
# List the backends we should relay operations to, they all have to be
# practically indistinguishable. Only TLS settings can be specified on
# a per-backend basis.
backend-server uri=ldaps://ldap2.example.com starttls=critical retry=5000
max-pending-ops=50 conn-max-pending=10
numconns=10 bindconns=5
backend-server uri=ldaps://ldap3.example.com starttls=critical retry=5000
max-pending-ops=50 conn-max-pending=10
numconns=10 bindconns=5
下記のコマンドで起動します。
# systemctl start slapd
bindconfパラメーター
lloaddはバックエンドのLDAPサーバーへの接続時に bindconfに指定された認証情報を使って接続します。 lloadd起動時にはbackendへのコネクションが接続されておらず、bindconfパラメーターを使って認証が行われます。
下記のパラメーターを使用します。
bindmethod
simpleまたはsaslを指定します。
binddn
bindで使用するdnを指定します。
saslmech
bindmethodでsaslを指定した場合の認証方式の指定時に必要になります。
credentials
binddnで指定したdnのパスワードを指定します。 bindmethodでsimpleを指定している場合は、cleartext(平文)でパスワードを指定する必要があります。
authcid
認証アイデンティティーを指定する時に使用します。
authzid
認証アイデンティティーを指定する時に使用します。
realm
realmを指定します。
secprops
セキュリティプロパティを指定します。
timeout
サーバーからのレスポンスを受け取るまでの待ち時間(秒)を指定します。
network-timeout
ネットワークコネクションが作成されるまでの待ち時間(秒)を指定します。
tcp-user-timeout
0以外の値が指定されている場合、OSのTCP_USER_TIMEOUTが上書きされます。
TLS通信を利用する場合は、下記のパラメーターを使用します。
tls_cacert
CA証明書を指定します。
tls_cert
lloaddから振り分け先に提示するクライアント証明書を指定します。
tls_key
秘密鍵を指定します。
tls_cacertdir
CA証明書のディレクトリを指定します。
tls_reqcert
TLSセッション確立時のサーバー認証方法を指定します。 never、allow、try、demandから1つを選択して指定します。
tls_reqsan
Subject Alternative Nameの認証方法を指定します。 never、allow、try、demandから1つを選択して指定します。
tls_cipher_suite
TLS通信時に使用する暗号スイートを指定します。
tls_protocol_min
接続時に許容可能なTLSプロトコルの最低バージョンを指定します。
tls_ecname
Diffie-Hellman鍵交換に使用する曲線を指定します。 OpenSSLでECDHEベースの暗号スイートを使用する時のみ使用します。
tls_crlcheck
サーバーの証明書が失効していないかを確認するために、CRLを使用するかどうかを指定します。 none、peer、allから1つを選択して指定します。
backend-serverパラメーター
backend-serverは、lloaddの振り分け先のLDAP情報を指定するパラメーターです。
下記の情報を指定することができます。
uri
LDAP URIを指定します。
retry
リトライ時間(ms)を指定します。デフォルトは5秒です。
keepalive
ソケットが接続中であるかどうかの確認で使用します。idle:probes:intervalの形式で指定します。 idleは接続がアイドル状態であるのに必要な時間(秒)です。 probesはコネクションを切断する前に送信するキープアライブ・プローブの最大数です。 intervalはキープアライブ・プローブ間の間隔時間(秒)です。
starttls
TLSセッションを確立するためのStartTLSの操作を使用するかどうかをyesまたはcriticalで指定します。 criticalを指定する場合、StartTLSリクエストが失敗するとそのセッションは廃棄されます。これは、TLSなしにsyncreplセッションが続いてしまうのを防ぐことができます。
tls_cert
lloaddから振り分け先に提示するクライアント証明書を指定します。
tls_key
秘密鍵を指定します。
tls_cacert
CA証明書を指定します。
tls_cacertdir
CA証明書のディレクトリを指定します。
tls_reqcert
TLSセッション確立時のサーバー認証方法を指定します。 never、allow、try、demandから1つを選択して指定します。
tls_cipher_suite
TLS通信時に使用する暗号スイートを指定します。
tls_crlcheck
サーバーの証明書が失効していないかを確認するために、CRLを使用するかどうかを指定します。 none、peer、allから1つを選択して指定します。
tls_protocol_min
接続時に許容可能なTLSプロトコルの最低バージョンを指定します。
numconns
アクティブコネクション数を指定します。
bindconns
LDAPクライアントからのbindリクエストを処理するためのアクティブコネクション数を指定します。
max-pending-ops
全てのバックエンドコネクションにおける未完了の操作数を制限します。デフォルトは0です。0はこのバックエンドに制限がないことを示します。
conn-max-pending
0に指定しない限り、アップストリームコネクション1つあたりの未完了の操作数を制限します。デフォルトは0です。
動作確認
動作環境
AlmaLinux 9.0
OpenLDAP 2.5 3台
OpenLDAPの起動
起動時の各号機の挙動を確認します。
設定が正しければ、1号機/2号機/3号機を起動した際に下記のログメッセージが記録されます。
1号機の起動時のログ
slapd starting
2号機/3号機の起動時のログ
ACCEPT from IP=1号機のIPアドレス:34958 (IP=0.0.0.0:636)
TLS established tls_ssf=256 ssf=256 tls_proto=TLSv1.3 tls_cipher=TLS_AES_256_GCM_SHA384
上記の状態で、試しに下記の操作を行い、各号機のログを確認します。
# /opt/osstech/bin/ldapmodify -x -W -D "cn=Manager,dc=example,dc=com" -f modifycn.ldif -H ldap://:1389
1号機のログ
operation_init: received a new operation, bind request with msgid=1 for client connid=31
handle_bind_response: received response for bind request msgid=1 by client connid=31, result=0
forward_final_response: connid=3 msgid=1 finishing up with a request for client connid=31
operation_init: received a new operation, modify request with msgid=2 for client connid=31
forward_final_response: connid=0 msgid=2 finishing up with a request for client connid=31
operation_init: received a new operation, unbind request with msgid=3 for client connid=31
handle_one_request: received unbind, closing client connid=31
2号機のログ(今回は2号機に振り分けられたため、3号機のログは変化なし。)
MOD dn="uid=testuser,ou=Users,dc=example,dc=com"
MOD attr=cn
RESULT tag=103 err=0 qtime=0.000032 etime=0.083721 text=
1号機のログにはlloaddが受け取ったLDAPリクエストがログに記録されます。 振り分けられたLDAP(今回は2号機)のログを確認することで、lloaddから送られたリクエストが振り分けられてLDAPサーバーに届いていることが確認できます。
2号機と3号機はマルチマスター構成にしているので、2号機の更新内容は3号機に同期されます。
OpenLDAPの停止
停止時の各号機の挙動を確認します。
1号機が停止する場合
lloaddも停止するため、振り分けられません。
1号機のログ
lloadd shutdown: Main event loop finished: rc=0 lload_listener_thread: event loop finished: rc=0 lloadd_io_task: Daemon 0, event loop finished: rc=1 lloadd_io_task: Daemon 1, event loop finished: rc=1 slapd stopped.
2号機が停止する場合
3号機に振り分けられます。
3号機が停止する場合
2号機に振り分けられます。
2号機と3号機が停止する(振り分け先が停止している)場合
LDAPクライアント側に下記のエラーが返され、リクエストは振り分けられません。
ldap_bind: Server is unavailable (52) additional info: no connections available
負荷分散方式
slapd.confのbackend-serverを選択する処理のソースコードによると、OpenLDAP 2.5の負荷分散方式はラウンドロビンでした。 大量のリクエストを投げることでも確認できました。
ソースコードのコメント
* Round-robin step:
* Rotate the queue to put this connection at the end, same for
* the backend.
この分散方式のデメリットとして、データの一貫性が得られないことが挙げられます。 具体的には、2号機に更新のリクエスト、3号機に参照のリクエストが送られる場合、2号機の更新が3号機に反映される前に参照の処理が行われてしまうことが考えられます。 この問題を回避するために、更新を伴うリクエストはlloaddを経由しないようにするなどの工夫が必要になります。
OpenLDAP 2.6では、slapd.confにtierのオプションを追記することでroundrobin/weighted/bestofを指定できます。1 また、write_coherenceやrestrict_controlの設定が可能であるため、本記事で説明したデメリットを回避することができます。
write_coherence
write_coherence 5
のように設定すると、書き込みが終了してから5秒経過するまで、lloaddは同じbackendに振り分けるようになります。restrict_control
restrict_control <OID> <action>
のように設定します。actionは下記が用意されています。reject
操作は拒否されます。
connection
今後の全ての操作は同じコネクションに振り分けられるようになります。
backend
タイムアウトしないことを除けば、write(action)と同じです。
write
write_coherenceと同じように扱えます。
ignore
制限に影響を与えません。