OpenLDAD部署与使用

温馨提醒

LDAP 相关概念

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# LDAP:轻量目录访问协议
# LDAP 服务是一个为只读访问而优化的非关系型数据库,呈树状结构组织数据。
# LDAP 主要用到用户信息查询或对各种服务访问做后台认证及用户数据权限管理。

# 主配置文件,记录根域信息,管理员名称、密码、日志、权限等
/etc/openldap/slapd.conf

# OpenLDAP 的 schema 存放的地址
/etc/openldap/schema/

# OpenLDAP 的数据文件
/var/lib/ldap/

# 模板数据库配置文件
/usr/share/openldap-servers/DB_CONFIG.example

# 监听的端口
默认监听端口:389(明文数据传输)
加密监听端口:636(密文数据传输)
1
2
3
4
5
6
7
使用LDAP(轻型目录访问协议)的主要原因是其开放性和灵活性。LDAP是一个工业标准的目录访问协议,被设计用于访问和操作目录服务器中的信息。它提供了一种标准的接口,使得客户端应用程序可以搜索和修改目录中的信息。

LDAP服务器的优势在于它与关系数据库相比,可以轻松地处理大量用户和组数据,并且更好地适应分布式环境。此外,LDAP服务器在查询上进行了很多优化,可以快速查询出想要的结果。

通俗来说,LDAP就像一张表,只需要用户名和口令,加上一些其他的东西,非常简单。它是一个轻量级的产品,主要目的是为了查,因此在架构和优化主要是针对读,而不是写,从效率和结构上都可以满足认证的需求。这就是为什么LDAP成为很多的统一认证的解决方案的优势所在。

此外,LDAP还支持Kerberos身份验证协议,可以实现单点登录和集中管理,为企业提供更安全、高效的用户身份验证和访问控制管理.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
dn(Distinguished Name):区分名称,LDAP中每个条目都有自己的dn,dn是该条目在整棵树中的唯一标识,如同文件系统中,带路径的文件名就是DN。

rdn(Relative dn):相对区别名称,好比linux中的相对路径。

dc(Domain Component):域名组件。其格式是将完整的域名分成几部分,如将http://example.com变成dc=example,dc=com。

uid(User ID):用户ID,如 san.zhang。

ou(Organization Unit):组织单元。

cn(Common Name):公共名称。

sn(surname):姓氏。

c(Country):国家,如“CN”或者“US”。

o(Organization):组织名,如XXX银行,XXX部门,XXX公司等等。

OpenLDAP 的 objectClass

objectClass含义
olcGlobal全局配置文件类型, 主要是cn=config.ldif 的配置项
top顶层的对象
organization组织,比如公司名称,顶层的对象
organizationalUnit重要, 一个目录节点,通常是group,或者部门这样的含义
inetOrgPerson重要, 我们真正的用户节点类型,person类型, 叶子节点
groupOfNames重要, 分组的group类型,标记一个group节点
olcModuleList配置模块的对象

OpenLDAP 常用关键字列表

关键字英文全称含义
dcDomain Component域名的部分,其格式是将完整的域名分成几部分,如域名为example.com变成dc=example,dc=com
ouOrganization Unit组织单位,类似于Linux文件系统中的子目录,它是一个容器对象,组织单位可以包含其他各种对象(包括其他组织单元),最多可以有四级,每级最长32个字符,可以为中文
cnCommon Name为用户名或服务器名,最长可以到80个字符,可以为中文
snSurname姓,如“Johansson”
dnDistinguished Name惟一辨别名,类似于Linux文件系统中的绝对路径,每个对象都有一个惟一的名称,如:dc: “cn=admin,ou=developer,dc=xbd,dc=com”,在一个目录树中DN总是惟一的
rdnRelative dn相对辨别名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,如“uid=tom”或“cn= Thomas Johansson”
cCountry国家,如“CN”或“US”等。
oOrganization组织名,如“Example, Inc.”

安装

使用 yum 安装

  • 安装

    1
    
    yum install -y openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel
  • OpenLDAP 相关配置文件

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    /etc/openldap/slapd.conf:OpenLDAP的主配置文件,记录根域信息,管理员名称,密码,日志,权限等
    
    /etc/openldap/slapd.d/:这下面是/etc/openldap/slapd.conf配置信息生成的文件,每修改一次配置信息,这里的东西就要重新生成
    
    /etc/openldap/schema/:OpenLDAP的schema存放的地方
    
    /var/lib/ldap/:OpenLDAP的数据文件
    
    /usr/share/openldap-servers/slapd.conf.obsolete 模板配置文件
    
    /usr/share/openldap-servers/DB_CONFIG.example 模板数据库配置文件
    
    OpenLDAP监听的端口: 默认监听端口:389(明文数据传输) 加密监听端口:636(密文数据传输)

