1. 程式人生 > >Install openLDAP on centos system

Install openLDAP on centos system

openlad 帳號集中管理

前言

LDAP(Lightweight Directory Access Protocol),輕型目錄訪問協議, 具體請閱讀官方文檔,深入了解還需閱讀RFC4510
目前主要使用場景為集中賬戶管理,對於管理的帳號未達到一定數量級時可能對這個的需求並不是很迫切,但當發展到一定層度的時期,就會很迫切的需要有一種集中管理帳號的方案。
如果資源不是特別緊張,建議初期就使用集中管理帳號方案,這樣當發展到一定數量級時,只要維護好這套系統即可,若沒有發展起來,也不會帶來過多的額外工作,總之好處多多。

約定

系統:centos 6.5
軟件版本:openldap-2.4.46
官網地址:http://www.openldap.org

源碼目錄:/usr/local/src/
安裝目錄:/data/openldap/
配置文件:/data/conf/
證書路徑:/etc/openldap/ssl/
數據庫:mdb

準備

安裝編譯依賴,下載、解壓源碼

yum install gcc gcc-c++ libtool-ltdl-devel openssl-devel cyrus-sasl-devel libgcrypt-devel libicu-devel openslp-devel
cd /usr/local/src
wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.46.tgz
tar zxf openldap-2.4.46.tgz

編譯、安裝

可通過./configure --help 查看編譯選項及參數
默認啟動bdb、hdb、mdb庫,這裏關閉bdb、hdb,使用mdb

cd openldap-2.4.46
./configure --prefix=/data/openldap --sysconfdir=/data/conf/ --enable-bdb=no --enable-hdb=no --enable-accesslog --enable-auditlog --enable-syslog --enable-modules --enable-debug --with-tls --enable-overlays=yes --enable-ppolicy=mod --enable-crypt
make depend
make
make install

--prefix:指定安裝目錄
--enable-bdb=no:關閉bdb 數據庫
--enable-hdb=no:關閉hdb 數據庫
--enable-modules=yes:啟用動態模塊
--enable-overlays:激活所有overlay

修改配置文件

此處僅列出需增加或修改的內容
此配置設定了TLS證書、訪問權限、ppolicy默認規則、索引等
slapd.conf

include     /DATA/conf/openldap/schema/collective.schema
include     /DATA/conf/openldap/schema/corba.schema
include     /DATA/conf/openldap/schema/cosine.schema
include     /DATA/conf/openldap/schema/duaconf.schema
include     /DATA/conf/openldap/schema/dyngroup.schema
include     /DATA/conf/openldap/schema/inetorgperson.schema
include     /DATA/conf/openldap/schema/java.schema
include     /DATA/conf/openldap/schema/misc.schema
include     /DATA/conf/openldap/schema/nis.schema
include     /DATA/conf/openldap/schema/openldap.schema
include     /DATA/conf/openldap/schema/pmi.schema
include     /DATA/conf/openldap/schema/ppolicy.schema

loglevel    256
logfile     /DATA/logs/openldap/slapd.log

moduleload  ppolicy.la
moduleload  ppolicy.so

# Certificate/SSL Section
TLSVerifyClient never
TLSCipherSuite DEFAULT
TLSCertificateFile /etc/openldap/ssl/CAcert.pem
TLSCertificateKeyFile /etc/openldap/ssl/CAkey.pem

access to attrs=userPassword,givenName,sn
    by self =xw
    by anonymous auth
    by dn.base="cn=admin,dc=example,dc=com" write
    by dn.base="cn=Manager,dc=example,dc=com" write
    by * none

access to *
    by self read
    by dn.base="cn=admin,dc=example,dc=com" write
    by dn.base="cn=Manager,dc=example,dc=com" write
    by * read

# enable on-the-fly configuration (cn=config)
database config
access to *
    by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
    by * none

# enable server status monitoring (cn=monitor)
database monitor
access to *
    by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read
    by dn.exact="cn=Manager,dc=example,dc=com" read
    by * none

#######################################################################
# MDB database definitions
#######################################################################

database    mdb
maxsize     1073741824
suffix      "dc=example,dc=com"
rootdn      "cn=Manager,dc=example,dc=com"
# Cleartext passwords, especially for the rootdn, should
# be avoid.  See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw      {SSHA}zrXUepdOBZmP1c4qHQdbaqFJ8nhB++Fk
# The database directory MUST exist prior to running slapd AND 
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory   /data/opt/openldap/var/openldap-data
#此段一定要加到database之後,否則會報錯
overlay     ppolicy
ppolicy_default "cn=default,ou=pwpolicies,dc=example.com"
ppolicy_hash_cleartext
ppolicy_use_lockout

