4. 系统定义角色与自定义角色

Snowflake 的访问控制体系建立在 RBAC(基于角色的访问控制)之上。理解这一点非常关键:在 Snowflake 中,权限从不直接授予用户,而是先授予角色,再把角色授予用户。用户通过“激活”某个角色来获得该角色所携带的权限。因此,角色体系的设计质量,直接决定了整个账户权限模型是否清晰、可维护、可审计。

Snowflake 预置了一组系统定义角色(System-Defined Roles),它们构成了权限管理的骨架。这些角色不能删除,也不能被重命名,但可以被授予给其他角色或用户。掌握它们的职责边界,是设计自定义角色体系的前提。

系统定义角色的职责分工

系统角色中最核心的是五个:ACCOUNTADMIN、SYSADMIN、SECURITYADMIN、USERADMIN 和 PUBLIC。它们之间存在明确的层级与制衡关系。

  • ACCOUNTADMIN:账户的最高权限角色,拥有账户级的所有管理能力,包括计费、复制、资源监控、创建其他管理角色等。它同时被授予 SYSADMIN 和 SECURITYADMIN,因此天然具备这两条线的全部权限。最佳实践是:日常操作不要使用 ACCOUNTADMIN,仅在账户级配置、故障恢复等场景下临时激活。
  • SYSADMIN:负责“对象与资源”这条线。所有数据库、模式、表、视图、仓库(Warehouse)等对象,理想情况下都应由 SYSADMIN 或其下级角色创建和持有。这样对象所有权集中,便于统一管理。
  • SECURITYADMIN:负责“权限与用户”这条线。它可以管理 GRANT(授权),包括授予和撤销角色、管理网络策略等。它拥有 MANAGE GRANTS 权限,是权限治理的核心角色。
  • USERADMIN:专注于用户和角色的创建与维护,可以创建用户、创建角色、授予角色,但不具备管理对象权限的能力。它适合交给 HR 或 IT 运维团队使用。
  • PUBLIC:每个用户自动拥有的角色,用于存放“所有用户都应具备”的最小权限。默认情况下 PUBLIC 几乎无权限,应保持其精简。

这五个角色并非平级。ACCOUNTADMIN 位于顶端,SYSADMIN 与 SECURITYADMIN 分列两条主线,USERADMIN 从属于 SECURITYADMIN,PUBLIC 则是最底层的公共角色。这种“双线制衡”的设计,使得对象管理与权限管理相互独立,避免单一角色权力过大。

Snowflake 系统定义角色层级与职责 ACCOUNTADMIN 账户级最高权限 · 计费/复制/监控 SYSADMIN 对象与资源线 · 数据库/仓库/表 SECURITYADMIN 权限与用户线 · MANAGE GRANTS USERADMIN 用户与角色创建 · 不含对象权限 自定义角色(业务线) 如 ANALYST_RO / ETL_RO PUBLIC 所有用户默认拥有 · 最小权限 账户级 对象线 权限线 用户线 自定义角色

为什么需要自定义角色

系统角色只提供了“管理骨架”,它们并不了解业务。真实场景中,不同团队需要不同的数据访问范围:分析师需要读取销售数据但不能修改,ETL 工程师需要写入原始层但不能访问财务明细,数据科学家需要读取特征表但不能删除。如果直接把这些权限授予 SYSADMIN,就会导致权限泛滥、无法审计。因此,必须为每条业务线设计专门的自定义角色。

设计自定义角色体系时,推荐遵循“功能角色 + 访问角色”的双层结构。功能角色(Functional Role)描述“做什么”,例如 ANALYST_RO、ETL_RO、DATA_SCIENTIST_RO;访问角色(Access Role)描述“能访问什么”,例如 SALES_READ_RO、FINANCE_READ_RO、RAW_WRITE_RO。功能角色继承访问角色,用户只被授予功能角色。这样当某个数据源的访问策略变化时,只需调整访问角色,所有继承它的功能角色自动生效,无需逐个修改用户。

自定义角色体系设计示例