docker-compose 部署

  • 自定义 ldif 文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    vim ./openldap/config/init.ldif
    
    dn: ou=People,dc=example,dc=net
    objectClass: organizationalUnit
    ou: people
    
    dn: ou=Group,dc=example,dc=net
    objectClass: organizationalUnit
    ou: group
  • yaml 文件

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    version: "3"
    services:
      openldap:
        container_name: "openldap"
        image: "osixia/openldap:latest"
        restart: always
        environment:
          LDAP_ORGANISATION: "openldap"
          LDAP_DOMAIN: "example.com"
          LDAP_ADMIN_PASSWORD: "123456"
          LDAP_CONFIG_PASSWORD: "123456"
          TZ: Asia/Shanghai
        command: [ '--copy-service' ]
        volumes:
          - ./ldap/data:/var/lib/ldap  						# 如果需要的话,可以配置挂载持久化目录
          - ./ldap/config:/etc/ldap/slapd.d  				# 如果需要的话,可以配置挂载持久化目录
          - ./openldap/config:/container/service/slapd/assets/config/bootstrap/ldif/custom 		# 注意这里是目录挂载到目录,需要提前创建放入自定义的ldif文件
        ports:
          - 388:389

OpenLDAP 配置

OpenLDAP 初始化

  • 设置 OpenLDAP 根密码

    1
    2
    3
    4
    5
    
    slappasswd
    
    New password:			# 密码为 123456
    Re-enter new password:
    {SSHA}3qqYRnslkZG0Da5ePYLqpxPDEfu9ucZk
  • 配置 OpenLDAP 数据库

    1
    2
    3
    4
    
    cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
    chown ldap:ldap /var/lib/ldap/
    chmod -R 700 /var/lib/ldap/
    systemctl enable --now slapd
  • 初始化配置

    1
    2
    3
    4
    5
    6
    7
    8
    
    # vim changepwd.ldif
    
    dn: olcDatabase={0}config,cn=config
    changetype: modify
    replace: olcRootPW
    olcRootPW: {SSHA}3qqYRnslkZG0Da5ePYLqpxPDEfu9ucZk
    
    # ldapadd -Y EXTERNAL -H ldapi:/// -f changepwd.ldif

    修改 olcDatabase={2}hdb.ldif 文件

    1
    2
    3
    4
    5
    
    vim /etc/openldap/slapd.d/cn\=config/olcDatabase\=\{2\}hdb.ldif
    
    olcSuffix: dc=chenji,dc=com								# 修改
    olcRootDN: cn=admin,dc=chenji,dc=com					# 修改
    olcRootPW: {SSHA}3jXcca4m9bZ5l5PeX/W1kAFsXePBWM9V		# 添加此行

    修改 olcDatabase={1}monitor.ldif 文件

    1
    2
    3
    
    vim /etc/openldap/slapd.d/cn\=config/olcDatabase\=\{1\}monitor.ldif
    
    olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=admin,dc=chenji,dc=com" read by * none

    验证 OpenLDAP 基本配置

    1
    
    slaptest -u
  • 导入 schema

    其中 core.ldif 默认已经加载了,不用导入

    1
    
    ls /etc/openldap/schema/*.ldif | while read f; do if [[ $f != */core.ldif ]]; then ldapadd -Y EXTERNAL -H ldapi:/// -f $f; fi; done
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    ls /etc/openldap/schema/
    collective.ldif    		# 定义了集体属性的schema
    corba.ldif   			# 定义了与CORBA相关的属性
    cosine.ldif    			# 定义了与Cosine协议相关的属性
    duaconf.ldif    		# 定义了与Dua配置文件相关的属性
    dyngroup.ldif    		# 定义了动态组的属性
    inetorgperson.ldif    	# 这是一个非常流行的schema,用于表示Internet风格的用户。它通常包括sn, givenname, mail, ou, cn等属性
    java.ldif    		# 定义了与Java相关的属性
    misc.ldif    		# 包含一些杂项属性
    nis.ldif    		# 定义了与NIS (Network Information Service) 相关的属性
    openldap.ldif    	# 定义了一些OpenLDAP特有的属性
    pmi.ldif    		# 定义了与PMI (Public Key Infrastructure) 相关的属性
    ppolicy.ldif		# 定义了密码策略相关的属性
    
    core.ldif			# 这是OpenLDAP的核心schema,它定义了许多基本的属性,如cn, ou, uid等

    由于要对接 RADIUS,所以我们需要把 RADIUS 的属性文件加进去

    1
    2
    
    curl https://estatic.toughstruct.net/radius.ldif > /etc/openldap/schema/radius.ldif
    ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/radius.ldif
  • 设定默认域

    编写 RootDN 的 ldif 文件

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    vim changedomain.ldif
    
    dn: olcDatabase={1}monitor,cn=config
    changetype: modify
    replace: olcAccess
    olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=admin,dc=gaoyufu,dc=net" read by * none
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcSuffix
    olcSuffix: dc=gaoyufu,dc=net
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcRootDN
    olcRootDN: cn=admin,dc=gaoyufu,dc=net
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcRootPW
    olcRootPW: {SSHA}3qqYRnslkZG0Da5ePYLqpxPDEfu9ucZk
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    add: olcAccess
    olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=gaoyufu,dc=net" write by anonymous auth by self write by * none
    olcAccess: {1}to dn.base="" by * read
    olcAccess: {2}to * by dn="cn=admin,dc=gaoyufu,dc=net" write by * read

    导入

    1
    
    ldapmodify -Y EXTERNAL -H ldapi:/// -f changedomain.ldif

    启用 memberof 功能

    开启memberof支持,新增用户支持memberof配置

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    vim add-memberof.ldif
    dn: cn=module{0},cn=config
    cn: modulle{0}
    objectClass: olcModuleList
    objectclass: top
    olcModuleload: memberof.la
    olcModulePath: /usr/lib64/openldap
    
    dn: olcOverlay={0}memberof,olcDatabase={2}hdb,cn=config
    objectClass: olcConfig
    objectClass: olcMemberOf
    objectClass: olcOverlayConfig
    objectClass: top
    olcOverlay: memberof
    olcMemberOfDangling: ignore
    olcMemberOfRefInt: TRUE
    olcMemberOfGroupOC: groupOfUniqueNames
    olcMemberOfMemberAD: uniqueMember
    olcMemberOfMemberOfAD: memberOf

    新增refint1.ldif文件

    1
    2
    3
    4
    5
    
    vim refint1.ldif
    
    dn: cn=module{0},cn=config
    add: olcmoduleload
    olcmoduleload: refint

    新增refint2.ldif文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    vim refint2.ldif
    
    dn: olcOverlay=refint,olcDatabase={2}hdb,cn=config
    objectClass: olcConfig
    objectClass: olcOverlayConfig
    objectClass: olcRefintConfig
    objectClass: top
    olcOverlay: refint
    olcRefintAttribute: memberof uniqueMember  manager owner

    加载配置,顺序不能错

    1
    2
    3
    
    ldapadd -Q -Y EXTERNAL -H ldapi:/// -f add-memberof.ldif
    ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f refint1.ldif
    ldapadd -Q -Y EXTERNAL -H ldapi:/// -f refint2.ldif

    创建组

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    vim base.ldif
    
    dn: dc=gaoyufu,dc=net
    objectClass: top
    objectClass: dcObject
    objectclass: organization
    o: gaoyufu com
    dc: gaoyufu
    
    dn: cn=admin,dc=gaoyufu,dc=net
    objectClass: organizationalRole
    cn: admin
    description: Directory admin
    
    dn: ou=People,dc=gaoyufu,dc=net
    objectClass: organizationalUnit
    ou: People
    
    dn: ou=Group,dc=gaoyufu,dc=net
    objectClass: organizationalUnit
    ou: Group

    导入

    1
    
    ldapadd -x -D cn=admin,dc=gaoyufu,dc=net -W -f base.ldif