# Indices to maintain
index   objectClass         eq,pres
index   ou,cn,mail,surname,givenname    eq,pres,sub
index   uidNumber,gidNumber,loginShell  eq,pres
index   uid,memberUid                   eq,pres,sub
index   nisMapName,nisMapEntry          eq,pres,sub

檢測配置文件

/data/openldap/sbin/slaptest -f /data/conf/openldap/slapd.conf -u
配置文件無誤輸出下行,如有錯誤會有具體信息提示
config file testing succeeded

生成動態配置文件

OpenLDAP 2.3及更高版本,使用運行時動態配置,...簡而言之就是修改配置後無需重啟...
將slapd.conf 配置文件生成為動態配置文件,目錄為slapd.d

/data/openldap/sbin/slaptest -f /data/conf/openldap/slapd.conf -F /data/conf/openldap/slapd.d

生成證書文件

生成頂級CA,支持TLS 協議

cd /etc/openldap/ssl/
openssl req -new -x509 -nodes -out CAcert.pem -keyout CAkey.pem -days 365 

準備基礎用戶及組文件

此處創建ldap用戶及組是通過寫ldif文件實現
創建一個DN,一個rootdn用戶,兩個組People、Groups,一個管理員用戶admin,一個密碼規則相關帳號

cat ~/base.ldif
# example.com
dn: dc=example,dc=com
dc: example
o: liepass.Inc
objectClass: dcObject
objectClass: organization

# Manager,example.com
dn: cn=Manager,dc=example,dc=com
cn: Manager
description: LDAP administrator
objectClass: organizationalRole
objectClass: top
roleOccupant: dc=example,dc=com

# People,example.com
dn: ou=People,dc=example,dc=com
ou: People
objectClass: top
objectClass: organizationalUnit

# Groups,example.com
dn: ou=Groups,dc=example,dc=com
ou: Groups
objectClass: top
objectClass: organizationalUnit

# administrators,example.com
dn: cn=admin,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: shadowAccount
cn: admin
sn: admin
uid: admin
userPassword: {SSHA}RCBSFS+fgrS/a3VvO3pwEmSj8G5d68nd

dn: ou=pwpolicies,dc=example,dc=com
ou: pwpolicies
objectClass: top
objectClass: organizationalUnit

# add default policy to DIT
# attributes preceded with # indicate the defaults and
# can be omitted
# passwords must be reset every 30 days, 
# have a minimum length of 6 and users will
# get a expiry warning starting 1 hour before
# expiry, when the consecutive fail attempts exceed 5
# the count will be locked and can only be reset by an 
# administrator, users do not need to supply the old 
# password when changing
dn: cn=default,ou=pwpolicies,dc=example,dc=com
objectClass: pwdPolicy
objectClass: person
objectClass: shadowAccount
objectClass: organizationalPerson
uid: default
sn: default
cn: default
pwdAttribute: userPassword
pwdMaxAge: 2592000
pwdExpireWarning: 3600
pwdInHistory: 3
#pwdCheckQuality: 0
pwdMaxFailure: 5
pwdLockout: TRUE
#pwdLockoutDuration: 0
#pwdGraceAuthNLimit: 0
#pwdFailureCountInterval: 0
pwdMustChange: TRUE
pwdMinLength: 8
pwdAllowUserChange: TRUE
pwdSafeModify: FALSE

啟動服務,並初始化ldif 文件

前臺啟動服務

/data/openldap/libexec/slapd -F /DATA/conf/openldap/slapd.d/ -h "ldap:/// ldaps:/// ldapi:///" -d 256

ldap:389
ldaps:636
-d:日誌級別
需要註意,TLS 協議使用的是ldap:389,不是ldaps:636

執行base.ldif

/data/openldap/bin/ldapadd -D "cn=Manager,dc=example,dc=com" -W -f ~/base.ldif

創建系統服務

根據實際情況修改如下變量
slapd=/usr/sbin/slapd
slaptest=/usr/sbin/slaptest
lockfile=/var/lock/subsys/slapd
configdir=/etc/openldap/slapd.d/
configfile=/etc/openldap/slapd.conf
pidfile=/var/run/slapd.pid
slapd_pidfile=/var/run/openldap/slapd.pid

