技術的雑談-ActiveDirectoryにLDAP経由でユーザなどを作る
環境
- Windows Server 2003R2 StandardEdition
目的
- LDAP経由でActiveDirectoryにユーザなどを作る・編集する
ActiveDirectoryとは
正直なところあまり詳しい事は知らないのですが…。
従来のWindowsNTのDomainの概念を拡張したアカウント統合ソリューションだと思えば大体あっているんじゃないかと思います。
Windows2000Serverあたりから「ActiveDirectory」というものが出現したようです。
ActiveDirectoryの特徴として、
- 従来のドメインを階層構造的に構築する「フォレスト」という概念が導入された。
- ActiveDirectoryサーバに対してLDAPでアクセスができるようになった。
- LDAPを通してドメイン(?)内のユーザ、グループ、ポリシーなどが参照・設定できるようになった。
というものがあります。
(と、いうか、私はここまでしか知りません…。)
このページでは主に一番下のLDAPを通してユーザ、グループを作る方法と、それらの配置位置を分ける(ou:OrganizatinalUnit)を作る方法について記述します。
※記述がメンドクサイので以下ActiveDirectoryをADと記述します。
接続
まず、LDAPに接続するにはbindを行う必要があります。
一般的には、
- bind DN = 接続ユーザ
- bind password = ユーザに対するパスワード
- 接続プロトコル = LDAP v2/v3
- 平文、SSL、TLSの種別
があります。
ADの場合、
- bind DN = ユーザID@ADドメイン名 (Administrator@test.jp)
- bind password = そのユーザのログインパスワード
- 接続プロトコル = v2,v3どちらでもOK(普通はv3を使いたいトコロ)
でOKですが、1点制限があって、
平文接続では閲覧のみなので、ユーザの追加・編集・削除をする時はSSL接続(ldaps)をして行う必要があります。
SSL接続するにはLDAPクライアント側にADサーバのサーバ証明書が必要なので、「管理ツール」→「証明機関」から必要な証明書をバイナリエクスポートしてクライアントに置いておく必要があります。
(今回の記述ではざくっと説明省略。2010/02/15 ページの最後に追記。)
なお、ADにLDAP接続するにはADに登録されているユーザであればOKっぽいですが、書き込みを行うには接続ユーザが「Domain Admins」又は「Enterprize Admins」グループに属している必要があるようです。
(ちょっと自信なし…。とりあえずAdministratorでは書けて、Domain Usersユーザでは書けない事を確認。)
よって、ADをいじくりまわしたい時は「ldapsで接続して」「管理者権限のユーザ情報でbind」を行う必要があります。
「サーバ証明書って何よ?」という人は…SSLの基本についてググることをお勧めします…。
AD-LDAPの特殊なポイント
OpenLDAPなどの「普通な」LDAPを使っていた人にとってAD-LDAPの困惑する点としては「topオブジェクトの改造されっぷり」でしょう。
普通のLDAPのtopオブジェクトは何も属性を持たない「お飾り」のようなものでしたが、AD-LDAP上では「Windowsとしてのセキュリティー属性」を持つように魔改造されています…。
具体的にはAD-LDAPでのスキーマでは、topオブジェクトに特に以下の必須属性が追加されています。
- instanceType
- nTSecurityDescriptor
- objectCategory
JXplorerやphpLDAPAdminで何かエントリーを追加しようとするとこれらの属性が「必須」として太字で書かれていたりします。
が!
実はこれらの属性ってエントリーの追加時にはAD-LDAPが勝手に振ってくれるんです。
なので、本来ldapaddするときにLDIFに含まれていなくても良いのです。
ただ、スキーマ定義上はMUST指定されてしまっている為、JXplorerやphpLDAPAdminなど「賢い」LDAPクライアントは、「instanceType属性が指定されてないよ〜」などとエラーにしてくれてしまいます。
試しにOpenLDAP付属の「ldapadd」などの「素直な」LDAPクライアントにinstanceTypeやnTSecurityDescriptionなどを書いていないLDIFを食わせてもADは何も文句を言わずにエントリーを作ってくれます。
あ〜も〜何で内部で自動生成する属性のスキーマをMUST指定してんだよ!Microsoftのアホ!
なので、JXplorerでは「Ignore Schema」をチェックを付けた状態で使えばOKです。
phpLDAPAdminは残念ながら同様の機能が見つけられなかったので…あきらめて下さい。(2010/01/13現在v1.2.0.4)
パスワードについて
AD上でユーザを表すobjectClassは「user」です。
userの中でユーザのパスワードを表す属性は「unicodePwd」です。
残念ながらuserPasswordではありません!
ADのお約束で、unicodePwdには以下の内容のbase64エンコードされた文字列を入れることになっています。
ダブルクォーテーションで囲った平文パスワードをUTF-16LEでエンコードし、それをbase64エンコードしたもの。
OpenLDAPなどのようにuserPasswordに平文パスワードをセットすると読み出し時にはMD5やSSHAにしてくれる…事はしてくれません。
それどころか上記の規則に合致していない文字列をセットしようとすると弾かれます。
さらに、unicodePwd属性は読み出せません。
Administrator権限だろうがなんだろうが、unicodePwd属性はldapsearchなどに引っかかりません。
Hash値ですら取り出せません。
unicodePwdの中の値が意図したものと同一かどうか確認するにはldapcompareなどのコマンドを使用します。
さらにさらに、一旦セットしたunicodePwdを変更する場合、JXplorerやphpLDAPAdminでユーザエントリーを開いただけではunicodePwd属性自体が表示されません。
(だってldapsearchに引っかからないんだもん。)
なので「unicodePwd自体がエントリーにセットされていないのね〜」とldapmodifyで「changetype: add」でunicodePwdに新しいパスワードをセットしようとすると、
'''「既にある単一属性をAddすんじゃねぇ!」とADに怒られます。
正しくは、「changetype: replace」で値を取り換えるか、一旦「changetype: delete」でunicodePwd属性自体を削除して、その後で改めて「changetype: add」で新しいパスワードを(上記の作法に従ってエンコードして)ブチ込む事になります。
トドメとして、AD上のunicodePwd属性にセットできるパスワードはADのパスワードポリシーのチェックを受けます。
つまり、パスワード強度(大文字・小文字・数字・記号の中から3種類以上含まれていないとダメとか、ユーザIDと同じパスワードはダメとか、過去xx代と同じパスワードは使えないとか)がADのパスワードポリシーを満たしていなくてはなりません。
そして、これらのパスワードに対する理不尽なまでに独自の作法に従っていない場合、LDAP的には単にエラーコード53で片づけられてしまいます。
ただ、詳細エラーメッセージを同時に取っているとその中に8ケタぐらいの詳細エラーコードが混じっています。
その詳細エラーコードを元にググるとこれまで述べたお作法の何に抵触しているのかわかる「場合も」ある、のです。
あーもー。
objectClassについて
ADでは下記のようにLDAP上のobjectClassとWindows的なエンティティーに紐付けがされています。
- objectClass:user = ユーザ
- objectClass:group = グループ
- objectClass:computer = ドメインのコンピュータアカウント
また、LDAP的な見た目ツリーを整理する為にobjectClass:organizationalUnit(つまりou)を定義することができます。
デフォルトの状態で、AD-LDAP上でのドメインユーザは
ou=Users,【ベースDN】
以下に入っています。
しかし、どうもADはどこのou配下にオブジェクトがあるかという事には一切関知せず、単にベースDNから(objectClass=ナントカ)の検索条件でHitすることによってAD上のオブジェクトを識別しているっぽいです。
なので、ベースDN直下にuser作ってみても、ouを100段ぐらい掘ってその中にuser作っても、同じように「Windowsユーザ」として扱ってくれます。
LDAP経由でアカウント作る時などは「LDAP経由で作ったエントリー」をWindowsネイティブなエントリーと区別する為に独自のouを掘ってその中に入れたりするのが良さそうです。
「有効な」ユーザを作る
単にldapaddでuserエントリーを作っただけだと大体「無効化されたユーザ」が作られるはずです。
ActiveDirectoryのユーザ管理GUIで開くと人間アイコンの前に赤の進入禁止標識がついているアイコンで表示されるアレです。
これをLDAP経由で作って即座にログインできるユーザにするには、userの「userAccountControl」値をセットしてやる必要があります。
userAccessControlは複数のフラグ値の合計でできています。
フラグ値の一覧はこの辺に出ていますが、
userAccountControl属性自体が無いと、「アカウント無効」の状態に自動的にセットされるようです。
一覧を元に計算すると、「アカウント有効」にするには「NORMAL_ACCOUNT(512)」がセットされていればとりあえずログインはできます。
但し、ドメインのポリシーによってはパスワードがセットされていないとログインできるユーザとして認められない可能性があります。
AD-LDAPへの操作
これまでに記述した注意点さえ守れば、後は大体普通のLDAPと同じ手段でアクセスできます。
linux上からOpenLDAPの「ldapadd」「ldapmodify」「ldapdelete」コマンドと、適切なLDIFファイルを使ってADをコントロールする事も出来ますし、
スキーマチェックを無視できるLDAPクライアント(とりあえずJXplorerは動作確認済み)を使ってもいいですし、
perlやphpなどから「Net::LDAP」や「php_ldap.so(dll)」のライブラリから操作することもできます。
補足:ADのサーバ証明書について
2010/02/15 追記
ADの証明書は、ADサーバ上にGUIでログインして、コントロールパネルの「プログラムの追加と削除」から「Windowsコンポーネントの追加と削除」を選択し、「証明機関」をインストールする事によって作れるようになれます。
(証明機関をインストールしていなくてもポート636は開いているんですが…何のキーでSSL動いているんだろう?(謎))
証明機関のインストール過程で証明機関の種類を聞いてくるのですが、とりあえず「エンタープライズ・マスター」とすると、ADサーバ自信がCAになるように設定されます。
で、インストール後のセットアップでCA証明書がエクスポートされるのですが、それをダブルクリックで開いて、2つ目のタブから「証明書をファイルに保存」したファイルがサーバ証明書として使用できるようになります。
(厳密にはADのサーバ証明書じゃなくてADが持っているCAのCA証明書なのですが…用途が限定されていないのでサーバ証明書ともなる?ようです。このあたりはOpenSSLでPKIを学んだ私にはちょっとワケワカメです。
普通は「サーバの秘密鍵を作る」→「秘密鍵に対する署名要求を作る」→「署名要求に対してCAで署名する」→「公開鍵を作成する」→「公開鍵を配布する」っていうものなんですけどね…。CA証明書とサーバ証明書が一緒って…いいの??)
ファイルに保存した証明書ファイルを、Linuxサーバなどにバイナリで転送し、例えばCentOSのOpenLDAP ClientでADにSSL接続する為には、/etc/openldap/certsディレクトリに置いて、/etc/openldap/ldap.confに「CACERTDIR=/etc/openldap/certs」などと書きくわえておくとADにldaps接続してもSSLのハンドシェークで成功するようになります。
が、1つだけ注意点があって、ADのLDAPSは証明機関をインストールした後にADサーバを再起動しないと有効にならないという事です。
(これは…ハマった…。多分ADサーバのLDAPサービスを再起動しないとADサーバが新しい証明書を使い始めないからじゃないかと思います。)
Windowsサーバで証明機関作った時に署名要求とかどーやるんだろうなぁ…。
そのうち調べてみたいな。
履歴
- 2010/02/15 -- ADのサーバ証明書のあたりを追記
- 2010/01/13 -- 初版
技術的雑談へ戻る