OpenLDAP 优化

  • 开启日志

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    # vim loglevel.ldif
    
    dn: cn=config
    changetype: modify
    replace: olcLogLevel
    olcLogLevel: stats
    
    # ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f loglevel.ldif
    
    # grep 'olcLogLevel' /etc/openldap/slapd.d/cn\=config.ldif
    olcLogLevel: Stats
  • 配置 rsyslog

    修改 /etc/rsyslog.conf 配置文件

    1
    2
    3
    
    cat >> /etc/rsyslog.conf << EOF
    local4.*  /var/log/slapd/slapd.log
    EOF

    重启 rsyslog,然后在目录/var/log/slapd/slapd.log下就可以看到slapd产生的日志了

    1
    2
    3
    4
    5
    6
    7
    
    mkdir -p /var/log/slapd
    
    chown ldap.ldap /var/log/slapd/
    
    systemctl restart rsyslog
    
    systemctl restart slapd   # 重启看到日志   ls /var/log/slapd/
  • 禁止匿名访问

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    # vim disable_anon.ldif
    dn: cn=config
    changetype: modify
    add: olcDisallows
    olcDisallows: bind_anon
    
    dn: cn=config
    changetype: modify
    add: olcRequires
    olcRequires: authc
    
    dn: olcDatabase={-1}frontend,cn=config
    changetype: modify
    add: olcRequires
    olcRequires: authc
    
    # ldapadd -Y EXTERNAL -H ldapi:/// -f disable_anon.ldif

