字节跳动大数据 SQL 权限精细化管理实践 | CommunityOverCode Asia 2023

技术

文章来源|火山引擎 LAS 团队

文章介绍了字节跳动大数据 SQL 权限精细化管控技术及其在实际业务中的应用,包括 SQL 权限精细化管控技术研发的背景,基于 SQL 血缘进行权限点提取的思路以及具体实践方案,重点从权限管控维度阐述了字节跳动的权限管理服务如何基于精准细粒度的 SQL 权限点信息,完成行列混合的资源粒度权限管控工作。 本篇文章提纲如下:

  • 项目背景

  • 基于 SQL 血缘的精准权限点提取

  • 行列混合权限多维度精细管控

0 1

项目背景

作为数据行业的从业者,我们都能察觉到近年来细粒度权限管控的需求日益增强,业界在安全合规侧的压力也在日益增大,所有的数据使用者都需要遵循权限最小化原则。而 SQL 作为数据分析领域最简单、最通用的语言之一,在大数据场景下的应用非常广泛。针对 SQL 场景,传统的权限管控方式基本都是库、表、列级别权限管控。此类权限管控粒度相对较粗,难以满足日益严格的数据监管需求。

我们可以通过如下两个简单的例子说明,列粒度权限难以满足用户侧的多元的使用需求:

  1. 有些公司多条业务线的数据可能会落入统一的埋点表中处理,这种情况下多业务线数据就会落到表中的同一个列进行存储,此时列粒度的管控显然是过于单薄的。
  2. 针对同样的一份数据,不同用户的可见范围可能不同。比如多位销售人员,可能有人负责华北地区,有人负责华东地区,但是所有的销售数据都统一存储于同一张表的同一个字段内,此时列粒度的权限管控无法满足用户侧可见范围各异的需求。

picture.image

基于上述背景,字节跳动数据引擎研发团队基于 ByteQuery 查询引擎和自研的权限服务 Gemini,设计了一套行列混合的精细化权限管控方案,该方案的整体交互流程可以参考下图。

picture.image

从用户视角来看,用户提交了一个 SQL,这个 SQL 会首先打到统一 SQL 优化引擎 ByteQuery 引擎上,ByteQuery 引擎会从 SQL 中提取到它真正查询使用的细粒度权限信息,然后把这个信息发给统一的权限管理服务 Gemini。Gemini 会鉴别用户具体的权限情况,将鉴权结果返回给 ByteQuery 引擎。如果用户拥有查询所需权限,ByteQuery 引擎会将 SQL 进一步优化后提交到执行引擎,进行具体的数据处理;如果用户缺少查询所需权限,则会拦截 SQL,提示用户去申请对应的权限信息。

为了完成 SQL 权限的精细化管控,本方案整体解决思路也分 2 部分:

(1)在 SQL 解析侧,对应上图 ByteQuery 引擎部分,方案基于 SQL 血缘能力定义了一套新的权限点提取规则,这个规则可以帮助用户完成细粒度的权限点提取工作。

(2)在权限管控侧,方案支持行列混合的权限管控,通过横向行粒度和纵向列粒度的权限点捆绑组合,就可以把查询的资源定位到行列重叠的资源单元格上,达到更细粒度的资源级别权限管控效果。

以下面的 SQL 为例可以解释"横向"和"纵向"行列捆绑组合的含义:

假设用户写了这样一个 SQL:select name from db.table whereid =3。经过上面的这套流程它最终检查的权限为:

  • 在纵向列粒度检查 name 这一列的列权限;
  • 在横向行粒度检查 id=3 这一行的行级别权限;
  • 行列权限捆绑组合后,最终检测的是纵向 name 列和横向 id=3 交汇单元格的行列混合权限。

可以将 db.table 表想象成如下图所示的二维表格,上面提到的 SQL 语句真正访问的数据其实就是标黄的资源方块:

picture.image

通过上文介绍的权限管控方式,可以让用户在做权限申请时就申请到行列交汇的最细粒度的资源单元格上,完成了资源单元格级别的权限管控的目的,达到了权限最小化的效果。

02

基于 SQL 血缘的精准权限点提取

