Stay hungry,Stay foolish

0%

集中认证1(OpenLDAP + Kerberos)

集中认证

说明

我们常说的认证平台或4A认证是指: 认证(Authentication)、授权(Authorization)、账号(Account)、审计(Audit)

认证: 是否允许你通过

授权: 通过后你拥有哪些权限

账号: 用以标记你是谁, 可以是人、设备、服务等

审计: 都做了什么, 留痕

这里集中认证实现的是账号+认证, 不同于单点登录(SSO, Single Sign On).

授权一般是业务自身来处理, 比如基于账号ID、账号某属性

审计一般是基于日志分析用户做了什么, 有什么安全风险

简单的需求分析

本质需求: 公司的IT系统、业务系统使用同一套用户/密码体系进行登录认证

这时候需进一步对需要登录的系统进行简单罗列:

  • Web
  • SSH
  • Switch

按照需要支持的协议拆分:

  • LDAP
  • Kerberos
  • Radius

是不是会有点懵…

不急, 框架定好, 一步一步搭建测试环境, 逐步满足需求

TODO: 各种选型的对比、认证原理

技术方案

基于简单的需求分析, 私下肯定会做一定的功课, 这里我们先做如下决策

  • OpenLDAP 用作账号管理
  • Kerberos 用作认证

测试环境, 一定要记住下面都是测试环境的产物, 只是为了快速验证方案

  • Ubuntu 18.04.5 LTS
  • slapd 2.4.45+dfsg-1ubuntu1.10
  • krb5-kdc 1.16-2ubuntu0.2

OpenLDAP 安装

一些概念不再敖述, 可自行官网通读手册或搜索

安装

1
2
apt install slapd
apt install ldap-utils
  • slapd OpenLDAP Server, ldap服务的守护进程
  • ldap-utils OpenLDAP utilites, ldap的客户端工具集, 比如ldapsearch

slapd改为使用slapd.conf配置文件, 而不是官网建议的slapd.d目录

尝试过基于slapd.d目录配置, 可读性、可维护性个人感觉太差了
1
2
3
cd /etc/ldap
mv slapd.d slapd.d.bak
cp /usr/share/slapd/slapd.conf .

结合配置示例, 剥离出一个最简配置如下slapd.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/misc.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/kerberos.schema

pidfile /var/run/slapd/slapd.pid
argsfile /var/run/slapd/slapd.args

loglevel stats
idletimeout 30
writetimeout 5

modulepath /usr/lib/ldap
moduleload back_hdb
database hdb
directory /var/lib/ldap/
dbconfig set_cachesize 0 1048576 0
dbconfig set_lg_bsize 2097152

suffix "dc=intra,dc=wafcloud,dc=cn"
rootdn "cn=root,ou=Control,dc=intra,dc=wafcloud,dc=cn"
rootpw "{SSHA}bjVQ5hStFSeqHyc/thFM4HX1HJ8AF6HA"

rootpw字段对应的值是通过slappasswd命令生成, 例如slappasswd -s virE8jUt

养成好习惯, 测试环境也避免使用弱密码

kerberos.schema来源于krb5-kdc-ldap软件包中的kerberos.schema.gz

其它参数具体意义可man slapd.conf

测试

1
ldapsearch -D 'cn=root,ou=Control,dc=intra,dc=wafcloud,dc=cn' -b 'dc=intra,dc=wafcloud,dc=cn' -h 127.0.0.1 -x -W
  • -x 简单认证
  • -W 交互输入密码; 也可以-w virE8jUt

测试命令建议都保存到某个test.sh文件用作测试样例, 后期配置调试会经常用到类似查询

数据初始化

ldapadd -x -D ‘cn=root,ou=Control,dc=intra,dc=wafcloud,dc=cn’ -h 127.0.0.1 -W -f init_ldap.ldif

init_ldap.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
dn: dc=intra,dc=wafcloud,dc=cn
dc: intra
objectClass: domain
objectClass: dcObject

dn: ou=Group,dc=intra,dc=wafcloud,dc=cn
ou: Group
objectClass: organizationalUnit

dn: ou=People,dc=intra,dc=wafcloud,dc=cn
ou: People
objectClass: organizationalUnit

