一、配置OpenLDAP传递身份验证到Active Directory
OpenLDAP作为一种开源的目录服务解决方案,与Windows Active Directory(AD)作为微软提供的目录服务系统,各自在特定场景下展现出优势。当前情况显示,部分应用场景(如应用集成、客户端配置)与OpenLDAP的集成更为顺畅,而另一些场景则严格依赖于AD的功能。因此,完全放弃其中任一系统均非明智之举,但这同时也带来了双重维护的挑战——不仅工作量显著增加,还涉及信息的分散管理、同步复杂性提升及错误率的潜在上升。
为解决这一难题,业界已发展出一种成熟且广泛应用的策略:通过让OpenLDAP采用Windows AD进行认证。此方案巧妙地实现了单点管理用户凭证(即用户密码),仅需在AD中维护一套认证信息,即可同时服务于OpenLDAP及依赖AD的应用场景。此方案不仅简化了维护工作,降低了出错风险,还促进了系统间的无缝协作,是平衡开放性与兼容性需求的有效手段。
1.LDAP client;这个是实际调用ldap服务的系统,也可以是类似ldapsearch之类的client 程序
2.Openldap; 开源服务端,实际进程为slapd
3.Saslauthd;简单认证服务层的守护进程,该进程要安装在openldap服务器上
4.Active directory;即windows AD
二、配置Saslauthd
安装Saslauthd
yum install cyrus-sasl cyrus-sasl-ldap cyrus-sasl-plain -y
启用saslauthd LDAP机制
cat /etc/sysconfig/saslauthd
SOCKETDIR=/run/saslauthd
MECH=ldap
FLAGS="-O /etc/saslauthd.conf"
配置ldap参数
cat /etc/saslauthd.conf
ldap_servers: ldap://192.168.1.1
ldap_search_base: dc=ts,dc=com
ldap_filter: (|(cn=%u)(userPrincipalName=%u))
ldap_bind_dn: CN=username,cn=Users,dc=ts,dc=com
ldap_password: password
ldap_timeout: 10
ldap_deref: never
ldap_restart: yes
ldap_scope: sub
ldap_use_sasl: no
ldap_start_tls: no
ldap_version: 3
ldap_auth_method: bind
开启saslauthd服务
systemctl enable --now saslauthd
sasl配置
cat /etc/sasl2/slapd.conf
mech_list: plain
pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux
重启OpenLDAP
systemctl restart slapd
测试绑定AD用户并添加至OpenLDAP
cat >> user1.ldif <<EOF
dn: uid=ad_test1,ou=people,dc=ts,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
uid: ad_test1
cn: ad_test1
sn: ad_test1
userpassword: {SASL}ad_test1@ts.com
givenname: ad_test1
mail: ad_test1@ts.com
EOF
ldapadd -x -w "password" -D "cn=Manager,dc=ts,dc=com" -f user1.ldif
使用ad密码进行认证
ldapwhoami -x -D uid=ad_test1,ou=People,dc=ts,dc=com -w password
三、AD同步至OpenLDAP
安装lsc
cat > /etc/yum.repos.d/lsc-project.repo << EOF
[lsc-project]
name=LSC project packages
baseurl=http://lsc-project.org/rpm/noarch
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project
EOF
rpm --import http://ltb-project.org/wiki/lib/RPM-GPG-KEY-LTB-project
yum install -y lsc java
AD域同步至OpenLDAP
mkdir /etc/lsc/ad2openldap/
cp /etc/lsc/logback.xml /etc/lsc/ad2openldap
cp /etc/lsc/lsc.xml /etc/lsc/ad2openldap
cat /etc/lsc/ad2openldap/lsc.xml
执行同步
/usr/bin/lsc -f /etc/lsc/ad2openldap -s all -c all -n
LSC会将Active Directory中的数据源同步到OpenLDAP,即lsc.xml的内容:
<?xml version="1.0" encoding="utf-8"?>
<lsc xmlns="http://lsc-project.org/XSD/lsc-core-2.1.xsd" revision="0">
<connections>
<ldapConnection>
<name>ad</name>
<url>ldap://192.168.1.1:389/dc=ts,dc=com</url>
<username>CN=admin,CN=Users,DC=ts,DC=com</username>
<password>password</password>
<authentication>SIMPLE</authentication>
<referral>IGNORE</referral>
<derefAliases>NEVER</derefAliases>
<version>VERSION_3</version>
<pageSize>1000</pageSize>
<factory>com.sun.jndi.ldap.LdapCtxFactory</factory>
<tlsActivated>false</tlsActivated>
</ldapConnection>
<ldapConnection>
<name>openldap</name>
<url>ldap://127.0.0.1:389/dc=ts,dc=com</url>
<username>cn=Manager,dc=ts,dc=com</username>
<password>password</password>
<authentication>SIMPLE</authentication>
<referral>THROW</referral>
<derefAliases>NEVER</derefAliases>
<version>VERSION_3</version>
<pageSize>-1</pageSize>
<factory>com.sun.jndi.ldap.LdapCtxFactory</factory>
<tlsActivated>false</tlsActivated>
</ldapConnection>
</connections>
<tasks>
<task>
<name>a-PeopleSyncTask</name>
<bean>org.lsc.beans.SimpleBean</bean>
<ldapSourceService>
<name>ad-source-service</name>
<connection reference="ad"/>
<baseDn>OU=TS科技,DC=ts,DC=com</baseDn>
<pivotAttributes>
<string>samAccountName</string>
</pivotAttributes>
<fetchedAttributes>
<string>description</string>
<string>cn</string>
<string>sn</string>
<string>givenName</string>
<string>mail</string>
<string>samAccountName</string>
<string>userPrincipalName</string>
</fetchedAttributes>
<getAllFilter>(&(objectClass=user)(!(cn=Administrator))(!(cn=Guest))(!(cn=DefaultAccount))(!(cn=krbtgt)))</getAllFilter>
<getOneFilter>(&(objectClass=user)(samAccountName={samAccountName}))</getOneFilter>
<cleanFilter>(&(objectClass=user)(samAccountName={uid}))</cleanFilter>
</ldapSourceService>
<ldapDestinationService>
<name>opends-dst-service</name>
<connection reference="openldap"/>
<baseDn>ou=People,dc=ts,dc=com</baseDn>
<pivotAttributes>
<string>uid</string>
</pivotAttributes>
<fetchedAttributes>
<string>description</string>
<string>cn</string>
<string>sn</string>
<string>userPassword</string>
<string>objectClass</string>
<string>uid</string>
<string>mail</string>
</fetchedAttributes>
<getAllFilter>(objectClass=inetorgperson)</getAllFilter>
<getOneFilter>(&(objectClass=inetorgperson)(uid={samAccountName}))</getOneFilter>
</ldapDestinationService>
<propertiesBasedSyncOptions>
<mainIdentifier>"uid=" + srcBean.getDatasetFirstValueById("samAccountName") + ",ou=People,dc=ts,dc=com"</mainIdentifier>
<defaultDelimiter>;</defaultDelimiter>
<defaultPolicy>FORCE</defaultPolicy>
<conditions>
<create>true</create>
<update>true</update>
<delete>false</delete>
<changeId>true</changeId>
</conditions>
<dataset>
<name>objectClass</name>
<policy>KEEP</policy>
<createValues>
<string>"organizationalPerson"</string>
<string>"inetOrgPerson"</string>
<string>"person"</string>
<string>"top"</string>
</createValues>
</dataset>
<dataset>
<name>description</name>
<policy>FORCE</policy>
<forceValues>
<string>js:srcBean.getDatasetFirstValueById("cn").toUpperCase() + " (" + srcBean.getDatasetFirstValueById("userPrincipalName") + ")"</string>
</forceValues>
</dataset>
<dataset>
<name>userPassword</name>
<policy>KEEP</policy>
<createValues>
<string>js:"{SASL}" + srcBean.getDatasetFirstValueById("userPrincipalName")</string>
</createValues>
</dataset>
<dataset>
<name>sn</name>
<policy>FORCE</policy>
<createValues>
<string>js:srcBean.getDatasetFirstValueById("cn")</string>
</createValues>
</dataset>
<dataset>
<name>uid</name>
<policy>KEEP</policy>
<createValues>
<string>js:srcBean.getDatasetFirstValueById("cn")</string>
</createValues>
</dataset>
<dataset>
<name>mail</name>
<policy>FORCE</policy>
<forceValues>
<string>js:srcBean.getDatasetFirstValueById("mail")</string>
</forceValues>
</dataset>
</propertiesBasedSyncOptions>
</task>
<task>
<name>b-GroupSyncTask</name>
<bean>org.lsc.beans.SimpleBean</bean>
<ldapSourceService>
<name>ad-src-service</name>
<connection reference="ad"/>
<baseDn>OU=TS科技,DC=ts,DC=com</baseDn>
<pivotAttributes>
<string>cn</string>
</pivotAttributes>
<fetchedAttributes>
<string>cn</string>
<string>member</string>
<string>description</string>
</fetchedAttributes>
<getAllFilter>(&(objectClass=group)(member=*))</getAllFilter>
<getOneFilter>(&(objectClass=group)(cn={cn}))</getOneFilter>
<cleanFilter>(&(objectClass=group)(cn={cn}))</cleanFilter>
<interval>100</interval>
</ldapSourceService>
<ldapDestinationService>
<name>openldap-dst-service</name>
<connection reference="openldap"/>
<baseDn>ou=Group,DC=ts,DC=com</baseDn>
<pivotAttributes>
<string>cn</string>
</pivotAttributes>
<fetchedAttributes>
<string>cn</string>
<string>member</string>
<string>objectClass</string>
<string>description</string>
</fetchedAttributes>
<getAllFilter>(objectClass=groupOfNames)</getAllFilter>
<getOneFilter>(&(objectClass=groupOfNames)(cn={cn}))</getOneFilter>
</ldapDestinationService>
<propertiesBasedSyncOptions>
<mainIdentifier>"cn=" + javax.naming.ldap.Rdn.escapeValue(srcBean.getDatasetFirstValueById("cn")) + ",ou=Group,DC=ts,DC=com"</mainIdentifier>
<defaultDelimiter>;</defaultDelimiter>
<defaultPolicy>FORCE</defaultPolicy>
<conditions>
<create>true</create>
<update>true</update>
<delete>false</delete>
<changeId>true</changeId>
</conditions>
<dataset>
<name>objectClass</name>
<policy>FORCE</policy>
<forceValues>
<string>"groupOfNames"</string>
<string>"top"</string>
</forceValues>
<delimiter>$</delimiter>
</dataset>
<dataset>
<name>default</name>
<policy>FORCE</policy>
</dataset>
</propertiesBasedSyncOptions>
</task>
</tasks>
</lsc>
附:
OpenLDAP禁止匿名登录
ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF
dn: cn=config
changetype: modify
add: olcDisallows
olcDisallows: bind_anon
EOF
ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF
dn: olcDatabase={-1}frontend,cn=config
changetype: modify
add: olcRequires
olcRequires: authc
EOF
开启OpenLDAP日志
cat > loglevel.ldif << EOF
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats
EOF
ldapmodify -Y EXTERNAL -H ldapi:/// -f loglevel.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"
echo 'local4.* /var/log/slapd.log' >> /etc/rsyslog.conf
systemctl restart rsyslog
systemctl restart slapd
OpenLDAP主从
master配置
创建一个对所有LDAP对象具有读访问权限的用户,用作slave访问master
cat > syncuser.ldif <<EOF
dn: uid=syncuser,dc=ts,dc=com
objectClass: simpleSecurityObject
objectclass: account
uid: syncuser
description: Replication User
userPassword: h-O0i5kua7sS
EOF
ldapadd -x -W -D "cn=tsadmin,dc=ts,dc=com" -f syncuser.ldif
开启syncprov module
cat >syncprov_mod.ldif <<EOF
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib64/openldap
olcModuleLoad: syncprov.la
EOF
ldapadd -Y EXTERNAL -H ldapi:/// -f syncprov_mod.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=module,cn=config"
开启syncprov
cat >syncprov.ldif <<EOF
dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpSessionLog: 100
EOF
slave配置
cat >syncrepl.ldif <<EOF
dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001
provider=ldap://10.31.2.21:389/
bindmethod=simple
binddn="uid=syncuser,dc=ts,dc=com"
credentials=h-O0i5kua7sS
searchbase="dc=ts,dc=com"
scope=sub
schemachecking=on
type=refreshAndPersist
retry="30 5 300 3"
interval=00:00:05:00
EOF
ldapmodify -Y EXTERNAL -H ldapi:/// -f syncrepl.ldif
参考链接:配置OpenLDAP传递身份验证到Active Directory