Email: Takayama Fumihiko <tekezo@pqrs.org>

FreeBSD で LDAP サーバ ver 0.2.1

始めに

以下は FreeBSD で LDAP サーバを立ててアドレス帳とかアカウント情報などの重要なデータを置くための方法のメモ。 最低限の LDAP サーバの知識は仮定する。

基本方針

サーバが置かれる場所は以下のような場所とする。
  • サーバのネットワーク接続は全て盗聴されている。
  • サーバの管理者が複数いたり、他人である。(= 自分一人のサーバではない)。
  • サーバは外部ネットワークから自由にアクセス出来る環境である。
  • LDAP のクライアントも完全に信頼が置けるとは言えない。
この上で、以下のポリシーで環境を構築。

通信はすべて TLS で保護

通信経路での盗聴を防止

ユーザーの生パスワードはサーバに置かない

生パスワードをサーバに置くということは LDAP の管理者に全てを預けるということ。 パスワードは一部の例外 (ldapanonymous ユーザのパスワード) を除き、暗号化して保管する。

anonymous には情報閲覧権を一切与えない

予期されないユーザへの情報漏洩を防止。 認証を通してのみ情報を公開する。

外のネットワークからも普通にアクセス可能な環境を構築

ノート PC 用。

基本環境

  • LDAP サーバの FQDN: a.ldap.tkym.org
  • 以下、コマンドラインでは zsh を使用。 csh 系だと動かないかも。
  • アカウント情報は cn=(.*),dc=user,dc=system,dc=account,dc=tkym,dc=org にて管理する。
  • anonymous によるアクセスを排除するために ldapanonymous ユーザを作成し、auth は ldapanonymous にて行う。 (cn=ldapanonymous,dc=user,dc=system,dc=account,dc=tkym,dc=org)
  • LDAP サーバの管理は ldaproot ユーザにて行う。 (cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org)

DIT 構成

+ dc=tkym,dc=org                               suffix
    + dc=account                               アカウントDB
    |   + dc=system                            システムアカウント
    |       + dc=user                          ユーザ情報
    |       |   + cn=ldaproot
    |       |   + cn=ldapanonymous
    |       |   + cn=tekezo
    |       |   + cn=mtak
    |       + dc=group                         グループ情報
    |           + cn=ldaproot
    |           + cn=ldapanonymous
    |           + cn=tekezo
    |
    + dc=address                               アドレス帳
        + dc=private                           個人用アドレス帳
            + cn=tekezo                        システムユーザ "tekezo" のアドレス帳
                + mail=tekezo@tkym.org
                + mail=tekezo@aiit.co.jp
            + cn=mtak                          システムユーザ "mtak" のアドレス帳
                + mail=mtak@tkym.org
                + mail=hogehoge@example.com

サーバのインストール

ports で
  • openldap-client-2.1.22
  • openldap-server-2.1.22_2
を導入。 WITH_SASL はお好みで。
(SASL 対応の DIGEST-MD5 は生パスワードの保管を要求するため今回はパス)

TLS の為の証明書の作成

TLS で通信を行うために独自 CA を立てて、証明書を作成。
(署名付きの証明書を用意出来るなら、独自 CA を立てることなどせずに slapd.conf の設定へ)

  • CA のファイルは /etc/ssl/CA 以下に。
  • LDAP 用の証明書は /usr/local/etc/openldap/certs 以下にファイルを保存。

/etc/ssl/openssl.cnf

以下の部分を変更。
dir             = ./                    # Where everything is kept

countryName_default             = JP
stateOrProvinceName_default     = NA
0.organizationName_default      = tkym.org

CA の作成

CA.sh を /etc/ssl/utils/CA.sh に設置。

以下のようにして CA の新規作成。 Common Name を忘れずに。 入力した pass phrase は証明書の署名の際に必要。
(証明書の pass phrase のようにサーバ再起動の際に必要になることはない)

# /etc/ssl/utils/CA.sh -newca
CA certificate filename (or enter to create)