dn: ou=Control,dc=intra,dc=wafcloud,dc=cn
ou: Control
objectClass: organizationalUnit

dn: cn=root,ou=Control,dc=intra,dc=wafcloud,dc=cn
cn: root
userPassword:: e1NTSEF9cU9kVnZqMzFCcy8xUVFBYXRKcXNxbFZSWWx1ZFhzbm8K
objectClass: simpleSecurityObject
objectClass: organizationalRole


dn: uid=test1,ou=People,dc=intra,dc=wafcloud,dc=cn
uid: test
uidNumber: 10001
gidNumber: 20000
sn: Test
cn: Test User1
userPassword:: e1NTSEF9cWxVcS9EdWx2b0syWExPMThWUU5NbzJlSmFjb1J2RWcK
loginShell: /bin/bash
homeDirectory: /home/test1
objectClass: person
objectClass: posixAccount
objectClass: inetOrgPerson
objectClass: organizationalPerson

dn: uid=test2,ou=People,dc=intra,dc=wafcloud,dc=cn
uid: test2
uidNumber: 10002
gidNumber: 20000
sn: Test
cn: Test User2
userPassword:: e1NTSEF9cWxVcS9EdWx2b0syWExPMThWUU5NbzJlSmFjb1J2RWcK
loginShell: /bin/bash
homeDirectory: /home/test2
objectClass: person
objectClass: posixAccount
objectClass: inetOrgPerson
objectClass: organizationalPerson

userPassword字段对应的值是通过slappasswd -s xxx | base64命令生成, 例如slappasswd -s 6WykeemU | base64

测试

1
2
ldapsearch -D 'uid=test1,ou=People,dc=intra,dc=wafcloud,dc=cn' -b 'dc=intra,dc=wafcloud,dc=cn' -h 127.0.0.1 -x -W
ldapsearch -D 'uid=test2,ou=People,dc=intra,dc=wafcloud,dc=cn' -b 'dc=intra,dc=wafcloud,dc=cn' -h 127.0.0.1 -x -W

注意这里是uid=

ACL

细心的话肯定发现了安全问题: 普通账号可以遍历整个LDAP库的任何字段, 包括userPassword

slapd.conf增加如下配置并重启服务

1
2
3
4
5
6
7
8
9
10
11
12
access to attrs=userPassword,shadowLastChange
by dn="cn=root,ou=Control,dc=intra,dc=wafcloud,dc=cn" write
by anonymous auth
by self write
by * none

access to dn.base=""
by * read

access to *
by dn="cn=root,ou=Control,dc=intra,dc=wafcloud,dc=cn" write
by users read

通过ldapsearch进行查询条件、限定条件组合测试; 线上环境ACL会是重点!

安利下Apache Directory Studio这个客户端软件, 效果如下

Kerberos 安装

关于Kerberos认证流程, 推荐这篇文章https://www.cnblogs.com/artech/archive/2007/07/05/807492.html

安装

1
apt install krb5-kdc krb5-admin-server
  • krb5-kdc Kerberos key server
  • krb5-admin-server Kerberos master server (kadmind)

乍一看这安装包的描述信息确实很懵逼, 这种情况下一般先把包下载到本地并并解压

krb5-kdc主要包含kdb5_util, kproplog, krb5kdc几个命令, 其中krb5kdc是守护进程(服务)

krb5-admin-server主要包含kadmind, kadmin.local, kprop, krb5_newrealm几个命令, 其中kadmind是守护进程(服务)

dpkg-reconfigure krb5-config交互式进行初步配置, 也可以直接复用下面的配置

/etc/krb5.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[libdefaults]
debug = true
default_realm = INTRA.WAFCLOUD.CN

[realms]
INTRA.WAFCLOUD.CN = {
kdc = 127.0.0.1
#admin_server = 127.0.0.1
default_domain = intra.wafcloud.cn
key_stash_file = /etc/krb5.keyfile
max_life = 1d 0h 0m 0s
max_renewable_life = 90d 0h 0m 0s
dict_file = /usr/share/dict/words
}

