GCP SQL Postgres 权限问题:无法使用生成的 symfony db 使用 postgres 用户运行查询

Posted

技术标签:

【中文标题】GCP SQL Postgres 权限问题:无法使用生成的 symfony db 使用 postgres 用户运行查询【英文标题】:GCP SQL Postgres problem with privileges : can't run a query with postgres user with generated symfony db 【发布时间】:2019-02-14 01:17:13 【问题描述】:

我正在努力使用 Google Cloud Platform 的 Cloud SQL 组件解决这个问题。我的技术堆栈包括在 Google Kubernetes Engine (GKE) 部署中托管我的应用程序,使用 Cloud SQL 代理 sidecar 连接到 pod 内的数据库。后端是一个 Symfony 项目。

我按照以下步骤创建和填充数据库(没有成功):

    创建 Cloud SQL Postgres 实例 向 k8s 容器添加代理以使用所有凭据连接到 Cloud SQL 实例,如GCP documentation 中所述 进入我的 Symfony (phpfpm) pod 并运行命令 php bin/console doctrine:schema:update --force 以更新架构。查询在数据库中执行,因此创建了架构等等。 我尝试使用postgres 用户从GCP 内的SQL 控制台连接打开数据库,并尝试执行一个简单的select * from foo; 查询。回复是Insufficient privilege: 7 ERROR: permission denied for relation

如何使用postgres用户查询数据库中的数据?

编辑:

我有这种关于用户的情况:

     Role name     |                         Attributes                         |           Member of           
-------------------+------------------------------------------------------------+-------------------------------
 acando14          | Create role, Create DB                                     | cloudsqlsuperuser,proxyuser
 cloudsqladmin     | Superuser, Create role, Create DB, Replication, Bypass RLS | 
 cloudsqlagent     | Create role, Create DB                                     | cloudsqlsuperuser
 cloudsqlreplica   | Replication                                                | 
 cloudsqlsuperuser | Create role, Create DB                                     | 
 postgres          | Create role, Create DB                                     | cloudsqlsuperuser,acando14
 proxyuser         | Create role, Create DB                                     | cloudsqlsuperuser

我在表格中有这种情况:

              List of relations
 Schema |      Name       | Type  |  Owner   
--------+-----------------+-------+----------
 public | article         | table | acando14

如果我使用 postgres 用户登录我的数据库 symfony 工作:

symfony => select * from article;
 id | model_id | code | size 
----+----------+------+------
(0 rows)

但如果我使用服务器执行代码,则响应是:

SQLSTATE[42501]:权限不足:7 错误:权限被拒绝 对于 PDOException 的关系员工(代码:42501):SQLSTATE [42501]: 权限不足:7 错误:关系的权限被拒绝..在

还有一个问题是我没有用命令生成所有的表,但是我必须在执行所有查询时生成它,太奇怪了……

谢谢你,问候

【问题讨论】:

k8s托管的服务以什么用户身份连接数据库? 使用代理用户... 【参考方案1】:

Google Cloud Platform (GCP) Cloud SQL (PostgreSQL) 中的默认 postgres 用户不是实例的超级用户 (GCP docs link):

当您创建新的 Cloud SQL for PostgreSQL 实例时...postgres 用户是 cloudsqlsuperuser 角色的一部分,并具有以下属性(权限):CREATEROLECREATEDB 和 @987654331 @。它没有SUPERUSERREPLICATION 属性。

超级用户属性授予用户绕过所有权限检查的能力,因此,它可以在数据库实例中的任何位置从任何数据库中读取数据 (PostgreSQL docs link):

数据库超级用户绕过所有权限检查,登录权限除外。

在 GCP 之外的典型 PostgreSQL 部署中,postgres 用户确实是超级用户。 Cloud SQL 中的这种偏差违反了 Postgres 的正常约定,即 postgres 用户始终可以凭借这些超级用户权限访问和更改集群中的任何对象。

如果没有此权限,您将需要更加小心创建数据库对象时使用的角色以及尝试访问它们时使用的角色,无论是在 Postgres shell 中以交互方式还是在您的应用程序中以编程方式。

我假设您在 k8s 部署中使用单独的专用用户来连接数据库,而不是 postgres 用户。默认情况下,该用户的角色将拥有由模式填充操作创建的对象。根据GRANT documentation,默认情况下,此所有者将拥有该对象的全套权限:

如果给定对象的“访问权限”列为空,则表示该对象具有默认权限(即,其权限列为空)。默认权限始终包括所有者的所有权限...


替代方案

(推荐)创建一个专用角色,该角色可以在postgres 用户和您登录数据库以填充其架构的任何其他用户之间共享。

在模式创建操作中配置填充数据库对象的操作,以在创建对象之前将其角色设置为此共享角色,以便所有用户都可以访问、管理和查看这些对象。默认情况下,新角色具有INHERIT 属性集,这意味着将来该角色的成员尝试访问由该角色创建的对象将成功。

