65.9K
CodeProject 正在变化。 阅读更多。
Home

物联网的企业级身份验证和访问控制(第一部分)。

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (4投票s)

2016年10月3日

CPOL

14分钟阅读

viewsIcon

12631

在嵌入式 Linux IoT 上实现 LDAP 和 Kerberos,为 IoT 提供企业级身份验证(第一部分)。

引言

物联网设备正日益普及,遍及各行各业。但是,安全且企业级别的身份验证和访问控制仍然是物联网面临的关键挑战。它们正在经历与分布式计算环境中桌面计算机相同的演变过程,并在改进其安全性。

由于处理能力增强和通信选项多样,大多数这些设备都可以在其固件上运行 Linux。其他设备,如 Raspberry Pi 和 BeagleBone,可以像定制传统桌面一样轻松地安装 Linux 和定制 GNU 工具。这使得部署 Linux 已有的海量工具和服务成为可能,包括企业级身份验证服务的开源版本。MIT Kerberos 等身份验证框架和 OpenLDAP 等目录服务是经受住时间考验的两个此类服务,今天它们在大型和小型企业中支持身份和身份验证服务。它们为当今物联网环境面临的身份验证挑战提供了成熟而稳健的解决方案。

本文介绍了在 Raspberry Pi 2 物联网设备上规划、配置和部署 Kerberos 身份验证基础设施,以安全地识别和验证访问网络中其他物联网设备的用户。

该解决方案的独特性在于它使用另一个物联网设备作为 Kerberos 和 LDAP 服务器。因此,它不需要传统服务器运行这些身份验证服务所需的庞大空间/功耗/投资,这自然适合于任何具有此类约束的物联网环境。由于该解决方案基于具有庞大用户社区的开源软件项目,因此在故障排除和升级方面得到了很好的支持。

Raspberry PI

我们需要完成以下任务,以便在 Raspberry Pi 物联网设备上配置和部署此解决方案

  1. 规划和设计我们的目录结构以满足解决方案的要求。
  2. 安装 OpenLDAP 服务器及相关工具
  3. 填充目录并准备 Kerberos 使用
  4. 安装 Kerberos 服务
  5. 配置和部署 Kerberos KDC
  6. 在 Kerberos 上设置用户主体和物联网设备主体
  7. 配置并检查所有设备的 Kerberos 身份验证

本文的第一部分涵盖了任务 1 至 3,第二部分(在此处发布 )涵盖了任务 4 至 7。

背景

让我们首先了解此身份验证基础设施的高级架构以及它们在物联网环境中的作用。

具有多个用户登录到多个物联网设备的环境会受到以下挑战的影响

  1. 每个用户的密码(或 SSH 密钥)必须在每个设备上设置。
  2. 当用户调离职位或离职时,需要禁用或更改密码/密钥。
  3. 如果使用密码,则需要定期更改密码以保护凭据,这进一步增加了重置和同步多个设备上相同密码的负担。
  4. 需要在所有设备上一致地设置强大的身份验证机制和策略;例如,使用更强的哈希函数存储密码/密钥,并强制执行密码复杂性规则等。
  5. 如果每个设备都自行验证用户,并且事件日志记录在本地;那么检测入侵和异常行为会更加困难,因为在网络上多个设备上发生的关联身份验证事件更难关联。

集中式身份验证基础设施可以解决所有这些问题,并提供更低的管理成本的额外好处。请参阅下图

architecture overview diagram

此设置的主要组件是

  1. 需要访问物联网设备的用户。
  2. 运行需要保护免受未经授权访问的服务物联网设备
  3. Kerberos 服务 - 身份验证服务 & 票证授予服务
  4. LDAP - 它既用作 Kerberos 的持久存储,又提供企业范围的目录服务,对用户、设备、角色、服务等进行分类。

Kerberos 提供了一个集中式服务来验证用户和物联网设备,并以非常安全协议协调这些消息。总的来说,它提供了以下好处

  1. 它为所有用户和物联网设备提供可靠的识别和身份验证机制。
  2. 它实现了集中的用户管理,从而降低了运营成本。
  3. 由于 Kerberos 和 LDAP 的悠久历史和普及,使用标准协议确保了与其他服务的轻松广泛的互操作性。
  4. 可靠地验证服务器到用户,这样他们就知道他们正在访问真实的物联网设备(已注册并因此受到 Kerberos KDC 的信任),而不是一个拦截流量以窃取信息的恶意设备。
  5. 整个基础设施的操作高度可配置,选项和设置易于修改,以适应环境和任何特定需求。

本文的第二部分在此处详细描述了 Kerberos 的高级功能概述和详细安装。

安装

我们首先安装 LDAP 服务器 slapd 及其支持库和工具。首先,更新所有存储库和任何过时的软件包,然后安装 slapd - LDAP 守护进程