[domain_realm]
.intra.wafcloud.cn = INTRA.WAFCLOUD.CN
intra.wafcloud.cn = INTRA.WAFCLOUD.CN

[logging]
default = SYSLOG:DEBUG
kdc = FILE=/var/tmp/kdc.log
admin_server = FILE=/var/tmp/kadmin.log

/etc/krb5kdc/kdc.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[kdcdefaults]
kdc_ports = 750,88

[realms]
INTRA.WAFCLOUD.CN = {
database_name = /var/lib/krb5kdc/principal
admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
acl_file = /etc/krb5kdc/kadm5.acl
key_stash_file = /etc/krb5kdc/stash
kdc_ports = 750,88
max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
master_key_type = des3-hmac-sha1
#supported_enctypes = aes256-cts:normal aes128-cts:normal
default_principal_flags = +preauth
}

/etc/krb5kdc/kadm5.acl

1
*/admin@INTRA.WAFCLOUD.CN   *

初始化数据库并启动服务

1
2
kdb5_util create -s -r INTRA.WAFCLOUD.CN
/etc/init.d/krb5-kdc start

kadmin.localkadmin都kerberos数据库的管理程序,区别是kadmin.local直接操作数据库, kadmin是通过连接kadmind

kadmin读取krb5.conf中的配置找到admin_server

添加一个test/admin

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
root@dev:~# kadmin.local
Authenticating as principal test/admin@INTRA.WAFCLOUD.CN with password.

kadmin.local: list_principals
K/M@INTRA.WAFCLOUD.CN
kadmin/admin@INTRA.WAFCLOUD.CN
kadmin/changepw@INTRA.WAFCLOUD.CN
kadmin/dev@INTRA.WAFCLOUD.CN
kiprop/dev@INTRA.WAFCLOUD.CN
krbtgt/INTRA.WAFCLOUD.CN@INTRA.WAFCLOUD.CN

kadmin.local: add_principal test/admin
WARNING: no policy specified for test/admin@INTRA.WAFCLOUD.CN; defaulting to no policy
Enter password for principal "test/admin@INTRA.WAFCLOUD.CN":
Re-enter password for principal "test/admin@INTRA.WAFCLOUD.CN":
Principal "test/admin@INTRA.WAFCLOUD.CN" created.

kadmin.local: list_principals
K/M@INTRA.WAFCLOUD.CN
kadmin/admin@INTRA.WAFCLOUD.CN
kadmin/changepw@INTRA.WAFCLOUD.CN
kadmin/dev@INTRA.WAFCLOUD.CN
kiprop/dev@INTRA.WAFCLOUD.CN
krbtgt/INTRA.WAFCLOUD.CN@INTRA.WAFCLOUD.CN
test/admin@INTRA.WAFCLOUD.CN

kadmin.local: change_password test/admin
Enter password for principal "test/admin@INTRA.WAFCLOUD.CN":
Re-enter password for principal "test/admin@INTRA.WAFCLOUD.CN":
Password for "test/admin@INTRA.WAFCLOUD.CN" changed.

可以下面这种方式添加一个test1

1
kadmin.local -q 'ank -pw 123456 test1'

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
root@dev:~# kinit test/admin
Password for test/admin@INTRA.WAFCLOUD.CN:
kinit: Password incorrect while getting initial credentials

root@dev:~# kinit test/admin
Password for test/admin@INTRA.WAFCLOUD.CN:

root@dev:~# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: test/admin@INTRA.WAFCLOUD.CN

Valid starting Expires Service principal
09/08/2021 09:59:52 09/09/2021 09:59:49 krbtgt/INTRA.WAFCLOUD.CN@INTRA.WAFCLOUD.CN

OpenLDAP + Kerberos

前面分别介绍了OpenLDAPKerberos测试环境下的精简部署方式, 明显认证还没有融合在一起

这时我们进行个简单的怎么融合的思维发散?

  • 共用某字段, 比如userPassword
  • 有某个起到转发桥梁, 把其中的一个认证服务转发给另一个服务

通过saslauthd把来自LDAP的认证转发给kerberos

saslauthd安装不再敖述, 变更其配置文件/etc/default/saslauthd中的MECHANISMS="kerberos5"重启服务即可

