3. 基于角色的访问控制(RBAC)核心

Snowflake 的访问控制体系以 RBAC(Role-Based Access Control,基于角色的访问控制)为核心。理解 RBAC 的关键,不是记住“角色”这个词,而是理解 Snowflake 中权限的授予对象是角色,用户通过被授予角色来间接获得权限。也就是说,权限不直接挂在用户身上,而是挂在角色上,用户与权限之间通过角色解耦。这一设计使得权限管理可以按“职责”而不是按“个人”来组织。

一、角色层次结构:权限沿继承链向下流动

Snowflake 的角色不是平铺的,而是构成一棵有向的层次树。角色可以被授予给另一个角色,形成“父角色—子角色”的继承关系。继承的方向是:父角色自动拥有其所有子角色的权限。换句话说,权限从子角色向父角色“向上汇聚”,而使用父角色的用户则“向下”获得整棵子树的权限。

系统内置的最高角色是 ACCOUNTADMIN,它位于层次结构顶端,拥有账户级管理能力。其下是 SECURITYADMIN(负责用户与角色管理)和 SYSADMIN(负责数据库对象管理),再往下是 USERADMIN(负责用户与角色创建)以及 PUBLIC(默认授予所有用户的公共角色)。自定义角色通常挂在 SYSADMIN 之下,形成业务职责分支。

ACCOUNTADMIN 账户最高管理角色 SECURITYADMIN 用户/角色/授权管理 SYSADMIN 数据库对象管理 USERADMIN 创建用户与角色 自定义角色 业务职责分支 ANALYST_RO 只读分析 ETL_RW 读写加载 PUBLIC 默认授予所有用户 账户级角色 系统管理角色 自定义角色 公共角色 箭头方向:父角色继承子角色权限(权限向上汇聚,用户向下获得)

需要特别注意的是,ACCOUNTADMIN 虽然位于顶端,但它并不自动继承 SYSADMIN 下的所有自定义角色——除非显式授予。因此,最佳实践是:日常对象管理使用 SYSADMIN,安全与权限管理使用 SECURITYADMIN,ACCOUNTADMIN 仅用于账户级紧急操作,避免日常使用。

二、系统角色与自定义角色

系统角色由 Snowflake 预定义,不可删除,其权限范围固定。它们承担的是“平台管理”职责,而不是“业务数据访问”职责。自定义角色则由用户按业务需要创建,用于承载具体的数据访问权限。两者的分工可以概括为:系统角色管平台,自定义角色管数据。

创建自定义角色的典型语句如下:

-- 使用 USERADMIN 创建角色
USE ROLE USERADMIN;
CREATE ROLE IF NOT EXISTS analyst_ro COMMENT = '只读分析角色';
CREATE ROLE IF NOT EXISTS etl_rw   COMMENT = 'ETL 读写角色';

-- 将自定义角色授予 SYSADMIN,纳入对象管理树
USE ROLE SECURITYADMIN;
GRANT ROLE analyst_ro TO ROLE sysadmin;
GRANT ROLE etl_rw     TO ROLE sysadmin;

-- 将角色授予用户
GRANT ROLE analyst_ro TO USER alice;
GRANT ROLE etl_rw     TO USER bob;

这里有一个容易被忽略的细节:创建角色后,必须把角色授予 SYSADMIN(或其它父角色),否则该角色会游离在层次结构之外,导致 SYSADMIN 无法管理其下的对象权限。这是 Snowflake RBAC 中非常关键的一步。

三、角色授权与继承:权限如何真正生效

角色授权分为两类:一是把对象权限授予角色,二是把角色授予用户或另一个角色。对象权限包括 SELECT、INSERT、UPDATE、DELETE、USAGE、CREATE 等,作用对象可以是数据库、模式、表、视图、仓库等。

-- 授予仓库使用权限
GRANT USAGE ON WAREHOUSE compute_wh TO ROLE analyst_ro;

-- 授予数据库与模式使用权限
GRANT USAGE ON DATABASE sales_db TO ROLE analyst_ro;
GRANT USAGE ON SCHEMA sales_db.public TO ROLE analyst_ro;

-- 授予表查询权限
GRANT SELECT ON TABLE sales_db.public.orders TO ROLE analyst_ro;

-- 授予未来表权限(关键:避免逐表授权)
GRANT SELECT ON FUTURE TABLES IN SCHEMA sales_db.public TO ROLE analyst_ro;

继承关系决定了权限的可见范围。当用户 alice 被授予 analyst_ro 后,她不仅拥有 analyst_ro 的直接权限,还拥有其所有子角色的权限。如果 analyst_ro 被授予了 reporting_ro,那么 alice 同时获得 reporting_ro 的权限。这种“一次授予、多层生效”的机制,正是 RBAC 降低管理成本的核心。

验证权限是否生效,可以使用以下命令:

-- 查看当前角色
SELECT CURRENT_ROLE();

-- 查看角色继承关系
SHOW GRANTS TO ROLE analyst_ro;

-- 查看用户被授予的角色
SHOW GRANTS TO USER alice;

-- 以指定角色执行查询,验证权限
USE ROLE analyst_ro;
SELECT COUNT(*) FROM sales_db.public.orders;

如果查询返回结果,说明权限链完整;如果报“Insufficient privileges”,则需要沿继承链逐层检查:用户是否被授予角色、角色是否被授予父角色、对象权限是否授予角色、仓库与数据库的 USAGE 是否齐备。

四、最佳实践

  • 按职责而非按人建角色。角色应对应岗位或业务职能,如 analyst_ro、etl_rw、finance_rw,而不是 alice_role。人员变动时只调整角色授予,不重建权限。
  • 保持层次结构清晰。自定义角色统一挂在 SYSADMIN 下,安全相关角色挂在 SECURITYADMIN 下,避免角色游离或形成环状继承。
  • 优先使用 FUTURE GRANTS。对模式中未来创建的表、视图使用 ON FUTURE 授权,避免新对象上线后权限缺失。
  • 最小权限原则。只授予完成工作所必需的最小权限,读多写少的场景优先使用只读角色,写权限单独建角色。
  • 限制 ACCOUNTADMIN 使用。日常操作使用 SYSADMIN 或自定义角色,ACCOUNTADMIN 仅用于账户级配置与紧急恢复。
  • 定期审计。使用 SHOW GRANTS 与 ACCOUNT_USAGE.GRANTS_TO_ROLES 定期检查权限授予情况,清理不再使用的角色与授权。
一个实用的判断方法:如果新增一个用户需要修改多处权限,说明角色设计过于分散;如果删除一个用户需要逐项回收权限,说明权限直接授予了用户而非角色。良好的 RBAC 设计应做到“用户只挂角色,权限只挂角色”。

总结来说,Snowflake RBAC 的核心在于:角色是权限的载体,继承是权限的放大器,层次结构是管理的骨架。掌握角色层次、系统角色与自定义角色的分工、授权与继承的生效路径,再配合最小权限与定期审计,才能构建出既安全又易维护的访问控制体系。