前文提到想要完成精细化的权限管控,需要做的第一步工作就是从用户的 SQL 中提取精准的、细粒度的权限点信息。下面以 Apache Hive 为例,介绍业界通用的 SQL 权限提取方案。

  • Apache Hive 在 SQL 解析时会从抽象语法树上收集各类 input, output 信息。这个信息就是 SQL 的输入输出表信息,这些表会被提取出来作为库表层面的权限点。
  • Apache Hive 在 SQL 解析和优化的过程中,会在表的查询节点 TableScan 节点上维护一个关联列信息 (referencedColumns),这些信息就是表实际使用的列信息,这些列会被提取出来作为列层面的权限点。
  • Hive 就是通过上述手段完成库权限、表权限和列权限的提取与管控。

下面再介绍字节跳动数据引擎研发团队基于血缘信息进行权限点提取的新方案。

在权限粒度层面,新方案支持了更细的库、表、行、列级别的权限提取。它并不关心具体的 SQL pattern,而是采取自上而下的视角,统一分析 SQL 中的权限构成部分。

新方案首先将 SQL 解析成一颗抽象语法树,使用统一的规则提取抽象语法树中特定的节点信息,将提取到的节点信息作为初始搜索节点,然后会基于表和列级别的血缘能力,将初始搜索节点转化为查询真正使用的底表的行 / 列信息,对底表的行 / 列进行权限验证。后文会对这一过程做进一步的详细描述。

picture.image

上文也简单提到过 ByteQuery 引擎,ByteQuery 是在开源的 Apache Calcite 基础上进一步定制优化而构建的统一查询引擎。优化后的 ByteQuery 引擎会作为公司内部统一的 SQL 查询入口使用。Apache Calcite 是开源的 SQL 解释器与优化器,在很多大数据服务上都有使用。Calcite 服务原生就支持了非常强大的列级别血缘能力,而 ByteQuery 引擎在 Apache Calcite 的基础上,又进一步定制优化了血缘能力,可以提供精准的、可配置化的列级别血缘能力。新方案会基于这个能力作为权限点提取的底座能力来使用。

下文会以一个 SQL 为例,介绍新方案是如何完成库表权限、列权限、行权限的提取以及组合拼接工作的。

picture.image

2.1 库表权限的的提取

首先介绍一下库表权限的提取,新方案会先对 SQL 进行解析与优化,生成详细的执行计划。此时所有对表的查询操作都会被转化为一个 TableScan 节点,新方案收集执行计划中所有的 TableScan 节点,并从节点中提取到库表信息,基于这个信息就可以拿到 SQL 查询使用的所有库表范围。

以下图中右侧这个 SQL 为例介绍一下库表权限的提取。这个 SQL 在解析、优化之后的执行计划就如右下角所示。在库表权限提取时,会提取这个执行计划中所有的 TableScan 节点 ,也就是下图中右下角标黄的三个节点,并基于这三个节点提取库表信息。以这个 SQL 为例,最终会提取到 table1、 table2、 table3 这三个表信息,这三张表会作为库表层面权限点使用。

picture.image

2.2 列级别的权限提取

接下来介绍一下列级别的权限提取。列级别权限提取遵循 2 条思路:

  • 提取 SQL 最终返回结果对应的列信息,这部分信息会对应用户实际的查询结果,需要对其鉴别列级别权限;
  • 提取两列相等的过滤条件信息,对这些列鉴别列级别权限。

在具体处理层面,新方案依然会先对 SQL 进行解析与优化,拿到详细的执行计划:

  1. 首先会拿到执行计划最外层算子持有的所有列信息,这些列代表了这个 SQL 最终返回结果对应的列信息,这部分信息会被采集起来作为初始搜索列使用。
  2. 其次会提取出执行计划上所有的过滤条件算子,这些过滤条件包含 Filter 算子和 Join 算子,新方案会从这些算子中拿到所有的 Condition 条件,从中筛选出两个列相等的过滤条件,将这些列采集起来也作为初始搜索列使用。
  3. 经过上面两步操作,提取到所有的初始搜索列之后,新方案会依托 ByteQuery 引擎的血缘能力,逐一对上述初始搜索列进行血缘探索,采集这些列依赖的底表血缘列信息,最终这些底表血缘列会作为真正的列权限点被提取校验。