测试

1
root@dev:~# testsaslauthd -u test1 -p 123456

这时肯定会报错… saslauthd只是配置了Kerberos, 去哪儿找呢? tcpdump -i any -n -p port 53也会发现DNS解析请求

建议自建一个DNS服务器, 其次绑定hosts; 下面是DNS的测试配置

1
2
3
4
5
6
7
8
9
10
11
$ORIGIN _tcp.intra.wafcloud.cn.
_kerberos-adm IN SRV 0 0 749 kdc01.intra.wafcloud.cn.

$ORIGIN _udp.intra.wafcloud.cn.
_kerberos IN SRV 0 0 88 kdc01.intra.wafcloud.cn.
_kerberos-master IN SRV 0 0 88 kdc01.intra.wafcloud.cn.
_kpasswd IN SRV 0 0 464 kdc01.intra.wafcloud.cn.

$ORIGIN intra.wafcloud.cn.
kdc01 A 192.168.3.108
kerberos CNAME kdc01

更多详情可参考https://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.1/doc/krb5-admin/Hostnames-for-KDCs.html

继续测试, auth.log大概率会有如下类似日志

1
2
3
saslauthd[13500]: auth_krb5: krb5_kt_read_service_key(): Key table file '/etc/krb5.keytab' not found (2)
saslauthd[13503]: auth_krb5: krb5_kt_read_service_key(): No key table entry found for host/dev@INTRA.WAFCLOUD.CN (-1765328203)
saslauthd[13503]: auth_krb5: krb5_kt_read_service_key(): No key table entry found for host/host@INTRA.WAFCLOUD.CN (-1765328203)

解决

1
2
3
4
kadmin.local -q "ank -clearpolicy -randkey host/localhost"
kadmin.local -q "ank -clearpolicy -randkey host/dev"
ktadd host/localhost
ktadd host/dev

直到测试OK, 代表saslauthdkerberos之间打通

1
2
root@dev:~# testsaslauthd -u test2 -p 123456
0: OK "Success."

下一步就是OpenLDAPsaslauthd打通

OpenLDAP主要是改动两个地方

  • 认证改为saslauthd
  • 用户属性中的userPassword改为{SASL}形式

认证改为saslauthd, /etc/ldap/sasl2/slapd.conf

1
2
pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux

change_test1_pass.ldif

userPassword生成方式 echo -n "{SASL}test1@INTRA.WAFCLOUD.CN" | base64 
1
2
3
4
dn: uid=test1,ou=People,dc=intra,dc=wafcloud,dc=cn
changetype: modify
replace: userPassword
userPassword:: e1NBU0x9dGVzdDFASU5UUkEuV0FGQ0xPVUQuQ04=

更改test1密码为{SASL}验证方式

1
ldapadd -x -D 'cn=root,ou=Control,dc=intra,dc=wafcloud,dc=cn' -h 127.0.0.1 -W -f change_test1_pass.ldif

通过kadmin.local更改test1密码测试并逐步验证

Kerberos ---> Saslauthd ---> OpenLDAP
1
2
3
kinit test1
testsaslauthd -u test1 -p 112233
ldapwhoami -D 'uid=test1,ou=People,dc=intra,dc=wafcloud,dc=cn' -h 127.0.0.1 -x -w 112233 -vvv

总结概要

  • OpenLDAP账户管理, Kerberos认证
  • Saslauthd 起到了中间桥梁的作用
  • 善于通过日志解决问题, 必要的时候调整日志级别记录更多信息/var/tmp/kdc.log /var/tmp/kadmin.log /var/log/syslog /var/log/auth.log

krb5kdc[10706]: Couldn’t open log file /var/log/krb5/kdc.log: Read-only file system

1
2
3
参考<https://bugs.launchpad.net/ubuntu/+source/freeipa/+bug/1874915>

日志文件需在特定目录下, 应该是个Bug

其它

此篇配置远未达到线上环境配置要求! 比如安全、扩展、维护等

后面一步步优化, 比如细心的同学发现slapd.conf中的include /etc/ldap/schema/kerberos.schema没用到啊