访问控制

Pigsty 内置四层角色模型与默认权限模板,将最小权限原则落实为可声明、可复用的集群配置。

认证 回答“你是谁”,授权回答“你能做什么”。

权限失控很少是因为缺少机制 —— PostgreSQL 的 GRANTREVOKE 足够精细。问题在于缺少一套被默认执行的约定: 业务上线时直接把账号设为属主;临时排障授予超级用户后没有及时回收;新表创建后遗漏授权,最终在生产环境触发权限错误。

Pigsty 提供了一套开箱即用的基础访问控制模型作为起点:四层角色、默认权限与数据库隔离。 它减少了逐库手工授权,但仍需要部署方按业务边界分配角色,并定期核对实际权限。

pigsty-acl.jpg


角色体系

Pigsty 默认创建四个 业务角色 —— 它们不可登录,作为权限组使用:

角色属性继承用途
dbrole_readonlyNOLOGIN-全局只读访问
dbrole_readwriteNOLOGINdbrole_readonly全局读写(DML),业务账号的默认选择
dbrole_adminNOLOGINdbrole_readwritepg_monitor对象创建(DDL),管理与发布流程使用
dbrole_offlineNOLOGIN-独立只读角色,可配合 HBA 限制到离线实例

以及四个 系统用户,各自只承担一种职责:

用户属性用途
postgresSUPERUSER数据库超级用户:不设密码,仅限本地 ident 登录
replicatorREPLICATION流复制与备份,附带 pg_monitor 与只读权限
dbuser_dbaSUPERUSER日常管理用户,继承 dbrole_admin
dbuser_monitor-监控用户,仅持有 pg_monitor 与只读权限

业务账号通过 roles 字段挂载到角色组上,权限随继承而来:

pg_users:
  - { name: dbuser_app    ,password: '...' ,roles: [dbrole_readwrite] }  # 常规业务账号
  - { name: dbuser_report ,password: '...' ,roles: [dbrole_readonly]  }  # 报表只读账号
  - { name: dbuser_etl    ,password: '...' ,roles: [dbrole_offline]   }  # 离线 ETL 账号

角色体系本身也是声明的一部分(pg_default_roles),可以定制。 该参数是一份完整列表;调整时应保留所需的系统用户与默认角色,并同步检查 HBA、默认权限和脚本中的角色引用。


默认权限

角色解决了“权限授予谁”,还剩下另一半问题:新创建的对象如何自动获得正确的权限?

PostgreSQL 的原生答案是 ALTER DEFAULT PRIVILEGES。Pigsty 通过 pg_default_privileges 将其声明化:

pg_default_privileges:            # 管理身份创建的新对象,自动应用以下权限
  - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
  - GRANT SELECT     ON TABLES    TO dbrole_readonly
  - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
  - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
  - GRANT SELECT     ON TABLES    TO dbrole_offline
  - GRANT SELECT     ON SEQUENCES TO dbrole_offline
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
  - GRANT INSERT     ON TABLES    TO dbrole_readwrite
  - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
  - GRANT DELETE     ON TABLES    TO dbrole_readwrite
  - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
  - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
  - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
  - GRANT REFERENCES ON TABLES    TO dbrole_admin
  - GRANT TRIGGER    ON TABLES    TO dbrole_admin
  - GRANT CREATE     ON SCHEMAS   TO dbrole_admin

只读角色获得查询与执行权限,读写角色叠加 DML,管理角色再增加对象管理所需的 DDL 辅助权限。

所有权约定

默认权限机制有一个经常被忽略的前提:它只对配置了默认权限的对象创建者生效。Pigsty 会为以下身份配置默认权限:

  • 数据库系统用户 pg_dbsu,默认为 postgres
  • 管理用户 pg_admin_username,默认为 dbuser_dba
  • dbrole_admin
  • 每个在 pg_databases 中声明的数据库属主。

应用 DDL 通常应使用声明的数据库属主;平台级管理与发布操作可以使用 dbuser_dba,或先 SET ROLE dbrole_admin。由其他用户直接创建的对象不会自动进入这套默认权限体系,除非另行为该用户配置 ALTER DEFAULT PRIVILEGES

这不是 Pigsty 的限制,而是 PostgreSQL 默认权限机制本身的工作方式:默认权限跟随对象创建者,而不是数据库或会话中的登录用户名自动传播。


数据库隔离

默认情况下,PostgreSQL 向 PUBLIC 授予数据库 CONNECT 权限。只要 HBA 同时允许连接,可登录用户就可能进入并不属于自己的数据库;多业务共享集群时尤其需要收敛这一默认值。

在数据库定义中声明 revokeconn,即可回收公共连接权限:

pg_databases:
  - { name: app_a ,owner: dbuser_a ,revokeconn: true }
  - { name: app_b ,owner: dbuser_b ,revokeconn: true }

启用后,该数据库上 PUBLICCONNECT 权限被撤销,只显式授予复制、监控、管理用户与数据库属主 —— 属主获得带 GRANT OPTION 的连接权限,可以自行决定向谁开放访问。在没有其他角色继承或额外授权的前提下,app_a 的账号将无法连接 app_b

与之配套,集群初始化时还会回收数据库与 public 模式上 PUBLICCREATE 权限:

REVOKE CREATE ON DATABASE app FROM PUBLIC;
REVOKE CREATE ON SCHEMA public FROM PUBLIC;

普通用户不再能在公共数据库或模式中随意创建对象,从而降低不安全 search_path 与对象覆盖带来的风险。 PostgreSQL 15 起已经收紧 public 模式的默认 CREATE 权限;Pigsty 将这项边界统一应用到所有受支持的大版本上。


离线角色与实例隔离

dbrole_offline 的设计用途,是为 ETL、报表和个人查询提供一组独立的只读权限。但角色本身只控制对象权限,并不会自动限制用户连接到哪类实例。

当前默认 HBA 中,+dbrole_offline 的内网规则没有设置 role,因此会应用到所有实例。要把它限制到 pg_role: offline 的专用实例,或标记了 pg_offline_query: true 的普通从库,需要在完整的 pg_default_hba_rules 列表中修改这一条规则:

pg_default_hba_rules:
  # 复制并保留其他默认规则,仅修改离线角色这一条
  - { user: '+dbrole_offline', db: all, addr: intra, auth: pwd, role: offline, order: 650,
      title: 'allow offline users on offline instances' }

定义 pg_default_hba_rules 会替换整组默认值,不能只保留示例中的一条。只有当 HBA 已按实例角色过滤,且用户没有同时继承其他可登录角色时,这类高消耗查询才会被限制到离线实例。资源隔离还应配合 独立服务入口、连接数和查询资源控制。


数据库之外

最小权限原则同样贯彻到主机层面:

  • 超级用户 postgres 不设密码,只能本地 ident 登录;其 sudo 权限默认限制在数据库相关服务的启停与日志查看(pg_dbsu_sudolimit)。
  • 监控用户 dbuser_monitor 默认持有 pg_monitor、只读角色与专用 monitor 模式权限,不具备业务表写权限。
  • 复制用户 replicator 被显式授予备份恢复所需的目录函数执行权限,而不是笼统的超级用户。

接下来