1. Install openldap
(the following steps are for all nodes)
1.1 Environment configuration
Environmental preparation
- Centos 7.9
- openLdap 2.44
- master IP : 172.28.1.6
- slaveIP: 172.28.1.3
- Domain name: daemon com
time synchronization
ntpdate ntp1.tencent.com
OpenLDAP is installed on both machines
yum -y install openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel migrationtools
Start OpenLDAP service
systemctl start slapd systemctl enable slapd
View version
slapd -VV

cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG chown ldap:ldap -R /var/lib/ldap/ chmod 700 -R /var/lib/ldap
1.2 configuring OpenLDAP database
Set the administrator password for OpenLDAP (the password is) Admin@123 #!)
slappasswd -s Admin@123#! {SSHA}6D/mgKyIa4jPyFE81eJhZOwXHxMvwozr
Generate changepwd LDIF file
cat >changepwd.ldif <<EOF #this is OpenLDAP admin password dn: olcDatabase={0}config,cn=config changetype: modify add: olcRootPW olcRootPW: {SSHA}6D/mgKyIa4jPyFE81eJhZOwXHxMvwozr EOF
Import changepwd ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f changepwd.ldif
Warm tip: if the above command displays the following error:
[root@openldap-master opt]# ldapadd -Y EXTERNAL -H ldapi:/// -f chrootpw.ldif
SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 modifying entry "olcDatabase={0}config,cn=config" ldap_modify: Inappropriate matching (18) additional info: modify/add: olcRootPW: no equality matching rule
Solution: modify modify The "add" of the corresponding option in LDIF is "replace"
Import basic mode
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif ldapadd -Y EXTERNAL -H ldapi:/// -f \ /etc/openldap/schema/inetorgperson.ldif

1.3 configure the configuration domain information on OpenLdap DB
Generate configuration changedomain LDIF file
cat > changedomain.ldif << EOF #this id DB domain config dn: olcDatabase={1}monitor,cn=config changetype: modify replace: olcAccess olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=extern al,cn=auth" read by dn.base="cn=admin,dc=daemon,dc=com" read by * none dn: olcDatabase={2}hdb,cn=config changetype: modify replace: olcSuffix olcSuffix: dc=daemon,dc=com dn: olcDatabase={2}hdb,cn=config changetype: modify replace: olcRootDN olcRootDN: cn=admin,dc=daemon,dc=com dn: olcDatabase={2}hdb,cn=config changetype: modify replace: olcRootPW olcRootPW: {SSHA}6D/mgKyIa4jPyFE81eJhZOwXHxMvwozr EOF
Note: the password in olcRootPw should be matched with the generated changedomain Same as LDIF file.
ldapadd -Y EXTERNAL -H ldapi:/// -f changedomain.ldif

Warm tip: if the above command displays the following error:
....... ldap_modify: Inappropriate matching (18) additional info: modify/add: olcRootPW: no equality matching rule
Solution: chdomain Replace all "add" in the LDIF file with "replace", and then re execute the above command!
1.4 turn off anonymous user access
cat >disable_anamouse.dif << EOF 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 EOF
Import configuration
ldapadd -Y EXTERNAL -H ldapi:/// -f disable_anamouse.dif
Generate basic domain information
cat >base.ldif << EOF #this base domain dn: dc=daemon,dc=com o: daemon.com dc: daemon objectClass: top objectClass: dcObject objectclass: organization dn: cn=admin,dc=daemon,dc=com cn: admin objectClass: organizationalRole description: Directory Manager EOF
Import configuration
ldapadd -x -D cn=admin,dc=daemon,dc=com -w Admin@123#! -f base.ldif
- -w is the password of the administrator: Admin@123 #
1.5 open memeberof
In many scenarios, we need to quickly query which one or more groups a user belongs to. memberOf provides such a function: if a user is added to a group through the member attribute, OpenLDAP will automatically create a memberOf attribute on the user, and its value is the dn of the group. Unfortunately, OpenLDAP does not enable this feature by default, so we need to enable it through the relevant configuration.
be careful:
- cn=module name, please check LS - L / etc / openldap / slapd D / cn \ = config / |grep module if the module is not written directly, the default value in Docker is module{0};
- olcDatabase={2}hdb please confirm LS - L / etc / openldap / slapd The name of D / CN = config / |grep olcdatabase. The default in docker is {1} MDB, and the default for CentOS RPM installation is {2} HDB.
- /usr/lib64/openldap is the path of the ldap module. The path is different in different systems. The default path of Centos is / usr/lib64/openldap, and the default path under Ubuntu system is / var/lib/ldap
Generate memberof LDIF file
cat >memberof.ldif << EOF #this is enable memberof dn: cn=module,cn=config cn: module objectClass: olcModuleList olcModuleLoad: memberof olcModulePath: /usr/lib64/openldap dn: olcOverlay=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 EOF
Generate refint1 LDIF file
cat >refint1.ldif << EOF dn: cn=module{0},cn=config add: olcmoduleload olcmoduleload: refint EOF
Generate refint2 LDIF file
cat> refint2.ldif<< EOF dn: olcOverlay=refint,olcDatabase={2}hdb,cn=config objectClass: olcConfig objectClass: olcOverlayConfig objectClass: olcRefintConfig objectClass: top olcOverlay: refint olcRefintAttribute: memberof uniqueMember manager owner EOF
Perform import configuration
ldapadd -Y EXTERNAL -H ldapi:/// -f memberof.ldif ldapmodify -Y EXTERNAL -H ldapi:/// -f refint1.ldif ldapadd -Y EXTERNAL -H ldapi:/// -f refint2.ldif