Making CA certificate ...
Generating a 1024 bit RSA private key
..............++++++
......++++++
writing new private key to '/etc/ssl/CA//private/./cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [JP]:
State or Province Name (full name) [NA]:
Locality Name (eg, city) []:
Organization Name (eg, company) [tkym.org]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:tkym.org
Email Address []:
最後にお約束のシンボリックリンク
# ln -s cacert.pem /etc/ssl/CA/$(openssl x509 -noout -hash < /etc/ssl/CA/cacert.pem).0

証明書の作成

以下のようにして証明書を作成。 Common Name は a.ldap.tkym.org に。 challenge password はサーバ再起動の際に slapd が自動起動しなくなるので空に。
(challenge password による保護が無くなる為、証明書の扱いは慎重に)。

# mkdir -p /usr/local/etc/openldap/certs/
# cd /usr/local/etc/openldap/certs/
# openssl req -new -nodes -keyout server-$(date '+%Y%m%d')-key.pem -out server-$(date '+%Y%m%d')-req.pem
Generating a 1024 bit RSA private key
........................................++++++
....++++++
writing new private key to 'server-20031107-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [JP]:
State or Province Name (full name) [NA]:
Locality Name (eg, city) []:
Organization Name (eg, company) [tkym.org]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:a.ldap.tkym.org
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
作成した証明書に署名。
# cd /etc/ssl/CA
# openssl ca -policy policy_match -out /usr/local/etc/openldap/certs/server-$(date '+%Y%m%d')-cert.pem -in /usr/local/etc/openldap/certs/server-$(date '+%Y%m%d')-req.pem
Using configuration from /etc/ssl/openssl.cnf
Enter pass phrase for .//private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Nov  7 13:45:00 2003 GMT
            Not After : Nov  2 13:45:00 2023 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = NA
            organizationName          = tkym.org
            commonName                = a.ldap.tkym.org
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                3A:C0:EF:11:F9:08:7F:80:4F:35:A3:9A:3A:E3:CF:A3:59:31:22:94
            X509v3 Authority Key Identifier:
                keyid:9D:9E:1D:BE:9A:C4:C6:B3:C3:42:DE:64:C7:99:D5:83:FA:3C:7E:4A
                DirName:/C=JP/ST=NA/O=tkym.org/CN=tkym.org
                serial:00