cat /etc/init.d/slapd
#!/bin/bash
#
# slapd   This shell script takes care of starting and stopping
#         ldap servers (slapd).
#
# chkconfig: - 27 73
# description: LDAP stands for Lightweight Directory Access Protocol, used #              for implementing the industry standard directory services.
# processname: slapd
# config: /etc/openldap/slapd.conf
# pidfile: /var/run/slapd.pid

### BEGIN INIT INFO
# Provides: slapd
# Required-Start: $network $local_fs
# Required-Stop: $network $local_fs 
# Should-Start: 
# Should-Stop: 
# Default-Start: 
# Default-Stop: 
# Short-Description: starts and stopd OpenLDAP server daemon
# Description: LDAP stands for Lightweight Directory Access Protocol, used
#              for implementing the industry standard directory services.
### END INIT INFO

# Source function library.
. /etc/init.d/functions

# Define default values of options allowed in /etc/sysconfig/ldap
SLAPD_LDAP="yes"
SLAPD_LDAPI="no"
SLAPD_LDAPS="no"
SLAPD_URLS=""
SLAPD_SHUTDOWN_TIMEOUT=3
# OPTIONS, SLAPD_OPTIONS and KTB5_KTNAME are not defined

# Source an auxiliary options file if we have one
if [ -r /etc/sysconfig/ldap ] ; then
    . /etc/sysconfig/ldap
fi

slapd=/usr/sbin/slapd
slaptest=/usr/sbin/slaptest
lockfile=/var/lock/subsys/slapd
configdir=/etc/openldap/slapd.d/
configfile=/etc/openldap/slapd.conf
pidfile=/var/run/slapd.pid
slapd_pidfile=/var/run/openldap/slapd.pid

RETVAL=0

#
# Pass commands given in $2 and later to "test" run as user given in $1.
#
function testasuser() {
    local user= cmd=
    user="$1"
    shift
    cmd="$@"
    if test x"$user" != x ; then
        if test x"$cmd" != x ; then
            /sbin/runuser -f -m -s /bin/sh -c "test $cmd" -- "$user"
        else
            false
        fi
    else
        false
    fi
}

#
# Check for read-access errors for the user given in $1 for a service named $2.
# If $3 is specified, the command is run if "klist" can‘t be found.
#
function checkkeytab() {
    local user= service= klist= default=
    user="$1"
    service="$2"
    default="${3:-false}"
    if test -x /usr/kerberos/bin/klist ; then
        klist=/usr/kerberos/bin/klist
    elif test -x /usr/bin/klist ; then
        klist=/usr/bin/klist
    fi
    KRB5_KTNAME="${KRB5_KTNAME:-/etc/krb5.keytab}"
    export KRB5_KTNAME
    if test -s "$KRB5_KTNAME" ; then
        if test x"$klist" != x ; then
            if LANG=C $klist -k "$KRB5_KTNAME" | tail -n 4 | awk ‘{print $2}‘ | grep -q ^"$service"/ ; then
                if ! testasuser "$user" -r ${KRB5_KTNAME:-/etc/krb5.keytab} ; then
                    true
                else
                    false
                fi
            else
                false
            fi
        else
            $default
        fi
    else
        false
    fi
}