Check whether the memberof module is loaded
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn|grep memberof

1.6 enable log configuration
Generate loglevel LDIF file
cat> loglevel.ldif<< EOF dn: cn=config changetype: modify replace: olcLogLevel olcLogLevel: stats EOF
Import loglevel ldif
ldapmodify -Y EXTERNAL -H ldapi:/// -f loglevel.ldif
Create slapd Log file
touch /var/log/openldap/slapd.log vim /etc/rsyslog.conf +73 #"+ 73" means to navigate to line 73 of the file ....... local4.* /var/log/slapd.log
Add LDAP password audit module
cat> auditlog<< EOF dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: {1}auditlog dn: olcOverlay=auditlog,olcDatabase={2}hdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcAuditLogConfig olcAuditlogFile: /var/log/openldap/auditlog.log EOF
Import configuration
touch /var/log/openldap/auditlog.log ldapmodify -Y EXTERNAL -H ldapi:/// -f auditlog.ldif
Restart the system log service and ldap service
systemctl restart rsyslog systemctl restart slapd systemctl status slapd
[root@openldap-master opt]# tail -f /var/log/slapd.log May 17 18:24:38 openldap-master slapd[26195]: daemon: shutdown requested and initiated. May 17 18:24:38 openldap-master slapd[26195]: slapd shutdown: waiting for 0 operations/tasks to finish May 17 18:24:38 openldap-master slapd[26195]: slapd stopped. May 17 18:24:38 openldap-master slapd[26399]: @(#) $OpenLDAP: slapd 2.4.44 (Apr 12 2018 19:17:38) $#012#011mockbuild@x86-01.bsys.centos.org:/builddir/build/BUILD/openldap-2.4.44/openldap-2.4.44/servers/slapd May 17 18:24:39 openldap-master slapd[26402]: slapd starting
1.7 add ppolicy La module
To customize the user password policy through the OpenLDAP server, you need to load the ppolicy module on the server.
Add ppolicy La module
cat >policy.ldif << EOF dn: cn=module{0},cn=config changetype: modify add: olcModuleLoad olcModuleLoad: {3}ppolicy.la EOF
Import configuration
ldapadd -y EXTERNAL -H ldapi:/// -f ppolicy.ldif
1.8 create OpenLDAP entry tree
Create ou
cat >ou.ldif << EOF dn: ou=shangjiankeji,dc=daemon,dc=com ou: shangjiankeji objectClass: organizationalUnit objectClass: top dn: ou=People,dc=daemon,dc=com ou: People objectClass: organizationalUnit objectClass: top EOF
Create two OU: shangjiankeji and People
ldapadd -x -D "cn=admin,dc=daemon,dc=com" -w 'Admin@123#!' -f ou.ldif
Create group
cat > group.ldif << EOF dn: cn=ops,ou=Group,dc=daemon,dc=com cn: ops objectClass: top objectClass: groupOfUniqueNames uniqueMember: dn: cn=dev,ou=Group,dc=daemon,dc=com cn: dev objectClass: top objectClass: groupOfUniqueNames uniqueMember: EOF
Create two groups ops and dev
ldapadd -x -D "cn=admin,dc=daemon,dc=com" -w ' Admin@123#! ' -f group.ldif
Create user
cat > user.ldif << EOF dn: uid=user01,ou=People,dc=daemon,dc=com cn: user01 objectClass: top objectClass: organizationalperson objectClass: inetorgperson objectClass: posixaccount loginShell: /bin/bash sn: user01 homeDirectory: /home/dev uid: user01 mail: user01@daemon.com mobile: 0 uidNumber: 1001 gidNumber: 0 userPassword: 123456 dn: uid=user02,ou=People,dc=daemon,dc=com cn: user02 objectClass: top objectClass: organizationalperson objectClass: inetorgperson objectClass: posixaccount loginShell: /bin/bash sn: user02 homeDirectory: /home/dev uid: user02 mail: user02@daemon.com mobile: 0 uidNumber: 1002 gidNumber: 0 userPassword: 123456 EOF
Create two users user01, user02
ldapadd -x -D "cn=admin,dc=daemon,dc=com" -w 'Admin@123#!' -f user.ldif
Add user user01 to dev group and user02 to ops group
cat > add-group.ldif << EOF dn: cn=dev,ou=Group,dc=daemon,dc=com changetype: modify add: uniqueMember uniqueMember: uid=user01,ou=People,dc=daemon,dc=com dn: cn=ops,ou=Group,dc=daemon,dc=com changetype: modify add: uniqueMember uniqueMember: uid=user02,ou=People,dc=daemon,dc=com EOF
ldapadd -x -D "cn=admin,dc=daemon,dc=com" -w 'Admin@123#!' -f add-group.ldif
View the user's memoerof attribute
ldapsearch -x -H ldap://127.0.0.1 -b dc=daemon,dc=com -D "cn=admin,dc=daemon,dc=com" -W memberOf
Note: the memberOf attribute is part of groupOfNames objectClass. We can't use posixGroup and groupOfNames at the same time, because they are both STRUCTURAL object classes (an entry can only have one STRUCTURAL object class).
2.openLDAP master-slave mode configuration
2.1 Master node configuration
Enable adding the syncprov module on the master to realize the master-slave replication function point. Add the syncprov module through the ldif file without restarting the ldap server.
Add syncprov module
cat >mod_syncprov.ldif << EOF dn: cn=module,cn=config objectClass: olcModuleList cn: module olcModulePath: /usr/lib64/openldap olcModuleLoad: syncprov.la EOF
Import configuration
ldapadd -Y EXTERNAL -H ldapi:/// -f mod_syncprov.ldif
Generate syncprov LDIF file
cat> syncprov.ldif << EOF dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov olcSpCheckpoint: 100 10 olcSpSessionLog: 100 EOF
Note:
- olcSpCheckpoint: 100 10 indicates that the synchronization conditions are met. When 100 entries are modified or pushed once a minute;
- olcSpSessionLog: 100 maximum number of session log entries
ldapadd -Y EXTERNAL -H ldapi:/// -f mod_syncprov.ldif
2.2 slave node configuration
Similarly, syncrepl also needs to be configured on the slave, because the master-slave replication implemented by syncrepl is one-way, that is, all operations of the master will be synchronized to the slave, and the slave cannot be synchronized to the master. In order to avoid inconsistency between the data on the master and the slave, the addition, deletion and modification of ldap information are prohibited on the slave, and only query operations are allowed. Because it is unidirectional, the slave needs some master authentication information to synchronize data from the master.
Generate syncrepl LDIF file
cat > syncrepl.ldif<< EOF dn: olcDatabase={2}hdb,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=001 provider=ldap://172.28.1.6: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 +" attrs="*,+" interval=00:00:00:3 EOF
Parameter Description:
- The provider is the address of the ldap master;
- binddn: refers to the basic information of the domain. Note: the administrator must be used to log in here, otherwise the user's password cannot be synchronized.
- credentials: ldap administrator's password
- searchbase: select the independent domain and root node to synchronize
- scope: set all entries to match
- schemachecking: set synchronous update time detection
- type: the synchronization mode is refreshAndPersist. In refreshOnly mode, subsequent operations are completed by client polling
- retry: the number and time of synchronous update retries are 5 times in the first 5 seconds, and then every 300 seconds
- attrs: copy all attributes
- interval here, the update time is set. Here, it is once every 3 seconds, the penultimate is minutes, and so on.
Import configuration
ldapadd -Y EXTERNAL -H ldapi:/// -f syncprov.ldif
3.phpldapadmin installation
Note: This is the docker installation
Prerequisite: please install the docker environment
cat >restart_ldap_php_admin.sh << EOF #/bin/bash docker rm -f ldap-php-admin || echo "ok" docker run --name ldap-php-admin \ -p 8080:80 \ --privileged \ --restart=always \ --env PHPLDAPADMIN_HTTPS=false \ --env PHPLDAPADMIN_LDAP_HOSTS=172.28.1.6 \ --detach osixia/phpldapadmin:stable EOF
Parameter Description:
- PHPLDAPADMIN_LDAP_HOSTS: ldap master IP
- PHPLDAPADMIN_HTTPS: false disable https access
For specific parameters, see: osixia/docker-phpLDAPadmin: A docker image to run phpLDAPadmin 🐳 (github.com)
4. User password self-service password modification service
Here is the installation of docker
prerequisite:
- The server needs to install docker environment
- To facilitate management, the configuration files in the container are mapped to the local.
mkdir /data/openldap/self-password/conf -p docker run -d --name self-password docker.io/ltbproject/self-service-password:1.4.3 docker cp self-assword:/var/www/conf/config.inc.php /data/openldap/self-password/conf chmod -R 777 /data/openldap/self-password/conf
Edit config Inc.php configuration file
Find the following:
$debug = false; # LDAP $ldap_url = "ldap://172.28.1.6:389 "; ##ldap masterip address $ldap_starttls = false; $ldap_binddn = "cn=admin,dc=daemon,dc=com"; #ldap domain administrator $ldap_bindpw = 'Admin@123#!'; # ldap administrator password // for GSSAPI authentication, comment out ldap_bind* and uncomment ldap_krb5ccname lines //$ldap_krb5ccname = "/path/to/krb5cc"; $ldap_base = "dc=daemon,dc=com"; #Domain information $ldap_login_attribute = "uid"; #User login uid $ldap_fullname_attribute = "cn"; #User name $ldap_filter = "(&(objectClass=person)($ldap_login_attribute={login}))"; $ldap_use_exop_passwd = false; $ldap_use_ppolicy_control = false; ........................ $hash = "MD5"; ## This is the password adding mode. The default is clear text. For security, it must be modified to MD5 or other encryption modes.
It is allowed to authorize php to operate ldap, otherwise the user password cannot be modified through the self-service password modification service
Operate on the ldap master node
cat >ldap_php.ldif << EOF dn: olcDatabase={2}hdb,cn=config changetype: modify add: olcAccess olcAccess: {0}to attrs=userPassword by self =xw by anonymous auth by * none olcAccess: {1}to * by * read EOF
Import configuration:
ldapadd -Y EXTERNAL -H ldapi:/// -f ldap_php.ldif
Generate self-service password modification startup script
cat >restart_self-service-password.sh << EOF #!/bin/bash docker rm -f self-password || echo "OK" docker run -d --name self-password -p 80:80 \ -v /data/openldap/self-password/conf:/var/www/conf \ docker.io/ltbproject/self-service-password:1.4.3 EOF
start-up
sh restart_self-service-password.sh
The password modified by ldapadmin tool is ciphertext
5. Enable openldap TLS encryption
5.1 generate self signed certificate
(any node operation)
1. Download cfssl tool
curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /usr/bin/cfssl curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /usr/bin/cfssljson curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /usr/bin/cfssl-certinfo chmod +x /usr/bin/cfssl /usr/bin/cfssljson /usr/bin/cfssl-certinfo
2. Create a temporary certificate directory
mkdir /data/openldap/ssl && cd /data/openldap/ssl
#ca profile
cat > ca-config.json << EOF { "signing": { "default": { "expiry": "87600h" }, "profiles": { "ldap": { "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "expiry": "87600h" } } } } EOF
expiry is the valid time of the certificate. Here it is 10 years.
#Self signed ca certificate request
cat > ldap-ca-csr.json << EOF { "CN": "ldap", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "Beijing", "L": "Beijing", "O": "ldap", "OU": "LDAP Security" } ] } EOF
#ldap certificate application data
cat > ldap-csr.json << EOF { "CN": "ldap", "hosts": [ "127.0.0.1", "172.28.0.0/16", "ldap.ops.prod.daemon.tech" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "Beijing", "L": "Beijing", "O": "ldap", "OU": "LDAP Security" } ] } EOF
be careful:
- The hosts field above is the host using this certificate
- Special attention must be paid to adding the IP address of the host and the address of the slave. Here I add the whole address segment
- Add the local loopback address. If it is a container, add the container name
- If you want to put it on the public network, you can add the FQDN address
Generate CA self signed certificate
cfssl gencert -initca ldap-ca-csr.json | cfssljson -bare ca
#ldap certificate signature. The files required for ldap are: ca certificate, ldap certificate and ldap private key
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=ldap ldap-csr.json | cfssljson -bare ldap
#View generated certificates
#Where LDAP key pem ldap. PEM ca.pem is what we need
ls ldap-key.pem ldap.pem ca.pem
5.2 enable OpenLDAP TLS module
(all node operations)
1. Upload the generated certificate to the LDAP server
Note: / etc/openldap/certs is the default storage directory of ldap
cp ca.pem /etc/openldap/certs/ca-bundle.crt cp ldap.pem /etc/openldap/certs/server.crt cp ldap-key.pem /etc/openldap/certs/server.key chown ldap.ldap /etc/openldap/certs -R
2. Generate mod_ssl.ldif file
cat > mod_ssl.ldif << EOF dn: cn=config changetype: modify replace: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/openldap/certs/ca-bundle.crt dn: cn=config replace: olcTLSCertificateFile olcTLSCertificateFile: /etc/openldap/certs/server.crt dn: cn=config replace: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/openldap/certs/server.key EOF
implement
ldapmodify -Y EXTERNAL -H ldapi:/// -f mod_ssl.ldif
Note: the command will probably fail with the following error
SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0modifying entry "cn=config" ldap_modify: Other (e.g., implementation specific) error (80)
You need to check the ldap.xml file in the / etc/openldap/certs directory crt,ldap. Whether the permissions of key and CA.pem are 644, and this error may continue to occur. If so, ignore and skip and execute the following steps.
SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 modifying entry "cn=config"
The result of executing the LDAP modify command: modifying entry "cn=config"ldap_modify: Inappropriate matching (18) additional info: modify/add: olcTLSCACertificateFile: no equality matching rule
If the above error is reported and the reason is unknown, you can skip the following steps
l directly edit / etc / openldap / slapd d/cn=config. LDIF file
Note: generally, it is not modified directly

Change the service configuration file / etc / openldap / LDAP conf
vim /etc/openldap/ldap.conf
#Configure authentication mode
TLS_REQCERT never
Set whether to validate client initiated tls connections.
- never: the default option is not to validate the client certificate.
- allow: check the client certificate. If there is no certificate or certificate error, the connection is allowed.
- try: check the client certificate, no certificate (allow connection), certificate error (terminate connection).
- demand | hard | true: check the client certificate. If there is no certificate or certificate error, the connection will be terminated immediately.
Restart the openldap server service
systemctl start slapd
#View the service status after restart
systemctl status slapd
Configure SSL/TLS security for LDAP Server
cat >tls.1.2.ldif << EOF dn: cn=config changetype: modify add: olcTLSProtocolMin olcTLSProtocolMin: 3.3 dn: cn=config changetype: modify add: olcTLSCipherSuite olcTLSCipherSuite: ECDHE-RSA-AES256-SHA384:AES256-SHA256:!RC4:HIGH:!MD5:!aNULL:!EDH:!EXP:!SSLV2:!eNULL dn: cn=config changetype: modify add: olcTLSDHParamFile olcTLSDHParamFile: /etc/openldap/certs/slapd.dh.params EOF
Note:
- olcTLSProtocolMin: 3.3 Support TLSv1.2 or better
- olcTLSCipherSuite: ECDHE-RSA-AES256-SHA384:AES256-SHA256:!RC4:HIGH:!MD5:!EDH:!EXP:!SSLV2:!eNULL Strongest available ciphers only
Create DH parameter file
openssl dhparam -out /etc/openldap/certs/slapd.dh.params.tmp 1024 mv /etc/openldap/certs/slapd.dh.params.tmp /etc/openldap/certs/slapd.dh.params

ldapmodify -Y EXTERNAL -H ldapi:/// -f tls.1.2.ldif
Configure OpenLDAP with TLS=required
Note:
This step is to forcibly enable TLS encryption. Only clients are allowed to connect through the password port (636 by default). Ignore this step if you want to specify it manually.
cat > force-ssl.ldif << EOF dn: olcDatabase={2}hdb,cn=config changetype: modify add: olcSecurity olcSecurity: tls=1 EOF
Note: execute the command to import the configuration to / etc / openldap / slapd d/cn=config/ olcDatabase={2}hdb. In LDIF file
ldapmodify -v -Y EXTERNAL -H ldapi:/// -f force-ssl.ldif
Modify the / etc/sysconfig/slapd file
Add ldaps:///
SLAPD_URLS="ldapi:/// ldap:/// ldaps:///"
systemctl restart slapd systemctl status slapd