以下图中的 SQL 为例,可以观察下图中右下角的执行计划,一个正常的查询操作,它最外层大概率是一个 Project 算子,这个算子对应的 col1,col2,col3 就是 SQL 最终的返回结果,这三个列会被提取出来作为初始搜索列保存。

另外新方案会提取出执行计划上所有的变量相等的 Condition 条件,这个 SQL 倒数第二行的 t1.col1 = t2.c1 会被提取,这个 Condition 中涉及的两个列也会被提取出来作为初始搜索列保存。

之后新方案会基于血缘能力对这些初始搜索列进行血缘探索,如下图中的特殊颜色标识所示,血缘能力可以帮助用户找到每一个初始搜索列对应的底表列信息。新方案将这些底表列收集起来,这些列就是最终提取到的列级别权限信息,最终提取的列级别权限范围如下图左下角所示。

picture.image

2.3 行级别的权限提取

接下来再介绍一下行级别的权限提取。行级别权限的提取思路为:如果过滤条件中是列和常量相等,这类条件对应的行信息,需要对其鉴别行级别权限。

在具体处理层面,新方案依然会先对 SQL 进行解析与优化,生成详细的执行计划,之后会从 Filter 算子和 Join 算子中提取所有的 Condition 条件,从中筛选出变量与常量相等的过滤条件,然后将这些行采集起来作为初始搜索信息使用。新方案依托 ByteQuery 引擎的血缘能力,逐一对上述初始搜索信息中的变量部分进行血缘探索,采集其依赖的底表血缘列信息,最终将"底表血缘列 = 常量值"这个信息收集起来,作为真正的行权限点提取校验。

以下图中右侧的 SQL 为例,

  1. dt= 20230101 , t1.col2= 'zhangsan' 等信息会被采集为初始搜索信息使用。
  2. 以 t1.col2='zhangsan' 为例,进一步检查 t1.col2 的血缘来源信息,发现它实际来源于 table1.a2 列和 table2.b2 列。
  3. 因此,对于t1.col2='zhangsan'初始搜索信息而言,最终检验的行级别权限点为 table1.a2='zhangsan',table2.b2='zhangsan'。

下图中右侧的 SQL 最终提取到的行权限点范围会如下图中左下角所示。

picture.image

2.4 权限组合匹配

上文已经从粗粒度到细粒度,逐层提取了库表权限、列权限和行权限,最后就需要对这些权限点信息整合成鉴权使用的具体资源。新方案按照表名对上述权限点信息进行组合匹配:

  • 如果表上有需要校验的行 / 列级别权限点,证明这些行 / 列才是用户实际查询的资源,新方案将直接检查该表的行 / 列级别权限;
  • 如果表上没有需要检验的行 / 列级别权限点,出于安全考虑,新方案会对该表检查表级别权限。

下图左侧是新方案上一步流程收集到的库表权限、列权限和行权限信息,经过组合匹配后,三张表上会各挂了一些行 / 列级别的权限信息,这就是这张表上实际采集到的权限点信息。新方案会将这部分权限点信息进行格式化处理,传递给统一的权限服务 Gemini 进行进一步的权限处理。

picture.image

03

行列混合权限多维度精细管控

前文已经介绍了如何在 SQL 解析层面完成权限的精细化提取,下文将介绍如何在权限处理侧完成权限的精细化管控。字节跳动数据引擎团队参考了开源的 Apache Sentry,Apache Ranger 的设计思想后,自研了权限服务 Gemini。Gemini 服务整体将一张表按照纵向列粒度进行权限划分,将权限分为库权限、表权限、列权限三级,并辅助以横向的行限制,最终可以将一张表切分为多个资源方块,并对这些资源方块进行细粒的权限管控,达到权限最小化的目的。

