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

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

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

  1. 创建云SQL Postgres实例
  2. 向K8S容器添加代理,使用所有凭据连接到云SQL实例,如GCP documentation
  3. 所述
  4. 进入My 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]:权限不足:7错误:权限被拒绝 对于PDO异常的关系员工(代码:42501):SQLSTATE[42501]: 权限不足:7错误:关系的权限被拒绝。在

另一个问题是,我没有用命令生成所有的表,但我必须执行所有的查询才能生成它,所以很奇怪...

谢谢,致以问候


解决方案

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

在为PostgreSQL创建新的云SQL实例时...postgres用户是cloudsqlsuperuser角色的一部分,具有以下属性(权限):CREATEROLECREATEDBLOGIN。它没有SUPERUSERREPLICATION属性。

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

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

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

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

我假设您的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 <TYPE> <name> OWNER TO symfonyapp将其所有权调整为您的自定义角色;例如:

    ALTER TABLE mytable OWNER TO symfonyapp;
    
无法将SUPERUSER角色属性直接授予postgres用户,因为您无权访问具有SUPERUSER权限的用户执行此操作!(只有超级用户才能使其他用户成为超级用户。)Google Cloud SQL for Postgresdocumentation指出,明确排除了对需要超级用户权限的任何功能的支持,因此您不能使用此方法。唯一的超级用户是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}
此外,使用云控制台中的[数据库]选项卡创建的新数据库在默认情况下将所有权分配给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角色。

相关文章