使用pgsql客户端连接postgresql服务器


psql客户端程序可以在命令行中被调用,在调用时可以定义相关参数,参数可以通过命令行指定,也可以使用参数文件来指定。网络的Socket不在此处讲解,本文重点讲解通过本地Socket(Unix域套接字)的相关连接方式方法。
Socket这种连接方式,在PostgreSQL有一种对该连接方式的别称:local(peer)认证方式,即这种认证方式是通过Unix Domain Socket连接方式认证的。
Unix Domain Socket 与 TCP/UDP Socket
看到Socket很多人可能会联想到网络编程常见的TCP/UDP Socket。本质上他们的作用都一样,都是为了网络通信而生。Unix Domain Socket是在此基础之上发展的IPC机制:在本机两个进程之间直接建立通信方式,不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,所以性能上和效率上比TCP/UDP Socket高一些,并且Unix Domain Socket是一种可靠的通信机制,而network socket是不可靠的通信,可能发生丢包、乱序等现象。
Unix Domain Socket的表现形式
是以文件形式存放在本机上,且通常不占用容量。以大多数运维人员非常熟悉的MySQL服务为例,默认配置下MySQL服务运行时会创建一个这样的文件:
# ll /var/lib/mysql/mysql.sock
srwxrwxrwx 1 mysql mysq 12月 28 21:30 /var/lib/mysql/mysql.sock
注意:第一个file类型标记是s,即socket。
# file /var/lib/mysql/mysql.sock
/var/lib/mysql/mysql.sock : socket
不同的设置下这个文件位置或文件名略有不同,具体位置可参考MySQL的配置文件中的socket配置项。
socket类似于命名管道(named pipe),且作用也相近。但是命名管道只能支持字节流,而Unix Domain Socket既能支持字节流,又能支持队列。另外Socket使用系统文件的地址来作为自己的身份,所以可以用于权限认证(PostgreSQL的Peer认证),它可以被系统进程引用。所以可以支持不同的进程同时使用,而命名管道是没有这种功能的。
Unix Domain Socket的使用
很多运行于Linux/Unix上的服务不止可以监听一个TCP/UDP端口,还支持监听一个Unix Domain Socket。如mysql的socket配置,redis的socket配置,nginx的listen配置,postgresql的unix_socket_directories配置等等。只要客户端支持Unix Domain Socket,就可以直接使用这种方式连接。
如MySQL的[client]配置段下面socket配置就直接指向unix domain socket地址,代表默认使用unix domain socket连接。psql默认连接方式也是如此,默认会在/var/run/postgresql/目录下查找.s.PGSQL.5432这个socket,可以通过psql -h path_of_socket_directory -p port连接其它目录下的socket文件,从而连接到非标准的5432端口的服务实例。另外不得不说一下,大多数使用C/C++语言开发的client也都支持Unix Domain Socket。
unix_socket_directories parameter in postgresql.conf (/tmp is still needed not to break psql and other programs):
unix_socket_directories = '/tmp,/var/pgsql'
PostgreSQL Unix domain socket (/tmp/.s.PGSQL.5432).
Configuration:
pg_hba.conf:
# TYPE DATABASE USER ADDRESS METHOD OPTION
local all all peer map=default
pg_ident.conf:
# MAPNAME SYSTEM-USERNAME PG-USERNAME
default postgres postgres
default freeoa project_great
postgresql.conf:
...
port = 5432
unix_socket_directories = '/var/run/postgresql'
...
Here are the permissions in my socket directory:
$ ll /var/run/postgresql/
-rw-r--r-- 1 postgres postgres 5 May 17 00:20 9.3-main.pid
srwxrwxrwx 1 postgres postgres 0 May 17 00:20 .s.PGSQL.5432
-rw------- 1 postgres postgres 70 May 17 00:20 .s.PGSQL.5432.lock
The PostgreSQL user project_great has been granted all privileges on the database project_great and both the user and the database exist.
这里并没有使用用户个人的配置文件:~/.pgpass。
机器上有两个postgres的实例时:
root@freeoa:~# ls -la /tmp/
total 20
...
srwxrwxrwx 1 postgres daemon 0 3月 19 21:43 .s.PGSQL.5432
-rw------- 1 postgres daemon 49 3月 19 21:43 .s.PGSQL.5432.lock
srwxrwxrwx 1 postgres daemon 0 3月 19 22:06 .s.PGSQL.5433
-rw------- 1 postgres daemon 40 3月 19 22:06 .s.PGSQL.5433.lock
Unix Domain Socket的限制
Unix域套接字的性能很高,安全性好,在network socket端口有限的情况下,Unix Domain Socket无需占用有限的TCP/UDP端口。但很明显的可以看到两个限制:
1)、只能本机访问,不能用于远程访问(Docker可以利用挂载的形式实现本机不同容器或容器与宿主机之前的访问,但还是在同一台主机上)
2)、只在POSIX兼容的系统有实现,意味着Windows下没有对应的实现
像Java这种编程语言为了简化跨平台的兼容性问题,底层也不提供Unix Domain Socket的支持。比如JDBC就没有Unix Domain Socket的连接实现,所以jdbc url在连接本机服务的时候,也只能写127.0.0.1,不能写Unix Domain Socket路径。
PostgreSQL的local连接与peer认证
说清楚了Unix Domain Socket之后,PostgreSQL的peer认证(对等认证)就很容易理解了。有关postgresql完整的认证方式,参见官方文档:
http://www.postgres.cn/docs/12/client-authentication.html
https://www.postgresql.org/docs/current/auth-methods.html
我们先看看默认安装下的postgresql的pg_hba.conf文件(已过滤空行和注释行):
# TYPE DATABASE USER ADDRESS METHOD OPTION
local all postgres peer
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
local replication all peer
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5
其中host代表client的访问方式是TCP,而local就代表client的访问方式是Unix Domain Socket。所以可以很明显的看到local行的配置是没有ip配置段的。
那么peer认证方式是怎么一回事呢?之前提到过,Unix Domain Socket是可以取到用户身份信息的,这个在Unix/Linux系统中就是用户账号,而peer则代表着用户执行psql命令以user身份运行,连接到数据库上对应的用户身份就是user这种方式。所以peer认证只支持local连接方式,因此在windows上不起作用。如果以myuser这个账号登录到Linux系统中,运行psql命令,那么连接到数据库上就是myuser这个用户,不需要密码认证。如果postgresql数据库中没有myuser这个用户,就会报错找不到这个用户;如果设定为trust,就会用postgres这个用户来直接登录,这会在本地使用上可能会导致一些不安全因素。
再看看postgres这个用户默认配置下限定local连接方式,认证方式是peer。代表postgres(默认的postgresql的管理员账户)必须以Unix Domain Socket方式连接,并且使用操作系统中的postgres用户身份运行。由于这个账户默认在Linux系统中是不允许直接登录的,所以我们需要su或sudo命令切换用户身份运行:
su - postgres
sudo -u postgres
由于psql默认就是以Unix Domain Socket方式连接(Windows系统则以TCP方式),所以无需指定其他连接参数。再比如在postgresql上创建了一个用户foaprx,但是我们的操作系统中没有foaprx这个账户,那么此时我们可以host或local的方式连接:
$ psql -U foaprx -h 127.0.0.1 -p 5433 freadb
psql (9.6.10, 服务器 9.6.5)
freadb=> \conninfo
以用户 "foaprx" 的身份, 在主机"127.0.0.1", 端口"5433"连接到数据库 "freadb
$ psql -U foaprw pdb
psql (9.6.10)
pdb=# \conninfo
以用户 "foaprw" 的身份,通过套接字"/tmp"在端口"5432"连接到数据库 "pdb"
psql -h /tmp/ -p 5433 -U foaprx freadb
freadb=> \conninfo
以用户 "foaprx" 的身份,通过套接字"/tmp/"在端口"5433"连接到数据库 "freadb"
直接指定-h参数为127.0.0.1或localhost,限定psql使用TCP方式连接postgresql,则可以命中配置文件中的'host all all 127.0.0.1/32 trust'这个配置,于是连接到数据库中。在对本地的连接默认是非常信任的,直接连接即可。
$ psql -h /tmp/ -p 5433 -U foaprx freadb
psql: 致命错误: 没有用于主机 "[local]", 用户 "foaprx", 数据库 "freadb", SSL 关闭 的 pg_hba.conf 记录
这是指定local的方法为peer的情况下所报出的错误,而设定为trust的连接结果正常的情况在上面有示例。
psql使用unix domain socket连接本机其他postgresql实例的方案:
psql -h path_of_socket_dir -p other_port
$ psql
psql (9.6.10)
postgres@[local]@postgres# \conninfo
以用户 "postgres" 的身份,通过套接字"/tmp"在端口"5432"连接到数据库 "postgres"
$ psql -h /tmp/ -p 5433
psql (9.6.10, 服务器 9.6.5)
postgres@[local:/tmp/]@postgres# \conninfo
以用户 "postgres" 的身份,通过套接字"/tmp/"在端口"5433"连接到数据库 "postgres"
那如果操作系统与数据库系统在用户名没有能对等使用呢?这里就可以使用pg_ident来开启的用户映射,并在对等认证上来验证一下。
注意:这可能需要在postgresql.conf的配置文件打开ident相关选项。
pg_ident.conf:
# MAPNAME SYSTEM-USERNAME PG-USERNAME
pgmapx freeoa foapro
pg_ident.conf:
local all all peer map=pgmapx
添加加完成后,保存并重启pg服务器,在Linux中进行测试:
freeoa@wklin:~$ psql -h /tmp/ -p 5433 freadb
psql:致命错误:对用户"postgres"的对等认证失败
freeoa@wklin:~$ psql -h /tmp/ -p 5433 -U foaprw freadb
psql:致命错误:对用户"foaprw"的对等认证失败
freeoa@wklin:~$ psql -h /tmp/ -p 5433 -U foapro freadb
psql (9.6.10, 服务器 9.6.5)
freadb=> \conninfo
以用户 "foapro" 的身份,通过套接字"/tmp/"在端口"5433"连接到数据库 "freadb"
相关的日志记录如下:
日志: 对于以"freeoa"身份认证为的用户"foaprx",在用户映射"pgmapx"中没有匹配
致命错误:对用户"foaprx"的对等认证失败
详细信息:与Connection相匹配的文件行位于 pg_hba.conf 85: "local all all peer map=pgmapx"
日志: 所提供的用户名(postgres)和被认证的用户名(freeoa)不匹配
修改数据库的用户密码
首先要知道对于大多数Unix发行版,默认Postgres用户既不需要也不使用密码进行身份验证;根据PostgreSQL最初的安装方式和使用的版本,默认的身份验证方法将是ident或peer(pg_hba.conf)。
ident身份验证使用在TCP端口113上运行的操作系统的标识服务器来验证用户的凭据。另一方面,对等身份验证用于本地连接,并验证操作系统的登录用户名是否与Postgres数据库的用户名匹配。
对于大多数系统,默认的PostgreSQL用户是postgres,身份验证不需要密码。因此要添加密码就必须首先以postgres用户身份登录和连接。如果成功连接并正在查看psql提示,如果收到一个错误,说明数据库postgres不存在,请尝试连接到template1数据库,如果成功,继续更改密码。
pg_hba.conf文件是身份验证规则的列表,大致内容有如下:
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all postgres peer
# IPv4 local connections:
host all all 127.0.0.1/32 trust
host all all 10.206.1.0/24 password
这个身份验证规则只是告诉Postgres,对于为用户postgres建立的到所有数据库的本地连接,使用对等协议进行身份验证。
注意:一些旧版本的Postgres更喜欢默认的身份验证方法ident,但是大多数现代安装将使用上面指定的peer。如果结果不同则可能需要测试两者。
现在更新配置文件后,重复登录并以默认用户身份连接部分中的步骤,尝试以默认postgres用户身份连接到,成功后来更改密码。
postgres=# ALTER USER postgres PASSWORD 'myPassword';
# ALTER USER 'username' WITH PASSWORD 'newPassword';
# ALTER USER username WITH ENCRYPTED PASSWORD 'password';
ALTER USER is an alias for ALTER ROLE
当然最方便最安全的方式在是终端交互界面下输入
\password
\password username
sudo -u postgres psql -c "\password"
要输入两次,完成后用\q退出后验证是否修改成功。
解决本地用户登录的安全问题
安装完成后Pg服务器后,默认任何用户默认都可以调用psql指令时以postgres的身份登录数据库服务器(不考虑上面的对等认证):
freeoa@wklin:~$ psql
postgres=#
[hto@wklin:~]$ psql
postgres@[local]@postgres# \conninfo
以用户 "postgres" 的身份,通过套接字"/tmp"在端口"5432"连接到数据库 "postgres"
为postgres用户设置密码后,退出后重新登录时依然不会有提示密码输入。是因为没有修改pg_hba.conf中的访问来源设定,如下的地方都要被注释或设定密码为非'trust':
# "local" is for Unix domain socket connections only
#local all all trust
# IPv4 local connections:
#host all all 127.0.0.1/32 trust
注释后的普通用户访问时报:
[hto@wklin:~]$ psql
psql: 致命错误: 没有用于主机 "[local]", 用户 "postgres", 数据库 "postgres", SSL 关闭 的 pg_hba.conf 记录
上面对local这行的注释基本上就禁止了通过本地socket连接服务器的可能。是否有一种只允许postgres通过Unix domain socket无密码登录服务器?
有,可以通过设定其socket的权限来实现,默认情况的socket在/tmp目录下,带有隐藏属性:
srwxrwxrwx 1 postgres daemon 0 5月 18 18:28 .s.PGSQL.5432
在postgresql.conf中,修改此行(假设用户组没有争议)
#unix_socket_permissions = 0740
同时开启(pg_hba.conf)
# "local" is for Unix domain socket connections only
local all all trust
重启测试如下:
[hto@wklin:~]$ psql -h /tmp -p 5432
psql: 无法联接到服务器: Permission denied
服务器是否在本地运行并且在 Unix 域套接字
"/tmp/.s.PGSQL.5432"上准备接受联接?
而postgres用户却能正常登录,没有报拒绝连接的错误。如果还不放心本地的连接,可将pg_hba.conf中的local行的用户列指定修改为postgres。
通过IP地址登录的情况:
[hto@wklin:~]$ psql -h172.18.0.8
口令:
postgres@172.18.0.8@postgres# \conninfo
以用户 "postgres" 的身份, 在主机"172.18.0.8", 端口"5432"连接到数据库 "postgres"
用户要知道postgres的密码才能连接,安全性高了许多。
[hto@wklin:~]$ psql -h127.0.0.1
口令:
postgres@127.0.0.1@postgres# \conninfo
以用户 "postgres" 的身份, 在主机"127.0.0.1", 端口"5432"连接到数据库 "postgres"
小结
默认情况下几乎所有的本地用户都可以以postgres的用户身份连接到postgres库,且为最高权限。这个虽然没有对网络开启,但也存存相当的未授权访问问题,在一些安全检测的情况下是不可能通过的,因此对其的安全加固是不可少的。
Socket这种连接方式,在PostgreSQL有一种对该连接方式的别称:local(peer)认证方式,即这种认证方式是通过Unix Domain Socket连接方式认证的。
Unix Domain Socket 与 TCP/UDP Socket
看到Socket很多人可能会联想到网络编程常见的TCP/UDP Socket。本质上他们的作用都一样,都是为了网络通信而生。Unix Domain Socket是在此基础之上发展的IPC机制:在本机两个进程之间直接建立通信方式,不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,所以性能上和效率上比TCP/UDP Socket高一些,并且Unix Domain Socket是一种可靠的通信机制,而network socket是不可靠的通信,可能发生丢包、乱序等现象。
Unix Domain Socket的表现形式
是以文件形式存放在本机上,且通常不占用容量。以大多数运维人员非常熟悉的MySQL服务为例,默认配置下MySQL服务运行时会创建一个这样的文件:
# ll /var/lib/mysql/mysql.sock
srwxrwxrwx 1 mysql mysq 12月 28 21:30 /var/lib/mysql/mysql.sock
注意:第一个file类型标记是s,即socket。
# file /var/lib/mysql/mysql.sock
/var/lib/mysql/mysql.sock : socket
不同的设置下这个文件位置或文件名略有不同,具体位置可参考MySQL的配置文件中的socket配置项。
socket类似于命名管道(named pipe),且作用也相近。但是命名管道只能支持字节流,而Unix Domain Socket既能支持字节流,又能支持队列。另外Socket使用系统文件的地址来作为自己的身份,所以可以用于权限认证(PostgreSQL的Peer认证),它可以被系统进程引用。所以可以支持不同的进程同时使用,而命名管道是没有这种功能的。
Unix Domain Socket的使用
很多运行于Linux/Unix上的服务不止可以监听一个TCP/UDP端口,还支持监听一个Unix Domain Socket。如mysql的socket配置,redis的socket配置,nginx的listen配置,postgresql的unix_socket_directories配置等等。只要客户端支持Unix Domain Socket,就可以直接使用这种方式连接。
如MySQL的[client]配置段下面socket配置就直接指向unix domain socket地址,代表默认使用unix domain socket连接。psql默认连接方式也是如此,默认会在/var/run/postgresql/目录下查找.s.PGSQL.5432这个socket,可以通过psql -h path_of_socket_directory -p port连接其它目录下的socket文件,从而连接到非标准的5432端口的服务实例。另外不得不说一下,大多数使用C/C++语言开发的client也都支持Unix Domain Socket。
unix_socket_directories parameter in postgresql.conf (/tmp is still needed not to break psql and other programs):
unix_socket_directories = '/tmp,/var/pgsql'
PostgreSQL Unix domain socket (/tmp/.s.PGSQL.5432).
Configuration:
pg_hba.conf:
# TYPE DATABASE USER ADDRESS METHOD OPTION
local all all peer map=default
pg_ident.conf:
# MAPNAME SYSTEM-USERNAME PG-USERNAME
default postgres postgres
default freeoa project_great
postgresql.conf:
...
port = 5432
unix_socket_directories = '/var/run/postgresql'
...
Here are the permissions in my socket directory:
$ ll /var/run/postgresql/
-rw-r--r-- 1 postgres postgres 5 May 17 00:20 9.3-main.pid
srwxrwxrwx 1 postgres postgres 0 May 17 00:20 .s.PGSQL.5432
-rw------- 1 postgres postgres 70 May 17 00:20 .s.PGSQL.5432.lock
The PostgreSQL user project_great has been granted all privileges on the database project_great and both the user and the database exist.
这里并没有使用用户个人的配置文件:~/.pgpass。
机器上有两个postgres的实例时:
root@freeoa:~# ls -la /tmp/
total 20
...
srwxrwxrwx 1 postgres daemon 0 3月 19 21:43 .s.PGSQL.5432
-rw------- 1 postgres daemon 49 3月 19 21:43 .s.PGSQL.5432.lock
srwxrwxrwx 1 postgres daemon 0 3月 19 22:06 .s.PGSQL.5433
-rw------- 1 postgres daemon 40 3月 19 22:06 .s.PGSQL.5433.lock
Unix Domain Socket的限制
Unix域套接字的性能很高,安全性好,在network socket端口有限的情况下,Unix Domain Socket无需占用有限的TCP/UDP端口。但很明显的可以看到两个限制:
1)、只能本机访问,不能用于远程访问(Docker可以利用挂载的形式实现本机不同容器或容器与宿主机之前的访问,但还是在同一台主机上)
2)、只在POSIX兼容的系统有实现,意味着Windows下没有对应的实现
像Java这种编程语言为了简化跨平台的兼容性问题,底层也不提供Unix Domain Socket的支持。比如JDBC就没有Unix Domain Socket的连接实现,所以jdbc url在连接本机服务的时候,也只能写127.0.0.1,不能写Unix Domain Socket路径。
PostgreSQL的local连接与peer认证
说清楚了Unix Domain Socket之后,PostgreSQL的peer认证(对等认证)就很容易理解了。有关postgresql完整的认证方式,参见官方文档:
http://www.postgres.cn/docs/12/client-authentication.html
https://www.postgresql.org/docs/current/auth-methods.html
我们先看看默认安装下的postgresql的pg_hba.conf文件(已过滤空行和注释行):
# TYPE DATABASE USER ADDRESS METHOD OPTION
local all postgres peer
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
local replication all peer
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5
其中host代表client的访问方式是TCP,而local就代表client的访问方式是Unix Domain Socket。所以可以很明显的看到local行的配置是没有ip配置段的。
那么peer认证方式是怎么一回事呢?之前提到过,Unix Domain Socket是可以取到用户身份信息的,这个在Unix/Linux系统中就是用户账号,而peer则代表着用户执行psql命令以user身份运行,连接到数据库上对应的用户身份就是user这种方式。所以peer认证只支持local连接方式,因此在windows上不起作用。如果以myuser这个账号登录到Linux系统中,运行psql命令,那么连接到数据库上就是myuser这个用户,不需要密码认证。如果postgresql数据库中没有myuser这个用户,就会报错找不到这个用户;如果设定为trust,就会用postgres这个用户来直接登录,这会在本地使用上可能会导致一些不安全因素。
再看看postgres这个用户默认配置下限定local连接方式,认证方式是peer。代表postgres(默认的postgresql的管理员账户)必须以Unix Domain Socket方式连接,并且使用操作系统中的postgres用户身份运行。由于这个账户默认在Linux系统中是不允许直接登录的,所以我们需要su或sudo命令切换用户身份运行:
su - postgres
sudo -u postgres
由于psql默认就是以Unix Domain Socket方式连接(Windows系统则以TCP方式),所以无需指定其他连接参数。再比如在postgresql上创建了一个用户foaprx,但是我们的操作系统中没有foaprx这个账户,那么此时我们可以host或local的方式连接:
$ psql -U foaprx -h 127.0.0.1 -p 5433 freadb
psql (9.6.10, 服务器 9.6.5)
freadb=> \conninfo
以用户 "foaprx" 的身份, 在主机"127.0.0.1", 端口"5433"连接到数据库 "freadb
$ psql -U foaprw pdb
psql (9.6.10)
pdb=# \conninfo
以用户 "foaprw" 的身份,通过套接字"/tmp"在端口"5432"连接到数据库 "pdb"
psql -h /tmp/ -p 5433 -U foaprx freadb
freadb=> \conninfo
以用户 "foaprx" 的身份,通过套接字"/tmp/"在端口"5433"连接到数据库 "freadb"
直接指定-h参数为127.0.0.1或localhost,限定psql使用TCP方式连接postgresql,则可以命中配置文件中的'host all all 127.0.0.1/32 trust'这个配置,于是连接到数据库中。在对本地的连接默认是非常信任的,直接连接即可。
$ psql -h /tmp/ -p 5433 -U foaprx freadb
psql: 致命错误: 没有用于主机 "[local]", 用户 "foaprx", 数据库 "freadb", SSL 关闭 的 pg_hba.conf 记录
这是指定local的方法为peer的情况下所报出的错误,而设定为trust的连接结果正常的情况在上面有示例。
psql使用unix domain socket连接本机其他postgresql实例的方案:
psql -h path_of_socket_dir -p other_port
$ psql
psql (9.6.10)
postgres@[local]@postgres# \conninfo
以用户 "postgres" 的身份,通过套接字"/tmp"在端口"5432"连接到数据库 "postgres"
$ psql -h /tmp/ -p 5433
psql (9.6.10, 服务器 9.6.5)
postgres@[local:/tmp/]@postgres# \conninfo
以用户 "postgres" 的身份,通过套接字"/tmp/"在端口"5433"连接到数据库 "postgres"
那如果操作系统与数据库系统在用户名没有能对等使用呢?这里就可以使用pg_ident来开启的用户映射,并在对等认证上来验证一下。
注意:这可能需要在postgresql.conf的配置文件打开ident相关选项。
pg_ident.conf:
# MAPNAME SYSTEM-USERNAME PG-USERNAME
pgmapx freeoa foapro
pg_ident.conf:
local all all peer map=pgmapx
添加加完成后,保存并重启pg服务器,在Linux中进行测试:
freeoa@wklin:~$ psql -h /tmp/ -p 5433 freadb
psql:致命错误:对用户"postgres"的对等认证失败
freeoa@wklin:~$ psql -h /tmp/ -p 5433 -U foaprw freadb
psql:致命错误:对用户"foaprw"的对等认证失败
freeoa@wklin:~$ psql -h /tmp/ -p 5433 -U foapro freadb
psql (9.6.10, 服务器 9.6.5)
freadb=> \conninfo
以用户 "foapro" 的身份,通过套接字"/tmp/"在端口"5433"连接到数据库 "freadb"
相关的日志记录如下:
日志: 对于以"freeoa"身份认证为的用户"foaprx",在用户映射"pgmapx"中没有匹配
致命错误:对用户"foaprx"的对等认证失败
详细信息:与Connection相匹配的文件行位于 pg_hba.conf 85: "local all all peer map=pgmapx"
日志: 所提供的用户名(postgres)和被认证的用户名(freeoa)不匹配
修改数据库的用户密码
首先要知道对于大多数Unix发行版,默认Postgres用户既不需要也不使用密码进行身份验证;根据PostgreSQL最初的安装方式和使用的版本,默认的身份验证方法将是ident或peer(pg_hba.conf)。
ident身份验证使用在TCP端口113上运行的操作系统的标识服务器来验证用户的凭据。另一方面,对等身份验证用于本地连接,并验证操作系统的登录用户名是否与Postgres数据库的用户名匹配。
对于大多数系统,默认的PostgreSQL用户是postgres,身份验证不需要密码。因此要添加密码就必须首先以postgres用户身份登录和连接。如果成功连接并正在查看psql提示,如果收到一个错误,说明数据库postgres不存在,请尝试连接到template1数据库,如果成功,继续更改密码。
pg_hba.conf文件是身份验证规则的列表,大致内容有如下:
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all postgres peer
# IPv4 local connections:
host all all 127.0.0.1/32 trust
host all all 10.206.1.0/24 password
这个身份验证规则只是告诉Postgres,对于为用户postgres建立的到所有数据库的本地连接,使用对等协议进行身份验证。
注意:一些旧版本的Postgres更喜欢默认的身份验证方法ident,但是大多数现代安装将使用上面指定的peer。如果结果不同则可能需要测试两者。
现在更新配置文件后,重复登录并以默认用户身份连接部分中的步骤,尝试以默认postgres用户身份连接到,成功后来更改密码。
postgres=# ALTER USER postgres PASSWORD 'myPassword';
# ALTER USER 'username' WITH PASSWORD 'newPassword';
# ALTER USER username WITH ENCRYPTED PASSWORD 'password';
ALTER USER is an alias for ALTER ROLE
当然最方便最安全的方式在是终端交互界面下输入
\password
\password username
sudo -u postgres psql -c "\password"
要输入两次,完成后用\q退出后验证是否修改成功。
解决本地用户登录的安全问题
安装完成后Pg服务器后,默认任何用户默认都可以调用psql指令时以postgres的身份登录数据库服务器(不考虑上面的对等认证):
freeoa@wklin:~$ psql
postgres=#
[hto@wklin:~]$ psql
postgres@[local]@postgres# \conninfo
以用户 "postgres" 的身份,通过套接字"/tmp"在端口"5432"连接到数据库 "postgres"
为postgres用户设置密码后,退出后重新登录时依然不会有提示密码输入。是因为没有修改pg_hba.conf中的访问来源设定,如下的地方都要被注释或设定密码为非'trust':
# "local" is for Unix domain socket connections only
#local all all trust
# IPv4 local connections:
#host all all 127.0.0.1/32 trust
注释后的普通用户访问时报:
[hto@wklin:~]$ psql
psql: 致命错误: 没有用于主机 "[local]", 用户 "postgres", 数据库 "postgres", SSL 关闭 的 pg_hba.conf 记录
上面对local这行的注释基本上就禁止了通过本地socket连接服务器的可能。是否有一种只允许postgres通过Unix domain socket无密码登录服务器?
有,可以通过设定其socket的权限来实现,默认情况的socket在/tmp目录下,带有隐藏属性:
srwxrwxrwx 1 postgres daemon 0 5月 18 18:28 .s.PGSQL.5432
在postgresql.conf中,修改此行(假设用户组没有争议)
#unix_socket_permissions = 0740
同时开启(pg_hba.conf)
# "local" is for Unix domain socket connections only
local all all trust
重启测试如下:
[hto@wklin:~]$ psql -h /tmp -p 5432
psql: 无法联接到服务器: Permission denied
服务器是否在本地运行并且在 Unix 域套接字
"/tmp/.s.PGSQL.5432"上准备接受联接?
而postgres用户却能正常登录,没有报拒绝连接的错误。如果还不放心本地的连接,可将pg_hba.conf中的local行的用户列指定修改为postgres。
通过IP地址登录的情况:
[hto@wklin:~]$ psql -h172.18.0.8
口令:
postgres@172.18.0.8@postgres# \conninfo
以用户 "postgres" 的身份, 在主机"172.18.0.8", 端口"5432"连接到数据库 "postgres"
用户要知道postgres的密码才能连接,安全性高了许多。
[hto@wklin:~]$ psql -h127.0.0.1
口令:
postgres@127.0.0.1@postgres# \conninfo
以用户 "postgres" 的身份, 在主机"127.0.0.1", 端口"5432"连接到数据库 "postgres"
小结
默认情况下几乎所有的本地用户都可以以postgres的用户身份连接到postgres库,且为最高权限。这个虽然没有对网络开启,但也存存相当的未授权访问问题,在一些安全检测的情况下是不可能通过的,因此对其的安全加固是不可少的。