例如,您可以为此目的使用 cloudsqlsuperuser 角色,在控制台中创建的所有用户和内置的 postgres 都自动成为该角色的成员。但是,我建议为此创建一个自定义角色:

CREATE ROLE symfonyapp;
GRANT symfonyapp TO postgres;
GRANT symfonyapp TO <your_k8s_application_user>;

稍后,在创建数据库对象时,请确保在创建数据库对象之前先承担symfonyapp 角色。在控制台运行:

SET ROLE symfonyapp;

以已授予symfonyapp 角色的用户身份登录时。您应该查看您正在使用的库的文档,以确定在以编程方式连接到数据库时如何设置角色。

如上创建一个角色,并将其分配给postgres 用户。此外,为角色赋予LOGIN 属性并设置密码,这样您就可以直接使用角色名称和密码登录数据库实例。在这种情况下,postgres 用户继承了角色的权限(例如它拥有的对象),并且可以直接登录,无需在第一次连接时调用SET ROLE

对于已创建的对象,您可以使用命令ALTER &lt;TYPE&gt; &lt;name&gt; OWNER TO symfonyapp 将其所有权调整为您的自定义角色;例如:

ALTER TABLE mytable OWNER TO symfonyapp;

无法将SUPERUSER 角色属性直接授予postgres 用户,因为您无权访问具有SUPERUSER 权限的用户来执行此操作! (只有超级用户可以让其他用户成为超级用户。)用于 Postgres 的 Google Cloud SQL documentation 指出特别排除了对任何需要超级用户权限的功能的支持,因此您无法使用此路线。唯一的超级用户是 cloudsqladmin 用户,默认创建并由 Google 用于代表您执行实例级管理操作;您可以重置密码并以此帐户登录以授予超级用户权限,但我不建议这样做,因为这可能会破坏其他托管功能。


工作示例

新创建的数据库集群中存在的默认角色集如下:

                                        List of roles
     Role name     |                         Attributes                         |      Member of
-------------------+------------------------------------------------------------+---------------------
 cloudsqladmin     | Superuser, Create role, Create DB, Replication, Bypass RLS | 
 cloudsqlagent     | Create role, Create DB                                     | cloudsqlsuperuser
 cloudsqlreplica   | Replication                                                | 
 cloudsqlsuperuser | Create role, Create DB                                     | 
 postgres          | Create role, Create DB                                     | cloudsqlsuperuser

此外,使用 Cloud Console 中的“数据库”标签创建的新数据库的所有权默认分配给 cloudsqlsuperuser 角色。 (如上面的角色列表所示,cloudsqlsuperuser 角色由postgres 用户继承。)

                                  List of databases
  Name  |       Owner       | Encoding |  Collate   |   Ctype    | Access privileges
--------+-------------------+----------+------------+------------+-------------------
 testdb | cloudsqlsuperuser | UTF8     | en_US.UTF8 | en_US.UTF8 |

因此,cloudsqlsuperuser 角色的成员默认拥有在数据库中创建对象的权限。但是,这样做时,默认情况下,它们的所有者将设置为创建它们的用户,而不是父角色:

testdb=> CREATE TABLE sometable (id SERIAL NOT NULL);
CREATE TABLE
testdb=> \dt sometable
           List of relations
 Schema |   Name    | Type  |  Owner
--------+-----------+-------+----------
 public | sometable | table | testuser

如果我们在创建表之前调用SET ROLE cloudsqlsuperuser,现在所有者将默认为cloudsqlsuperuser角色,这将允许postgres和角色的其他成员默认分配给角色的默认权限:

您还可以在创建表时使用触发器和其他方法来set the role automatically。

testdb=> SET ROLE cloudsqlsuperuser;
SET
testdb=> CREATE TABLE anothertable (id SERIAL NOT NULL);
CREATE TABLE
testdb=> \dt anothertable;
                 List of relations
 Schema |     Name     | Type  |       Owner
--------+--------------+-------+-------------------
 public | anothertable | table | cloudsqlsuperuser
(1 row)

对于生产用途,如“替代方案”部分所述,我建议使用专用角色而不是内置的 cloudsqlsuperuser 角色。

【讨论】:

非常感谢!我会尝试您的解决方案...如果我使用您的第一个解决方案,我会收到此错误:错误:必须是超级用户才能更改超级用户...我该如何解决? 啊,当然,您将无法这样做,因为postgres 本身不是超级用户,并且您无权访问任何超级用户。 (您必须是超级用户才能分配超级用户权限,而 Cloud SQL 中唯一属于此类用户的用户是 cloudsqladmin,最好不要为其重置密码。) 我也尝试了您的第二种选择,但它不起作用...代理用户没有权限... 您是否要创建一个新角色?您尝试将角色创建为哪个用户?

以上是关于GCP SQL Postgres 权限问题:无法使用生成的 symfony db 使用 postgres 用户运行查询的主要内容,如果未能解决你的问题,请参考以下文章