在我的devops架构中持续构建系统(CI)、持续部署系统(CD)、版本仓库的账号身份验证功能是通过OpenLDAP的用户身份管理功能来实现的。所以有必要把OpenLDAP拿出来单独介绍下。
本篇会介绍openLDAP的具体安装步骤、安装完成后利用openLDAP命令行工具和openLDAP客户端工具进行用户和组织机构数据的添加、最后对openLDAP常用的属性进行了整理方便查阅。
先简单介绍下OpenLDAP,了解下它是什么,能做什么
OpenLDAP 是一个开源的轻量级目录访问协议 (LDAP) 的实现,被用于构建和管理分布式目录信息服务。它基于 "轻量级目录访问协议",这是一个国际标准,用于访问和维护分布式目录信息。目录信息通常包含组织的用户和资源的数据,比如人员、组、机构、电话号码和其他资源。
利用 OpenLDAP,可以实现多种有关目录管理和身份验证的功能。下面是是一些常见的用途:
- 用户身份管理:可以集中管理所有用户账户和凭证,便于管理整个组织的身份验证和授权策略。
- 单点登录 (SSO):结合其他身份验证服务(如 SAML, OAuth2 或 Kerberos),可以提供单点登录功能,允许用户使用同一套凭证登录不同的系统和应用。
OpenLDAP 中经常会涉及到Entry、Object Class、Schema、Attribute等字眼,这里先行解释一下:
- 条目(Entry): 目录中的每个条目代表了一个实体,并拥有一套唯一的属性集。条目通常表示人、组织、组等,它是 LDAP 目录中存储信息的基本单元。
- 属性(Attribute):每个条目都由一系列的属性所描述,属性有一个类型(通常是它们的名称,如 cn 或 sn)和与之关联的值(可以是字符串、日期、URL 等)。
- 模式(Schema):为了确保数据的一致性和可理解性,LDAP 使用模式来预定义条目的结构和规则。模式就像是目录的“蓝图”,规定了可以添加哪些对象类和属性。
- 对象类(Object Class):对象类是一组属性的集合,定义了条目的类型和必需的以及可选的属性。例如,person 对象类要求有 sn 和 cn 属性,而 organizationalPerson 可以包含更多的属性。
- DN(Distinguished Name):是目录中每个条目的绝对路径名,让 LDAP 可以精确地定位每个对象。
大概了解后,就准备来安装openLDAP
本次安装方式采用源码编译,在开始安装前
先介绍下安装环境:
操作系统 | ubuntu server | 最小化安装即可 |
openLDAP版本 | LTS | 下面步骤中有下载地址 |
docker 版本 |
开始安装:
第一步:下载openLDAP 源码包
下载地址:OpenLDAP, Download 选择香港镜像地址下载,这里选择LTS版本,目前最新的版本是
第二步:编译安装
# 下载安装包并解压
wget -P /opt/soft/libs https://mirror-hk.koddos.net/OpenLDAP/openldap-release/openldap-.tgz
cd /opt/soft/libs
tar -zxvf openldap-.tgz
# 安装gcc编译环境
apt install gcc automake autoconf libtool make -y
# 编译安装
cd /opt/soft/libs/openldap-
./configure --prefix=/opt/soft/openldap
make depend
make
su root -c 'make install'
安装完成后,还需配置openLDAP
配置openLDAP,主要有两个环节:编辑openLDAP的配置文件( slapd.ldif )和 导入slapd.ldif 配置数据 到数据库中(LMDB)
第一步:编辑openLDAP的配置文件( slapd.ldif )
文件位置在安装目录(etc/openldap)下, 主要修改 LMDB database definitions 配置项,修改olcSuffix、olcRootDN、olcRootPW 三项,下面这张截图是修改前的默认配置。
修改 olcSuffix 配置项
# 原配置
olcSuffix: dc=my-domain,dc=com
# 现配置
olcSuffix: dc=dckj,dc=com
修改 olcRootDN 配置项
# 原配置
olcRootDN: cn=Manager,dc=my-domain,dc=com
# 现配置
olcRootDN: cn=Manager,dc=dckj,dc=com
修改 olcRootPW 配置项
使用 slappasswd 命令生成密码的密码,命令格式如下:
/opt/soft/openldap/sbin/slappasswd -s 明文密码,如下:
# 原配置
olcRootPW: secret
# 现配置
# 先生成密文密码,这里简单设置密码为 adm@dckj,实际使用中增加密码复杂度
/opt/soft/openldap/sbin/slappasswd -s adm@dckj
{SSHA}rJYtY6GxM4F/k7eX0WMtYHhAE2sKb9UM
# 设置密码
olcRootPW: {SSHA}rJYtY6GxM4F/k7eX0WMtYHhAE2sKb9UM
修改完成后 ,slapd.ldif 文件中 LMDB database definitions 配置区域看起来像下面这样
#######################################################################
# LMDB database definitions
#######################################################################
#
dn: olcDatabase=mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: mdb
olcDbMaxSize:
olcSuffix: dc=dckj,dc=com
olcRootDN: cn=admin,dc=dckj,dc=com
# Cleartext passwords, especially for the rootdn, should
# be avoided. See slappasswd(8) and slapd-config(5) for details.
# Use of strong authentication encouraged.
olcRootPW: {SSHA}rJYtY6GxM4F/k7eX0WMtYHhAE2sKb9UM
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode recommended.
olcDbDirectory: /opt/soft/openldap/var/openldap-data
# Indices to maintain
olcDbIndex: objectClass eq
dn: olcDatabase=monitor,cn=config
objectClass: olcDatabaseConfig
olcDatabase: monitor
olcRootDN: cn=config
olcMonitoring: FALSE
第二步:导入slapd.ldif 配置数据 到数据库中(LMDB)
在进行导入操作之前,有必要先简单介绍下 LMDB,LMDB(Lightning Memory-Mapped Database)是一个轻量级(只有32kb的大小)的嵌入式数据库,具有纯内存数据库的读性能,同时保留了标准的基于磁盘的数据库的持久性。openLDAP使用LMDB作数据的持久化存储操作。 感兴趣的同学可以点击链接 LMDB | symas 了解更多关于 LMDB方面资料。
在执行导入操作的时候,使用的是slapadd命令,slapadd 是 OpenLDAP中一个命令行工具,主要用来将条目批量添加到 LDAP 目录数据库中。一般情况下,可以使用它在初次配置 LDAP 服务器时导入一个大量条目的 LDIF (LDAP Data Interchange Format) 文件。
# 创建数据库目录
mkdir -pv /opt/soft/openldap/var/openldap-data
# 创建动态配置目录
mkdir -pv /opt/soft/openldap/etc/slapd.d
# 执行导入命令
/opt/soft/openldap/sbin/slapadd \
-n 0 \
-F /opt/soft/openldap/etc/slapd.d \
-l /opt/soft/openldap/etc/openldap/slapd.ldif
OpenLDAP 版本以后引入了一个叫做 "slapd-config" 的动态配置系统(也被称为 cn=config)。动态配置存储在一个 LDAP 数据库中,并且可以在运行时修改而无需重启 slapd 服务,所以在上面脚本中提前创建目录并通过 -F 参数指定动态配置目录
配置导入完成后,就可以启动 LDAP 服务
LDAP服务默认使用端口
# 启动LDAP?服务
su root -c "/opt/soft/openldap/libexec/slapd -F /opt/soft/openldap/etc/slapd.d"
启动完成后可以通过下面的命令来检查LDAP服务是否正常启动
/opt/soft/openldap/bin/ldapsearch \
-x \
-b '' \
-s base '(objectclass=*)' namingContexts
出现下面的输出,即代表服务启动成功
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts
#
#
dn:
namingContexts: dc=dckj,dc=com
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
启动完成后,现在LDAP服务还不能使用,还需要初始化条目
之所以需要初始化条目是因为OpenLDAP初始化过程会创建起始的目录结构,为之后添加其它条目提供基础。在 LDAP 中,所有的信息都是以层次结构的形式存储的,就像一个反转的树状结构,其中每个节点被称为一个“条目”(entry)。树的最顶层是根条目(Base DN或Root DN),它是所有其他条目的起点,初始化就是创建最顶层是根条目。
cat > admin.ldif << 'EOF'
dn: dc=dckj,dc=com
objectclass: dcObject
objectclass: organization
o: dckj Company
dc: dckj
dn: cn=admin,dc=dckj,dc=com
objectclass: organizationalRole
cn: admin
EOF
#执行初始化条目
/opt/soft/openldap/bin/ldapadd \
-x \
-D "cn=admin,dc=dckj,dc=com" \
-w adm@dckj \
-f admin.ldif
# 执行成功后输出
adding new entry "dc=dckj,dc=com"
adding new entry "cn=admin,dc=dckj,dc=com"
到此,openLDAP安装配置已经完成,openLDAP已经具备读写数据功能,在进行读写数据操作之前,先了解下openLDAP 常用的 objectClass 类型,这有助于后面读写数据操作。
整理比较常用的 objectClass 类型
描述 | 常用属性 | |
person | 用于表示最基本的人员信息。它包括一些最基础且通用的属性,足以识别和描述一个人。 person ObjectClass 通常被用作创建更具体人员条目的基础,比如 organizationalPerson 和 inetOrgPerson ObjectClasses 都是在 person 的基础上进一步扩展的 |
|
organizationalPerson | 继承person ObjectClass,用于表示具有某些工作相关属性的人员。它增加了一些特定的属性来更好地反映一个人在其组织中的职务信息。 |
|
inetOrgPerson | 继承 organizationalPerson 和 person ObjectClasses,并添加了更多属性以支持详细及各种应用场景下的个人信息管理,用于描述个人的多方面信息 |
|
organizationalUnit | 用来表示组织的部门或者单位的 ObjectClass。它通常用于建立组织中的层级结构,如部门、分支。 |
|
groupOfNames | 用于表示一组个体,通常是为了表示权限组、分发列表或其他任何需要将多个 LDAP 对象(如人员、账户等)聚合为一个集合的场景 |
|
了解完常用的 objectClass ,下面将介绍如何在openLDAP中添加以及人员数据。这将会涉及到 organizationalUnit 和 person 两种类型的 objectClass。
首先通过LDAP命令工具添加和查询数据
在 LDAP 中,添加数据是指将新的条目(entry)或信息添加到目录服务中存储,添加数据到 LDAP 的典型情况:
- 建立新的组织单元
- 创建新用户账号
查询数据操作就是通过指定的搜索条件来检索存储在LDAP中的数据,常见的操作有:
- 查询所有组织机构
- 查询组织单元下的所有用户
- 查询指定的用户
在下面步骤中会按照先建立新的组织单元,然后在新建的组织单元中创建新的用户账号然后在结合查询场景来介绍。
通过LDAP命令工具添加数据
建立新的组织单元要用到LDAP 中的organizationalUnit ObjectClass, 在创建之前,先介绍下LDAP 中的organizationalUnit 类型, organizationalUnit(OU)是一个用来表示组织的部门或者单位的 ObjectClass。它通常用于建立组织中的层级结构,如部门、分支或不同的功能组。
organizationalUnit ObjectClass 包含以下属性:
- ou:必填属性,表示组织单位的名称。
- description:可选属性,用来描述组织单位。
- uniqueIdentifier:可选属性,用于给组织单位指定一个唯一的识别码。
- userPassword:可选属性,如果组织单位条目需要密码保护,可以使用这个属性。
- seeAlso:可选属性,可以包含指向其他相关条目的 DN(Distinguished Name)。
- telephoneNumber:可选属性,用于存储与组织单位相关的电话号码。
- 添加组织单元条目
cat > add_organizationa_A.ldif << 'EOF'
dn: ou=A,dc=dckj,dc=com
objectClass: organizationalUnit
ou: A
description: A 部门
EOF
/opt/soft/openldap/bin/ldapadd \
-x \
-D "cn=admin,dc=dckj,dc=com" \
-w adm@dckj \
-f add_organizationa_A.ldif
- 在已有的单元下面添加组织单元
cat > add_organizationa_A1.ldif << 'EOF'
dn: ou=A1,ou=A,dc=dckj,dc=com
objectClass: organizationalUnit
ou: A1
description: A 部门的下级部门 A1
EOF
/opt/soft/openldap/bin/ldapadd \
-x \
-D "cn=admin,dc=dckj,dc=com" \
-w adm@dckj \
-f add_organizationa_A1.ldif
- 在组织单元下面创建新用户账号
创建新用户账号,需要用到LDAP person ObjectClass,当然还可以用 organizationalPerson 和 inetOrgPerson。其实方式都一样,只是organizationalPerson 和 inetOrgPerson这两个ObjectClass 定义的属性比 person多一点,一般情况下person就够用了,那么在这里就以person为例来介绍。
在 LDAP 中,person 是一个结构化的 ObjectClass,定义了一些基本属性集合,这些属性通常用来描述与人相关的条目的基础信息。
根据 LDAP 标准,person ObjectClass 包含以下属性:
- cn (Common Name):必填属性,通常表示人的全名或者他们通常的名字。
- sn (Surname):必填属性,通常表示人的姓氏。
- description:可选属性,可以包含关于人的任何描述信息。
- userPassword:可选属性,通常用来存储用户的密码。
- telephoneNumber:可选属性,用来存储用户的电话号码。
在 person ObjectClass 中,cn 和 sn 是必须的,而其余属性是可选的,可以选择是否填写这些可选属性。person ObjectClass 通常还会与其他 ObjectClasses 结合使用,比如 organizationalPerson 和 inetOrgPerson,这样可以为条目提供更丰富的属性集合。
在这里添加两个用户 tom and jerry,分别添加到 A 和 A1 组织单元中
cat > add_user_tom.ldif << 'EOF'
dn: cn=tom,ou=A,dc=dckj,dc=com
objectClass: person
cn: tom
sn: tom
userPassword:
telephoneNumber:
description: tom
EOF
cat > add_user_jerry.ldif << 'EOF'
dn: cn=jerry,ou=A1,ou=A,dc=dckj,dc=com
objectClass: person
cn: jerrytomjerry
sn: jerry
userPassword:
telephoneNumber:
description: jerry
EOF
/opt/soft/openldap/bin/ldapadd \
-x \
-D "cn=admin,dc=dckj,dc=com" \
-w adm@dckj \
-f add_user_tom.ldif
/opt/soft/openldap/bin/ldapadd \
-x \
-D "cn=admin,dc=dckj,dc=com" \
-w adm@dckj \
-f add_user_jerry.ldif
通过LDAP命令工具查询数据
查询和检索 LDAP服务器中存储的数据库主要用到 ldapsearch命令。通过指定不同的选项和参数,用户可以精确地定义他们想要检索的数据类型和范围。比如用户查找、组织结构浏览。
比较常用的参数:
- H 或 –-host:指定 LDAP 服务器的 URI。例如:ldapsearch -H ldap://localhost。
- -D:绑定 DN (Distinguished Name),即以哪个用户身份进行操作。通常需要管理员权限才能查询所有数据。
- -w 或 -W:指定绑定操作的密码。-w 后面直接跟密码,而 -W 会提示用户输入密码。
- -b 或 –-basedn:指定搜索的基础 DN,决定从哪个点开始搜索 LDAP 目录树。
- -s:指定搜索的范围。可能的值包括 base(仅搜索基础 DN)、one(搜索基础 DN 的一级子项)、sub(搜索所有下级项)。
- -LLL:输出更易读的格式,不包含版本信息和注释。
- -x:使用简单认证而不是 SASL。
- 查询所有用户
/opt/soft/openldap/bin/ldapsearch \
-x \
-b 'dc=dckj,dc=com' '(objectclass=person)' \
-D 'cn=admin,dc=dckj,dc=com' \
-w adm@dckj
返回之前添加的两个用户:
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (objectclass=person)
# requesting: ALL
#
# tom, A, dckj.com
dn: cn=tom,ou=A,dc=dckj,dc=com
objectClass: person
cn: tom
sn: tom
userPassword:: MTIzNDU2
telephoneNumber:
description: tom
# jerry, A1, A, dckj.com
dn: cn=jerry,ou=A1,ou=A,dc=dckj,dc=com
objectClass: person
cn: jerrytomjerry
cn: jerry
sn: jerry
userPassword:: MTIzMTIz
telephoneNumber:
description: jerry
# search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2
- 查询A部门下所有用户
/opt/soft/openldap/bin/ldapsearch \
-x \
-b 'ou=A,dc=dckj,dc=com' '(objectclass=person)' \
-D 'cn=admin,dc=dckj,dc=com' \
-w adm@dckj
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (objectclass=person)
# requesting: ALL
#
# tom, A, dckj.com
dn: cn=tom,ou=A,dc=dckj,dc=com
objectClass: person
cn: tom
sn: tom
userPassword:: MTIzNDU2
telephoneNumber:
description: tom
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
- 查询A部门下指定用户
可用于判断用户是否存在,账号密码是否正确场景
/opt/soft/openldap/bin/ldapsearch \
-x \
-b 'cn=tom,ou=A,dc=dckj,dc=com' '(objectclass=person)' \
-D 'cn=admin,dc=dckj,dc=com' \
-w adm@dckj
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (objectclass=person)
# requesting: ALL
#
# tom, A, dckj.com
dn: cn=tom,ou=A,dc=dckj,dc=com
objectClass: person
cn: tom
sn: tom
userPassword:: MTIzNDU2
telephoneNumber:
description: tom
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
如果尝试在A部门查询jerry用户数据(事实上jerry在A部门的下级A1部门中),可以看到下面的查询结果返回 No such object
/opt/soft/openldap/bin/ldapsearch \
-x \
-b 'cn=jerry,ou=A,dc=dckj,dc=com' '(objectclass=person)' \
-D 'cn=admin,dc=dckj,dc=com' \
-w adm@dckj
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (objectclass=person)
# requesting: ALL
#
# search result
search: 2
result: No such object
matchedDN: ou=A,dc=dckj,dc=com
# numResponses: 1
- 查询A组织单元及下级组织单元
/opt/soft/openldap/bin/ldapsearch \
-x \
-b 'ou=A,dc=dckj,dc=com' '(objectclass=organizationalUnit)' \
-D 'cn=admin,dc=dckj,dc=com' \
-w adm@dckj
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (objectclass=organizationalUnit)
# requesting: ALL
#
# A, dckj.com
dn: ou=A,dc=dckj,dc=com
objectClass: organizationalUnit
ou: A
description:: QSDpg6jpl6g=
# A1, A, dckj.com
dn: ou=A1,ou=A,dc=dckj,dc=com
objectClass: organizationalUnit
ou: A1
description:: QSDpg6jpl6jnmoTkuIvnuqfpg6jpl6ggQTE=
# search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2
- 仅查询A组织单元不查询A部门下级部门
通过设置 -s one参数 来设置搜索作用域为one,即只搜索基DN的一级子对象
/opt/soft/openldap/bin/ldapsearch \
-x \
-s one \
-b 'ou=A,dc=dckj,dc=com' '(objectclass=organizationalUnit)' \
-D 'cn=admin,dc=dckj,dc=com' \
-w adm@dckj
# extended LDIF
#
# LDAPv3
# base with scope oneLevel
# filter: (objectclass=organizationalUnit)
# requesting: ALL
#
# A1, A, dckj.com
dn: ou=A1,ou=A,dc=dckj,dc=com
objectClass: organizationalUnit
ou: A1
description:: QSDpg6jpl6jnmoTkuIvnuqfpg6jpl6ggQTE=
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
- 查询LDAP中所有数据
/opt/soft/openldap/bin/ldapsearch \
-x \
-b 'dc=dckj,dc=com' '(objectclass=*)' \
-D 'cn=admin,dc=dckj,dc=com' \
-w adm@dckj
# extended LDIF
#
# LDAPv3
# base with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# dckj.com
dn: dc=dckj,dc=com
objectClass: dcObject
objectClass: organization
o: dckj Company
dc: dckj
# admin, dckj.com
dn: cn=admin,dc=dckj,dc=com
objectClass: organizationalRole
cn: admin
# A, dckj.com
dn: ou=A,dc=dckj,dc=com
objectClass: organizationalUnit
ou: A
description:: QSDpg6jpl6g=
# A1, A, dckj.com
dn: ou=A1,ou=A,dc=dckj,dc=com
objectClass: organizationalUnit
ou: A1
description:: QSDpg6jpl6jnmoTkuIvnuqfpg6jpl6ggQTE=
# tom, A, dckj.com
dn: cn=tom,ou=A,dc=dckj,dc=com
objectClass: person
cn: tom
sn: tom
userPassword:: MTIzNDU2
telephoneNumber:
description: tom
# jerry, A1, A, dckj.com
dn: cn=jerry,ou=A1,ou=A,dc=dckj,dc=com
objectClass: person
cn: jerrytomjerry
cn: jerry
sn: jerry
userPassword:: MTIzMTIz
telephoneNumber:
description: jerry
# search result
search: 2
result: 0 Success
# numResponses: 7
# numEntries: 6
通过LDAP客户端操作
LDAP的客户端有很多,这里推荐两款:phpLDAPadmin 和 Apache Directory Studio。
- phpLDAPadmin
phpLDAPadmin 是一个基于 Web 的 LDAP 客户端,允许用户通过网页界面管理 LDAP 服务器。它使得执行各种 LDAP 目录操作变得更加简单和直观,包括浏览、搜索、编辑和删除 LDAP 条目,以及管理用户和群组等操作。
使用 docker 来安装phpldapadmin
docker run -p : \
--name ldapadmin \
--env PHPLDAPADMIN_LDAP_HOSTS= \
--detach osixia/phpldapadmin
安装完成后,在浏览器中访问
https://:/
点击 login ,输入用户和密码登陆
用户名:cn=admin,dc=dckj,dc=com
密码:adm@dckj
- Apache Directory Studio
Apache Directory Studio 是基于 Eclipse ,开源LDAP工具,使用起来也比较简单,这里就不在过多的介绍。
下载地址:
https://directory.apache.org/studio/
LDAP相关的就介绍到这,接下来的时间会搭建kubernetes集群,并在集群上面部署相关的开发基础套件,整合成一套devops方案,我看了下kubernetes 最新的版本是版本,我之前搭建的版本是版本,这次重头安装,详细记录操作步骤,陆续的发布出来。