PostgreSQL复制命令出现权限被拒绝错误

4
我正在尝试将文件复制到PostgreSQL表中。表所有者是postgres,文件所有者也是postgres。
该文件位于/tmp目录下。
但是我仍然收到错误消息:
“无法打开文件“/tmp/file”以进行读取:权限被拒绝”
我不明白我做错了什么,因为我找到的所有帖子都说,如果我在/tmp中拥有文件,并且所有者是postgres,则COPY命令应该起作用。

1
请在文件中添加您使用的语法和权限。 - Miljen Mikic
是的,编辑您的答案并提到:PostgreSQL版本、如何安装Pg、操作系统和版本、文件权限(ls -l filenamels --lcontext filename)、表权限(在psql中使用\d+ tablename)、您运行的确切命令文本+错误消息将会很有帮助。 - Craig Ringer
2个回答

6
一个猜测:您正在使用Fedora、Red Hat Enterprise Linux、CentOS、Scientific Linux或其他默认启用SELinux的发行版。
在您特定的操作系统/版本上,PostgreSQL的SELinux策略不允许服务器读取PostgreSQL数据目录外的文件,或者该文件是由受定向策略覆盖的服务创建的,因此它具有PostgreSQL不允许读取的标签。
您可以通过以root身份运行以下命令来确认是否存在此问题:
setenforce 0

然后重新测试。运行:

setenforce 1

在测试后重新启用SELinux。 setenforce 不是永久的;无论如何,在重新启动时SELinux都会自动重新启用。永久禁用SELinux通常不是解决此类问题的好方法;如果您确认问题是SELinux,则可以进一步探讨。


由于您没有指定您使用的操作系统或版本,PostgreSQL版本,您正在运行的确切命令,文件上的ls -al,表上的\d+等等,很难提供更多细节,或者知道这是否不只是一个猜测。尝试更新您的答案,包括所有这些信息以及文件的ls --lcontext


2
@user1439690 很好,现在你知道它是SELinux了。setenforce只是一个临时措施。正确的解决方法是设置文件的SELinux上下文。请参见https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Security-Enhanced-Linux/chap-Security-Enhanced-Linux-SELinux_Contexts.html。 - Craig Ringer

1

COPY命令加上文件名可以直接让PostgreSQL服务器从文件中读取或写入数据。文件必须可被PostgreSQL用户(即服务器运行的用户ID)访问,且文件名必须从服务器的视角指定。(来源:postgresql documentation

因此,该文件应该由运行PostgreSQL服务器的Unix用户可读(或可写),而不是您的用户!为确保绝对正确性,您可以尝试运行sudo -u postgres head /tmp/test.csv(假设您被允许使用sudo,并且数据库用户为postgres)。

如果失败了,可能与SELinux有关(正如Craig Ringer所提到的)。在最常见的SELinux策略(Red Hat/Fedora/CentOS、Scientific Linux、Debian等使用的“targeted”参考策略)下,PostgreSQL服务器进程受限制:它只能读/写少数文件类型。

否认可能不会被记录在auditd的日志文件(/var/log/audit/audit.log)中,因为存在donaudit规则。因此,通常的SELinux快速测试适用,例如:通过运行getenforce;setengorce 0;getenforce停止SELinux约束任何进程,然后测试postgresql的COPY。然后通过运行setenforce 1重新激活SELinux(这个命令修改运行状态而不是配置文件,所以SELinux将在重启后处于活动状态(强制执行)。

修复问题的正确方法是更改要加载的文件的SELinux上下文。一个快速的hack是运行:

chcon -t postgresql_tmp_t /tmp/a.csv

但是,如果文件系统重新标记或创建新文件,则此文件标记将无法保存。您需要创建一个带有SELinux文件上下文映射的目录:

which semanage || yum install policycoreutils-python
semanage fcontext -a -t postgresql_tmp_t '/srv/psql_copydir(/.*)?'
mkdir /srv/psql_copydir
chmod 750 /srv/psql_copydir
chgrp postgres /srv/psql_copydir
restorecon -Rv /srv/psql_copydir
ls -Zd /srv/psql_copydir

任何在该目录中创建的文件都应该自动具有正确的文件上下文,以便postgresql服务器可以读/写它。(要检查postgres正在运行的SELinux上下文,请运行ps xaZ | grep "postmaste[r]" | grep -o "[a-z_]*_t",这应该会打印出postgresql_t。要列出postgresql_t可以写入的上下文类型,请使用sesearch -s postgresql_t -A | grep ': file.*write'命令。命令sesearch属于setools-console RPM包)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接