添加用户及用户组

  • 配置LDAP的顶级域(dc=chenji,dc=com为例)及管理域

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    # 与上面的“配置 LDAP 服务--修改 olcDatabase={2}hdb.ldif 文件” 相同
    
    # cn=admin中的admin表示OpenLDAP管理员的用户名,dc是我们组织信息,而olcRootPW表示OpenLDAP管理员的密码,用刚刚 slappasswd 生成的密码
    vim db.ldif
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcSuffix
    olcSuffix: dc=chenji,dc=com
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcRootDN
    olcRootDN: cn=admin,dc=chenji,dc=com
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    add: olcRootPW
    olcRootPW: {SSHA}ZQnsvYcVp5XoXHq538FZCUkAljubXTlp
    
    ldapmodify -Y EXTERNAL -H ldapi:/// -f db.ldif
  • 添加 monitor.ldif

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    # 与上面的“配置 LDAP 服务--修改 olcDatabase={1}monitor.ldif 文件” 相同
    
    vim monitor.ldif
    
    dn: olcDatabase={1}monitor,cn=config
    changetype: modify
    replace: olcAccess
    olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" read by dn.base="cn=admin,dc=chenji,dc=com" read by * none
    
    ldapadd -x -D cn=admin,dc=chenji,dc=com -W -f monitor.ldif
  • 创建基本组信息

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    # 创建一个组织,并在其下创建一个admin的组织角色(该角色内的用户具有管理整个 LDAP 的权限)和 People 和 Group 两个组织单元
    vim base.ldif
    
    dn: dc=chenji,dc=com
    dc: chenji
    objectClass: top
    objectClass: domain
    
    dn: cn=admin,dc=chenji,dc=com
    objectClass: organizationalRole
    cn: admin
    description: LDAP Manager
    
    dn: ou=People,dc=chenji,dc=com
    objectClass: organizationalUnit
    ou: People
    
    dn: ou=Group,dc=chenji,dc=com
    objectClass: organizationalUnit
    ou: Group
    
    ldapadd -x -W -D "cn=admin,dc=chenji,dc=com" -f base.ldif
    
    # 通过以上步骤,我们就设置了一个 LDAP 目录树,其中 dn: dc=chenji,dc=com 是该树的根节点
    # 其下有一个管理域(dn: cn=admin ,dc=chenji,dc=com)
    # 两个组织单元(dn: ou=People,dc=chenji,dc=com)及(dn: ou=Group,dc=chenji,dc=com)

添加系统普通用户

  • 安装 migrationtools

    1
    2
    
    # 默认是没有 migrationtools 所需的命令,安装
    yum install migrationtools
  • 创建普通用户

    1
    
    useradd test
  • 创建 OpenLDAP 根域条目

    1
    
    /usr/share/migrationtools/migrate_base.pl > base.ldif
  • 修改 migrationtools 配置文件,把内容改为自己的域(71行左右)

    1
    2
    3
    4
    5
    6
    7
    
    vim /usr/share/migrationtools/migrate_common.ph
    
    # Default DNS domain
    $DEFAULT_MAIL_DOMAIN = "chenji.com";
    
    # Default base 
    $DEFAULT_BASE = "dc=chenji,dc=com";
  • 通过 migrationtools 工具生成 LDAP 模板文件并生成系统用户及组 LDIF 文件

    1
    2
    3
    4
    
    tail -n 1 /etc/passwd > system
    /usr/share/migrationtools/migrate_passwd.pl system people.ldif
    tail -n 1 /etc/group > group
    /usr/share/migrationtools/migrate_group.pl group group.ldif
  • 利用 ldapadd 导入模板文件

    1
    2
    3
    4
    5
    
    # 导入 LDIF 文件到 OpenLDAP 目录树中,生成用户
    ldapadd -x -W -D "cn=admin,dc=chenji,dc=com" -f people.ldif
    
    # 导入 LDIF 文件至 OpenLDAP 目录树中,生成用户组
    ldapadd -x -W -D "cn=admin,dc=chenji,dc=com" -f group.ldif

备份的三种方法

  • slapcat 备份

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    cat >/data/openldap/init/backup/backup.sh <<EOF
    #!/bin/bash
    echo '准备开始备份ldap'
    DATEFORMATTYPE=\$(date +%Y-%m-%d)
    echo \$DATEFORMATTYPE
    
    LDAPSCAT=/usr/sbin/slapcat
    #备份目录
    BACKDIR=/init/backup
    
    slapcat -v -l \${BACKDIR}/backup_\${DATEFORMATTYPE}.ldif
    
    #删除10天前的备份
    find ${BACKDIR} -mtime +10 -name "*.ldif" -exec rm -rf {} \; >& /dev/null
    EOF
    
    chmod +x /data/openldap/init/backup/backup.sh
    sh /data/openldap/init/backup/backup.sh

    参数说明

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    -v:启用verbose模式,输出更详细的备份信息
    -c:启用continue模式,会忽略错误,继续执行备份
    -g:禁用subordinate gluing,不备份子数据库
    -d level:开启debug模式,输出debug信息
    -b suffix:使用指定的后缀来决定哪个数据库需要备份。这个参数不能与-n一起使用
    -n dbnum:为指定的第dbnum个数据库生成备份。这个参数不能与-b一起使用
    -a filter:过滤条件,比如 slapcat -a "(!(entryDN:dnSubtreeMatch:=ou=People,dc=example,dc=com))" 会备份所有dc=example,dc=com下的不包含ou=People,dc=example,dc=com子树的数据
    -f slapd.conf:指定slapd.conf配置文件
    -F confdir:指定slapd配置文件目录,比如CentOS下的/etc/openldap/slapd.d。如果-f和-F同时被指定,则使用-f的配置,如果两者都没有被指定,则使用默认配置
    -l ldif-file:需要生成的ldif文件名称

    删除所有数据

    1
    
    ldapdelete -x -D "cn=admin,dc=example,dc=com" -w 123456 -r "dc=example,dc=com"		# -r 递归删除指定条目的所有子条目

    恢复数据

    1
    2
    
    slapadd -l /root/openldap.ldif
    ldapadd -x -D "cn=admin,dc=example,dc=com" -H ldap://192.168.1.10:389 -W -f slapdata.ldif
  • ldapsearh 备份

    1
    
    ldapsearch -x -b 'dc=example,dc=com' -H ldap://192.168.1.10:389 -D 'cn=admin,dc=example,dc=com' -W > backup.ldif
  • 整目录备份

    1
    2
    
    cd /data/openldap
    tar zcvf backup.tar.gz  data config init certs

