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

本文详细介绍了PostgreSQL中search+bind和simplebind两种认证方式的区别和实现过程,包括交互流程、配置示例及安全建议。
上一篇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",""

[参考]
<think>我们正在处理一个关于PostgreSQLpg_hba.conf文件不存在的问题。根据用户提供的信息,用户尝试使用vi命令编辑文件,但发现vi命令不存在,并且可能文件路径也不正确。现在用户明确询问当pg_hba.conf文件不存在时的解决方法。 根据引用[1]和[2],pg_hba.conf文件通常位于PostgreSQL的数据目录中。默认路径可能是`/var/lib/pgsql/<pg_version>/data`,但具体路径可能因安装方式和版本而异。 我们需要考虑以下情况: 1. 文件确实不存在(可能是新安装或配置错误)。 2. 文件存在但路径不正确(用户可能没有找到正确路径)。 3. 文件被重命名或移动。 解决方案: 步骤1:确认PostgreSQL的数据目录 我们可以通过以下方法找到数据目录: - 查看运行中的PostgreSQL进程的命令行参数(如`ps -ef | grep postgres`),其中`-D`参数指定数据目录。 - 查询PostgreSQL:`SHOW data_directory;`(需要能够连接到数据库) 步骤2:在数据目录中查找pg_hba.conf 如果数据目录存在,进入该目录并查找pg_hba.conf。 步骤3:如果文件不存在,创建它 如果确实没有这个文件,我们可以创建一个默认的pg_hba.conf文件。 步骤4:重新加载配置 具体操作如下: 方法一:通过命令行查找数据目录(在容器内或主机上) 1. 查找postmaster进程的启动参数: ```bash ps -ef | grep postmaster ``` 在输出中,查找`-D`或`--pgdata`参数,后面跟着的就是数据目录。 2. 如果能够连接到数据库,使用SQL命令: ```bash psql -U postgres -c "SHOW data_directory;" ``` 方法二:在可能的数据目录中查找 常见的PostgreSQL数据目录包括: - `/var/lib/postgresql/<version>/data` - `/var/lib/pgsql/<version>/data` - `/usr/local/var/postgres` - `/etc/postgresql/<version>/main`(但通常配置文件在/etc下,而数据目录在/var/lib) 方法三:创建pg_hba.conf文件 如果确定数据目录,但其中没有pg_hba.conf文件,则创建一个。默认内容如下: ``` # TYPE DATABASE USER ADDRESS METHOD local all all trust host all all 127.0.0.1/32 trust host all all ::1/128 trust ``` 注意:默认配置可能不安全,请根据实际需要调整。 方法四:检查PostgreSQL的配置参数 我们可以查看`postgresql.conf`文件中的`hba_file`参数,该参数指定了pg_hba.conf的路径。但要注意,如果postgresql.conf中指定了hba_file,而该文件不存在,那么需要创建它。 步骤:在数据目录中找到postgresql.conf,查看其中是否有`hba_file`设置。 方法五:在容器中,如果文件被误删,可以考虑从镜像中重新复制一个默认文件(但需要谨慎,因为可能覆盖其他配置) 创建文件后,需要重新加载配置: - 进入psql:`psql -U postgres` - 执行:`SELECT pg_reload_conf();` 另外,根据引用[3],PostgreSQL在收到SIGHUP信号时会重新加载配置文件(包括pg_hba.conf)。所以也可以发送信号: ```bash # 查找主进程ID head -1 $PGDATA/postmaster.pid # 然后发送SIGHUP kill -HUP <pid> ``` 针对用户的具体情况(在容器中,且没有vi),我们可以使用cat命令或echo命令来创建或修改文件。 示例操作(在容器内): 1. 进入容器: ```bash kubectl exec -it postgres-0 -n label-studio -- bash ``` 2. 确定数据目录(假设我们通过环境变量$PGDATA知道,或者通过进程查看): ```bash echo $PGDATA # 或者 ps -ef | grep postmaster ``` 假设数据目录为`/var/lib/postgresql/data` 3. 进入数据目录,检查pg_hba.conf是否存在: ```bash cd /var/lib/postgresql/data ls -l pg_hba.conf ``` 4. 如果不存在,创建文件: ```bash cat > pg_hba.conf <<EOF # TYPE DATABASE USER ADDRESS METHOD local all all trust host all all 127.0.0.1/32 trust host all all ::1/128 trust host all all 0.0.0.0/0 md5 EOF ``` 5. 重新加载配置: ```bash psql -U postgres -c "SELECT pg_reload_conf()" ``` 注意:在容器中,如果数据目录是挂载的卷,那么创建文件后,即使容器重启,文件也会存在。 如果用户无法进入容器,也可以使用kubectl命令直接创建文件: ```bash kubectl exec -n label-studio postgres-0 -- bash -c "cat > /var/lib/postgresql/data/pg_hba.conf <<EOF ...(文件内容)... EOF" ``` 然后重新加载配置。 但是,如果整个数据目录都是通过持久化卷挂载的,那么也可以直接在卷中创建文件(需要知道卷在宿主机上的路径)。 最后,需要注意的是,如果PostgreSQL启动时没有找到pg_hba.conf,它可能会使用默认的配置(通常只允许本地连接,且认证方式为trust)。因此,如果文件不存在,PostgreSQL可能不会报错,但会使用默认行为。 所以,如果用户遇到连接问题,检查pg_hba.conf是否存在以及配置是否正确是必要的。 生成相关问题: 1. 如何确定PostgreSQL的数据目录? 2. 如何在不重启PostgreSQL的情况下重新加载配置? 3. PostgreSQL的默认认证方式是什么? 4. 在容器中如何持久化PostgreSQL的配置? 5. pg_hba.conf文件中的METHOD有哪些选项?各有什么含义?</think>### PostgreSQL pg_hba.conf 文件不存在解决方法 #### 问题诊断 当 `pg_hba.conf` 文件不存在时,通常由以下原因导致: 1. **数据目录错误**:PostgreSQL 实际数据目录与预期路径不符[^1] 2. **初始化失败**:`initdb` 初始化过程未完成或失败 3. **权限问题**:用户无权访问数据目录 4. **配置覆盖**:`postgresql.conf` 中的 `hba_file` 参数指定了非常规路径[^2] --- #### 解决方案 ##### 步骤1:确认真实数据目录 ```bash # 查找运行中的PostgreSQL进程 ps -ef | grep postmaster | grep -v grep # 输出示例: # postgres 12345 1 0 10:00 ? 00:00:00 /usr/lib/postgresql/16/bin/postgres -D /opt/postgres/data ``` `-D` 参数后的路径即为真实数据目录(示例中为 `/opt/postgres/data`)[^1] ##### 步骤2:检查非常规路径配置 ```bash # 进入PostgreSQL命令行 psql -U postgres -- 查询配置路径 SHOW hba_file; SHOW config_file; ``` 如果 `hba_file` 显示非常规路径(如 `/etc/postgresql/custom/pg_hba.conf`),需检查该路径[^2] ##### 步骤3:重新初始化数据目录 ```bash # 停止PostgreSQL服务 sudo systemctl stop postgresql # 备份原有数据(谨慎操作!) mv /var/lib/postgresql/data /var/lib/postgresql/data.bak # 重新初始化 sudo -u postgres initdb -D /var/lib/postgresql/data ``` ##### 步骤4:手动创建配置文件 ```bash # 创建默认pg_hba.conf cat << EOF > /var/lib/postgresql/data/pg_hba.conf # TYPE DATABASE USER ADDRESS METHOD local all all trust host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 EOF # 设置正确权限 chown postgres:postgres /var/lib/postgresql/data/pg_hba.conf chmod 0600 /var/lib/postgresql/data/pg_hba.conf ``` ##### 步骤5:重载配置 ```bash # 方法1:发送SIGHUP信号 pg_ctl reload -D /var/lib/postgresql/data # 方法2:SQL命令 psql -U postgres -c "SELECT pg_reload_conf()" ``` PostgreSQL 通过捕获 SIGHUP 信号实现配置重载[^3] --- #### 验证配置 ```bash # 检查文件是否存在 ls -l /var/lib/postgresql/data/pg_hba.conf # 检查加载状态 psql -U postgres -c "SHOW hba_file" ``` --- #### 预防措施 1. **记录初始化路径**: ```bash initdb -D /path/to/data | tee initdb.log ``` 2. **配置版本控制**: ```bash # 将配置文件纳入Git管理 cd /var/lib/postgresql/data git init git add pg_hba.conf postgresql.conf ``` 3. **容器环境最佳实践**: ```dockerfile FROM postgres:16 VOLUME ["/custom-config"] CMD ["postgres", "-c", "hba_file=/custom-config/pg_hba.conf"] ``` --- ### 相关问题 1. 如何验证 PostgreSQL 配置是否已正确加载? 2. PostgreSQL 不同认证方式(trust/md5/scram-sha-256)有何安全差异? 3. 在 Kubernetes 中如何持久化 PostgreSQL 配置? 4. PostgreSQL 启动时报错 "could not open pg_hba.conf" 如何解决? 5. 如何通过 SQL 查询当前生效的 pg_hba 规则? [^1]: PostgreSQL 数据目录结构及默认路径 [^2]: pg_hba.conf 文件位置的自定义配置方法 [^3]: PostgreSQL 信号处理机制与配置重载原理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值