我正在尝试从 PHP Web 应用程序连接到 PostgreSQL Unix 域套接字。相关系统组件:
- CentOS 7 x64(强制使用 SELinux)
- postgresql93 9.3.5-2PGDG.rhel7
- nginx 1.6.2-1.el7.ngx
- php 通用 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,我可以通过 TCP/IP 在 127.0.0.1:5432 使用它,没有任何问题,但是当我尝试连接到它的 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"?
文件/tmp/.s.PGSQL.5432存在,我可以使用连接查询语言:
$ psql -Uusername db_name
psql (9.3.5)
Type "help" for help.
db_name=>
因此 PostgreSQL 方面应该没有问题。或者有问题?
相关内容来自/var/lib/pgsql/9.3/data/pg_hba.conf:
local all username trust
Unix 域套接字文件位置的更改/var/lib/pgsql/9.3/data/postgresql.conf没有帮助:
unix_socket_directories = '/var/run/pgsql'
什么也没有/var/log/audit/audit.log,但我尝试禁用 SELinux,只是为了确保万无一失:
# setenforce 0
这没有帮助,所以它不是 SELinux。
相关内容来自斯特拉斯的php-fpm:
[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
文件名正确,再次,文件/tmp/.s.PGSQL.5432存在:
$ ls -l /tmp/.s.PGSQL.5432
srwxrwxrwx. 1 postgres postgres 0 Nov 1 09:47 /tmp/.s.PGSQL.5432
看起来 php-fpm 进程没有被 chroot:
# ls -l /proc/882/root
lrwxrwxrwx. 1 apache apache 0 Oct 31 19:54 /proc/882/root -> /
此时我已经不知道问题出在哪里了,如果能得到任何帮助我都会非常感激。
答案1
我已经解决了这个问题。最初的原因在于 php-fpm 的 systemd 服务文件/usr/lib/systemd/system/php-fpm.service:
[Service]
PrivateTmp=true
这意味着 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
取消注释并修改unix_socket_directories参数/var/lib/pgsql/9.3/data/postgresql.conf(/tmp仍然需要不破坏 psql 和其他程序):
unix_socket_directories = '/tmp,/var/pgsql'
这里还有另一个棘手的部分……在原始帖子中,我写道我尝试更改 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"?
没有权限——这是可以抗争的事情。
一切都正常
# setenforce 0
问题是:
# audit2allow -a
#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;
并且可以修复:
# audit2allow -a -M httpd_postgresql_unix_socket_connect
# semodule -i httpd_postgresql_unix_socket_connect.pp
内容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;
重新打开 SELinux:
# setenforce 1
一切正常!
PS 我很高兴知道是否有办法通过更改某些文件上下文或布尔值来避免自定义 SELinux 模块。可能是这样,因为 SELinux 允许 nginx 使用 php-fpm Unix 域套接字(/var/运行/php5-fpm.sock),但由于某种原因阻止使用 PostgreSQL Unix 域套接字(/var/pgsql/.s.PGSQL.5432)。