OpenLDAP 启用 lts

  • 升级 openssl

  • 配置 lts 证书

    编写根证书配置文件

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    # vim ca.conf
    [ req ]
    distinguished_name  = req_distinguished_name
    string_mask         = utf8only
    x509_extensions     = v3_ca
    prompt              = no
    
    [ req_distinguished_name ]
    countryName                     = CN
    stateOrProvinceName             = Shanxi
    localityName                    = Shanxi
    organizationName                = gaoyufu
    organizationalUnitName          = gaoyufu
    commonName                      = gaoyufu Certificate Authority
    emailAddress                    = admin@gaoyufu.org
    
    [ v3_ca ]
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always,issuer
    basicConstraints = critical, CA:true
    keyUsage = critical, digitalSignature, keyCertSign

    生成根证书的 4096 位 RSA 私钥,并签发 20年根证书

    1
    2
    
    # openssl genrsa -out ca.key 4096
    # openssl req -x509 -new -sha512 -nodes -key ca.key -days 7307 -out ca.crt -config ca.conf
  • 编写服务器证书配置

    commonName 和 sans 部分要与服务器主机名一致

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    # vim server.conf
    [ req ]
    prompt              = no
    days                = 365
    default_md          = sha256
    distinguished_name  = req_distinguished_name
    x509_extensions      = v3_server
    
    [ req_distinguished_name ]
    countryName                     = CN
    stateOrProvinceName             = Shanxi
    localityName                    = Shanxi
    organizationName                = gaoyufu
    organizationalUnitName          = gaoyufu
    commonName                      = fabric01-test_aliyun
    emailAddress                    = admin@gaoyufu.org
    
    [ v3_server ]
    basicConstraints = CA:false
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always,issuer:always
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth, clientAuth
    subjectAltName = @sans
    
    [ sans ]
    DNS.0 = fabric01-test_aliyun

    签发服务器证书请求,再用根证书签发服务器证书

    1
    2
    3
    
    # openssl genrsa -out server.key 2048
    # openssl req -config server.conf -key server.key -new -out server.csr
    # openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -out server.crt -extfile server.conf -extensions v3_server -CAcreateserial

    验证服务器证书

    1
    2
    
    # openssl verify -CAfile ca.crt server.crt
    server.crt: OK
  • OpenLDAP 配置 lts

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    # 指定 DH 参数
    # wget -O server.key https://ssl-config.mozilla.org/ffdhe2048.txt	
    # vim tls.ldif
    dn: cn=config
    changetype: modify
    add: olcTLSCACertificateFile
    olcTLSCACertificateFile: /path/to/ca.crt
    -
    add: olcTLSCertificateFile
    olcTLSCertificateFile: /path/to/server.crt
    -
    add: olcTLSCertificateKeyFile
    olcTLSCertificateKeyFile: /path/to/server.key
    -
    add: olcTLSCipherSuite
    olcTLSCipherSuite: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
    -
    add: olcTLSDHParamFile
    olcTLSDHParamFile: /path/to/server.key

    更新配置

    1
    
    slapmodify -n 0 -F /usr/local/etc/slapd.d -l certs.ldif

    禁用明文操作

    1
    2
    3
    4
    5
    6
    7
    
    # vim ssf.ldif
    dn: cn=config
    changetype: modify
    add: olcSecurity
    olcSecurity: ssf=128
    
    # slapmodify -n 0 -F /usr/local/etc/slapd.d -l ssf.ldif

部署 phpldapadmin

PHPLDAPadmin是一个用于管理LDAP(轻量级目录访问协议)的Web界面。它可以帮助用户轻松管理和编辑LDAP目录

