TT Lab
はじめる
学ぶ 学習パス コース

企業認証の連携

LDAPツリーと検索フィルタ、そして組織図の罠

TT Labで続きを見る

一言でいうと

LDAPはツリーであり、このツリーでグループが人を指すのか、人がグループを指すのかが照会の方向を決めます。この方向を誤ると、ログインがユーザー数に比例して遅くなります。

なぜ必要なのか

「社内アカウントを付けてください」は、結局LDAP照会で終わります。ところが、フィルターをいい加減に書くと、無効なアカウントやサービスアカウントまでユーザー一覧に入ってきて、返す属性を指定しないと、10万人のディレクトリで全属性を取得してサーバーを苦しめます。

もっと静かな問題は方向です。このディレクトリはグループがmemberで人を指すため、ユーザーのエントリをどれだけ見ても、所属グループは出てきません。これを知らずに、ログインのたびに全グループを走査するコードが、実際に作られます。ユーザーが100人のときは誰も気づかず、1万人になるとログインが3秒になります。

DIT: ディレクトリはツリーです

LDAPのデータは、DIT(Directory Information Tree)というツリーに格納されます。各ノード(エントリ)は、DN(Distinguished Name)で一意に特定されます。

dc=labhub,dc=co,dc=kr                         ← 루트 (Base DN)
├── ou=People
│    ├── uid=hong,ou=People,dc=labhub,dc=co,dc=kr
│    └── uid=kim,ou=People,dc=labhub,dc=co,dc=kr
├── ou=Groups
│    ├── cn=dev-team,ou=Groups,...
│    └── cn=role-admin,ou=Groups,...
└── ou=Disabled                               ← 퇴사자 격리 구역

このコードブロックの韓国語コメントは、順に、ルート(Base DN)と、退職者の隔離区域を意味します。

DNは下から上へ読みます。uid=hong,ou=People,dc=labhub,dc=co,dc=krは、「labhub.co.krの組織のPeopleという部署のhong」です。ファイルパスと逆の方向なので、最初は混乱します。

主な属性の略語は、これくらいを知っていれば始められます。

略語 意味 例
dc domainComponent dc=labhub,dc=co,dc=kr
ou organizationalUnit ou=People
cn commonName cn=홍길동(韓国語の人名)、cn=dev-team
uid userid uid=hong
sn / givenName 姓 / 名 sn=홍(韓国語の姓)、givenName=길동(韓国語の名)
mail メール hong@labhub.co.kr
title 役職 title=과장(韓国語の役職名で、課長の意味)
member グループのメンバー(DN) member=uid=hong,ou=People,...

検索フィルター: RFC 4515の前置記法

LDAPのフィルターは、演算子が先に来る括弧表記です。最初は見慣れませんが、ルールは単純です。

(uid=hong)                          단순 일치
(cn=홍*)                            앞부분 일치 (와일드카드)
(&(A)(B))                           A 그리고 B
(|(A)(B))                           A 또는 B
(!(A))                              A 가 아님
(objectClass=*)                     해당 속성이 존재

このコードブロックの韓国語は、各フィルターの意味を順に、単純一致、前方一致(ワイルドカード。韓国語の姓を使った例)、AかつB、AまたはB、Aではない、その属性が存在する、と説明しています。

組み合わせると、こうなります。

(&(objectClass=inetOrgPerson)(ou=개발팀)(title=과장))
(&(objectClass=inetOrgPerson)(|(title=부장)(title=차장))(!(ou=총무팀)))

これらのフィルターの韓国語の値は、順に、開発チーム(部署)、課長(役職)、部長と次長(役職)、総務チーム(部署)を意味します。

ldapsearchでは、こう書きます。

ldapsearch -x -H ldap://127.0.0.1:1389 \
  -D "cn=admin,dc=labhub,dc=co,dc=kr" -w labhub123 \
  -b "dc=labhub,dc=co,dc=kr" \
  "(&(objectClass=inetOrgPerson)(title=과장))" uid cn ou

このコマンドのフィルターにある韓国語の値は、課長(役職)を意味します。

