PostgreSQL pg_hba.conf "search bind" configure Use LDAP auth

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介:
上一篇BLOG讲了一下在PostgreSQL的pg_hba.conf中配置ldap simple bind的认证方式.
PostgreSQL还支持另一种bind方式.
search+bind
相当于PostgreSQL server需要两次和ldap server交互. 交互过程如下.
In the second mode, which we will call the search+bind mode, the server first binds to the LDAP directory with a fixed user name and password, specified with ldapbinddn and ldapbindpasswd, and performs a search for the user trying to log in to the database. If no user and password is configured, an anonymous bind will be attempted to the directory. The search will be performed over the subtree at ldapbasedn, and will try to do an exact match of the attribute specified in ldapsearchattribute. Once the user has been found in this search, the server disconnects and re-binds to the directory as this user, using the password specified by the client, to verify that the login is correct. This mode is the same as that used by LDAP authentication schemes in other software, such as Apache mod_authnz_ldap and pam_ldap. This method allows for significantly more flexibility in where the user objects are located in the directory, but will cause two separate connections to the LDAP server to be made.

使用tcpdump在PostgreSQL server抓包过滤LDAP server的IP, 
[root@db-172-16-3-39 ~]# tcpdump -i eth0 -n |grep 172.16.3.150
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
第一次交互开始
14:30:17.084862 IP 172.16.3.39.61806 > 172.16.3.150.ldap: S 1377838322:1377838322(0) win 5840 <mss 1460,nop,nop,sackOK,nop,wscale 7>
14:30:17.085228 IP 172.16.3.150.ldap > 172.16.3.39.61806: S 3204831424:3204831424(0) ack 1377838323 win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 7>
14:30:17.085256 IP 172.16.3.39.61806 > 172.16.3.150.ldap: . ack 1 win 46
14:30:17.085329 IP 172.16.3.39.61806 > 172.16.3.150.ldap: P 1:15(14) ack 1 win 46
14:30:17.085597 IP 172.16.3.150.ldap > 172.16.3.39.61806: . ack 15 win 115
14:30:17.086100 IP 172.16.3.150.ldap > 172.16.3.39.61806: P 1:15(14) ack 15 win 115
14:30:17.086111 IP 172.16.3.39.61806 > 172.16.3.150.ldap: . ack 15 win 46
14:30:17.086340 IP 172.16.3.39.61806 > 172.16.3.150.ldap: P 15:87(72) ack 15 win 46
14:30:17.087060 IP 172.16.3.150.ldap > 172.16.3.39.61806: P 15:77(62) ack 87 win 115
14:30:17.087070 IP 172.16.3.150.ldap > 172.16.3.39.61806: P 77:91(14) ack 87 win 115
14:30:17.087155 IP 172.16.3.39.61806 > 172.16.3.150.ldap: . ack 91 win 46
14:30:17.087227 IP 172.16.3.39.61806 > 172.16.3.150.ldap: P 87:94(7) ack 91 win 46
第一次交互结束fin
14:30:17.087247 IP 172.16.3.39.61806 > 172.16.3.150.ldap: F 94:94(0) ack 91 win 46
第二次交互开始
14:30:17.087310 IP 172.16.3.39.61807 > 172.16.3.150.ldap: S 1292716247:1292716247(0) win 5840 <mss 1460,nop,nop,sackOK,nop,wscale 7>
第一次交互结束fin
14:30:17.087537 IP 172.16.3.150.ldap > 172.16.3.39.61806: F 91:91(0) ack 95 win 115
14:30:17.087549 IP 172.16.3.39.61806 > 172.16.3.150.ldap: . ack 92 win 46
第二次交互继续
14:30:17.087613 IP 172.16.3.150.ldap > 172.16.3.39.61807: S 3434126489:3434126489(0) ack 1292716248 win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 7>
14:30:17.087636 IP 172.16.3.39.61807 > 172.16.3.150.ldap: . ack 1 win 46
14:30:17.087677 IP 172.16.3.39.61807 > 172.16.3.150.ldap: P 1:58(57) ack 1 win 46
14:30:17.087935 IP 172.16.3.150.ldap > 172.16.3.39.61807: . ack 58 win 115
14:30:17.088268 IP 172.16.3.150.ldap > 172.16.3.39.61807: P 1:15(14) ack 58 win 115
14:30:17.088282 IP 172.16.3.39.61807 > 172.16.3.150.ldap: . ack 15 win 46
14:30:17.088357 IP 172.16.3.39.61807 > 172.16.3.150.ldap: P 58:65(7) ack 15 win 46
第二次交互结束fin
14:30:17.088368 IP 172.16.3.39.61807 > 172.16.3.150.ldap: F 65:65(0) ack 15 win 46
14:30:17.088728 IP 172.16.3.150.ldap > 172.16.3.39.61807: F 15:15(0) ack 66 win 115
14:30:17.088743 IP 172.16.3.39.61807 > 172.16.3.150.ldap: . ack 16 win 46

