
熊二最近对 Ident以及Peer认证方式有点困惑,于是在熊大的要求下,做了一些验证。最后基本上搞明白了二者的关系。
身份验证方法的工作原理是从身份(ident)服务器获取客户机的操作系统用户名,并将其用作允许的数据库用户名(带有可选的用户名映射)。这只支持TCP/IP连接。在pg_hba.conf中需要通过map配置项来支持Ident认证。
1. 客户机sean-rh2上,root用户
yum install oidentd
2. 启动它
systemctl start oidentd
服务器端sean-rh1, 用户:postgres
-- 加入一个map配置 至 pg_hba.conf
-- host mydb mydb samenet ident map=myident
cat >> pg_hba.conf <<EOF
local all all trust
host mydb mydb samenet ident map=myident
host all all 0.0.0.0/0 scram-sha-256
local replication all trust
host replication all 0.0.0.0/0 scram-sha-256
EOF
-- 添加具体的记录项至pg_ident.conf
-- 具体情况是将操作系统用户sean映射到数据库用户sean
cat > pg_ident.conf <<EOF
# MAPNAME SYSTEM-USERNAME PG-USERNAME
myident sean mydb
EOF
1. 服务器相关数据库及用户准备:
postgres=# create user mydb with password 'test123';
CREATE ROLE
postgres=# create database mydb owner mydb;
CREATE DATABASE
ostgres=# create user demo with password 'test123';
CREATE ROLE
postgres=# create database demo owner demo;
CREATE DATABAS
[23:53:00-postgres@sean-rh1:/var/lib/pgsql/14/data]$ psql -h 127.0.0.1 -U demo
Password for user demo:
psql (14.8)
Type "help" for help.
demo=>
[23:46:29-postgres@sean-rh1:/var/lib/pgsql/14/data]$ psql -h 127.0.0.1 -U mydb
psql: error: connection to server at "127.0.0.1", port 5555 failed: FATAL: Ident authentication failed for user "mydb"
[23:46:41-postgres@sean-rh1:/var/lib/pgsql/14/data]$ psql -U mydb
psql (14.8)
Type "help" for help.
mydb=> \q
熊二问:为何127.0.0.1以及数据库用户:mydb,也连不上。
熊大答:因为127.0.0.1也走到了samenet那个filter。而当前用户是Postgres. 所以通不过。
熊二又问:为何使用-h 127.0.0.1 -U demo, 就提示输入密码,然后又能过呢?
熊大答:因为使用的是用户demo, 它会走到规则:host all all 0.0.0.0/0 scram-sha-256, 自然就按正常流程要求输入密码。只要密码正确,就可以通过验证。
2. 在客户机:sean-rh2上尝试连接:
-- 提示:客户机上已经启动了identd服务。
-- 并且已经提前建好了用户:sean, 与PG相关的环境变量也都配置准备完毕。
-- 用户sean登录:
-- 使用db用户: mydb,直接连接,无需密码
[sean@sean-rh2 ~]$ psql -U mydb -h sean-rh1 mydb -c "select version()"
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 14.8 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
(1 row)
-- 如果使用的是别的用户,如demo, 则需要输入密码
[sean@sean-rh2 ~]$ psql -U demo -h sean-rh1 demo -c "select version()"
Password for user demo: *******
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 14.8 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
(1 row)
熊二:如此看来,Ident认证主要是针对网络环境下,客户端的用户不是真正的数据库用户,同时又不想输入密码的一种“替代”方案?
熊大:差不多这意思。有时候,尤其是在同一个域下的不同操作系统用户下边,为了方便,同时又不想透露密码信息,对某些特殊的用户给定这些特权,提供了便利。
熊二:老大,我看了官方文档,好像那个Peer认证与这个Ident认证差不太多啊。它俩有什么区别?
熊大:有区别的。Peer主要用于本机的Unix Socket,并且也不需要oidentd服务来获取当前操作系统用户名与DB服务器进行交互。因为当前主机是知道系统用户名的。这样好理解吗?我们看看下边的示例:
服务器端sean-rh1, 用户:postgres
-- 加入一个map配置 至 pg_hba.conf
-- local all all ident map=myident
-- 在local本机下,使用ident就相当于用的是peer认证
cat > pg_hba.conf <<EOF
local all all ident map=myident
host mydb mydb samenet ident map=myident
host all all 0.0.0.0/0 scram-sha-256
local replication all trust
host replication all 0.0.0.0/0 scram-sha-256
EOF
-- 添加具体的记录项至pg_ident.conf
-- 具体情况是将操作系统用户sean映射到数据库用户sean
cat > pg_ident.conf <<EOF
# MAPNAME SYSTEM-USERNAME PG-USERNAME
myident sean mydb
EOF
-- 使用root用户创建普通用户sean
useradd sean -m -d /home/sean
-- 用户sean登录:
-- 设置好相应的PostgreSQL环境变量,使其能访问psql
-- 用户sean环境下
[00:24:49-sean@sean-rh1:/home/sean]$ psql -U mydb -c "select 1 as eval"
eval
------
1
(1 row)
[00:23:09-sean@sean-rh1:/home/sean]$ psql -U mydb -h /tmp -c "select 1 as eval"
eval
------
1
(1 row)
[00:26:36-sean@sean-rh1:/home/sean]$ psql -U demo demo -c "seelct 1 as eval"
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5555" failed: FATAL: Peer authentication failed for user "demo"
[00:23:16-sean@sean-rh1:/home/sean]$ psql -U mydb -h localhost -c "select 1 as eval"
psql: error: connection to server at "localhost" (::1), port 5555 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
connection to server at "localhost" (127.0.0.1), port 5555 failed: FATAL: Ident authentication failed for user "mydb"
熊二:老大,你来看,上边/tmp用的是unix socket, 不带-h, 用的也是unix socket, 结果就是走的Peer. 为何 -h localhost,却让我们走Ident?上边使用demo用户连接,报:Peer认证不通过,是因为找不到对应的mapping。
熊大:嗯,是有点微妙,localhost与127.0.0.1是同一个意思,它不走unix socket ,走的是samenet。于是你看到了Ident验证路径了。你不信,你启动一下本机的oidentd服务,最终一定会通过。而demo用户认证不通过,因为它走的就是Peer那个路径。但是mapping里头(pg_ident文件)找不到对应项。
于是熊二做了一个补充验证:
-- 在同一主机服务器上:sean-rh1, 启动oidentd服务。
[00:26:59-sean@sean-rh1:/home/sean]$ sudo -s
[00:31:06-root@sean-rh1:/home/sean]$ systemctl start oidentd
[00:31:16-root@sean-rh1:/home/sean]$ su - sean
-- 再次连接mydb , 以-h localhost方式:
[00:31:23-sean@sean-rh1:/home/sean]$ psql -U mydb -h localhost -c "select 1 as eval"
eval
------
1
(1 row)
结果验证证明熊大的结论是正确的。
熊大:不过呢,关于Ident认证,也有一些限制。
熊二:什么限制?
熊大:限制如下:
“Ident认证协议”在RFC 1413中有描述。实际上,每个类unix操作系统都附带一个默认监听TCP端口113的标识服务器。身份服务器的基本功能是回答诸如“哪个用户发起了从您的端口X发出并连接到我的端口Y的连接?”之类的问题。由于PostgreSQL在建立物理连接时知道X和Y,因此它可以询问连接客户端的主机上的身份服务器,并且理论上可以确定任何给定连接的操作系统用户。
此过程的缺点是它依赖于客户机的完整性:如果客户机不受信任或受到威胁,攻击者可以在端口113上运行几乎任何程序,并返回他们选择的任何用户名。因此,这种身份验证方法只适用于封闭的网络,在这种网络中,每台客户机都受到严格控制,数据库和系统管理员的操作密切相关。换句话说,您必须信任运行身份服务器的机器。注意这个警告:
标识协议不打算用作授权或访问控制协议。
一些标识服务器有一个非标准选项,使用只有原始计算机的管理员知道的密钥对返回的用户名进行加密。这个选项不能在与PostgreSQL一起使用标识服务器时使用,因为PostgreSQL没有任何方法来解密返回的字符串来确定实际的用户名。
简言之,使用了非标准选项的Ident服务器,PostgreSQL将不能与其一块儿工作。
熊二:嗯,学到了。这下,彻底搞清楚了Ident和Peer两个认证方式。虽然不常用,但是很管用。
1.https://www.postgresql.org/docs/14/auth-ident.html:https://www.postgresql.org/docs/14/auth-ident.html
2.https://www.postgresql.org/docs/14/auth-username-maps.html: https://www.postgresql.org/docs/14/auth-username-maps.html
我是【Sean】, 欢迎大家长按关注并加星公众号:数据库杂记。为你提供及时更新。

原文作者:数据库杂记;如有侵权,请联系管理员删除。