検索範囲(-s)も知っておくと便利です: base(自分だけ)、one(直下の子だけ)、sub(配下すべて、デフォルト)。大きなディレクトリでsubを乱用すると遅くなります。

グループ: 2つの方向があります

メンバーシップを表現する方法は2つあります。そして、この違いが性能と同期を左右します。

  1. グループが人を指す(groupOfNamesのmember属性)
    • グループのエントリに、メンバーのDN一覧が入っています
    • 「このグループのメンバーは誰か」は速いです
    • 「この人が所属するグループは何か」は、全グループを調べる必要があります
  2. 人がグループを指す(memberOf属性)
    • ユーザーのエントリに、所属グループのDN一覧があります
    • ADはこれを自動で管理します。OpenLDAPはオーバーレイを有効にする必要があります
    • 「この人のグループは何か」が速いです。ログイン時の権限判定に有利です

実務の落とし穴: memberはあるのにmemberOfがないディレクトリで、ログインのたびに全グループをスキャンするコードが作られます。ユーザーが100人のときは気づかず、1万人になるとログインが3秒になります。

ADとOpenLDAPの実務上の違い

項目 Active Directory OpenLDAP
ログインID属性 sAMAccountName(またはuserPrincipalName) 通常はuid
不変の識別子 objectGUID entryUUID
グループの逆参照 memberOfを標準で提供 memberofオーバーレイが必要
パスワード属性 unicodePwd(平文のLDAPでは変更不可) userPassword
アカウント状態 userAccountControlのビット 別の規約

不変の識別子がなぜ重要か。人は結婚して名前が変わり、部署を移ってDNが変わります。uidやDNをキーにして同期すると、同じ人が新規ユーザーとして2回できます。必ずobjectGUID / entryUUIDのような不変の値を連携キーに使います。この設計を誤ると、アカウントの重複作成事故が起き、それは静かに数か月間溜まります。

userAccountControlはビットフラグです。ADを扱うなら、この3つは覚えておくと便利です。

0x0002  ACCOUNTDISABLE        계정 비활성
0x0010  LOCKOUT               잠김
0x10000 DONT_EXPIRE_PASSWD    비밀번호 만료 없음

512   = 정상 계정
514   = 정상 + 비활성 (512 + 2)
66048 = 정상 + 비밀번호 만료 없음 (512 + 65536)

このコードブロックの韓国語は、各値の意味を順に、アカウント無効、ロックアウト、パスワード期限なし、正常なアカウント、正常+無効、正常+パスワード期限なし、と説明しています。

そのため、「有効なユーザーだけ」を取り出すADのフィルターは、こうなります。

(&(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))

真ん中のOIDは、「ビットAND」のマッチングルールです。初めて見ると暗号のようですが、「userAccountControlに2のビットが立っているものを除外」という意味です。このフィルターを使わないと、無効なアカウントやコンピューターアカウントまでユーザー一覧に入ってきます。

同期の2つの落とし穴

ディレクトリからこちらのシステム(またはIdP)へユーザーを定期的に同期するときに、必ず出会う問題です。

  1. 差分同期は削除を検出できません。 「最近変更されたエントリ」を取得する方式では、消えたエントリを見る方法がありません。そのため、退職者のアカウントがこちら側に残り続けます。これが幽霊アカウントの常連の原因です。 → 差分同期は頻繁に(1時間ごと)、全件同期は定期的に(週1回)あわせて実行します。
  2. 変更時刻はディレクトリサーバーの時計です。 NTPがずれたサーバーが1台でもあると、その区間の変更が静かに漏れます。症状は「たまに1人だけ反映されません」で、原因の特定が非常に難しいです。

平文の389は監査で指摘される対象です

ldap://の平文接続でbindすると、パスワードがネットワークを平文で通過します。本番環境では、ldaps://(636)またはStartTLSを使う必要があり、平文の構成はセキュリティ監査で即座に指摘されます。

(このラボ環境はcapabilityの制約で1024未満のポートを開けないため、1389の平文を使っています。学習用にそうしているだけで、本番の構成ではないことを覚えておきましょう。)