yum 安装

  • 配置安装源

    1
    2
    3
    
    rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-7.rpm
    yum -y install epel-release
    yum-config-manager --enable remi-php74
  • 安装

    1
    2
    3
    4
    
    yum install php-Smarty php74-php-fpm php74-php-gd php74-php-json php74-php-mbstring php74-php-xmlrpc php74-php-opcache php74-php-ldap -y
    systemctl enable --now php74-php-fpm.service
    systemctl status php74-php-fpm.service
    yum install -y phpldapadmin
  • 修改配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    vim /etc/phpldapadmin/config.php
    
    #398行,dn为使用dn登陆,cn为使用用户名登陆,可选其一
    $servers->setValue('login','attr','dn');
    // $servers->setValue('login','attr','uid');
    #460行,关闭匿名登录,必做
    $servers->setValue('login','anon_bind',false);
    #519行,保证用户属性的唯一性
    $servers->setValue('unique','attrs',array('mail','uid','uidNumber','cn','sn'));
  • 配置 nginx 代理

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    vim /etc/nginx/conf.d/phpldapadmin.conf
    
    server {
            listen          8080;
            server_name     localhost;
            access_log      /var/log/nginx/phpldapadmin_access.log;
            error_log       /var/log/nginx/phpldapadmin_errors.log;
    
            root /usr/share/phpldapadmin/htdocs/;
            index index.php index.html;
    
           location ~ \.php {
                    fastcgi_split_path_info ^(.+\.php)(/.+)$;
                    fastcgi_pass 127.0.0.1:9000;
                    fastcgi_index index.php;
                    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                    include fastcgi_params;
            }
    }

    如出现如下报错解决办法

    Deprecated: Array and string offset access syntax with curly braces is deprecated in /usr/share/phpldapadmin/lib/functions.php on line 1641

    1
    2
    3
    4
    5
    6
    7
    8
    
    vim /usr/share/phpldapadmin/lib/functions.php
    
    1640         if (in_array('sambaaccount',$object_classes) &&
    1641                 '$' == $rdn[ strlen($rdn) - 1 ])			# 将使用大括号 {} 的数组或字符串偏移量访问语法修改为使用方括号 []
    1642                 return 'nt_machine.png';
    
    nginx -s reload
    systemctl restart php74-php-fpm.service
  • 访问

    http://IP:8080

    DN:cn=admin,dc=gaoyufu,dc=net

    密码:123456

docker-compose 部署

  • yaml 文件

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    version: "3"
    services:
      phpldapadmin:
        image: osixia/phpldapadmin:0.9.0
        container_name: phpldapadmin
        hostname: phpldapadmin
        restart: always
        environment:
          TZ: Asia/Shanghai 							# 设置容器时区与宿主机保持一致
          PHPLDAPADMIN_HTTPS: "false" 					# 是否使用https
          PHPLDAPADMIN_LDAP_HOSTS: openldap 			# 指定LDAP连接地址
        ports:
          - 8090:80
        volumes:
          - ./phpadmin:/var/www/phpldapadmin  			# 如果需要的话,可以配置挂载持久化目录

    当打开phpldapadmin页面发现是英文时可以执行以下命令

    1
    
    docker exec -it phpldapadmin sed -i -e 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales

部署 self-service-password