sudo apt-get update
 ...
 Fetched 9,281 kB in 1min 30s (102 kB/s)
 Reading package lists... Done

sudo apt-get upgrade
 Reading package lists... Done
 Building dependency tree
 Reading state information... Done
 Calculating upgrade... Done
 ...

sudo apt-get install slapd ldap-utils
 Enter the ldap administrator password: Long9and8difficult7password!

安装过程中将提示输入管理员密码,在安装过程中输入,请确保选择一个长而复杂的密码并记住它或将其存储在密码库中。

安装 Kerberos 和其他我们稍后将使用的实用程序包

sudo apt-get install krb5-kdc-ldap krb5-kdc krb5-admin-server 
sudo apt-get install pwgen sharutils ldapscripts

规划目录结构

LDAP 目录以分层方式组成,表示一个树形结构,其中根条目(LDAP 基础)是域名组件。例如,codeproject.com 的目录树根将是“dc=codeproject,dc=com”。树下的所有节点要么是称为属性的叶节点,要么是包含更多属性的对象。属性的概念类似于 RDBMS 数据库字段,它可以保存多种类型的数据 - 字符串、数字、日期、时间戳、LDAP 名称等。
如果您需要将 LDAP 基础更改为与您的域不同的名称,请首先编辑 /etc/hosts 以添加该名称并将主机名设置为所需的基后缀;例如,在一台名为 abcd.net 的机器上,我将安装一个 LDAP 基础 examplefirm.com,因此我已将此条目添加到 /etc/hosts 文件中以简化安装

127.0.2.1       iot01.examplefirm.com iot01

我们将创建一个 OpenLDAP 目录,其结构如下,位于根目录下

  • ou=People : 此对象包含由其用户 ID 唯一标识的个人用户。每个用户对象将进一步包含诸如 firstname、lastname 等属性。此对象基于 inetOrgPerson 定义的模式,但由我们自定义的附加模式 iotOrgPerson 修改。
  • ou=Groups : 此对象表示旨在用作基于角色的访问控制角色的用户集合,此对象基于 groupOfNames 模式,但已由我们自定义的模式 orgGroupOfPeople 修改。
  • ou=Computers : 此对象包含单独的物联网设备,每个设备对象包含 ip-address、服务、所有者、序列号、描述等属性。此对象基于 ieee802Device 模式,但已由我们自定义的模式 iotEquipment 修改。

我们的自定义模式及其对象类型(类)和属性列出如下,将以下内容保存到文件 iot.schema 中,非常仔细地输入这些命令,注意不要更改或省略大小写字符、换行符和括号。

#$Id: iot.schema,v 1.3 2016/09/05 23:01:00 ark-sf Exp $
# OID prefix: 1.3.6.1.4.1.92300.
# Attributes: 1.3.6.1.4.1.92300.1.1 to 1.3.6.1.4.1.92300.1.21
#
attributetype (1.3.6.1.4.1.92300.1.1 NAME 'accountActive'
        DESC 'A boolean telling whether an account is active or not'
        EQUALITY booleanMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.2 NAME 'lastPasswordChange'
        DESC 'Time in unix time of last password change'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.3 NAME 'quotaBytes'
        DESC 'A string that represents the quota in bytes available for a mailbox'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.4 NAME 'mailbox'
        DESC 'The absolute path to the mailbox for a mail account in a non-default location'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.5 NAME 'lastChange'
        DESC 'Time in unix time of last change'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.6 NAME 'maildrop'
        DESC 'RFC822 Mailbox - mail alias'
        EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )

attributetype ( 1.3.6.1.4.1.92300.1.22 NAME 'modifiedBy'
        DESC 'DN of modifier'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

attributetype ( 1.3.6.1.4.1.92300.1.8 NAME 'actualJoiningDate'
        DESC 'Time in unix time of actual joining date'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.9 NAME 'leavingDate'
        DESC 'Time in unix time of leaving date'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.10 NAME 'homeEmail'
        DESC 'RFC822 Mailbox - mail alias'
        EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )

attributetype ( 1.3.6.1.4.1.92300.1.11 NAME 'assistantEmail'
        DESC 'RFC822 Mailbox - mail alias'
        EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )

attributetype ( 1.3.6.1.4.1.92300.1.12 NAME 'assistantPhone'
        DESC 'RFC1274: assistants telephone number'
        EQUALITY telephoneNumberMatch
        SUBSTR telephoneNumberSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

attributetype ( 1.3.6.1.4.1.92300.1.15 NAME 'emergencyPhone'
        DESC 'RFC1274: home telephone number'
        EQUALITY telephoneNumberMatch
        SUBSTR telephoneNumberSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

attributetype ( 1.3.6.1.4.1.92300.1.16 NAME 'emergencyContactPerson'
        DESC 'Person to contact in case of emergency'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

attributetype (1.3.6.1.4.1.92300.1.17 NAME 'accountAuthorized'
        DESC 'A boolean telling whether an accounts changes are authorized or not'
        EQUALITY booleanMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )

attributetype ( 1.3.6.1.4.1.92300.1.18 NAME 'authorizedBy'
        DESC 'DN of authorizor'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

objectclass ( 1.3.6.1.4.1.92300.4 NAME 'iotOrgPerson'
        DESC 'Defines entries representing people in the organization.'
        SUP 'inetOrgPerson' STRUCTURAL
        MAY ( homeDirectory $ loginShell $ accountActive $ lastPasswordChange $ uidNumber $ gidNumber $ info $ manager $ emergencyPhone $ personalTitle $ emergencyContactPerson $ homePostalAddress $ accountAuthorized $ actualJoiningDate $ leavingDate $ homeEmail $ assistantEmail $ assistantPhone $ quotaBytes $ mail $ authorizedBy $ modifiedBy $ lastChange) )

objectclass (1.3.6.1.4.1.92300.2 NAME 'iotEquipment'
        DESC 'An IoT device which belongs to the firm, extends ieee802Device.'
        SUP ieee802Device AUXILIARY
        MAY ( cn $ serialNumber $ description $ owner $ ipHostNumber $ macAddress $ associatedDomain $ authorizedBy $ modifiedBy $ lastChange $ lastPasswordChange) )

objectclass ( 1.3.6.1.4.1.92300.3 NAME 'orgGroupOfPeople'
        DESC 'Extends attributes of entries representing groups in the organization.'
        SUP groupOfNames STRUCTURAL
        MAY ( mail $ displayName $ description $ gidNumber $ authorizedBy $ modifiedBy $ lastChange $ accountActive) )

将此文件保存在 /etc/ldap/schema 文件夹中。

LDAP 配置

我们现在准备部署此模式,然后填充目录树。

安装自定义模式

通过列出 /etc/ldap/slapd.d/cn=config/cn=schema 下的文件来查看当前安装的模式列表。以下模式应已默认以 ldif 格式加载

sudo ls -al /etc/ldap/slapd.d/cn=config/cn=schema

 total 48
 drwxr-x--- 2 openldap openldap  4096 Sep  7 23:09 .
 drwxr-x--- 3 openldap openldap  4096 Sep  7 23:09 ..
 -rw------- 1 openldap openldap 15596 Sep  7 23:09 cn={0}core.ldif
 -rw------- 1 openldap openldap 11381 Sep  7 23:09 cn={1}cosine.ldif
 -rw------- 1 openldap openldap  6513 Sep  7 23:09 cn={2}nis.ldif
 -rw------- 1 openldap openldap  2875 Sep  7 23:09 cn={3}inetorgperson.ldif

由于我们需要向 LDAP 添加 Kerberos 相关属性,将模式定义文件 kerberos.schema.gz 复制到 LDAP,我们稍后将使用它。

sudo gzip -d /usr/share/doc/krb5-kdc-ldap/kerberos.schema.gz
sudo cp -v /usr/share/doc/krb5-kdc-ldap/kerberos.schema /etc/ldap/schema/

创建一个配置文件 schema_convert.conf,该文件引用所有必需的模式文件及其依赖项,我们将使用它将我们的模式转换为 ldif 格式。在此文件中输入以下命令

include /etc/ldap/schema/core.schema
include /etc/ldap/schema/collective.schema
include /etc/ldap/schema/corba.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/duaconf.schema
include /etc/ldap/schema/dyngroup.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/java.schema
include /etc/ldap/schema/misc.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/openldap.schema
include /etc/ldap/schema/ppolicy.schema
include /etc/ldap/schema/kerberos.schema
include /etc/ldap/schema/iot.schema

创建一个输出目录 ldif_output 并运行 slapcat 工具将这些模式转换为 ldif 文件。使用 grep 搜索并识别索引

sudo slapcat -f schema_convert.conf -F ldif_output -n 0 | grep iot,cn=schema
 dn: cn={13}iot,cn=schema,cn=config

请注意索引号为 13。现在转换模式文件并将此索引模式加载到使用前面注意到的索引(即 13)指定的 cn 名称中,位于 cn 属性中

sudo slapcat -f schema_convert.conf -F ldif_output -n0 -H ldap:///cn={13}iot,cn=schema,cn=config -l cn=iot.ldif


转换后的模式现在位于 cn=iot.ldif;编辑文件 cn=iot.ldif 以删除索引号和周围的大括号,文件的前几行应如下所示

dn: cn=iot,cn=schema,cn=config
...
cn: iot

您还应该从文件末尾删除以下行,属性的实际值在您的系统上会有所不同

structuralObjectClass: olcSchemaConfig
entryUUID: 37997368-1d73-1036-8f90-7340b7d1064d
creatorsName: cn=config
createTimestamp: 20160903050850Z
entryCSN: 20160903050850.827754Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20160903050850Z

最后,使用 ldapadd 将新模式添加到 slapd-config DIT

sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f cn\=iot.ldif
 adding new entry "cn=iot,cn=schema,cn=config"

通过查看当前加载的模式来确认所有内容都已正确配置,使用以下命令

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn

dn: cn=config

dn: cn=module{0},cn=config

dn: cn=schema,cn=config

dn: cn={0}core,cn=schema,cn=config

dn: cn={1}cosine,cn=schema,cn=config

dn: cn={2}nis,cn=schema,cn=config

dn: cn={3}inetorgperson,cn=schema,cn=config

dn: cn={4}iot,cn=schema,cn=config

dn: olcBackend={0}mdb,cn=config

dn: olcDatabase={-1}frontend,cn=config

dn: olcDatabase={0}config,cn=config

dn: olcDatabase={1}mdb,cn=config

使用以下命令查看任何特定模式的详细信息

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn={4}iot,cn=schema,cn=config olcObjectClasses
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn={4}iot,cn=schema,cn=config olcAttributeTypes

安装 Kerberos 模式

遵循与之前相同的过程(iot.schema)将 Kerberos 模式转换为 ldif 格式,我们将重用之前创建的 schema_convert.conf 文件。

sudo slapcat -f schema_convert.conf -F ldif_output -n 0 | grep kerberos,cn=schema
 dn: cn={12}kerberos,cn=schema,cn=config

请注意此模式的索引号为 12。现在转换模式文件,并使用以下命令将此索引模式加载到指定的 cn 属性中

sudo slapcat -f schema_convert.conf -F ldif_output -n0 -H ldap:///cn={12}kerberos,cn=schema,cn=config -l cn=kerberos.ldif

转换后的模式现在位于文件 cn=kerberos.ldif 中;编辑此文件以删除 cn 和 dn 属性中的索引号及其周围的大括号,文件的前几行应如下所示

dn: cn=kerberos,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: kerberos

您还应该从文件末尾删除以下行,属性的实际值在您的系统上会有所不同

structuralObjectClass: olcSchemaConfig
entryUUID: 379925de-1d73-1036-8f8f-7340b7d1064d
creatorsName: cn=config
createTimestamp: 20160903050850Z
entryCSN: 20160903050850.827754Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20160903050850Z

最后,使用 ldapadd 将此模式添加到 LDAP 配置

sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f cn\=kerberos.ldif
adding new entry "cn=kerberos,cn=schema,cn=config"

通过列出当前加载的模式来确认所有内容都已正确配置

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn

dn: cn=config

dn: cn=module{0},cn=config

dn: cn=schema,cn=config

dn: cn={0}core,cn=schema,cn=config

dn: cn={1}cosine,cn=schema,cn=config

dn: cn={2}nis,cn=schema,cn=config

dn: cn={3}inetorgperson,cn=schema,cn=config

dn: cn={4}iot,cn=schema,cn=config

dn: cn={5}kerberos,cn=schema,cn=config

dn: olcBackend={0}mdb,cn=config

dn: olcDatabase={-1}frontend,cn=config

dn: olcDatabase={0}config,cn=config

dn: olcDatabase={1}mdb,cn=config

您可以使用这些命令查看 Kerberos 模式的模式对象和属性

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn={5}kerberos,cn=schema,cn=config olcObjectClasses
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn={5}kerberos,cn=schema,cn=config olcAttributeTypes

检查和更新 LDAP 基础

有时安装脚本不会创建 LDAP 基础(根 DN),在这种情况下,您需要自己将其添加到配置中。使用以下命令

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:///

dn: olcDatabase={1}mdb,cn=config
replace: olcRootDN
olcRootDN: cn=admin,dc=examplefirm,dc=com

dn: olcDatabase={1}mdb,cn=config
replace: olcSuffix
olcSuffix: dc=examplefirm,dc=com

 [Ctrl-D]

最好重新启动 slapd 服务以确保更改已生效

sudo service slapd restart

您可能还需要将根 DN 填充到目录信息树中,使用这些命令

sudo ldapadd -x -D cn=admin,dc=examplefirm,dc=com -W
Enter LDAP Password:
dn: dc=examplefirm,dc=com
objectClass: organization
objectClass: dcObject
objectClass: top
dc: examplefirm
o: examplefirm.com

 adding new entry "dc=examplefirm,dc=com"
 [Ctrl-D] 

向 LDAP 目录添加内容

现在模式已安装到目录中,我们可以开始填充目录树了。

输入以下命令以在 add_base.ldif 文件中的 LDAP 基础下创建顶级对象

# file: add_base.ldif
dn: ou=People,dc=examplefirm,dc=com
objectClass: organizationalUnit
ou: People

dn: ou=Groups,dc=examplefirm,dc=com
objectClass: organizationalUnit
ou: Groups

dn: ou=Computers,dc=examplefirm,dc=com
objectClass: organizationalUnit
ou: Computers

使用 ldapadd 工具运行此文件中的命令添加对象,它将提示您输入之前设置的 LDAP 管理员密码

sudo ldapadd -x -D cn=admin,dc=examplefirm,dc=com -W -f add_base.ldif
 Enter LDAP Password:
 adding new entry "ou=People,dc=examplefirm,dc=com"

 adding new entry "ou=Groups,dc=examplefirm,dc=com"

 adding new entry "ou=Computers,dc=examplefirm,dc=com"

 

接下来,将一些用户添加到 People ou(ou 表示组织单位)。以 LDIF 格式将以下命令输入到文件 add_users.ldif

# file: add_users.ldif
dn: uid=user01,ou=People,dc=examplefirm,dc=com
objectClass: iotOrgPerson
uid: user01
sn: lastnameone
givenName: firstnameone
cn: user01
displayName: firstnameone
uidNumber: 10001
gidNumber: 10001
employeeNumber: 1
employeeType: Employee
homeDirectory: /home/user01
loginShell: /bin/bash
title: user01
mail: user01@examplefirm.com
userPassword:
o: Example Firm
mobile: 1234567890
accountActive: TRUE
street: ABC Road
l: Mumbai
st: Maharashtra

dn: uid=user02,ou=People,dc=examplefirm,dc=com
objectClass: iotOrgPerson
uid: user02
sn: lastnametwo
givenName: firstnametwo
cn: user02
displayName: firstnametwo
uidNumber: 10002
gidNumber: 10002
employeeNumber: 2
employeeType: Employee
homeDirectory: /home/user02
loginShell: /bin/bash
title: user02
mail: user02@examplefirm.com
userPassword:
o: Example Firm
mobile: 1234567890
accountActive: TRUE
street: ABC Road
l: Mumbai
st: Maharashtra

使用此命令将这些添加到目录中

sudo ldapadd -x -D cn=admin,dc=examplefirm,dc=com -W -f add_users.ldif
 Enter LDAP Password:
 adding new entry "uid=user01,ou=People,dc=examplefirm,dc=com"

 adding new entry "uid=user02,ou=People,dc=examplefirm,dc=com"

 

接下来,将一些设备(主机/服务器/计算机/等)添加到 Computers ou。将以下 ldif 命令输入到文件 add_computers.ldif

dn: cn=iot01.examplefirm.com,ou=Computers,dc=examplefirm,dc=com
objectClass: ipHost
objectClass: bootableDevice
objectClass: ieee802Device
objectClass: iotEquipment
objectClass: device
objectClass: top
cn: iot01
ipHostNumber:  10.10.1.1
associatedDomain: examplefirm.com
description: Raspberry Pi based Kerberos and LDAP server
macAddress:  A1:B2:C3:00:11:22
o: Example Firm Pvt. Ltd.
manager: uid=user01,ou=People,dc=examplefirm,dc=com
serialNumber: ABCD010101Z

dn: cn=host,cn=iot01.examplefirm.com,ou=Computers,dc=examplefirm,dc=com
objectClass: top
objectClass: ipService
cn: host
ipServicePort: 22
ipServiceProtocol: ssh

dn: cn=HTTP,cn=iot01.examplefirm.com,ou=Computers,dc=examplefirm,dc=com
objectClass: top
objectClass: ipService
cn: HTTP
ipServicePort: 80
ipServiceProtocol: http

dn: cn=iot02.examplefirm.com,ou=Computers,dc=examplefirm,dc=com
objectClass: ipHost
objectClass: bootableDevice
objectClass: ieee802Device
objectClass: iotEquipment
objectClass: device
objectClass: top
cn: iot02
ipHostNumber: 10.10.1.2
associatedDomain: examplefirm.com
description: Raspberry Pi based iot for weather monitoring
macAddress: A1:B2:C3:00:11:23
o: Example Firm Pvt. Ltd.
manager: uid=user02,ou=People,dc=examplefirm,dc=com
serialNumber: ABCD010102Y

dn: cn=host,cn=iot02.examplefirm.com,ou=Computers,dc=examplefirm,dc=com
objectClass: top
objectClass: ipService
cn: host
ipServicePort: 22
ipServiceProtocol: ssh

dn: cn=iot03.examplefirm.com,ou=Computers,dc=examplefirm,dc=com
objectClass: ipHost
objectClass: bootableDevice
objectClass: ieee802Device
objectClass: iotEquipment
objectClass: device
objectClass: top
cn: iot03
ipHostNumber: 10.10.1.3
associatedDomain: examplefirm.com
description: Beaglebone based iot for physical intrusion detection
macAddress: A1:B2:C3:00:11:24
o: Example Firm Pvt. Ltd.
manager: uid=user03,ou=People,dc=examplefirm,dc=com
serialNumber: ABCD010103X

dn: cn=host,cn=iot03.examplefirm.com,ou=Computers,dc=examplefirm,dc=com
objectClass: top
objectClass: ipService
cn: host
ipServicePort: 22
ipServiceProtocol: ssh

接下来,使用命令将这些添加到 ldap 服务器

sudo ldapadd -x -D cn=admin,dc=examplefirm,dc=com -W -f add_computers.ldif
 Enter LDAP Password:
 adding new entry "cn=iot01.examplefirm.com,ou=Computers,dc=examplefirm,dc=com"

 adding new entry "cn=host,cn=iot01.examplefirm.com,ou=Computers,dc=examplefirm,dc=com"

 adding new entry "cn=HTTP,cn=iot01.examplefirm.com,ou=Computers,dc=examplefirm,dc=com"

 adding new entry "cn=iot02.examplefirm.com,ou=Computers,dc=examplefirm,dc=com"

 adding new entry "cn=host,cn=iot02.examplefirm.com,ou=Computers,dc=examplefirm,dc=com"

 adding new entry "cn=iot03.examplefirm.com,ou=Computers,dc=examplefirm,dc=com"

 adding new entry "cn=host,cn=iot03.examplefirm.com,ou=Computers,dc=examplefirm,dc=com"

这样就完成了我们的 LDAP 设置,基础设施的目录部分现在已准备好支持 Kerberos 以及用于用户和设备管理的的企业目录。

尽管我在这些示例中使用了 ldap 工具的命令行版本,但您也可以使用 Jxplorer 或 Apache DS 等 GUI LDAP 管理器。它们通过其点按式界面简化了 LDAP 管理。

Screenshot of GUI based LDAP manager - Jxplorer

配置的其余部分优化了 LDAP 服务器,并作为所需用于管理服务器的有用命令的参考。

为 LDAP 数据库创建索引

为了加快 LDAP 查询速度并防止完全扫描目录树,最好为 ldap 数据库将频繁访问的属性创建索引,例如 accountActive、krbPrincipalName 和 accountAuthorized。

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -W -c
Enter LDAP Password:

dn: olcDatabase={1}mdb,cn=config
add: olcDbIndex
olcDbIndex: accountActive eq

modifying entry "olcDatabase={1}mdb,cn=config"

dn: olcDatabase={1}mdb,cn=config
add: olcDbIndex
olcDbIndex: accountAuthorized eq,pres

modifying entry "olcDatabase={1}mdb,cn=config"

dn: olcDatabase={1}mdb,cn=config
add: olcDbIndex
olcDbIndex: krbPrincipalName eq,sub

modifying entry "olcDatabase={1}mdb,cn=config"

[ctrl+D]

通过查询所有当前设置的索引来验证这些索引是否配置正确

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b olcDatabase={1}mdb,cn=config olcDbIndex
dn: olcDatabase={1}mdb,cn=config
olcDbIndex: objectClass eq
olcDbIndex: cn,uid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: member,memberUid eq
olcDbIndex: accountActive eq
olcDbIndex: accountAuthorized eq,pres
olcDbIndex: krbPrincipalName eq,sub

访问控制

OpenLDAP 使用特殊的 ACL 条目来验证用户在读取或写入对象之前的权限。要查看数据库后端的 ACL,请使用以下命令

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcDatabase={1}mdb)' olcAccess
dn: olcDatabase={1}mdb,cn=config
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by * read

使用此命令查看前端 ACL

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcDatabase={-1}frontend)' olcAccess
dn: olcDatabase={-1}frontend,cn=config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external
 ,cn=auth manage by * break
olcAccess: {1}to dn.exact="" by * read
olcAccess: {2}to dn.base="cn=Subschema" by * read

要实现比默认值更严格的访问,您可以动态编辑 ACL,其语法与动态配置相同。有关修改 ACL 以保护 Kerberos 相关属性的说明,请参阅本文第二部分中的命令。修改 ACL 时,请确保管理员始终拥有完全访问权限,否则您可能会被锁定在数据库之外。

最后,重新启动 OpenLDAP 服务以确保所有更改都已提交并被服务器使用

sudo service slapd restart

检查服务器的系统日志以验证服务器是否已正确启动。

结论

本文的下一部分将介绍安装和配置 Kerberos KDC 和管理服务器以完成身份验证基础设施;并将其用于验证 Raspberry 物联网设备。

附录 1 - 模式维护

本节列出了用于修改模式属性的有用命令,作为参考

sudo ldapadd -Q -Y EXTERNAL -H ldapi:///

dn: cn={4}examplefirm,cn=schema,cn=config
add: olcAttributeTypes
olcAttributeTypes: {13}(1.3.6.1.4.1.42300.4.13 NAME 'mailAliasAddress' DESC 'RFC822 alias email address of this recipient' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )

modifying entry "cn={4}examplefirm,cn=schema,cn=config"
[press Ctrl-D to exit]

使用以下命令添加模式属性

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:///

dn: cn={6}examplefirmext,cn=schema,cn=config
changetype: modify
delete: olcObjectClasses
olcObjectClasses: {0}

modifying entry "cn={6}examplefirmext,cn=schema,cn=config"

changetype: add
add: olcObjectClasses
olcObjectClasses: {1}( 1.3.6.1.4.1.42300.6 NAME 'examplefirmOrgPersonExt' DESC 'Extends attributes of entries representing people in example organization.'
  SUP top AUXILIARY MAY ( info $ manager $ emergencyPhone $ persona
 lTitle $ emergencyContactPerson $ homePostalAddress $ tentativeJoiningDate $
 accountAuthorized $ actualJoiningDate $ leavingDate $ homeEmail $ assistantEm
 ail $ assistantPhone ) )

modifying entry "cn={6}examplefirmext,cn=schema,cn=config"
 [press Ctrl-D to exit]

用于从模式中删除所有现有属性的命令

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:///

dn: cn={4}iot,cn=schema,cn=config
changetype: modify
delete: olcAttributeTypes
olcAttributeTypes: {0}
-
delete: olcAttributeTypes
olcAttributeTypes: {0}
-
delete: olcAttributeTypes
olcAttributeTypes: {0}
-
delete: olcAttributeTypes
olcAttributeTypes: {0}
-
delete: olcAttributeTypes
olcAttributeTypes: {0}
-
delete: olcAttributeTypes
olcAttributeTypes: {0}
-
delete: olcAttributeTypes
olcAttributeTypes: {0}
-
delete: olcAttributeTypes
olcAttributeTypes: {0}

向模式 iot 添加新属性的命令

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:///

dn: cn={4}iot,cn=schema,cn=config
changetype: modify
add: olcAttributeTypes
olcAttributeTypes: {3}( 1.3.6.1.4.1.92300.1.26 NAME 'emergencyContactPerson' DESC 'Person to contact in case of emergency' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
olcAttributeTypes: {4}( 1.3.6.1.4.1.92300.1.27 NAME 'tentativeJoiningDate' DESC 'Time in unix time of tentative joining date' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: {5}( 1.3.6.1.4.1.92300.1.28 NAME 'accountAuthorized' DESC 'A boolean telling whether an accounts changes are authorized or not' EQUALITY  booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
olcAttributeTypes: {6}( 1.3.6.1.4.1.92300.1.29 NAME 'actualJoiningDate' DESC 'Actual joining date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE )
olcAttributeTypes: {7}( 1.3.6.1.4.1.92300.1.30 NAME 'leavingDate' DESC 'Employee leaving date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE )
olcAttributeTypes: {8}( 1.3.6.1.4.1.92300.1.31 NAME 'homeEmail' DESC 'RFC822 Mailbox - mail alias' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
olcAttributeTypes: {9}( 1.3.6.1.4.1.92300.1.32 NAME 'assistantEmail' DESC 'RFC822 Mailbox - mail alias' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
olcAttributeTypes: {10}( 1.3.6.1.4.1.92300.1.33 NAME 'assistantPhone' DESC 'RFC1274: assistants telephone number' EQUALITY telephoneNumberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

修改类对象的命令

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:///

dn: cn={4}iot,cn=schema,cn=config
changetype: modify
delete: olcObjectClasses
olcObjectClasses: {0}
-
add: olcObjectClasses
olcObjectClasses: ( 1.3.6.1.4.1.92300.1 NAME 'iotOrgPerson' DESC 'Defines entries representing people in example organization.' SUP inetOrgPerson STRUCTURAL MAY ( homeDirectory $ loginShell $ accountActive $ uidNumber $ gidNumber $ jPEGPhoto $ info $ manager $ personalTitle $ emergencyContactPerson $ homePostalAddress $ tentativeJoiningDate $accountAuthorized $ actualJoiningDate $ leavingDate $ homeEmail $ assistantEmail $ assistantPhone ) )

modifying entry "cn={4}iot,cn=schema,cn=config"
[Press Ctrl+D to exit]

请注意,OpenLDAP 2.4 版本不支持动态配置模式的删除。因此,如果要删除模式,一种变通方法是清空模式中的所有 objectclasses 和 attributetypes,使其失效。如果需要修改模式,可以更改现有条目或添加具有所需模式定义的新条目。

附录 2 - 更改管理员密码

如果您忘记了管理员密码或需要更改 LDAP 服务器的密码,您可以按照以下步骤重置(假设您拥有 sudo 权限)。

首先,通过运行此命令获取密码的 SSHA 哈希值以获取 SSHA 哈希值,例如,如果我们的密码是 goodpassword

slappasswd -s goodpassword
{SSHA}HnZrrqQ4jjMdqsOGpOrnM010S2LvBEGa

接下来,在配置数据库上运行 ldapmodify 并将此哈希值添加到 mdb 配置对象中的 olcRootPW 属性

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:///

dn: olcDatabase={1}mdb,cn=config
replace: olcRootPW
olcRootPW: {SSHA}HnZrrqQ4jjMdqsOGpOrnM010S2LvBEGa

modifying entry "olcDatabase={1}mdb,cn=config"
[Ctrl-D]

附录 3 - 更新和维护内容的命令

对于常规维护活动,如修改或删除条目,请使用以下命令

从 ldap 中删除条目

sudo ldapdelete -x -D cn=admin,dc=examplefirm,dc=com -W 'uid=user01,ou=People,dc=examplefirm,dc=com'

通过添加新属性修改 ldap 对象

sudo ldapmodify -x -D cn=admin,dc=examplefirm,dc=com -W -v -c

dn: uid=user01,ou=People,dc=examplefirm,dc=com
add: quotaBytes
quotaBytes: 500000000

[press Ctrl-D to exit interactive entry in stdin]

修改并替换对象中的属性

sudo ldapmodify -x -D cn=admin,dc=examplefirm,dc=com -W -v

dn: uid=user01,ou=People,dc=examplefirm,dc=com
changetype: modify
replace: userPassword
userPassword: mypassword

replace userPassword:
        mypassword
modifying entry "uid=user01,ou=People,dc=examplefirm,dc=com"
modify complete

[press Ctrl-D to exit interactive entry in stdin]

查询具有给定 objectClasses 和属性的对象列表

ldapsearch -x –LLL -s base -b "cn=subschema" objectclasses

另一个带有搜索过滤器的查询示例,多个过滤器可以组合成类似 lisp 的模式,例如 (&(condition1)(condition2)) 等。

ldapsearch -x -LLL -b ou=People,dc=examplefirm,dc=com '(objectClass=iotOrgPerson)' displayName uid mail EmployeeType

dn: uid=user01,ou=People,dc=examplefirm,dc=com
uid: user01
displayName: firstnameone
employeeType: Employee
mail: user01@examplefirm.com

dn: uid=user02,ou=People,dc=examplefirm,dc=com
uid: user02
displayName: firstnametwo
employeeType: Employee
mail: user02@examplefirm.com

附录 4 - 自定义 LDAP 事件日志记录

OpenLDAP 支持多个日志记录级别,详细程度递增。配置系统时,您可以将其设置为详细日志记录模式,例如“stats”,一旦配置完成,请将其更改为“parse”。

以下是日志级别及其含义的列表(摘自 slapd-config man page)- 日志级别是累加的,可用级别是

  • 1      (0x1 trace) trace 函数调用
  • 2      (0x2 packets) debug 数据包处理
  • 4      (0x4 args) 详细的跟踪调试(函数参数)
  • 8      (0x8 conns) 连接管理
  • 16     (0x10 BER) 打印发送和接收的数据包
  • 32     (0x20 filter) 搜索过滤器处理
  • 64     (0x40 config) 配置文件处理
  • 128    (0x80 ACL) 访问控制列表处理
  • 256    (0x100 stats) stats 日志连接/操作/结果
  • 512    (0x200 stats2) stats 日志条目发送
  • 1024   (0x400  shell)  print  communication  with   shell backends
  • 2048   (0x800 parse) 条目解析
  • 16384  (0x4000 sync) LDAPSync 复制
  • 32768  (0x8000   none) 仅记录任何消息,无论日志级别如何设置(无法抑制的最关键事件)

例如,使用此配置文件 logging.ldif 将日志级别设置为 stats ,该级别以更详细的方式记录事件

dn: cn=config
changetype: modify
add: olcLogLevel
olcLogLevel: stats

执行此文件中的命令来实施更改

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f logging.ldif
 modifying entry "cn=config"

关注点

在部署过程中,我遇到了 OID 曲线的概念,它被用作一种目录服务命名空间。这是新信息,大多数管理员几乎都忘记了。通过向 IANA 申请,私人组织可以获得其自己的 OID 曲线的私人企业编号 (PEN) 以供其使用。这是注册 PEN 以用作 LDAP DIT 中自定义标识符的在线表格 - http://pen.iana.org/pen/PenApplication.page 。我们在本文的示例配置中使用了随机选择的数字 1.3.6.1.4.1.92300。只要目录不公开托管,并且不与已建立的 PEN 冲突(这将导致重用他人创建的模式时出现问题),内部目录服务使用哪个 PEN ID 应该无关紧要。

另一个有趣的发现是 OpenLDAP 模式在创建后很难修改。因此,在将模式部署到生产系统之前,您需要对模式定义和属性类型非常确定。最好在生产系统上部署更改之前,在测试/开发服务器上进行实验。

历史

  1. 原始版本(2016 年 9 月 29 日)
  2. 更新以更正拼写错误和语法错误(2016 年 10 月 3 日)
  3. 更新以添加屏幕截图和更多命令描述(2016 年 10 月 4 日)
© . All rights reserved.