function configtest() {
    local user= ldapuid= dbdir= file=
    # Check for simple-but-common errors.
    user=ldap
    prog=`basename ${slapd}`
    ldapuid=`id -u $user`
    # Unaccessible database files.
    dbdirs=""
    if [ -d $configdir ]; then
        for configfile in `ls -1 $configdir/cn\=config/olcDatabase*.ldif`; do
            dbdirs=$dbdirs"
            "`LANG=C egrep ‘^olcDbDirectory[[:space:]]*:[[:space:]]+[[:print:]]+$‘ $configfile | sed ‘s,^olcDbDirectory: ,,‘`
        done
    elif [ -f $configfile ]; then
        dbdirs=`LANG=C egrep ‘^directory[[:space:]]+‘ $configfile | sed ‘s,^directory[[:space:]]*,,‘ | tr -d \"`
    else
        exit 6
    fi
    for dbdir in $dbdirs; do
        if [ ! -d $dbdir ]; then
            exit 6
        fi
        for file in `find ${dbdir}/ -not -uid $ldapuid -and \( -name "*.dbb" -or -name "*.gdbm" -or -name "*.bdb" -or -name "__db.*" -or -name "log.*" -or -name alock \)` ; do
            echo -n $"$file is not owned by \"$user\"" ; warning ; echo
        done
        if test -f "${dbdir}/DB_CONFIG"; then
            if ! testasuser $user -r "${dbdir}/DB_CONFIG"; then
                file=DB_CONFIG
                echo -n $"$file is not readable by \"$user\"" ; warning ; echo
            fi
        fi
    done
    # Unaccessible keytab with an "ldap" key.
    if checkkeytab $user ldap ; then
        file=${KRB5_KTNAME:-/etc/krb5.keytab}
        echo -n $"$file is not readable by \"$user\"" ; warning ; echo
    fi
    # Check the configuration file.
    slaptestout=`/sbin/runuser -m -s "$slaptest" -- "$user" "-u" 2>&1`
    slaptestexit=$?
#   slaptestout=`echo $slaptestout 2>/dev/null | grep -v "config file testing succeeded"`
    # print warning if slaptest passed but reports some problems
    if test $slaptestexit == 0 ; then
        if echo "$slaptestout" | grep -v "config file testing succeeded" >/dev/null ; then
            echo -n $"Checking configuration files for $prog: " ; warning ; echo
            echo "$slaptestout"
        fi
    fi
    # report error if configuration file is wrong
    if test $slaptestexit != 0 ; then
        echo -n $"Checking configuration files for $prog: " ; failure ; echo
        echo "$slaptestout"
        if /sbin/runuser -m -s "$slaptest" -- "$user" "-u" > /dev/null 2> /dev/null ; then
            #dirs=`LANG=C egrep ‘^directory[[:space:]]+[[:print:]]+$‘ $configfile | awk ‘{print $2}‘`
            for directory in $dbdirs ; do
                if test -r $directory/__db.001 ; then
                    echo -n $"stale lock files may be present in $directory" ; warning ; echo
                fi
            done
        fi
        exit 6
    fi
}

function start() {
    [ -x $slapd ] || exit 5
    [ `id -u` -eq 0 ] || exit 4
    configtest
    # Define a couple of local variables which we‘ll need. Maybe.
    user=ldap
    prog=`basename ${slapd}`
    harg="$SLAPD_URLS"
    if test x$SLAPD_LDAP = xyes ; then
        harg="$harg ldap:///"
    fi
    if test x$SLAPD_LDAPS = xyes ; then
        harg="$harg ldaps:///"
    fi
    if test x$SLAPD_LDAPI = xyes ; then
        harg="$harg ldapi:///"
    fi
    # System resources limit.
    if [ -n "$SLAPD_ULIMIT_SETTINGS" ]; then
        ulimit="ulimit $SLAPD_ULIMIT_SETTINGS &>/dev/null;"
    else
        ulimit=""
    fi
    # Release reserverd port
    [ -x /sbin/portrelease ] && /sbin/portrelease slapd &>/dev/null || :
    # Start daemons.
    echo -n $"Starting $prog: "
    daemon --pidfile=$pidfile --check=$prog $ulimit ${slapd} -h "\"$harg\"" -u ${user} $OPTIONS $SLAPD_OPTIONS 
    RETVAL=$?
    if [ $RETVAL -eq 0 ]; then
        touch $lockfile
        ln $slapd_pidfile $pidfile
    fi
    echo
    return $RETVAL
}

function stop() {
    # Stop daemons.
    prog=`basename ${slapd}`
    [ `id -u` -eq 0 ] || exit 4
    echo -n $"Stopping $prog: "

    # This will remove pid and args files from /var/run/openldap
    killproc -p $slapd_pidfile -d $SLAPD_SHUTDOWN_TIMEOUT ${slapd}
    RETVAL=$?

    # Now we want to remove lock file and hardlink of pid file
    [ $RETVAL -eq 0 ] && rm -f $pidfile $lockfile
    echo
    return $RETVAL
}

# See how we were called.
case "$1" in
    configtest)
        configtest
        ;;
    start)
        start
        RETVAL=$?
        ;;
    stop)
        stop
        RETVAL=$?
        ;;
    status)
        status -p $pidfile ${slapd}
        RETVAL=$?
        ;;
    restart|force-reload)
        stop
        start
        RETVAL=$?
        ;;
    condrestart|try-restart)
        status -p $pidfile ${slapd} > /dev/null 2>&1 || exit 0
        stop
        start
        ;;
    usage)
        echo $"Usage: $0 {start|stop|restart|force-reload|status|condrestart|try-restart|configtest|usage}"
        RETVAL=0
        ;;
    *)
        echo $"Usage: $0 {start|stop|restart|force-reload|status|condrestart|try-restart|configtest|usage}"
        RETVAL=2