Certificate is to be certified until Nov  2 13:45:00 2023 GMT (7300 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
最後に使い勝手を良くするためのシンボリックリンクと permission の設定。
# cd /usr/local/etc/openldap/certs/
# ln -s server-$(date '+%Y%m%d')-cert.pem server.cert
# ln -s server-$(date '+%Y%m%d')-key.pem server.key
# chmod 600 *
# chown -R ldap:ldap *

メモ。 CA のチェック方法。

# openssl verify -CAfile /etc/ssl/CA/cacert.pem /usr/local/etc/openldap/certs/server.cert
/usr/local/etc/openldap/certs/server.cert: OK

a.ldap.tkym.org の /usr/local/etc/openldap/slapd.conf に追加

TLSCertificateFile /usr/local/etc/openldap/certs/server.cert
TLSCertificateKeyFile /usr/local/etc/openldap/certs/server.key
TLSCACertificateFile /etc/ssl/CA/cacert.pem

a.ldap.tkym.org の /usr/local/etc/openldap/ldap.conf に追加 (もしくは該当部分を修正)

HOST a.ldap.tkym.org

BASE dc=tkym,dc=org
TLS_CACERT /etc/ssl/CA/cacert.pem

slapd の起動

とりあえず debug モードで起動。 空けるポートは ldaps のみ。
# /usr/local/libexec/slapd -u ldap -g ldap -h 'ldaps://' -d 4

接続テスト

LDAP サーバ上で ldapsearch を実行。
% ldapsearch -v -x -H 'ldaps://a.ldap.tkym.org'
ldap_initialize( ldaps://a.ldap.tkym.org )
filter: (objectclass=*)
requesting: ALL
# extended LDIF
#
# LDAPv3
# base <> with scope sub
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 0 Success

# numResponses: 1

LDAP サーバへのデータの投入

まずデータを入れる前に slapd の rootdn の設定と ACL から。

/usr/local/etc/openldap/slapd.conf に追加 (もしくは該当部分を修正)

anonymous を排除し、ldapanonymous を保護するために以下のように ACL を追加

ldapanonymous の情報変更の権限を持つのは ldaproot のみ。 PAM を使用する場合クライアントに ldapanonymous の生パスワードを保管する必要があるため、 ldapanonymous 自身に権限を与えるとクライアントから ldapanonymous の情報を変更されてしまう。

# ACL for "ldapanonymous" user
access to dn="cn=ldapanonymous,dc=user,dc=system,dc=account,dc=tkym,dc=org" attr=userPassword
        by dn="cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org" write
        by self read
        by anonymous auth
        by * none

access to dn="cn=ldapanonymous,dc=user,dc=system,dc=account,dc=tkym,dc=org"
        by dn="cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org" write
        by self read
        by users read
        by * none

# ACL for generic user
access to attr=userPassword
        by dn="cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org" write
        by self write
        by dn="cn=ldapanonymous,dc=user,dc=system,dc=account,dc=tkym,dc=org" auth
        by anonymous auth
        by * none

access to *
        by dn="cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org" write
        by self write
        by users read
        by * none

さらに rootdn を一時的に登録。 パスワードは slappasswd で。
(ldaproot の登録が終わり次第 rootdn は消去)

rootdn         "cn=root,dc=tkym,dc=org"
rootpw         {SSHA}T3fgugypIx0W+sFyrryEUOHDwKuzbb/6

データの投入

以下のような ldif を書いてデータ投入。
################################################################################
# directory hierarchy
dn: dc=tkym,dc=org
dc: tkym
objectClass: dcObject
objectClass: organization
o: TKYM

dn: dc=account,dc=tkym,dc=org
dc: account
objectClass: dcObject
objectClass: organization
o: ACCOUNT

dn: dc=system,dc=account,dc=tkym,dc=org
dc: system
objectClass: dcObject
objectClass: organization
o: SYSTEM

dn: dc=user,dc=system,dc=account,dc=tkym,dc=org
dc: user
objectClass: dcObject
objectClass: organization
o: USER

dn: dc=group,dc=system,dc=account,dc=tkym,dc=org
dc: group
objectClass: dcObject
objectClass: organization
o: GROUP


################################################################################
# user data

# ldaproot
dn: cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org
objectclass: inetOrgPerson
objectclass: posixAccount
uid: ldaproot
cn: ldaproot
sn: ldaproot
uidNumber: 10001
gidNumber: 10001
homeDirectory: /nonexistent
userPassword: {SSHA}50O5S3BR784E9rJ0pA0YAzCR0B9x7Yky

dn: cn=ldaproot,dc=group,dc=system,dc=account,dc=tkym,dc=org
objectclass: posixGroup
cn: ldaproot
gidNumber: 10001
memberUid: ldaproot


# ldapanonymous
dn: cn=ldapanonymous,dc=user,dc=system,dc=account,dc=tkym,dc=org
objectclass: inetOrgPerson
objectclass: posixAccount
uid: ldapanonymous
cn: ldapanonymous
sn: ldapanonymous
uidNumber: 10002
gidNumber: 10002
homeDirectory: /nonexistent
userPassword: {SSHA}50dUziBV0E1QD0E+S46qwPPo15i3tUUR

dn: cn=ldapanonymous,dc=group,dc=system,dc=account,dc=tkym,dc=org
objectclass: posixGroup
cn: ldapanonymous
gidNumber: 10002
memberUid: ldapanonymous


# tekezo
dn: cn=tekezo,dc=user,dc=system,dc=account,dc=tkym,dc=org
objectclass: inetOrgPerson
objectclass: posixAccount
uid: tekezo
cn: tekezo
sn: Takayama
givenName: Fumihiko
uidNumber: 20001
gidNumber: 20001
homeDirectory: /home/tekezo
userPassword: {SSHA}c/k3GuQ2uCG3AGJ/ODqQPli5aPjoh3PX

dn: cn=tekezo,dc=group,dc=system,dc=account,dc=tkym,dc=org
objectclass: posixGroup
cn: tekezo
gidNumber: 20001
memberUid: tekezo
% ldapadd -x -H 'ldaps://a.ldap.tkym.org' -D 'cn=root,dc=tkym,dc=org' -W -f new.ldif

rootdn の削除

ldaproot の登録が終了したら /usr/local/etc/openldap/slapd.conf から rootdn の情報を消去。 以後管理は
% ldapadd -x -H 'ldaps://a.ldap.tkym.org' -D 'cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org' -W -f new2.ldif
のように ldaproot で行う。

クライアントの設定

a.ldap.tkym.org に接続するための設定。 a.ldap.tkym.org の /etc/ssl/CA/cacert.pem をクライアントの /etc/ssl/cacert.pem-a.ldap.tkym.org にコピー。

/usr/local/etc/openldap/ldap.conf

TLS_CACERT /etc/ssl/cacert.pem-a.ldap.tkym.org

接続テスト

% ldapsearch -v -x -b "dc=tkym,dc=org" -H 'ldaps://a.ldap.tkym.org' -D 'cn=ldaproot,dc=user,dc=system,dc=account,dc=tkym,dc=org' -W

PAM の設定 (RedHat の場合)

とりあえず authconfig で LDAP を使うように設定。

/etc/ldap.conf の設定

コメントを除くとこんな感じ。
host a.ldap.tkym.org
base dc=system,dc=account,dc=tkym,dc=org
ssl on

binddn cn=ldapanonymous,dc=user,dc=system,dc=account,dc=tkym,dc=org
bindpw secret

ldapanonymous の生パスワードを記述することになるので /etc/ldap.conf の管理は厳重に。
ldapanonymous のパスワードが漏れても、被害は第三者への情報漏洩のみで済むが…。 (=認証システムの破壊には至らない)

su を LDAP 対応に

/etc/pam.d/su を
#%PAM-1.0
auth       sufficient   /lib/security/$ISA/pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth       sufficient   /lib/security/$ISA/pam_wheel.so trust use_uid
# Uncomment the following line to require a user to be in the "wheel" group.
#auth       required     /lib/security/$ISA/pam_wheel.so use_uid
auth       sufficient   /lib/security/$ISA/pam_stack.so service=system-auth
account    sufficient   /lib/security/$ISA/pam_stack.so service=system-auth
password   sufficient   /lib/security/$ISA/pam_stack.so service=system-auth
session    required     /lib/security/$ISA/pam_stack.so service=system-auth
session    optional     /lib/security/$ISA/pam_xauth.so

auth        sufficient    /lib/security/$ISA/pam_ldap.so use_first_pass
account     [default=bad success=ok user_unknown=ignore service_err=ignore system_err=ignore] /lib/security/$ISA/pam_ldap.so
password    sufficient    /lib/security/$ISA/pam_ldap.so use_authtok
session     optional      /lib/security/$ISA/pam_ldap.so
とかそんな感じ?

DER の作成

LDAP サーバ上で /etc/ssl/CA/cacert.pem の DER ファイルを作成。
# openssl x509 -inform pem -in /etc/ssl/CA/cacert.pem -outform der -out cacert.der
これを適当な Web サーバ上に置き IE でアクセスし、認証証の登録を行う。

TODO

  • PAM 系をもうちと丁寧に。
  • autofs とか nfs とか codafs とか。
  • Outlook や Mozilla での利用方法とか。

更新履歴

ver0.2 → ver0.2.1
  • ldapuser → ldapanonymous に変更
  • posixGroup を追加
ver0.1 → ver0.2
  • ldapanonymous に対する ACL を修正。
  • その他、加筆修正。

Comments for This Page.
Date: 2003-11-08 00:00 (JST)