通过 VPN 访问 PostgreSQL:pg_hba 会看到哪个源地址
监听器、防火墙和第一条匹配的 HBA 规则是三个决定。选择前缀之前,先确认 PostgreSQL 真正收到的源地址。
PostgreSQL 从不知道客户端在 VPN 上。它收到来自某个地址的 TCP 连接和一组凭据,然后决定如何处理。因此,让访问依赖隧道意味着把三个独立的决定安排一致,然后检查服务器实际看到的那一个地址,而不是你在图上画的地址。
三个不应合并的决定
服务器在哪里监听是一个决定。哪些流量能到达该地址是第二个,由主机防火墙及其前面的任何网络边界决定。哪个数据库身份可以从哪个源认证是第三个,在 pg_hba.conf 中决定。
每一个由不同组件执行,每一个以不同消息失败。在讨论中把它们合并,正是人们最终去编辑 HBA 文件来修防火墙问题的原因。请保持顺序:没有绑定的监听器无法到达,被过滤的端口无法连接,而 HBA 规则只决定连接建立之后发生什么。当改动没有效果时,先弄清你实际改的是三层中的哪一层。
服务器在哪里监听
绑定到实际分配给机器的地址,而不是接口名:
listen_addresses = '10.20.0.30'数据库可能位于 VPN 网关之后,自身没有隧道接口,这正是应该写地址而不是接口名的原因。修改该设置需要完全重启;重新加载不够。
然后在主机及其前面每个边界上过滤端口,通常是 5432。绑定到私有地址并不等于对外拒绝,因为端口转发或云地址映射仍可能把数据包送到那个私有监听器。
HBA 实际看到的地址
在路由接入下,服务器看到每个客户端的内部隧道地址。在源地址转换下,它看到的是网关转换后的地址,所有客户端都塌缩成那一个值。在选择要允许的前缀之前,先通过服务器自己的连接证据检查源地址。
对于已经使用 TLS 和 SCRAM 的部署,一个刻意收窄的远程访问示例如下:
hostssl appdb app_login 10.8.0.0/24 scram-sha-256
host all all 0.0.0.0/0 reject
host all all ::/0 reject这允许来自指定地址池的一个角色和一个数据库通过 TLS 连接,然后拒绝其他远程 TCP 访问。它不是完整 HBA 文件的替代品:保留本地管理、复制以及任何其他获准的服务,并把窄规则放在更宽的允许之前。
发生地址转换时,HBA 无法凭原始地址区分客户端。请保持网络准入严格,要求真实的数据库凭据,绝不要用 trust 认证代替真实账户。
第一条匹配获胜,没有回退
PostgreSQL 从上到下读取文件,并使用第一条匹配连接的记录。如果该记录的认证失败,不会有第二次尝试,因此前面的一条宽泛允许会悄悄压过后面的一条拒绝。
这条顺序规则就是精心写下的拒绝从不生效的最常见原因。把具体规则放在前面、宽泛规则放在最后,然后把文件当作序列而不是集合来读。你加在末尾的规则不是策略,而是一条注释。把它移到前面并重新加载,再下结论说文件被忽略。
HBA 参考定义了顺序以及 host 与 hostssl 记录的区别,当规则的重点是连接必须加密时,这一点很重要。
重新加载、重启与被拒绝的情况
HBA 改动通过重新加载生效,pg_hba_file_rules 视图可帮助你发现解析错误。该视图描述文件当前的内容,而不是运行中的服务器是否成功加载了它们,所以列表干净并不能证明新规则已经生效。
监听器改动需要单独重启,当改动看起来没有效果时,这两种操作很容易混淆。
用全新会话测试:使用预期账户的已批准客户端能连接,同一账户从未获批准的路径不能连接,未获授权的数据库身份从 VPN 内部仍然失败。这三个结果把网络边界与数据库授权分开,而这正是把决定分开的意义。