esac

exit $RETVAL

添加系統服務

chmod +x /etc/init.d/slapd  && chkconfig slapd on

部署web 管理應用

可選web 有phpldapadmin、ldap-account-manager,ldapadmin
本文不對具體安裝(可見官方文檔)做說明,只對需要註意的點分別做說明

phpldapadmin

請先copy並編輯config.php.example 文件
讀取的SSL/TLS配置文件是/etc/openldap/ldap.conf增加如下內容

# 證書路徑
TLS_CACERTDIR   /etc/openldap/ssl/
TLS_REQCERT allow

ERROR 1

Fatal error: Cannot redeclare password_hash() in /DATA/html/phpldap/lib/functions.php on line 2236
修改lib/functions.php 文件
將password_hash全部替換為password_hash_custom

sed -i "s/password_hash/password_hash_custom/g" lib/functions.php
sed -i "s/password_hash/password_hash_custom/g" lib/TemplateRender.php
sed -i "s/password_hash/password_hash_custom/g" lib/ds_ldap_pla.php
sed -i "s/password_hash/password_hash_custom/g" lib/PageRender.php
sed -i "s/password_hash/password_hash_custom/g" config/config.php

ERROR 2

Unrecognized error number: 8192: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead
修改lib/functions.php 2568 2573

<           $a[$key] = preg_replace(‘/\\\([0-9A-Fa-f]{2})/e‘,"‘‘.chr(hexdec(‘\\1‘)).‘‘",$rdn);
---
>           $a[$key] = preg_replace_callback(‘/\\\([0-9A-Fa-f]{2})/‘,function(){return "‘‘.chr(hexdec(‘\\1‘)).‘‘";},$rdn);

<       return preg_replace(‘/\\\([0-9A-Fa-f]{2})/e‘,"‘‘.chr(hexdec(‘\\1‘)).‘‘",$dn);
---
>       return preg_replace_callback(‘/\\\([0-9A-Fa-f]{2})/‘,function(){return "‘‘.chr(hexdec(‘\\1‘)).‘‘";},$dn);

修改lib/ds_ldap.php 1120 1125

<               $a[$key] = preg_replace(‘/\\\([0-9A-Fa-f]{2})/e‘,"‘‘.chr(hexdec(‘\\1‘)).‘‘",$rdn);
---
>               $a[$key] = preg_replace_callback(‘/\\\([0-9A-Fa-f]{2})/‘,function(){return "‘‘.chr(hexdec(‘\\1‘)).‘‘";},$rdn);

<           return preg_replace(‘/\\\([0-9A-Fa-f]{2})/e‘,"‘‘.chr(hexdec(‘\\1‘)).‘‘",$dn);
---
>           return preg_replace_callback(‘/\\\([0-9A-Fa-f]{2})/‘,function(){return "‘‘.chr(hexdec(‘\\1‘)).‘‘";},$dn);

參考:https://bugs.launchpad.net/ubuntu/+source/phpldapadmin/+bug/1241425/comments/4

ldap-account-manager

ldap-account-manager讀取的SSL/TLS配置文件是/etc/ldap.conf增加如下內容

# 證書路徑
TLS_CACERTDIR   /etc/openldap/ssl/
TLS_REQCERT allow

參考

openldap 官方文檔:http://www.openldap.org/doc/admin24/index.html
TLS 配置說明:http://www.openldap.org/faq/data/cache/185.html
生成CA:https://blog.csdn.net/howeverpf/article/details/21622545?reload
Archlinux:https://wiki.archlinux.org/index.php/OpenLDAP
Archlinux:https://wiki.archlinux.org/index.php/LDAP_authentication
TLS 1.3概述:http://www.inforsec.org/wp/?p=1960
objectClass 介紹:https://blog.csdn.net/qq_27376871/article/details/52037317
ppolicy:http://www.zytrax.com/books/ldap/ch6/ppolicy.html

phpldapadmin相關:
http://permalink.gmane.org/gmane.comp.ldap.davedap/4937
http://forums.debian.net/viewtopic.php?f=5&t=111508

Install openLDAP on centos system