LDAPプロトコル、データ階層、およびエントリ構成の理解
紹介
LDAP(Lightweight Directory Access Protocol)は、階層的なディレクトリ構造からデータを保存および取得するために使用されるオープンプロトコルです。主に組織とその資産およびユーザーに関する情報を保存するために使用されるLDAPは、あらゆる種類のエンティティとその特性を定義するための柔軟なソリューションです。
多くのユーザーにとって、LDAPは特殊な用語に依存し、一般的でない略語を使用し、相互に作用する部品の大きなシステムの一部として実装されることが多いため、理解するのが難しいと感じるかもしれません。このガイドでは、テクノロジーを扱うための良い基盤を持つために、LDAPの基本について紹介します。
ディレクトリサービスとは何ですか?
ディレクトリサービスは、データをキーとバリューの形式で保存、整理、表示するために使用されます。通常、ディレクトリはルックアップ、検索、読み取り操作向けに最適化されており、書き込み操作にはあまり最適ではないため、頻繁に参照されるがあまり変化しないデータに対して非常にうまく機能します。
ディレクトリサービスに保存されているデータは、しばしば記述的な性質を持ち、エンティティの特性を定義するために使用されます。ディレクトリサービスでよく表現される物理的なオブジェクトの例としては、アドレス帳があります。それぞれの人は、ディレクトリ内のエントリによって表され、連絡先情報、業務場所などを説明するキー・バリューペアが含まれます。ディレクトリサービスは、質的で記述的な情報をアクセス可能にしたい多くのシナリオで役立ちます。
LDAPとは何ですか?
LDAP、すなわち軽量ディレクトリアクセスプロトコルは、ディレクトリサービスにアクセスする方法を定義する通信プロトコルです。より広く言えば、LDAPはディレクトリサービス内のデータがユーザーにどのように表現されるべきかを形作り、ディレクトリサービス内にデータエントリを作成するために使用されるコンポーネントの要件を定義し、異なる基本要素がエントリを構成するためにどのように使用されるかを概説します。
LDAPはオープンプロトコルであるため、多くの異なる実装が利用可能です。OpenLDAPプロジェクトは、最もサポートされているオープンソースのバリアントの一つです。
基本的なLDAPデータコンポーネント
私たちは上記で、LDAPがディレクトリデータベースと通信し、情報を照会、追加、または変更するために使用されるプロトコルであることを議論しました。しかし、この単純な定義は、このプロトコルをサポートするシステムの複雑さを誤解させます。LDAPがユーザーにデータを表示する方法は、いくつかの定義された構造コンポーネントの相互作用および関係に非常に依存しています。
属性
LDAPシステム内のデータは、主に属性と呼ばれる要素に格納されます。属性は基本的にキーと値のペアです。他のシステムとは異なり、キーにはエントリのために選択されたオブジェクトクラスによって決められた予め定義された名前があります(これについては後で説明します)。さらに、属性内のデータは属性の初期定義で定義された型と一致しなければなりません。
属性の値を設定するには、属性名と属性値をコロンとスペースで区切ります。電子メールアドレスを定義するmailという属性の例は次のようになります:
mail: admin@example.com
属性とそのデータを参照する際(設定していない場合)、両方は代わりに等号で結ばれます:
mail=example.com
属性値には、LDAPシステムで保存しアクセスしたい実際のデータのほとんどが含まれています。LDAP内の他の要素は、構造や組織などのために使用されます。
エントリー
属性自体はあまり役に立ちません。意味を持たせるためには、何かと関連付けられなければなりません。LDAPの中では、エントリの中で属性を使用します。エントリは基本的に何かを説明するために使われる名前の下にある属性の集合です。
例えば、システム内のユーザーのエントリーや、在庫内の各アイテムのエントリーを持つことができます。これは、リレーショナルデータベースシステムの行や、アドレス帳内の単一のページにおおよそ類似しています(ここでの属性は、これらのモデルの各フィールドを表します)。属性は何かの質や特性を定義する一方で、エントリーはこれらの属性を名前の下に集めることによってアイテム自体を説明します。
LDIF(LDAPデータインターチェンジフォーマット)で表示される例としては、次のようなものになります:
dn: sn=Ellingwood,ou=people,dc=digitalocean,dc=com
objectclass: person
sn: Ellingwood
cn: Justin Ellingwood
上記の例は、LDAPシステム内で有効なエントリである可能性があります。
DIT
LDAPに慣れてくると、属性によって定義されたデータはオブジェクトに関する利用可能な情報の一部しか表していないことを認識するのが簡単です。残りの情報は、エントリのLDAPシステム内での配置と、それが意味する関係にあります。
例えば、ユーザーと在庫アイテムの両方のエントリーを持つことができる場合、それらを区別する方法はどのようなものでしょうか?異なるタイプのエントリーを区別する方法の一つは、関係やグループを確立することです。これは主に、エントリーが作成されたときにどこに配置されるかに依存します。エントリーはすべて、データ情報ツリー(DIT)と呼ばれる木の枝としてLDAPシステムに追加されます。
DITは、ファイルシステムに似た組織構造を表します。ここで、各エントリ(トップレベルエントリを除く)は正確に1つの親エントリを持ち、その下に任意の数の子エントリを持つことができます。LDAPツリーのエントリはほぼ何でも表すことができるため、一部のエントリは主に組織的な目的で使用され、ファイルシステム内のディレクトリに似ています。
このようにして、あなたは「people」と「inventoryItems」のエントリーを持つことができます。実際のデータエントリーは、それらの子として作成し、タイプをより明確に区別できます。あなたの組織的なエントリーは、データを最も良く表現するために恣意的に定義することができます。
最後のセクションの例のエントリでは、dn行におけるDITの一つの指標を見ることができます。
dn: sn=Ellingwood,ou=people,dc=digitalocean,dc=com
この行はエントリの識別名と呼ばれ(詳細は後述)、エントリを識別するために使用されます。それはDITのルートに戻るためのフルパスのように機能します。この場合、私たちが作成しているエントリはsn=Ellingwoodと呼ばれています。直接の親はou=peopleと呼ばれるエントリで、おそらく人々を記述するエントリのコンテナとして使用されています。このエントリの親は、DITのルートとして機能するlinux-console.netドメイン名から派生しています。
LDAPデータコンポーネントの定義
最後のセクションでは、LDAPシステム内でデータがどのように表現されるかについて議論しました。しかし、データを保存するコンポーネントがどのように定義されるかについても話す必要があります。たとえば、データは各属性に定義された型に一致しなければならないと述べました。これらの定義はどこから来るのでしょうか?再び複雑さの観点から下から始めて、上に進んでいきましょう。
属性定義
属性はかなり複雑な構文を使用して定義されます。属性の名前、属性を参照するために使用できる他の名前、入力されるデータのタイプ、さらにさまざまなその他のメタデータを示す必要があります。このメタデータは属性を説明したり、LDAPに属性の値をどのようにソートまたは比較するかを伝えたり、他の属性との関係を示したりすることができます。
例えば、これは name 属性の定義です:
attributetype ( 2.5.4.41 NAME 'name' DESC 'RFC4519: common supertype of name attributes'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
'name'は属性の名前です。最初の行にある番号は、属性を他のすべての属性と区別するために属性に割り当てられたグローバルに一意なOID(オブジェクトID)です。エントリの残りの部分は、検索中にエントリがどのように比較されるかを定義し、属性のデータ型要件に関する情報の所在を示すポインタを持っています。
属性定義の重要な部分の一つは、属性がエントリ内で複数回定義できるかどうかです。たとえば、定義では姓はエントリごとに一度だけ定義できるとし、"姪"の属性は単一のエントリ内で複数回定義できることを許可するかもしれません。属性はデフォルトでマルチバリューであり、エントリごとに一度しか設定できない場合には
属性の定義は、属性の使用や設定よりもはるかに複雑です。幸いなことに、ほとんどの場合、自分自身の属性を定義する必要はありません。なぜなら、最も一般的な属性はほとんどのLDAP実装に含まれており、他の属性も簡単にインポートできるからです。
オブジェクトクラス定義
属性は、オブジェクトクラスと呼ばれるエンティティ内で収集されます。オブジェクトクラスは、特定の物事を説明するのに役立つ関連属性のグループに過ぎません。たとえば、「人」はオブジェクトクラスです。
エントリは、使用したいオブジェクトクラスの名前を指定する特別な属性objectClassを設定することで、オブジェクトクラスの属性を使用する能力を得ます。実際、objectClassは、追加のオブジェクトクラスを指定することなくエントリに設定できる唯一の属性です。
ですので、人物を説明するエントリを作成する場合、objectClass person(または、personから派生したより具体的な人物オブジェクトクラスのいずれか — これについては後で説明します)を含めることで、そのオブジェクトクラス内のすべての属性を使用できるようになります。
dn: . . .
objectClass: person
その後、エントリ内でこれらの属性を設定する能力を持つことになります:
- 一般名
- 説明: エントリの人間が読める説明
- 参照: 関連する項目への参照
- sn: 姓
- 電話番号: 電話番号
- ユーザーパスワード: ユーザーのためのパスワード
objectClass 属性は、異なる objectClass の属性が必要な場合に複数回使用することができますが、何が許可されているかを決定するルールがあります。ObjectClass は複数の「タイプ」のいずれかとして定義されます。
オブジェクトクラスの主な2つのタイプは、構造的または補助的です。エントリは必ず1つの構造クラスを持たなければなりませんが、そのクラスに追加の属性を付加するために0個以上の補助クラスを持つことができます。構造的オブジェクトクラスはエントリを作成し定義するために使用され、一方、補助オブジェクトクラスは追加の属性を通じて追加機能を加えます。
オブジェクトクラスの定義は、提供される属性が必須であるか(MUST の仕様によって示される)またはオプションであるか(MAY の仕様によって示される)を決定します。複数のオブジェクトクラスが同じ属性を提供することができ、属性のMAYまたはMUSTのカテゴリはオブジェクトクラスによって異なる場合があります。
例えば、personオブジェクトクラスはこのように定義されています:
objectclass ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
これは構造的なオブジェクトクラスとして定義されており、エントリーを作成するために使用できます。作成されたエントリーは必ず surname と commonname 属性を設定し、userPassword、telephoneNumber、seeAlso、または description 属性を設定するかどうかを選択できます。
スキーマ
オブジェクトクラスの定義と属性の定義は、さらに スキーマ として知られる構造でグループ化されます。従来のリレーショナルデータベースとは異なり、LDAPのスキーマは単に関連するオブジェクトクラスと属性のコレクションです。単一のDITは、必要なエントリと属性を作成するために、多くの異なるスキーマを持つことができます。
スキーマには追加の属性定義が含まれることが多く、他のスキーマで定義された属性を要求する場合があります。例えば、上で説明したpersonオブジェクトクラスは、personオブジェクトクラスを使用するすべてのエントリに対してsurnameまたはsn属性が設定されることを要求します。これらがLDAPサーバー自体に定義されていない場合、これらの定義をサーバーの語彙に追加するために、これらの定義を含むスキーマを使用することができます。
スキーマのフォーマットは基本的に上記のエントリの組み合わせで、次のようになります:
. . .
objectclass ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' )
DESC 'RFC2256: last (family) name(s) for which the entity is known by' SUP name )
attributetype ( 2.5.4.4 NAME ( 'cn' 'commonName' )
DESC 'RFC4519: common name(s) for which the entity is known by' SUP name )
. . .
データの整理
LDAPシステム内のエントリを構築するために使用される一般的な要素について説明し、これらの構成要素がシステム内でどのように定義されているかについて話しました。しかし、LDAP DIT内で情報自体がどのように整理され、構造化されているかについてはあまり話していません。
DIT内のエントリの配置
DITは、既存のエントリの関係を説明する階層にすぎません。新しいエントリを作成する際には、既存のエントリの子として自らを「フック」する必要があります。これにより、関係を定義し、意味を割り当てるために使用される木構造が作成されます。
DITの最上部は、各以下のノードがいかにして子孫であるかを示す最も広いカテゴライズです。通常、最上部のエントリは単にそのDITが使用される組織を示すラベルとして使用されます。これらのエントリは望ましい任意のオブジェクトクラスで構成できますが、通常はドメインコンポーネント(例:dc=example,dc=comは、example.comに関連する情報を管理するLDAP用)、場所(例:l=new_york,c=usはNYの組織やセグメント用)、または組織のセグメント(例:ou=marketing,o=Example_Co)を使用して構成されます。
組織に使用されるエントリ(フォルダのように使用される)は、通常、ou=という単純な記述属性ラベルを使用するorganizationalUnitオブジェクトクラスを使用しています。これらは、一般的に最上位のDITエントリ(ou=people、ou=groups、ou=inventoryなどのようなもの)における一般的なカテゴリに使用されます。LDAPは、ツリー内で上下に情報を探すのではなく、横に沿って情報を見つけるように最適化されているため、一般的な組織の枝を持ち、特定の属性の割り当てを通じてさらなる細分化を示すことで、DIT階層をそれほど深く保つのが最善です。
DIT内の名前付けと参照エントリ
私たちはエントリをその属性によって参照します。これは、各エントリがDIT階層のレベルで明確な属性または属性のグループを持たなければならないことを意味します。この属性または属性のグループはエントリの相対的識別名(RDN)と呼ばれ、ファイル名のように機能します。
エントリを明確に参照するには、エントリのRDNとその親エントリのすべてのRDNを組み合わせて使用します。このRDNのチェーンはDITの階層の最上部に戻り、問題のエントリへの明確なパスを提供します。このRDNのチェーンをエントリの識別名またはDNと呼びます。新しいエントリを作成する際には、LDAPシステムが新しいエントリをどこに配置するかを知り、エントリのRDNが他のエントリによってすでに使用されていないことを確認できるように、エントリのDNを指定する必要があります。
たとえば、RDNはファイルシステムで見る相対ファイルまたはディレクトリ名のようなものと考えることができます。一方、DNは絶対パスにもっと類似しています。重要な違いは、LDAPのDNが最も特定的な値を左側に持っているのに対し、ファイルパスは右側に最も特定的な情報を含んでいるということです。DNはRDN値をカンマで区切ります。
例えば、John Smithという名前の人のエントリは、example.comの組織の「人物」エントリの下に置かれるかもしれません。組織内に複数のJohn Smithがいる可能性があるため、ユーザーIDがエントリのRDNとしてより良い選択かもしれません。このエントリは次のように指定されることがあります:
dn: uid=jsmith1,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
cn: John Smith
sn: Smith
uid: jsmith1
このインスタンスでuid属性にアクセスするためにinetOrgPersonオブジェクトクラスを使用する必要がありました(次のセクションで見るように、personオブジェクトクラスで定義されたすべての属性には引き続きアクセスできます)。
LDAP継承
結局のところ、LDAPシステム内のデータが互いに関連する方法の多くは、階層、継承、入れ子の問題です。LDAPは、設計においていくつかのオブジェクト指向の概念を実装しているため、多くの人にとって最初は奇妙に見えます。これは主に、以前に話し合ったクラスの使用と、これから話す継承の利用可能性から来ています。
オブジェクトクラスの継承
各オブジェクトクラスは、そのタイプのオブジェクトの特性を説明するクラスです。
ただし、単純な継承とは異なり、LDAPのオブジェクトは複数のクラスのインスタンスであることができ、実際にそうであることがよくあります(いくつかのプログラミング言語は、多重継承を通じて同様の機能を提供しています)。これは、LDAPのクラスの概念が、持つべき属性の集合に過ぎないため可能です。これにより、エントリに対して複数のクラスを指定することができ(ただし、1つのSTRUCTURAL オブジェクトクラスのみが存在する必要があります)、その結果、オブジェクトは最も厳密なMUSTまたはMAYの宣言が優先される属性の統合集合へのアクセスを持つことができます。
オブジェクトクラスの定義では、属性を継承する親オブジェクトクラスを識別することができます。これは、SUP の後に継承するオブジェクトクラスを記述することで行われます。たとえば、organizationalPerson オブジェクトクラスは次のように始まります:
objectclass ( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL
. . .
SUP識別子に続くobjectClassは親objectClassです。親は定義されているobjectClassの型(例えばSTRUCTURALやAUXILIARY)を共有しなければなりません。子objectClassは自動的に親の属性および属性要件を継承します。
エントリーにオブジェクトクラスを割り当てるときは、継承チェーンの最も具体的な子孫を指定するだけで、すべての属性にアクセスすることができます。最後のセクションでは、これを使用して、私たちのジョン・スミスエントリーの唯一のオブジェクトクラスとしてinetOrgPersonを指定しながら、personおよびorganizationalPersonオブジェクトクラスで定義された属性にアクセスできるようにしました。inetOrgPersonの継承階層は次のようになります:
inetOrgPerson -> organizationalPerson -> person -> top
ほとんどすべてのobjectClassの継承ツリーは、“top”と呼ばれる特別なobjectClassで終わります。これは抽象的なobjectClassで、その唯一の目的はobjectClass自体が設定されることを要求することです。これは継承チェーンの頂点を示すために使用されます。
属性継承
同様に、属性自体は定義中に親属性をリストすることができます。その属性は、親属性で設定されたプロパティを引き継ぎます。
これは、一般的な属性のより具体的なバージョンを作成するためにしばしば使用されます。たとえば、姓は名前の一種であり、比較や等価性のチェックに同じ方法を使用できます。姓はこれらの特性を受け継いで「名前」属性の一般的な形を取得することができます。実際、実際の姓の定義には親属性へのポインタ以上のものは含まれていない場合があります。
これは便利です、なぜなら一般的な形が変わらない場合でも、要素を解釈する人々にとって有用な特定の属性の作成を可能にするからです。ここで議論したsurname属性の継承は、人々が苗字と一般的な名前を区別するのに役立ちますが、その値の意味を除けば、LDAPシステムにおいて苗字と名前の違いはほとんどありません。
LDAPプロトコルのバリエーション
私たちは冒頭でLDAPが実際にはディレクトリサービスと連携するための通信インターフェースを定義するプロトコルであることを言及しました。これは一般的にLDAPまたはldapプロトコルとして知られています。
通常の形式にいくつかのバリエーションが見られるかもしれないことは言及する価値があります。
- ldap://: これは、ディレクトリサービスへの構造化されたアクセスを可能にする基本的なLDAPプロトコルです。
- ldaps://: このバリアントは、SSL/TLS経由のLDAPを示すために使用されます。通常のLDAPトラフィックは暗号化されていませんが、大多数のLDAP実装はこれをサポートしています。このLDAP接続の暗号化方法は実際には非推奨であり、代わりにSTARTTLS暗号化の使用が推奨されます。安全でないネットワーク上でLDAPを運用している場合は、暗号化が強く推奨されます。
- ldapi://: これはIPCを介してLDAPを示すために使用されます。これは、管理目的のためにローカルLDAPシステムに安全に接続するためにしばしば使用されます。外部ネットワークポートを使用するのではなく、内部ソケットを介して通信します。
すべての3つの形式はLDAPプロトコルを利用していますが、最後の2つはどのように使用されているかに関する追加情報を示しています。
結論
LDAPプロトコルとLDAPの実装がユーザーにデータをどのように表現するかについて、かなり良い理解を持っているべきです。システムの要素がどのように相互に関連しているのか、そしてそれらがどこから特性を取得するのかを理解することで、LDAPシステムの管理と使用がより簡単で予測可能になります。