self-service-password是一个用于重置和更改密码的Web应用程序,旨在提供一种方便的方式来管理密码。这个应用程序可以与LDAP目录进行交互,允许用户在不需要依赖管理员或访问密码的情况下更改其密码。通过self-service-password,用户可以通过一个简单的Web界面访问其密码,并在需要时进行更改。这个应用程序还提供了许多安全功能,例如密码重置链接和双因素身份验证,以保护用户的账户和数据安全。

  • 添加软件源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    vim /etc/yum.repos.d/ltb-project.repo
    
    [ltb-project-noarch]
    name=LTB project packages (noarch)
    baseurl=https://ltb-project.org/rpm/$releasever/noarch
    enabled=1
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project
    # rpm --import https://ltb-project.org/wiki/lib/RPM-GPG-KEY-LTB-project
  • 安装

    php7.4 安装方法同上

    1
    2
    
    yum -y install self-service-password
    yum -y install sendmail
  • 配置 nginx 代理

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    
    vim /etc/nginx/conf.d/self-service-password.conf
    
    server {
        listen 8888;			# 前端页面端口,可自行更改
    
        root /usr/share/self-service-password/htdocs;
        index index.php index.html index.htm;
    
    # Make site accessible from http://localhost/
        server_name localhost;
    
    # Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
        sendfile off;
    
        gzip on;
        gzip_comp_level 6;
        gzip_min_length 1000;
        gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
        gzip_vary on;
        gzip_proxied any;
        gzip_disable "MSIE [1-6]\.(?!.*SV1)";
    
    # Add stdout logging
        access_log /var/log/php-access.log;
        error_log /var/log/php-error.log;
    
    # pass the PHP scripts to FastCGI server listening on socket
    #
        location ~ \.php {
            #fastcgi_pass unix:/var/run/php-fpm.socket;
            fastcgi_split_path_info       ^(.+\.php)(/.+)$;
            fastcgi_param PATH_INFO       $fastcgi_path_info;
            fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_index index.php;
            try_files $fastcgi_script_name =404;
            fastcgi_read_timeout 600;
            fastcgi_pass 127.0.0.1:9000;
            include fastcgi_params;
        }
    
        error_page 404 /404.html;
        location = /404.html {
                root /usr/share/nginx/html;
                internal;
        }
    
    # deny access to . files, for security
    #
        location ~ /\. {
                log_not_found off;
                deny all;
        }
    
        location ~ /scripts {
                log_not_found off;
                deny all;
        }
    
    }
    
    
    nginx -s reload
  • 配置 self-service-password

    • 关联 ldap

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      
      cd /usr/share/self-service-password/conf/
      
      vim config.inc.php
      
      $ldap_url = "ldap://127.0.0.1:389";
      $ldap_starttls = false;
      $ldap_binddn = "cn=admin,dc=example,dc=com";
      $ldap_bindpw = '123465';
      // for GSSAPI authentication, comment out ldap_bind* and uncomment ldap_krb5ccname lines
      //$ldap_krb5ccname = "/path/to/krb5cc";
      $ldap_base = "dc=example,dc=com";
      $ldap_login_attribute = "uid";
      $ldap_fullname_attribute = "cn";
      $ldap_filter = "(&(objectClass=person)($ldap_login_attribute={login}))";
      $ldap_use_exop_passwd = false;
      $ldap_use_ppolicy_control = false;
    • 配置邮件

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      
      ## Mail
      # LDAP mail attribute
      $mail_attributes = array( "mail", "gosaMailAlternateAddress", "proxyAddresses" );
      # Get mail address directly from LDAP (only first mail entry)
      # and hide mail input field
      # default = false
      $mail_address_use_ldap = false;
      # Who the email should come from
      $mail_from = "132465789@163.com";
      $mail_from_name = "LDAP密码重置服务";
      $mail_signature = "本邮件为通过密码自助修改LDAP账号密码,无需回复,如有重置密码遇到问题可以联系运维同学";
      # Notify users anytime their password is changed
      $notify_on_change = true;
      # PHPMailer configuration (see https://github.com/PHPMailer/PHPMailer)
      $mail_sendmailpath = '/usr/sbin/sendmail';
      $mail_protocol = 'smtp';
      $mail_smtp_debug = 0;
      $mail_debug_format = 'html';
      $mail_smtp_host = 'smtp.163.com';
      $mail_smtp_auth = true;
      $mail_smtp_user = '132465798@163.com';
      $mail_smtp_pass = '11111111111111111111';
      $mail_smtp_port = 465;
      $mail_smtp_timeout = 30;
      $mail_smtp_keepalive = false;
      $mail_smtp_secure = 'ssl';
      $mail_smtp_autotls = true;
      $mail_smtp_options = array();
      $mail_contenttype = 'text/plain';
      $mail_wordwrap = 0;
      $mail_charset = 'utf-8';
      $mail_priority = 3;
    • 配置重置密码

      $keyphrase是配置文件中的一个重要参数。它用于加密和验证密码重置链接,确保链接的安全性和有效性。

      当用户请求密码重置时,系统会生成一个包含$keyphrase的加密链接,并将其发送给用户。用户点击链接后,系统会使用相同的$keyphrase来验证链接的有效性,并允许用户重置密码。

      因此,$keyphrase的作用是确保密码重置链接的安全性和验证过程的正确性。建议将$keyphrase设置为一个强密码,并定期更改以增加安全性。

      1
      
      $keyphrase = "zzzzzzzzzzzzzzz";	
    • 设置中文页面

      1
      
      $lang = "zh-CN";
    • 更换自定义 logo

      1
      
      $logo = "images/ltb-logo.png";

OpenLDAP 高可用

实现方法

OpenLDAP的高可用可以通过多种方式实现

主从同步(Master-Slave Synchronization):在主从同步模式下,主服务器负责处理所有写操作,并将这些操作复制到从服务器。从服务器仅处理读操作,并保持与主服务器的数据同步。为了实现主从同步,您需要确保主服务器和从服务器的OpenLDAP配置完全一致,包括目录结构、条目和权限等。您还需要在主服务器上配置适当的复制规则和过滤器,以指定哪些数据需要复制到从服务器。

双主镜像(Dual-Master Replication):在双主镜像模式下,两个服务器都配置为主服务器,并且它们之间相互复制数据。当一个服务器出现故障时,另一个服务器可以继续提供服务,并且数据仍然保持一致。为了实现双主镜像模式,您需要确保两个服务器的OpenLDAP配置完全一致,并配置适当的复制规则和过滤器。此外,您还需要使用一种负载均衡机制来将客户端请求分发到两个服务器上,例如使用NGINX+keepalived。

OpenLDAP 不管是主从同步还是双主镜像模式都需要满足以下六点

  • OpenLDAP 服务器之间要保持时间同步
  • OpenLDAP 软件包版本保持一致
  • OpenLDAP 节点之间域名可以相互解析
  • 配置OpenLDAP 同步复制,需要提供完全一样的配置及目录树信息
  • 数据条目保持一致
  • 额外的schema文件保持一致