Gemini 的权限管控主要有以下 3 个特点:

  • 在传统的库权限、表权限、列权限之上,新增加了一种行限制权限,行限制权限可以作为一种特殊的资源附属在表权限 / 列权限上面。
  • 每一个表权限 / 列权限可以同时捆绑多个行权限资源,不同表权限 / 列权限的行限制相互独立。
  • 通过 横向行级别 / 纵向列级别 权限点的捆绑组合,将查询资源定位到行列重叠的‘资源单元格’上,达到更细粒度的资源级别权限管控效果。

基于上述特点,Gemini 支持以下 5 种权限粒度:

  • 库权限;
  • 表权限;
  • 表 + 行权限 ( 表 + id=1 行限制权限,效果绿色标示);
  • 列权限 ( age 列权限,效果紫色标示);
  • 列 + 行权限 ( name 列 + id=3 行限制权限,效果黄色标示)。

可以将下图中右侧的二维表格想象成一张 Hive 表,可以看到各个权限粒度的管控范围:

  • 有库权限可以访问库下所有表的数据,可以访问右侧二维表格的所有数据。
  • 有表权限可以访问表中所有行列,可以访问右侧二维表格的所有数据。
  • 如果把行限制附加在表粒度上,就是表 + 行权限,它对应表上横向某行的数据。假如用户拥有 (表 + id=1 行限制) 权限,那么可以访问横向第一行的数据,如图中标绿色所示。
  • 有列权限可以访问纵向该列的数据,假如用户拥有 age 列权限,那么可以访问纵向 age 列数据,如图中标紫色所示。
  • 如果把行限制附加在列粒度上,就是列 + 行权限,它对应表上横向某行和纵向某列交汇的资源单元格权限。假如用户拥有 (name 列 + id=3 行限制) 的列 + 行权限,那么可以访问行列交汇的单元格,如图中标黄色所示。

picture.image

为了方便用户的使用,不同粒度的权限间存在继承关系,继承关系如下:

  • 有库权限,即拥有该库下所有表的权限;
  • 有表权限,即拥有该表上所有的 [表 + 行] 权限,也拥有该表的所有列权限;
  • 有 [表 + 行] 权限,即拥有该表上对应行限制的所有的 [列 + 行] 的权限;
  • 有列权限,即拥有该列所有的 [列 + 行] 的权限。

简单概括:

  • 库权限是表权限的全集;
  • 表权限既是 [表 + 行] 权限的全集, 也是列权限的全集;
  • [表 + 行] 是在该行上 [列 + 行] 的全集 ; 列权限是该列上 [列 + 行] 的全集。

picture.image

下面以一张 Hive 表为例,展示用户在拥有不同粒度权限资源的情况下,最终可访问的数据范围,用户可访问的资源将使用黄色进行标识。

picture.image

picture.image

介绍完 Gemini 侧的权限管控能力后再回到最初的 SQL,左侧的 SQL 是前文一直使用的相对复杂的一个三表查询语句,经过 ByteQuery 层精细的权限点提取后,新方案会在 table1, table2, table3 三张表上各提取到部分行、列粒度权限点。到了 Gemini 层面,用户只需要申请上述三张表上,行列交汇对应的列 + 行级别资源权限即可完成对该 SQL 查询。

通过这样的处理方式,用户只需要申请 6 个列 + 行级别的资源权限,就可以查询左侧这个相对复杂的三表查询语句。用户实际可以访问的资源范围如下图黄色标识所示,可以看到用户申请的权限就是其真正查询的资源,没有申请任何冗余的资源权限,通过这种方式就完成了权限的最小化管控。

picture.image

以上就是字节跳动大数据 SQL 权限精细化管控技术及其在实际业务中的应用实践,我们团队也持续将先进技术、最佳实践提炼并打造成对外商业化产品——火山引擎 湖仓一体分析服务 LAS 对外提供服务,帮助企业轻松搭建大数据云原生湖仓,也有一系列细颗粒度数据权限管控方案,欢迎对这方面有需求、感兴趣的用户来体验,我们提供友好、开发、敏捷的新人上手体验资源与环境。

点击【阅读原文】观看演讲视频。

推荐阅读

开源贡献难吗?

字节跳动 YARN 云原生化演进实践|CommunityOverCode Asia 2023

字节跳动 Spark 支持万卡模型推理实践|CommunityOverCode Asia 2023

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论