无法连接到 PostgreSQL unix 域套接字

Ser*_*lov 6 postgresql nginx centos php-fpm

我正在尝试从 PHP Web 应用程序连接到 PostgreSQL Unix 域套接字。相关系统组件:

  • CentOS 7 x64(强制执行 SELinux)
  • postgresql93 9.3.5-2PGDG.rhel7
  • nginx 1.6.2-1.el7.ngx
  • php-common 5.4.16-23.el7_0.3
  • php-fpm 5.4.16-23.el7_0.3
  • php-pdo 5.4.16-23.el7_0.3
  • php-pgsql 5.4.16-23.el7_0.3

PostgreSQL 正在侦听标准端口 5432,我在 127.0.0.1:5432 通过 TCP/IP 使用它没有问题,但是当我尝试连接到它的 Unix 域套接字时,出现以下错误:

Cannot connect to database: SQLSTATE[08006] [7] could not connect to server:
No such file or directory
    Is the server running locally and accepting
    connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
Run Code Online (Sandbox Code Playgroud)

文件/tmp/.s.PGSQL.5432存在,我可以使用psql连接:

$ psql -Uusername db_name
psql (9.3.5)
Type "help" for help.

db_name=>
Run Code Online (Sandbox Code Playgroud)

所以从 PostgreSQL 方面应该没有问题。或者有吗?

来自/var/lib/pgsql/9.3/data/pg_hba.conf 的相关行:

local    all    username        trust
Run Code Online (Sandbox Code Playgroud)

/var/lib/pgsql/9.3/data/postgresql.conf 中更改 Unix 域套接字文件的位置没有帮助:

unix_socket_directories = '/var/run/pgsql'
Run Code Online (Sandbox Code Playgroud)

/var/log/audit/audit.log中没有任何内容,但我试图禁用 SELinux,只是为了确定:

# setenforce 0
Run Code Online (Sandbox Code Playgroud)

这没有帮助,所以它不是 SELinux。

来自php-fpm 的strace的相关行:

[pid   882] socket(PF_LOCAL, SOCK_STREAM, 0) = 5
[pid   882] fcntl(5, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
[pid   882] fcntl(5, F_SETFD, FD_CLOEXEC) = 0
[pid   882] connect(5, {sa_family=AF_LOCAL, sun_path="/tmp/.s.PGSQL.5432"}, 110) = -1 ENOENT (No such file or directory)
[pid   882] close(5)                    = 0
Run Code Online (Sandbox Code Playgroud)

文件名是正确的,同样,文件/tmp/.s.PGSQL.5432存在:

$ ls -l /tmp/.s.PGSQL.5432
srwxrwxrwx. 1 postgres postgres 0 Nov  1 09:47 /tmp/.s.PGSQL.5432
Run Code Online (Sandbox Code Playgroud)

看起来 php-fpm 进程没有被 chroot'ed:

# ls -l /proc/882/root
lrwxrwxrwx. 1 apache apache 0 Oct 31 19:54 /proc/882/root -> /
Run Code Online (Sandbox Code Playgroud)

在这一点上,我不知道问题出在哪里,我将不胜感激。

Ser*_*lov 10

我已经解决了这个问题。它的最初原因是在 php-fpm /usr/lib/systemd/system/php-fpm.service 的systemd 服务文件中:

[Service]
PrivateTmp=true
Run Code Online (Sandbox Code Playgroud)

这意味着 php-fpm 无法看到/tmp/.s.PGSQL.5432/tmp 中的任何其他内容。为了解决这个问题,我通过以下步骤更改了 PostgreSQL Unix 域套接字文件的位置:

  • 创建一个新目录/var/pgsql(注意更改 SELinux 文件上下文):

    # mkdir /var/pgsql
    # chown posgres:postgres /var/pgsql
    # chmod 0755 /var/pgsql
    # semanage fcontext -a -t httpd_var_run_t "/var/pgsql(/.*)?"
    # restorecon -R /var/pgsql
    
    Run Code Online (Sandbox Code Playgroud)
  • /var/lib/pgsql/9.3/data/postgresql.conf 中取消注释并修改unix_socket_directories参数(为了不破坏 psql 和其他程序,仍然需要/tmp):

    unix_socket_directories = '/tmp,/var/pgsql'
    
    Run Code Online (Sandbox Code Playgroud)

这是另一个棘手的部分......在最初的帖子中我写道,我试图更改 Unix 域套接字文件的位置,我真的做到了。我错过的是更改后的错误消息。我认为错误是一样的,但事实并非如此:

Error (256): Cannot connect to database: SQLSTATE[08006] [7] could not connect to
server: Permission denied
    Is the server running locally and accepting
    connections on Unix domain socket "/var/pgsql/.s.PGSQL.5432"?
Run Code Online (Sandbox Code Playgroud)

权限被拒绝- 这是一个可以对抗的事情。

一切都与

# setenforce 0
Run Code Online (Sandbox Code Playgroud)

问题是:

# audit2allow -a

#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;
Run Code Online (Sandbox Code Playgroud)

它可以被修复:

# audit2allow -a -M httpd_postgresql_unix_socket_connect
# semodule -i httpd_postgresql_unix_socket_connect.pp
Run Code Online (Sandbox Code Playgroud)

httpd_postgresql_unix_socket_connect.te 的内容:

module httpd_postgresql_unix_socket_connect 1.0;

require {
        type httpd_t;
        type initrc_t;
        class unix_stream_socket connectto;
}

#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;
Run Code Online (Sandbox Code Playgroud)

重新开启 SELinux:

# setenforce 1
Run Code Online (Sandbox Code Playgroud)

一切正常!

PS 我很高兴知道是否有办法通过更改某些文件上下文或布尔值来避免自定义 SELinux 模块。可能是这种情况,因为 SELinux 允许 nginx 使用 php-fpm Unix 域套接字(/var/run/php5-fpm.sock),但由于某些原因阻止使用 PostgreSQL Unix 域套接字(/var/pgsql/.s .PGSQL.5432)。