假设某零售公司有销售分析、财务分析和数据工程三条业务线,可以设计如下角色结构。以下 SQL 为教学示例,参数与命名可根据实际调整。

-- 1. 创建访问角色(描述可访问的数据范围)
CREATE ROLE SALES_READ_RO;
CREATE ROLE FINANCE_READ_RO;
CREATE ROLE RAW_WRITE_RO;

-- 2. 创建功能角色(描述业务职能)
CREATE ROLE ANALYST_RO;
CREATE ROLE FINANCE_ANALYST_RO;
CREATE ROLE ETL_RO;

-- 3. 功能角色继承访问角色
GRANT ROLE SALES_READ_RO   TO ROLE ANALYST_RO;
GRANT ROLE FINANCE_READ_RO TO ROLE FINANCE_ANALYST_RO;
GRANT ROLE RAW_WRITE_RO    TO ROLE ETL_RO;

-- 4. 将功能角色挂到 SYSADMIN 之下,保持对象管理线统一
GRANT ROLE ANALYST_RO         TO ROLE SYSADMIN;
GRANT ROLE FINANCE_ANALYST_RO TO ROLE SYSADMIN;
GRANT ROLE ETL_RO             TO ROLE SYSADMIN;

-- 5. 授予对象权限给访问角色
GRANT USAGE ON DATABASE RETAIL_DB TO ROLE SALES_READ_RO;
GRANT USAGE ON SCHEMA RETAIL_DB.SALES TO ROLE SALES_READ_RO;
GRANT SELECT ON ALL TABLES IN SCHEMA RETAIL_DB.SALES TO ROLE SALES_READ_RO;

GRANT USAGE ON WAREHOUSE ANALYST_WH TO ROLE ANALYST_RO;

这段脚本体现了几个关键原则。第一,访问角色只持有对象权限,功能角色只负责“继承”和“被授予用户”,职责分离。第二,所有自定义角色最终都挂到 SYSADMIN 之下,保证对象所有权链条完整,未来 SYSADMIN 可以统一管理所有下级对象。第三,仓库(Warehouse)的使用权限授予功能角色而非访问角色,因为仓库是计算资源,与数据访问范围无关。

设计自定义角色时,建议遵循“最小权限 + 角色继承”原则:用户只直接拥有一个功能角色,功能角色通过继承获得多个访问角色的权限。这样既减少了 GRANT 的数量,也让权限审计变得简单——只需查看功能角色的继承链,就能知道一个用户最终能访问什么。

角色命名与治理建议

角色命名应具备自解释性。推荐使用“业务域_职能_后缀”的格式,例如 SALES_ANALYST_RO、FINANCE_READ_RO、ETL_RAW_WRITE_RO。后缀统一使用 _RO 表示只读、_RW 表示读写、_ADMIN 表示管理,便于快速识别权限级别。

治理层面,应定期执行以下检查:确认没有用户直接持有 ACCOUNTADMIN;确认所有自定义角色都挂在 SYSADMIN 或 SECURITYADMIN 之下;确认 PUBLIC 角色没有被授予敏感对象权限;确认离职或转岗用户的角色授予已被回收。Snowflake 提供 ACCOUNT_USAGE 中的 GRANTS_TO_ROLES、GRANTS_TO_USERS 等视图,可以编写查询来审计这些关系。

不要将自定义角色直接授予 ACCOUNTADMIN,也不要让业务角色绕过 SYSADMIN 独立存在。一旦角色脱离 SYSADMIN 层级,对象所有权就会分散,后续的权限排查和批量管理会变得非常困难。正确的做法是:自定义角色始终作为 SYSADMIN 的下级角色存在。

总结来说,系统定义角色提供了账户管理的骨架,自定义角色则承载了业务权限的细节。设计时把握三条主线:对象线归 SYSADMIN,权限线归 SECURITYADMIN,用户线归 USERADMIN;自定义角色采用“功能角色继承访问角色”的双层结构,并统一挂到 SYSADMIN 之下。这样构建出来的角色体系,既符合 Snowflake 的最佳实践,也能在业务扩张时保持可维护、可审计。