而simple bind则只需要交互一次.
LDAP authentication can operate in two modes. In the first mode, which we will call the simple bind mode, the server will bind to the distinguished name constructed as prefix username suffix. Typically, the prefix parameter is used to specify cn=, or DOMAIN\ in an Active Directory environment. suffix is used to specify the remaining part of the DN in a non-Active Directory environment.

使用tcpdump在PostgreSQL server抓包过滤LDAP server的IP, 
[root@db-172-16-3-39 ~]# tcpdump -i eth0 -n |grep 172.16.3.150
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
交互开始
14:31:59.340873 IP 172.16.3.39.61808 > 172.16.3.150.ldap: S 608404204:608404204(0) win 5840 <mss 1460,nop,nop,sackOK,nop,wscale 7>
14:31:59.341230 IP 172.16.3.150.ldap > 172.16.3.39.61808: S 1781266100:1781266100(0) ack 608404205 win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 7>
14:31:59.341257 IP 172.16.3.39.61808 > 172.16.3.150.ldap: . ack 1 win 46
14:31:59.341372 IP 172.16.3.39.61808 > 172.16.3.150.ldap: P 1:58(57) ack 1 win 46
14:31:59.341638 IP 172.16.3.150.ldap > 172.16.3.39.61808: . ack 58 win 115
14:31:59.342345 IP 172.16.3.150.ldap > 172.16.3.39.61808: P 1:15(14) ack 58 win 115
14:31:59.342356 IP 172.16.3.39.61808 > 172.16.3.150.ldap: . ack 15 win 46
14:31:59.342431 IP 172.16.3.39.61808 > 172.16.3.150.ldap: P 58:65(7) ack 15 win 46
结束fin
14:31:59.342451 IP 172.16.3.39.61808 > 172.16.3.150.ldap: F 65:65(0) ack 15 win 46
14:31:59.342776 IP 172.16.3.150.ldap > 172.16.3.39.61808: F 15:15(0) ack 66 win 115
14:31:59.342787 IP 172.16.3.39.61808 > 172.16.3.150.ldap: . ack 16 win 46

不管哪种模式, client都不需要和ldap server进行交互. 
为了安全考虑, 建议client 和 PostgreSQL server之间使用ssl连接. ldap server和PostgreSQL server之间也使用ssl连接.

search bind模式首先要根据pg_hba.conf中配置的ldap server, ldapbasedn,查找ldapattribute, 如果匹配到客户端提供的用户的话, 然后根据ldapattribute得到的值(作为下一次LDAP认证的用户名)以及客户端提供的密码进行第二次ldap认证.

[root@db-172-16-3-150 ldap]# ldapsearch -w 123321 -D "cn=Manager,dc=my-domain,dc=com" -b "ou=People,dc=my-domain,dc=com"
# new, People, my-domain.com
dn: uid=new,ou=People,dc=my-domain,dc=com
uid: new
cn: new
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
loginShell: /bin/bash
uidNumber: 503
gidNumber: 500
homeDirectory: /home/new
userPassword:: e1NTSEF9WXJtTE8vNm1TWk9rUitmQ2J0SWJXSE9BTW9qdTljQ3o=

# digoal, People, my-domain.com
dn: uid=digoal,ou=People,dc=my-domain,dc=com
uid: digoal
cn: digoal
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword:: e2NyeXB0fSQ2JFpqcTdKVTY4JGJVOWc1TjZBdi43MmxGWS9zeGp5QTdnenNqMzZ
 CUmVzS0F4T3IvaGUxaGYvLy9oZ05HV2xzSTEvVVQ0a0FsQmROU040eEl3ZzJLWldNTXdadElCdG4u
shadowLastChange: 16203
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 507
gidNumber: 510
homeDirectory: /home/digoal

search+bind的配置和simple bind差不多.
simple bind : 
host all new 0.0.0.0/0 ldap ldapserver=172.16.3.150 ldapport=389 ldapprefix="uid=" ldapsuffix=",ou=People,dc=my-domain,dc=com"
search bind : 
host all new 0.0.0.0/0 ldap ldapserver=172.16.3.150 ldapport=389 ldapsearchattribute="uid" ldapbasedn="ou=People,dc=my-domain,dc=com"

postgres@db5-> psql -h 172.16.3.39 -p 1999 -U digoal postgres
Password for user digoal: digoal
psql (9.1.3, server 9.3.1)
WARNING: psql version 9.1, server version 9.3.
         Some psql features might not work.
Type "help" for help.

postgres=# \du
                             List of roles
 Role name |                   Attributes                   | Member of 
-----------+------------------------------------------------+-----------
 digoal    | Superuser                                      | {}
 new       |                                                | {}
 postgres  | Superuser, Create role, Create DB, Replication | {}
 srcheck   |                                                | {}

postgres@db5-> psql -h 172.16.3.39 -p 1999 -U new postgres
Password for user new: 111111
psql (9.1.3, server 9.3.1)
WARNING: psql version 9.1, server version 9.3.
         Some psql features might not work.
Type "help" for help.

postgres=> 

