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

GCP SQL Postgres problem with privileges : can't run a query with postgres user with generated symfony db

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

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

  1. 创建云SQL Postgres 实例
  2. 将代理添加到 k8s 容器以使用所有凭据连接到云 SQL 实例,如 GCP documentation
  3. 中所述
  4. 输入我的 Symfony (phpfpm) pod 和 运行 命令 php bin/console doctrine:schema:update --force 来更新架构。查询在数据库中执行,因此会创建架构等等。
  5. 我尝试使用 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]: Insufficient privilege: 7 ERROR: permission denied for relation employee at PDOException(code: 42501): SQLSTATE[42501]: Insufficient privilege: 7 ERROR: permission denied for relation .. at

另一个问题是我没有用命令生成所有表,但我必须生成它来执行所有查询,太奇怪了...

谢谢,问候

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

When you create a new Cloud SQL for PostgreSQL instance... the postgres user is part of the cloudsqlsuperuser role, and has the following attributes (privileges): CREATEROLE, CREATEDB, and LOGIN. It does not have the SUPERUSER or REPLICATION attributes.

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

A database superuser bypasses all permission checks, except the right to log in.

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

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

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

If the “Access privileges” column is empty for a given object, it means the object has default privileges (that is, its privileges column is null). Default privileges always include all privileges for the owner...


备选方案

  • (推荐)创建一个专用角色,可以在 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 <TYPE> <name> OWNER TO symfonyapp将它们的所有权调整为您的自定义角色;例如:

    ALTER TABLE mytable OWNER TO symfonyapp;
    

无法直接将 SUPERUSER 角色属性授予 postgres 用户,因为您无权访问具有 SUPERUSER 权限的用户! (只有超级用户可以让其他用户成为超级用户。)Google Cloud SQL for Postgres 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 中的 "Databases" 选项卡创建的新数据库的所有权默认分配给 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

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

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

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)

对于生产用途,如 "Alternatives" 部分所述,我建议使用专用角色而不是内置 cloudsqlsuperuser 角色。