主从同步

  • 主节点配置

    添加 syncprov 模块

    1
    2
    3
    4
    5
    6
    7
    
    cat >mod_syncprov.ldif << EOF
    dn: cn=module,cn=config
    objectClass: olcModuleList
    cn: module
    olcModulePath: /usr/lib64/openldap
    olcModuleLoad: syncprov.la
    EOF

    导入配置

    1
    
    ldapadd -Y EXTERNAL -H ldapi:/// -f mod_syncprov.ldif

    生成 syncprov.ldif 文件

    1
    2
    3
    4
    5
    6
    7
    8
    
    cat> syncprov.ldif << EOF
    dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    olcSpCheckpoint: 100 10	# 表示同步的满足条件,当满足修改100个条目或者1分钟主动进行推送一次
    olcSpSessionLog: 100	# 会话日志条目的最大数量
    EOF
    1
    
    ldapadd -Y EXTERNAL -H ldapi:/// -f mod_syncprov.ldif
  • 从节点配置

    生成 syncrepl.ldif 文件

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    cat > syncrepl.ldif<< EOF
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    add: olcSyncRepl
    olcSyncRepl: rid=001
      provider=ldap://192.168.1.10:389/		# ldap master的地址
      bindmethod=simple		# 加密方式
      binddn="cn=admin,dc=daemon,dc=com"	# 为域的基本信息,注这里一定要用管理员进行登录,否则同步不到用户的密码
      credentials=Admin@123#!		# ldap管理员的密码
      searchbase="dc=daemon,dc=com"		# 选择要同步的独立域,根节点
      scope=sub						# 设置所有的条目匹配,这里是子树
      schemachecking=on				# 启用模式检查
      type=refreshAndPersist	# 同步模式为refreshAndPersist, refreshOnly 模式下后续操作由客户端轮询完成
      retry="5 5 300 +"		# 指定重试的时间间隔,这里是5分钟内重试5次,300秒后继续尝试
      attrs="*,+"			# 指定要同步的属性,这里是所有属性(+表示包括 operational 和结构性属性
      interval=00:00:00:3	# 指定同步的时间间隔,这里是每3秒同步一次,倒数第二个是分钟以此类推
    EOF 

    导入配置

    1
    
    ldapadd -Y EXTERNAL -H ldapi:/// -f syncprov.ldif

双主镜像

  • 第一个主节点

    添加 syncprov 模块

    1
    2
    3
    4
    5
    6
    7
    
    cat >mod_syncprov.ldif << EOF
    dn: cn=module,cn=config
    objectClass: olcModuleList
    cn: module
    olcModulePath: /usr/lib64/openldap
    olcModuleLoad: syncprov.la
    EOF

    导入配置

    1
    
    ldapadd -Y EXTERNAL -H ldapi:/// -f mod_syncprov.ldif

    生成 syncprov.ldif 文件

    1
    2
    3
    4
    5
    6
    7
    8
    
    cat> syncprov.ldif << EOF
    dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    olcSpCheckpoint: 100 10
    olcSpSessionLog: 100
    EOF

    开启镜像同步

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    cat > syncrepl.ldif<< EOF
    dn: cn=config
    changetype: modify
    replace: olcServerID
    olcServerID: 0
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    add: olcSyncRepl
    olcSyncRepl: rid=001
      provider=ldap://192.168.1.10:389
      bindmethod=simple
      binddn="cn=admin,dc=daemon,dc=com"
      credentials=Admin@123#!
      searchbase="dc=daemon,dc=com"
      scope=sub
      schemachecking=on
      type=refreshAndPersist
      retry="5 5 300 +"
      interval=00:00:00:3
    -
    add: olcMirrorMode
    olcMirrorMode: TRUE
    
    dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
    changetype: add
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    EOF

    导入配置

    1
    
    ldapadd -Y EXTERNAL -H ldapi:/// -f syncprov.ldif
  • 第二个主节点

    添加 syncprov 模块

    1
    2
    3
    4
    5
    6
    7
    
    cat >mod_syncprov.ldif << EOF
    dn: cn=module,cn=config
    objectClass: olcModuleList
    cn: module
    olcModulePath: /usr/lib64/openldap
    olcModuleLoad: syncprov.la
    EOF

    导入配置

    1
    
    ldapadd -Y EXTERNAL -H ldapi:/// -f mod_syncprov.ldif

    生成 syncprov.ldif 文件

    1
    2
    3
    4
    5
    6
    7
    8
    
    cat> syncprov.ldif << EOF
    dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    olcSpCheckpoint: 100 10
    olcSpSessionLog: 100
    EOF

    开启镜像同步

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    cat > syncrepl.ldif<< EOF
    dn: cn=config
    changetype: modify
    replace: olcServerID
    olcServerID: 1
    
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    add: olcSyncRepl
    olcSyncRepl: rid=001
      provider=ldap://192.168.1.20:389
      bindmethod=simple
      binddn="cn=admin,dc=daemon,dc=com"
      credentials=Admin@123#!
      searchbase="dc=daemon,dc=com"
      scope=sub
      schemachecking=on
      type=refreshAndPersist
      retry="5 5 300 +"
      interval=00:00:00:3
    -
    add: olcMirrorMode
    olcMirrorMode: TRUE
    
    dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
    changetype: add
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    EOF 

    导入配置

    1
    
    ldapadd -Y EXTERNAL -H ldapi:/// -f syncprov.ldif