search + bind还可以满足一个比较特殊的认证需求,例如用户在数据库中需要使用cn以外的属性值(比如displayName)作为角色名。
例子:
首先我们需要在域中创建一个用户,有权限查询域中的条目。
例如这个用户叫ad_for_pg,密码是pwd_ad_for_pg。
它的DN为" cn=ad_for_pg,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com"
配置对应pg_hba.conf:

ldapbinddn="cn=ad_for_pg,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com" 
ldapbindpasswd="pwd_ad_for_pg"

这个用户将用于搜索域服务器中的  ldapbasedn 和  ldapsearchattribute。

接下来要指定pg_hba.conf中的  ldapbasedn和 ldapsearchattribute。
例如我是德哥,在域中的DN为 "cn=德哥,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com",但是我不想在数据库中使用“德哥”作为数据库中的用户名,我想使用域中的displayName来作为数据库中的用户名,比如我的displayName是"Digoal.Zhou"。
配置对应pg_hba.conf:

ldapsearchattribute="displayName" 
ldapbasedn="cn=德哥,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com"

ldapbinddn和 ldapbindpasswd在域服务器中搜索到指定的 ldapbasedn和 ldapsearchattribute后,断开pg和ldapserver的连接,重新以   ldapbasedn和 ldapsearchattribute  以及 客户端提供的密码到域服务器进行认证。认证成功,则登录成功。
配置如下:

$ vi pg_hba.conf
host all "Digoal.Zhou" 0.0.0.0/0 ldap ldapserver=192.168.xxx.xxx ldapport=389 ldapsearchattribute="displayName" ldapbasedn="cn=德哥,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com" ldapbinddn="cn=ad_for_pg,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com" ldapbindpasswd="pwd_ad_for_pg"

$ pg_ctl reload

创建displayName对应的角色:
postgres=# create role "Digoal.Zhou" login;

认证测试:
psql -h 172.16.3.221 -U "Digoal.Zhou"
Password for user Digoal.Zhou:  输入ldapbasedn + ldapsearchattribute对应的域密码
psql (9.4.1)
Type "help" for help.
postgres=> 


注意,ldapbinddn和ldapbindpassword一定要配置正确,并且要有查询域条目的权限,否则可能报错如下:
2015-05-12 17:07:40.169 CST,"Digoal.Zhou","postgres",23459,"172.16.3.221:23481",5551c2dc.5ba3,2,"authentication",2015-05-12 17:07:40 CST,39/77777,0,LOG,00000,"could not search LDAP for filter ""(displayName=Digoal.Zhou)"" on server ""192.168.xxx.xxx"": Operations error",,,,,,,,"CheckLDAPAuth, auth.c:2028",""
2015-05-12 17:07:40.169 CST,"Digoal.Zhou","postgres",23459,"172.16.3.221:23481",5551c2dc.5ba3,3,"authentication",2015-05-12 17:07:40 CST,39/77777,0,FATAL,28000,"LDAP authentication failed for user ""Digoal.Zhou""","Connection matched pg_hba.conf line 94: ""host all ""Digoal.Zhou"" 0.0.0.0/0 ldap ldapserver=192.168.xxx.xxx ldapport=389 ldapsearchattribute=""displayName"" ldapbasedn=""cn=德哥,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com"" ldapbinddn=""cn=ad_for_pg,ou=质xxxx心,ou=skymobi,dc=sky-mobi,dc=com"" ldapbindpasswd="""pwd_ad_for_pg"""",,,,,,,"auth_failed, auth.c:285",""

[参考]
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
存储 网络协议 安全
|
关系型数据库 PostgreSQL
PostgreSQL sharding : citus 系列7 - topn 加速(count(*) group by order by count(*) desc limit x) (use 估值插件 topn)
标签 PostgreSQL , topn , topn.number_of_counters , count(*) group by order by count(*) desc limit x 背景 count(*) group by order by count(*) desc limit x 用来统计 topn。
1368 0
|
关系型数据库 PostgreSQL
PostgreSQL sharding : citus 系列6 - count(distinct xx) 加速 (use 估值插件 hll|hyperloglog)
标签 PostgreSQL , hll , hyperloglog , distinct , 加速 , citus.count_distinct_error_rate 背景 在分布式数据库中,计算count(distinct xxx),需要对distinct 的字段, 1、去重, 2、重分布去重后的数据,(这一步,如果distinct值特别多,那么就会比较耗时) 3、然后再去重, 4、最后count (xxx), 5、求所有节点的count SUM。
1783 0
|
弹性计算 关系型数据库 测试技术
PostgreSQL 11 tpcc 测试(103万tpmC on ECS) - use sysbench-tpcc by Percona-Lab
标签 PostgreSQL , tpcc 背景 环境 阿里云虚拟机 [root@pg11-test ~]# lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: ...
4107 0
|
网络协议 关系型数据库 网络安全
PostgreSQL 10.1 手册_部分 III. 服务器管理_第 20 章 客户端认证_20.1. pg_hba.conf文件
20.1. pg_hba.conf文件 客户端认证是由一个配置文件(通常名为pg_hba.conf并被存放在数据库集簇目录中)控制(HBA表示基于主机的认证)。在initdb初始化数据目录时,它会安装一个默认的pg_hba.conf文件。
1561 0