我们每天做很多事情,而不需要刻意思考它们。这些机械化的动作或自动化行为基于我们的日常惯例,以及我们随着时间积累信任的信息。我们的惯例可以是简单的,也可以是复杂的,行动通常会分组并分类到不同的逻辑范畴。例如,考虑一下在一天结束前锁门的惯例;这是一个常见的风险防范行为,因为我们不能指望每个人都以我们的最佳利益为出发点。把这种风险防范想象成一个简单的故事:为了防止未经授权的人员进入物理空间(如家、车、办公室等),引入了访问控制(如锁机制)来保护资源(如房子、车子等),并且只有在能够验证信任的情况下,才允许授权进入(如钥匙、凭证)。
从最简单的角度来看,防止入侵的唯一手段是钥匙。虽然钥匙可以通过锁提供对特定物理空间的访问,但钥匙的持有者还必须知道被保护资源的物理位置;否则,钥匙就毫无意义。这是一个典型的场所安全示例,它作为一个思维模型,在构建我们湖仓资源的分层治理和安全模型时是很有用的。毕竟,湖仓是一个保护我们珍贵数据的安全空间,前提是我们共同治理其中的资源。
但究竟什么是数据资源的治理呢?当治理领域有很多组件时,我们该如何开始呢?
注意: 本章为构建湖仓中数据资产(资源)的可扩展数据治理策略提供了基础。虽然我们尽量覆盖尽可能多的内容,但请将本章视为参考章节,仅触及湖仓数据治理的众多组件的表面。例如,我们不会涉及与合规性和区域特定规则(如GDPR、CCPA、被遗忘权政策等)相关的治理,也不会从非工程或非技术的角度讨论一般治理。
湖仓治理
在深入讨论湖仓治理之前,首先介绍现代治理的多个组成部分是非常重要的。原因在于“治理”这个词是一个重载词,依据不同人的理解,它有着不同的含义。因此,为了超越基本的访问控制和传统的数据库级治理,我们需要介绍可以共同构成湖仓治理完整解决方案的系统和服务。
湖仓治理有许多组成部分,如图12-1所示,但从高层来看,我们可以将它们简单地分为身份和访问管理(IAM)服务(1)以及目录服务(2–8)。这样我们可以构建一个更易于采用的工作模型。
例如,除非我们了解谁(或什么)请求访问我们的数据(身份服务),否则我们无法管理使访问成为可能的权限——这就是身份服务与策略之间的联合。此外,如果不将我们IAM服务(1)中的策略和规则与物理文件系统(3)结合起来,我们将无法管理存储在目录元存储(2)中的数据库(模式)、表、视图以及其他资产。鉴于现代数据治理中,元数据管理(2)和物理文件系统资源(3)是分离的,任何湖仓治理的基础都始于以统一、可控的方式进行资源访问权限的委派。
现代湖仓治理包括(4)在每个操作行为的层面上,基于事件日志进行数据管理操作的全面审计,通常通过IAM(1)对目录或元存储(3)中注册的资源进行状态变化的事件日志来捕捉。
通过审计事件日志的基础,集成监控(5)使治理平台能够在出现异常时发出通知,或者当资源不符合要求时(通过追踪和主动监控)。使用类似于审计日志的技术,性能、运行时指标和其他统计数据可以在作业运行期间捕获,从而实现数据质量和系统级别的可观测性。
要实现真正的系统级可观测性,需要连接各个点,包括(7)数据资产的血缘(至少是从目录 -> 模式 -> 表),追踪所有权(谁拥有什么),以及数据的访问、转换和“使用”的位置(即端到端血缘中的位置和点)。了解关键任务表的数据质量目标和活跃数据管道的整体性能,提供了湖仓行为的全景视图。同样值得一提的是,用于审计、性能和可观测性的相同指标可以被重新利用来追踪总体拥有成本(TCO)洞察,尤其是在寻求减少开支或弃用表时非常有用。
我们将在第14章专门讨论数据共享(通过Delta Sharing),但如果没有本章所讨论的集成服务(1、2、3、4、5),包括数据血缘(7),在以成本效益和受治理的方式有效共享单一真实数据源时将变得更加复杂。
最后但同样重要的是,所有辛勤工作的“点缀”是能够将“我们知道的关于数据的一切”结合起来,从而提供强大的数据发现(8)。这一点无疑是当前数据横跨大量孤岛、平台、系统和服务时最普遍的问题之一。
湖仓治理的核心组件包括访问控制、湖仓数据目录和元存储、弹性数据管理、审计日志、监控、数据共享、数据血缘和数据发现。常见的做法是将所有这些组件整合到一个单一的目录解决方案下。接下来,我们将讨论每个组件的作用,并深入探讨每个方面:
访问控制(1)
访问控制提供了通过防泄漏的抽象层来保护和治理湖仓中的数据资产的功能——对于Delta Lake表访问来说,这意味着完全没有直接访问底层存储的权限。如果没有识别用户或服务的能力,就无法批准或拒绝访问,也无法授权创建、读取(查看)、写入(插入)、更新(或插入更新)或删除的权限。没有访问控制的话,一切就像西部荒野一样。
湖仓数据目录和元存储(2)
这一组件使得找到和查看数据资产成为可能,包括目录、数据库(模式)、表、视图、卷和文件,并能治理这些资源的访问和控制权限。目录1提供了关于每个资源的关键信息——定义它的位置(例如在云存储中的位置),以及关联的所有者和与资源类型相关的具体数据,例如每个表的列、约束和表属性(如我们在第5章中探讨的),以及特定于数据库(dbproperties)的元数据,包含一组托管的或外部的表。
因此,访问控制和数据目录是相辅相成的,没有一个就无法有另一个。
弹性数据管理(3)
湖仓架构的最后一个核心组件是数据湖。我们现在知道,Delta协议有助于提供模式强制和演化功能(如第5章所示),并且通过在表级别引入不变量,借助Delta协议,我们减少了数据管理的复杂性。数据湖为元存储中包含的数据库和表提供了弹性扩展性,并通过数据目录广泛提供这些资源。而正如我们将要学习的那样,身份和访问管理在安全治理数据资产中起着关键作用。
结合起来,强大的基础模型可以构建为湖仓提供动力,为其他关键功能铺平道路,包括审计服务、对访问的全面监控,以及生成关于数据操作和行为的洞察:
审计日志(4)
审计日志可以简单到仅捕获湖仓行为的变化——例如,更改角色或策略,影响哪些身份能够在高度受控的资源(如目录、数据库和表)上执行关键操作,如创建或删除。另一个常见的用例是记录关键变化的发生,例如对表进行ALTER TABLE操作(记录操作的表版本),或者表被删除、截断或丢弃。最后,记录因权限失败导致作业失败也是明智的。捕获访问失败的原因是,它有助于揭示哪些工作流(作业、管道)尝试访问可能包含高度敏感数据的资源(因此访问被正确地阻止);相同的过程可以捕捉到权限丧失的情况(可能因其他原因被撤销),这些信息有助于更快地恢复中断的作业。
审计日志可以直接存储在Delta Lake表中,以简化它们与更强大安全工作流的集成,并提供数据源来支持主动监控。
监控(5)
通过审计日志(用于安全目的)以及在目录、数据库和表级别(供工程师、分析师和科学家使用)捕捉湖仓行为,简单来说就是提供度量或事件的记录(时间序列)。假设审计日志存储在Delta Lake中,并且数据资产变更日志也存储在Delta Lake中,这些数据源可以用来创建主动监控解决方案。
监控需要将度量进行汇总并转化为关键绩效指标(KPI),并将事件(审计事件)转化为度量(KPI),以生成洞察。每个KPI提供一个衡量标准,用于理解湖仓中的趋势或特定数据资产的趋势,这对于发出警报(通过提醒或呼叫)或为团队提供中央通信渠道至关重要。监控审计级别事件的一个好起点是查看特定数据资产的访问频率。相同的访问数据还可以用来显示何时数据资产受欢迎、何时很少被访问,或甚至从未被读取或写入。
统一的数据质量指标、访问和权限历史记录以及系统范围内的事件跟踪共同作用,像飞行记录仪一样观察与数据资产相关的变化——将重要的历史时刻与治理堆栈中多个系统和服务的状态结合起来。如果没有适当的监控和审计日志,高级功能如只读数据共享、零副本共享和数据血缘记录将无法发挥其应有的强大作用。
数据共享与零副本共享(6)
我们在第9章首次介绍了数据共享的概念,并将在第14章的整章内容中探讨通过Delta Sharing协议实现的数据共享。数据共享是湖仓治理中的一个复杂组成部分,因为它需要运营成熟度,首先建立一个高信任度的数据生态系统。当我们与控制范围外的用户和服务共享数据时,只有在数据可以直接(原地)读取而不需要从湖仓中导出时,数据共享才会降低成本并减少数据管理开销。因此,Delta Sharing协议要求基础设施(1、2、3、4、5,实际上还包括7)到位,因为管理共享和接收者的加入仅是内部访问管理范式的扩展。
数据血缘(7)
数据血缘可以是主动的或被动的。主动血缘在数据应用运行时自动生成。这可以通过利用框架来记录上游数据源,并通过额外的作业级元数据来实现;成功运行作业时,它会自动创建并维护下游资源的元数据。与主动血缘不同,被动血缘讲述的是过去发生的事情和可能发生的事情。这意味着血缘信息是在离线状态下注册和记录的,在作业运行时不会直接修改或同步。
每个数据应用(管道、工作流、流式或批处理)从一个或多个源(通过读取)获取数据,转换数据,然后将其(通过写入)发送到湖仓内外的其他位置(表),或者流处理器(如Apache Kafka或Pulsar)。通过我们对每个数据应用的了解,我们可以构建方向性血缘图(DLAG),并利用血缘数据在源中发现故障或数据质量问题时运行下游影响分析。我们将在第13章更广泛地讨论数据血缘。
我们捕获有关可观察状态变化、操作和关键数据资产的行动的数据,以创建已发生的历史记录。这些信息有助于管理合规性审计(如GDPR、CCPA等)、识别风险、跟踪数据质量随时间的变化,并在期望偏离时采取行动,甚至可以自动化警报,定位数据中断。
数据发现(8)
数据发现的使用方式取决于企业中的不同角色,通常分为面向工程的数据库发现和面向业务的数据库发现。
第一类能力更侧重于数据资产(数据库、表、*查询、*仪表板、*监控、*警报)在湖仓内部的架构存储库,主要面向工程师、科学家和分析师。第二类则更像是一个跨越多个数据源和子组织的组织搜索引擎。第二种数据发现引擎的常见角色是面向业务用户,他们正在寻找尚未位于湖仓中的数据。
数据发现成为一个至关重要的组成部分,确保不同角色可以迅速识别出开始工作的最佳起点——无需通过一系列冗长的会议或复杂的协调努力。通过重新利用对特定表访问频率的洞察(来自审计[4]),以及基于用户反馈的可用性评分(1-5),还可以定义数据资产的流行度评分(或数据NPS评分),以帮助根据使用情况和总体可用性来呈现数据资产。
正如任何数据工程师都会告诉你的,运行时可能会发生各种问题——例如,数据资产的访问权限可能会被撤销(无论是出于正确还是错误的原因),导致数据管道失败或性能下降。表格可能被弃用,进入只读模式,不再更新,甚至可能被意外删除(没有适当的治理检查和平衡)。如果没有清晰的权限、更改历史记录、表状态或已建立的沟通模式来向数据利益相关者传达状态变化或降级,信任就会受到破坏。
没有明确的沟通线路,信任容易被打破。数据治理是维持高信任环境的一种方式,提供可靠的工具和服务,不仅仅限于安全性和合规性,还能帮助连接不同的数据团队,共同解决复杂问题。
注意
本章略过了地区性数据治理和合规性规定,以及跨区域数据访问的设计模式。这些话题不在本书的范围内,但它们仍然是任何完整治理解决方案的核心要素。然而,本章讨论的主题将有助于您实现合规。对于那些希望深入研究数据治理主题的读者,请参考Ole Olesen-Bagneux的《The Enterprise Data Catalog》(O'Reilly)。
数据治理的出现
数据治理被定义为一个涵盖各种原则和实践的总括性框架,结合了工具和工作流,以治理组织的数据资产,贯穿其完整生命周期。数据的生命周期包括从创建到删除的全过程,涵盖所有的转换,以及在整个过程中任何时刻的数据访问和使用。
通过Delta表的视角来考虑数据生命周期:
我们的数据通道就是表本身。
每个表提供一个容器,存储一组有限或无限的数据集,并伴随有一个事务日志,记录每次对表的修改,包括是谁、做了什么、在哪里以及如何进行的变更。
表不是凭空出现或消失的。每个表首先必须被创建,数据行必须被插入、读取、修改或删除,最后,表也必须被删除(丢弃)才能完成整个生命周期。
为了扩展表级数据生命周期管理的范围,图12-2提供了一个简单的示意图,展示了从数据创建到归档,最终到销毁的常见步骤。
与其他常见的周期(如软件开发周期)类似,常见的数据生命周期从 (1) 创建开始,接着是 (2) 存储,(3) 使用,(4) 分享,(5) 归档,最终到 (6) 销毁。这个生命周期封装了在资源层面上发生的完整操作和行动历史(时间线)。
这些可观察的时间点对于数据治理至关重要,同时也对于工程师从维护和可用性的角度管理表格非常重要。每个表都是一个可以治理的资源,称为数据资产。
注意
在这里使用“资产”这个术语是很重要的。数据资产(表)由代表组织的个人(或团队)直接拥有、管理和治理。该组织则提供资金来管理数据资产,并支付负责各个方面的团队成员,包括工程、产品、安全、隐私和治理等。
作为经验法则,数据资产应当仅在它们仍然提供价值时才被维护。当我们将数据视为只在不再有用时才被销毁时,数据生命周期管理变得更加合理。
我们在第9章中学习了数据质量的金字塔架构。这种新颖的设计模式介绍了三层数据精炼方法,从铜(bronze)到银(silver),再到金(gold)。这种架构在我们考虑随着时间推移如何管理数据资产的生命周期时,起到了实用的作用,并且在我们考虑数据在某一特定层级上保留多久时,也提供了有力支持。
借助图12-3,我们可以可视化数据资产随着时间推移以及跨越铜、银、金等数据质量逻辑边界的精炼过程。
图12-3展示了一个经过精心策划的数据产品(表格G)的源表及其转换的血缘关系。从金层(gold)数据资产向后追溯,我们看到随着血缘关系回溯至银层(D–F),表格的价值逐渐降低,最终回到我们的铜层数据资产(A–C)。为什么从概念上来说,单个表格比之前的六个表格组合更有价值?
简而言之,构建、管理、监控和维护表格G的数据资产依赖关系的复杂性,意味着它所代表的成本要高于各个单独部分的成本。考虑到铜层数据资产(A–C)所代表的原始数据,预计它们只会在需要进一步访问、精炼、连接或由直接下游数据消费者(D–F)使用时存活,而同样的预期也适用于银层数据资产,它们只能在需要的情况下存在,并且随着数据链条向下延伸,必须简化并提高数据质量。
通过数据产品的视角来思考端到端的血缘关系是一种有益的方式。
注意
对于那些没有通过传统的金字塔架构进行精炼的数据,例如你可能有Salesforce数据被引入到数据湖中。由于这些数据已经适合用途且质量较高,因此可以合理地说这些数据直接被引入到精心策划层(gold)。在大多数情况下,当数据被精炼时,它会为企业增添更多价值。
数据产品及其与数据资产的关系
“数据产品”这一术语指的是构建、生产和管理给定精心策划的数据产品所需的代码、数据、元数据,以及逻辑基础设施。图12-4详细展示了代码、数据和关于数据的数据(元数据)之间的交集,以及运行和提供数据产品的基础设施。
Zhamak Dehghani在她的架构范式“数据网格”(data mesh)中首次提出了数据产品的创新理念,她建议,任何精心策划的数据产品必须是专门构建的,并且能够直接使用,无需额外与其他表进行连接。3 换句话说,生产数据产品的成本和努力应该完全由数据产品的消费者来承担。这条规则有助于将“数据产品”与“服务”联系起来,而服务本身就是生产有用、适用的数据。你仍然可以将来自不同数据产品的数据进行连接,以创建新的数据产品,但事实是,数据产品的消费者无需进行额外的连接,就能将其用于他们的目的。
从逻辑上讲,我们也可以假设,数据产品必须依赖一个或多个数据资产。因此,当我们讨论数据资产和数据产品时,最终我们是在讨论对组织具有足够价值的数据,这些数据经过精心设计、构建、测试、发布、监控和维护,以生成一组包含特定数据产品的有价值数据资产。如果这种严格的要求和对运营的承诺让你想到了传统的软件项目,那么这是正确的。
创建高质量的数据要求工程师遵循标准的软件开发生命周期(SDLC)。这本质上意味着,在数据产品生命周期中,设计时需要确保“没有惊讶”的运行时行为。
湖仓中的数据产品
鉴于组织通过大规模的数据摄取网络生成的数据量似乎不断增加,并且这些数据之间的依赖关系图越来越复杂,因此,湖仓必须提供通用能力来跟踪高度有价值的数据资产的生命周期——无论是流式数据还是静态数据。
这意味着必须能够追踪数据资产的元数据,包括上游依赖关系,以及任何下游数据资产的依赖关系。这对于下游消费者尤其至关重要,他们必须理解并应对数据量的变化,以及给定源或表的模式和结构的修改,还必须考虑到数据生产的频率等其他预期和要求。
保持高信任度
为了维持对数据产品的隐性信任,我们必须确保为数据产品提供明确且有意附加的元数据——包括数据血缘、数据质量和端到端数据可观察性的结合。例如,通过展示所有涉及生产某个关键表格的过程都遵循相同的纪律,我们可以确保数据消费者获得足够的信息以建立信心,这种做法也会建立起一个高信任的环境。你也可以说,高信任是严格遵循规范和流程的结果,这些规范和流程共同作用,创建了高保真的数据产品。最近,数据管理人员和数据产品负责人也已经合作,确保信任成为数据生产者与数据消费者之间合同的一部分,从而为数据产品的使用者和提供者之间的合作提供了人性化的保障,除了依赖度量和监控指标之外。
如果我们退一步考虑,需要什么工具、工作流程(湖仓编排)、元数据、过程、架构原则和工程最佳实践来管理包含在Delta表中的数据,这些数据代表着从数据摄取到删除的整个数据历程,涉及多个系统和服务、用户及其角色、数据分类和访问策略,以及代表数据管理最佳实践的精心策划的数据产品,我们很快就会意识到,现代数据治理的范畴和规模有多大。
数据资产与访问
在传统数据库管理的早期,并没有像今天的数据治理组织那样,有专门的团队负责管理组织如何高效地收集、摄取、转换、编目、标记、访问和弃用数据;相反,数据库访问管理的责任通常由数据库管理员承担。这个管理员负责授予用户权限、运行高成本的查询,并确保数据库持续运行。
用户或用户组可以执行哪些操作的治理,通常是通过权限来管理的,使用以下SQL语法组:数据控制语言(DCL)、数据定义语言(DDL)和数据操作语言(DML)。接下来,我们将讨论数据资产模型。
数据资产模型
在湖仓中,资源的治理通常描述了一个策略与一个称为数据资产的可治理对象之间的关系。在最简单的传统意义上,数据资产就是一个表(TABLE)或视图(VIEW),而策略则是一个GRANT权限。包含表资源的数据库或模式也是一个数据资产,因为策略通过GRANT权限授予一个用户(称为“主体”)对数据资产(数据库、表或视图)执行操作(例如展示或选择)的权限。在任何主体能够对资源执行操作之前,必须首先创建数据资产。
这个数据资产模型如图12-5所示,它适用于任何需要通过常见SQL权限进行访问和使用控制的可安全管理的对象。
一个主体可以在数据资产上执行的操作和行为是通过数据定义语言(DDL)和数据操作语言(DML)来管理的。数据定义语言(DDL)包括CREATE、ALTER、DROP操作,数据操作语言(DML)包括INSERT和UPDATE操作,而通过数据控制语言(DCL)中的GRANT和REVOKE语句管理一个或多个操作和行为的执行权限。
如今,数据资产已经发展到不仅仅包含传统的数据库表或视图,还包括其他需要访问和使用控制(授权)策略来管理的资源,例如仪表板、查询(这些查询又是仪表板的核心)、笔记本、机器学习模型等。
通过SQL GRANT管理数据访问
SQL类系统中的操作治理通过DCL、DDL和DML的语法进行管理。以下是这些能力的简要回顾。
数据控制语言(DCL)
这种特殊语法用于SQL类系统中的访问管理。通过使用GRANT和REVOKE操作,将一组授权的操作(权限)与一组用户(USER)或角色(GROUP)关联,允许它们执行DDL和DML定义的操作,或者撤销之前授予的一个或多个权限。
GRANT权限的语法根据数据库的不同而有所不同,但一般都支持ANSI-SQL标准语法:
% GRANT priv_type [(column list)]
ON [object_type]
TO user_or_role, [user_or_role]
控制用户或组可以执行哪些操作不仅是简单的加法。许多情况下,权限是仅在有限时间内授予的,然后再被移除。为了满足授予临时权限的要求,可以通过REVOKE语法撤销权限:
% REVOKE priv_type [(column list)]
ON [object_type]
TO user_or_role, [user_or_role]
数据定义语言(DDL)
这种语法提供以下标准操作:CREATE、ALTER、DROP、COMMENT和RENAME。我们在第五章中直接使用了DDL操作,也通过使用Delta Scala、Python和Rust配套库间接使用了DDL。我们学习了如何创建和修改表、修改列的注释,甚至在不需要时删除表。
CREATE语法用于定义可治理的数据资产。以下是标准SQL CREATE语法的示例:
% CREATE [OR REPLACE] TABLE [IF NOT EXISTS] table_name (
[column_name, type, ...]
) USING DELTA
TBLPROPERTIES ('key'='value')
CLUSTER BY (...)
ALTER语法用于修改可治理的数据资产。以下是如何修改表的属性以及如何向现有表中添加列的示例:
% ALTER TABLE table_name
SET TBLPROPERTIES ('key'='value')
% ALTER TABLE table_name
ADD COLUMNS (
[column_name, type, ...],
)
数据操作语言(DML)
这种语法提供了对资源执行标准操作(SELECT、INSERT、UPDATE和DELETE)的权限:
% select [column,] from [table or inner select]
[where,] [group by,] [having,] [order by], [limit]
DCL与DDL和DML结合使用,允许将权限授予用户或组,使其能够执行由DDL创建的资源上管理的一些或所有操作,并执行由DML启用的操作。
尽管数据操作的规模和数量在全球范围内不断增长,但使用简单的GRANT和REVOKE权限来控制数据资产的访问和授权,仍然是采用统一治理策略的最简单路径。然而,当我们开始考虑与那些根本不支持SQL的系统和服务进行互操作时,问题几乎立刻出现。
统一数据仓库与数据湖的治理
在前面的部分中,我们发现传统的数据治理能力始于SQL数据库中添加DCL语法,这使得通过使用GRANT和REVOKE语句来允许或拒绝访问特定资源成为可能。
通过使用GRANT语句,授权与特定用户或角色相关联的特定权限,从而允许在受保护资源(数据资产)上执行一组操作。使用DCL进行的访问治理适用于传统的孤立数据库(如MySQL和Postgres),以及通过Databricks、AWS、Snowflake等供应商提供的现代数据仓库。
然而,在使用传统的SQL GRANT进行湖仓治理时存在一个挑战:并不是所有系统和服务都理解SQL。更糟糕的是,我们无法简单地使用单一的治理模型来保护所有数据资产。
考虑到一个简单的事实,湖仓的表面下方仍然存放着一个传统的数据湖。这意味着我们需要处理底层数据的权限和访问模型,以便提供一个类似SQL的接口来统一湖仓的治理。
权限管理
湖仓的表面下方就是数据湖。正如我们现在所知道的,数据湖是一种数据管理范式,帮助组织原始数据,使用的是传统文件系统中的原始结构。在大多数情况下,使用云对象存储,并且在这些弹性系统的根目录下是包含对象的桶(bucket),其结构是扁平化的。
桶(bucket)封装了一个资源根目录“/”,表示一个逻辑结构,类似于标准文件系统,但存在于云对象存储中。图12-6展示了桶的组成部分。例如,从根目录开始,我们有顶层目录(路径和分区)及其底层文件。
每个目录包含一组非结构化(原始)数据——如日志文件、图片、视频或可共享的资产(如配置文件(properties、YAML、JSON等)和库(JAR、wheels、eggs))——以及我们的结构化但未经处理的数据。
提示:
对于结构化数据,建议使用一个知名的基于行的格式,如Apache Avro或Google的Protobuf,或基于列的格式,如Apache Parquet,这些格式可以通过Delta实用工具简单地转换为Delta的表格式,如下所示:
% from delta.tables import *
deltaTable = DeltaTable.convertToDelta(
spark,
"parquet.`<path-to-table>`")
除了所有其他类型的非结构化和结构化数据外,数据湖还存储我们的管理(或未管理)Delta表。因此,在后台存储了许多可能类型的文件。
理解如何保护底层文件系统免受未经授权的访问对于湖仓治理至关重要,幸运的是,SQL-like权限与经典操作系统(OS)文件系统权限共享相似的数据管理范式——文件和目录的访问是通过用户、组(类似于角色)和权限来控制的,允许读取、写入和执行操作。
文件系统权限
我们笔记本上的操作系统与我们在远程服务器上配置的操作系统共享相似的访问和委派模式。例如,操作系统负责监督有限资源(计算、内存、存储)在许多短期和长期进程(操作)之间的分配。每个进程本身是执行命令(操作)的结果,执行与用户、组和权限集相关联。使用这种模型,操作系统能够构建简单的治理规则。
让我们通过实际的 ls 命令来看一个例子:
% ls -lah /lakehouse/bronze/
该命令的输出是文件系统资源(文件、目录)的列表及其元数据。元数据包括资源类型(文件或目录)、访问模式(权限)、引用(依赖于此资源的资源)、所有者(用户)和组关联,以及文件大小、最后修改日期和文件名或目录名:
- 文件类型
由单个字符表示。文件用-表示,目录用d表示。 - 权限
包括读取(r)、写入(w)和执行(x)。权限分别为资源所有者、特定访问组以及其他所有人(称为其他用户)管理。 - 引用
跟踪有多少其他资源链接到此资源。 - 所有者
每个资源都有一个所有者。所有者是操作系统中的已知用户。资源的所有者拥有完全控制权,可以通过分配组级权限来管理其他用户和进程的交互。 - 组
用户可以与一个或多个组关联。组使多个用户和进程可以一起工作,同时限制某些特权。在操作系统上下文中,组类似于数据仓库中的角色。对于每个资源,可以为特定组授予权限(除了资源的所有者),并且对于未知的组成员,也可以应用默认权限。
当所有这些元素结合在一起时,我们可以开始看到文件系统权限与它们如何应用于湖仓治理之间的联系。考虑以下示例输出,它告诉我们关于 ecomm_aggs_table 的信息:
% ls -lh /lakehouse/bronze/ecomm_aggs_table/
drwxr-x-–-@ 338 dataeng eng_analysts 11K Oct 23 12:53 _delta_log
drwxr-x-–-@ 130 dataeng eng_analysts 4.1K Oct 23 12:34 date=2019-10-01
drwxr-x-–-@ 130 dataeng eng_analysts 4.1K Oct 23 12:34 date=2019-10-02
首先,_delta_log 目录告诉我们我们正在查看一个Delta表。它由名为 dataeng 的用户拥有,拥有完整的读取、写入和执行权限(rwx)。此外,该表可以被 eng_analysts 组的成员读取和执行,但该组的成员无法修改表,因为他们仅授权为只读访问。对于操作系统中的任何其他用户,他们在尝试与此路径下的文件交互时会收到异常(未授权)信息。
类似的权限模型也可以应用于我们的云对象存储。主要区别在于我们如何识别用户和管理组。
云对象存储访问控制
数据湖的存储与计算分离确保了我们的数据资产的位置与运行计算进程的服务器之间有物理边界。如果我们深入探讨这种关注点分离,我们还会发现,我们实际上与传统操作系统级别的用户权限模型相隔离,因为绑定到本地计算进程的用户(身份)在没有添加密钥(或令牌)的情况下无法直接为对象存储所识别,密钥或令牌向远程进程表明我们确实被授权执行某个操作。这个密钥有助于识别请求并授权一个简单的规则集,以允许或拒绝请求的操作,形式为远程执行(读取、写入或删除)。
在没有共享操作系统的情况下,我们在处理数据(计算)与存储数据的地方之间建立信任关系,利用身份验证。身份帮助我们回答以下问题:
- 给定的运行时进程的身份(用户)是什么,它如何应用于传统的用户权限模型?
- 如何使一个或多个云端资源可以被访问?
- 一旦身份被确认,如何授权特定的操作和操作行为?
这一范式不再依赖于经典的文件系统权限(用户、组、权限),而转向一个更灵活的系统,称为身份和访问管理,简称IAM(Identity and Access Management)。
身份与访问管理 (IAM)
如果你听到有人敲门,你会开门吗?你会让陌生人进来吗?IAM(身份与访问管理)存在的原因是确保在一个不明实体(它可能并不像它声称的那样)和你的内部系统之间建立一种基于信任的相互关系。那么,在动态的云环境中,我们如何识别用户、系统或服务呢?
身份
每个身份代表一个用户(人类)或一个服务(API、管道作业、任务等)。身份不仅涵盖了个人用户,还包括服务主体,这些服务主体通常被戏称为“无头用户”,因为它们不是人类,但仍代表系统代表用户执行操作。身份像护照一样,证明用户的合法性。此外,身份用于通过策略将用户与一组权限关联起来。
通常,会为个人用户颁发访问令牌,并且也会为服务主体颁发长期令牌和证书(certs)。
身份验证
虽然身份可能是合法的,但身份验证的目的就是确保这一点。大多数系统会为身份颁发(生成)密钥或令牌,并且这些密钥或令牌的有效期通常是有限的;这迫使身份定期重新进行身份验证,证明它们仍然是合法的。如果是恶意行为者(黑客、伪装者)试图重用他们为非法目的窃取的令牌,那么短时间的令牌有效期(TTL)将限制被盗身份的潜在影响。作为经验法则,系统越安全,令牌的TTL通常越短。
授权
身份和身份验证机制结合在一起,确保用户不仅仅是冒名顶替者。这两个概念与授权过程紧密相关。授权类似于GRANT权限。我们可以假设用户的身份已经通过验证(因为他们已经通过了验证,证明了自己确实是他们所声称的人),他们能够进入资源的物理位置(使用密钥、证书或令牌访问数据资产)。授权过程就是用户与一组策略文件之间的桥梁,这些策略文件描述了用户在给定系统中可以执行的操作。
访问管理
简而言之,访问管理就是提供控制数据访问的方法,执行安全检查和平衡,它是治理的基石。访问控制提供了一种手段,用于识别可以在特定资源(数据资产、文件、目录、机器学习模型)上执行哪些操作和行为,并基于策略批准或拒绝这些操作。
创建用户(身份)、发放凭证(令牌)、认证和授权访问资源的整个过程,其实与GRANT机制非常相似——而其反向操作是REVOKE,即使当前凭证失效。没有能力移除身份,过程就不完整,这也完成了全生命周期的访问控制。
IAM提供了实现类似GRANT权限管理的缺失能力,通过使用身份和访问策略来管理我们的数据湖资源。
在下一节中,我们将探讨访问策略,并了解基于角色的访问控制如何通过使用角色(或行为主体)简化数据访问管理,我们还将学习如何创建和使用策略代码。
数据安全
在治理体系中,有许多不同的组成部分。为了有效地扩展解决方案,必须在开始阶段或在现有解决方案中仔细整合一些重要的规则和工作方式。
例如,你可能听说过“鸭子测试”:如果它看起来像鸭子、游得像鸭子、叫得像鸭子,那么它可能就是鸭子。这指的是我们能够对不熟悉的事物进行推理,并将其归类为“我们已知的事物”。针对我们湖仓中操作的不同角色或行为主体,我们可以使用修改版的“鸭子测试”来创建有限数量的角色,以识别谁拥有对哪些数据资产的访问权限,这是走向更复杂的身份验证策略生成的第一步。
基于角色的访问控制 (RBAC)
基于角色的访问控制(RBAC)用于批准或拒绝系统访问,并授权特定角色在资源上执行特定权限,以履行其职责。
对于湖仓,考虑一下我们在日常工作中扮演的角色(工程师、科学家、分析师、业务职能),我们所在的团队和组织,我们业务的逻辑划分(这有助于建立数据域),我们系统、服务和数据产品的运行环境(开发、测试、生产),以及最后,我们管理和访问的数据的分类(完全访问、限制访问、敏感、极敏感)。有时候,角色所体现的界限可能会有些模糊,因此RBAC中的“R”有时也可以表示“资源”。
让我们通过一个故事来理解RBAC。为了故事的需要,假设我们都在一家全球连锁超市“Complete Foods”工作,销售本地有机食品。Complete Foods不仅在线销售产品,也在实体店销售,每个店铺都位于特定的地区,购物趋势因地区、季节不同而有所差异。这意味着,尽管所有商店都在同一个公司旗下运营并且共享大多数相同的产品,但由于商店所在位置的不同,区域库存、供应商关系、销售数据和客户情况会有所不同。
然而,要求访问湖仓数据的员工角色和职责将保持一致,访问权限的级别将基于需求和理由(使用场景),并且在访问高度机密数据或需要访问客户数据进行营销和广告活动时,还需接受数据隐私、治理和主权的培训。
角色不是人。每个角色可以由人或服务承担。重要的是从简单开始,明确“谁、什么、哪里、如何”。
基于角色的访问控制(RBAC)角色建立
当我们抽象出与组织中常见角色相关的角色时,理解“谁、什么、哪里、如何、为什么”会变得更加简化。让我们来看看组织中常见角色的一些划分标准:
工程角色
这可以应用于硬件、软件、安全、平台、数据和机器学习等领域的任何开发者角色,包括无头用户。责任包括维护销售系统(线下和在线)、编写和维护移动应用程序、定义事件数据、建立数据捕获和摄取网络,以及处理信用卡号码和用户家庭地址等个人数据,学习客户购物习惯,以确保在适当的地区和适当的季节提供正确的产品。
访问模式:所有(读取、读写、管理员)
角色名称:role/developerRole
分析师角色
包括商业分析师或专家。此角色负责与业务和工程团队合作,确保有正确的数据可用,以准确捕捉关键的业务操作,并通过生成见解来帮助决策,例如何时将南瓜香料产品重新上架,或在不同地区提供哪些非乳制奶类产品。
访问模式:主要为只读数据,能够创建和分享查询、构建仪表板、分析历史数据或新兴趋势
角色名称:role/analystRole
科学家角色
包括数据科学家和行为科学家。职责包括与工程师和分析师合作,确保正确的数据按时流入正确的位置,为推荐和其他推理模型提供动力。
访问模式:主要为只读,能够创建表格以支持模型训练并捕获测试和实验结果
角色名称:role/scientistRole
业务角色
包括经理、主管、人力资源,甚至是领导层。此角色负责建立和维护Complete Foods品牌,涵盖了本地和全球的责任,以及区域店经理或采购员,所有这些人都需要访问销售数据、预测数据以及与员工或其他业务领域相关的数据。此外,工程领导层将需要不同于工程经理和主管的访问权限和能力。
访问模式:主要为只读;人力资源可能需要创建、修改和删除员工数据
角色名称:role/businessRole
授权访问湖仓中给定数据资产(资源)的过程可以通过以下几个方面的联合来确定:
- 用户的角色和职责(谁和什么)
- 资源的位置(桶和前缀)(哪里)
- 他们操作的环境(开发、测试、生产)
- 数据分类(一般访问、限制访问、敏感等),说明了“什么”
- 操作(行为):读取(查看)、修改(读写)、或管理员(读取、写入、创建或删除)(如何)
所以记住:我们始终需要牢记“谁、什么、哪里、如何”,以及“是否”应授予访问权限。
可以这样理解:如果我们授予一个身份(谁)访问权限,那么(什么)操作是实现给定任务所需的(如何),他们需要在哪个环境中(哪里)获得用户级访问权限还是无头用户访问权限?最后,授予读取级别与读写级别访问权限可能带来的潜在风险是什么?
此外,除了是否应该授予访问权限的考虑,另一个必须始终牢记的问题是,身份是否被允许查看(读取)表中所有的数据。通常,数据会根据安全性和隐私考虑划分成不同的组,以便进行访问控制。
接下来,我们将探讨数据分类模式。
数据分类
以下分类器是识别数据湖中特定位置存储的数据类型的一种有用方式。
作为一个简单的抽象,我们可以将数据分类视为交通信号灯模式。交通信号灯指示驾驶员继续前行(绿灯)、减速(黄灯)或停车(红灯)。作为类比,当我们考虑如何管理对数据资产的访问时,交通信号灯模式提供了一个简单的思维模型,帮助我们为数据打上标签,区分其为绿色、黄色或红色。
当不确定分类时
每个组织处理的数据类型都不同。如果不确定,可以考虑如果某个数据集(例如表格、原始数据等)泄露到公共领域,可能对公司造成的损害。鉴于个人用户数据的严格法律规定,一些数据将自动被归为黄色或红色分类。例如,GDPR、CCPA和SOC2等法规提供了指导方针,可以帮助你在这方面做出决策。每个公司都必须遵循这些标准,通过政策来定义标准,帮助确保正确操作。随着你处理不同的数据集,直觉上你会越来越容易判断什么是合适的。
例如,访问被分类为“绿色”的数据可以自动化,只要确保数据资源不会泄露敏感数据。例如,美国地质调查局(USGS)提供的地震和灾害数据就是一个“绿色”的实际例子,它通常对公众开放。
对于被分类为“黄色”或“红色”的数据,授予访问权限时需要考虑谁有权访问,为什么需要访问以及访问时长,以及这种访问如何可能对组织产生益处或危害。当不确定时,始终考虑“是否”。如果我们授予这个数据的访问权限,我们是否信任访问者做出正确的决策?
建立规则和统一的工作方式可以帮助确保数据按照统一的标准分类,从而将决策过程变得更加科学:
一般访问
这个分类假设数据对一般受众可用。例如,假设Complete Foods认为通过允许Instacart、Uber Eats和DoorDash等服务访问我们的库存数据,可以销售更多的杂货。通过开放访问——注册、获取令牌并访问Delta共享端点——我们可以确保任何外部组织都可以访问与“通用访问”角色相关的特定表格,并且这些访问权限仅限于只读。
信号灯模式:绿色访问级别
限制访问
这个分类假设数据是只读的,且访问权限基于“需要知道”(使用)原则进行批准。继续前面的Complete Foods例子,虽然通过“通用访问”分类使外部服务能够访问库存数据,帮助拓展我们的杂货业务和品牌,但有些数据代表了我们的竞争优势,必须保持仅供内部使用,或仅限于外部域访问。
例如,假设我们有一个公开的产品价格(在店内和通过我们的合作伙伴服务),但我们也有一个内部价格,代表了获取某个产品的实际成本。在大多数情况下,我们不希望公开差价(即获取商品的成本和销售价格之间的差额),因为这代表了我们的竞争优势,以及非常真实的定价谈判。
信号灯模式:绿色、黄色或红色访问级别
敏感访问
这个分类适用于任何敏感数据。敏感数据如果泄露,将对组织造成损害,但它不包含如信用卡号、社会保障号码、工资信息或医疗健康信息(这些会导致HIPAA数据合规问题)。敏感数据可能包含个人身份信息(PII),例如用户的姓名、地址、电子邮件地址、生日、供应商信息(例如我们购买农产品的农场),以及与企业运营相关的其他数据。敏感数据还可能包含消费者行为数据,但不会暴露用户的姓名、地址或其他PII。如果每天的汇总数据在泄露后可能造成损害,例如如果数据表明公司季度销售数字呈下降趋势,即便这些趋势以百分比而非实际数据形式呈现,仍然会对公司声誉造成损害,这种数据应当被标记为“极为敏感”。
信号灯模式:黄色或红色访问级别
极敏感访问
这个分类适用于组织和用户可访问的最为敏感的数据,包括员工工资信息、公司财务记录、用户信用卡数据、医疗保健数据、家庭住址等。访问这些数据资产通常需要完成内部培训,并提供完整的访问审计记录。许多这样的数据通常仅限于人力资源(HR)部门、薪资部门及公司内部的特定行为主体使用。
信号灯模式:红色访问级别
现在,我们已经确定了与数据访问相关的基本角色和身份(例如developerRole、analystRole、scientistRole、businessRole),以及数据的常见分类(如通用访问、限制访问、敏感访问、极敏感访问),接下来可以将身份和数据访问策略以及策略作为代码(Policy-as-Code)联系起来。
使用前缀模式促进组织成功
在S3存储桶和策略方面,我们可以做的最有用的事情之一就是提前花时间整理数据湖,以简化如何管理Delta表。这通常涉及设置一个S3存储桶、添加一个仓库目录,并希望团队能做正确的事情。然而,前期工作应该包括设置一些关键模式,确保跨环境、顶层目录、各个数据库(模式)及其底层表之间的无缝运行时执行,同时为数据应用及其元数据、库和配置提供专用空间。
让我们来看一下示例12-1中的湖屋结构。
示例 12-1:探索湖屋命名空间模式
arduino 复制代码 ├── s3://com.common_foods.[dev|prod] └── common_foods ├── consumer │ ├── _apps │ │ └── clickstream │ │ ├── app.yaml │ │ └── v1.0.0 │ │ ├── _checkpoints │ │ │ ├── commits │ │ │ ├── metadata │ │ │ ├── offsets │ │ │ └── state │ │ ├── config │ │ │ └── app.properties │ │ └── sources │ │ └── clickstream_app_v1.0.0.whl │ └── clickstream │ ├── _delta_log │ ├── event_date=2024-02-17 │ └── event_date=2024-02-18 ├── {table}湖屋命名空间模式允许我们将数据应用与它们生成的物理Delta表放在一起。这减少了管理基础事项(如基于团队的访问控制、业务级数据管理等)所需的策略数量,同时也简化了访问权限管理,比如访问哪个环境的问题。当一切设置正确时,开发环境可以作为新想法的试验场,使用模拟数据并结合匿名的生产数据进行构建(此处存在更高风险,因此需要遵循“谁、什么、哪里、如何、为什么、如果”规则)。通过物理存储桶将两个环境分开,使得遵循交通信号灯模式变得更加容易,因为开发和预发布环境通常是全开放的,而我们的生产环境几乎总是合理地属于黄色或红色访问级别,特别是涉及到个人数据时。
回顾本章前面提到的文件系统所有权模式,我们为给定的资源(如文件、应用、目录)提供顶级所有权,默认为管理员,然后为批准的身份提供“只读”的组级访问,而对其他人的访问则被直接阻止。
这种为负责数据领域的工程师提供默认组成员身份的模式,以及为特定领域提供关键数据的应用,应当作为新成员入职流程的一部分,在他们经过培训并熟悉公司工作方式后进行安排。
从示例12-1提供的湖屋布局中,我们可以看到在
common_foods目录下的consumer分类下,包含了一个clickstream数据应用及其相关的表资源。以下是这些目录的内容:元数据(app.yaml)
这可以包括资源配置和其他重要的应用元数据,例如拥有团队、PagerDuty或Slack频道信息。此外,app.yaml还可以包含任何运行时要求,如CPU核心数、内存、最小和最大执行器数量、访问策略等。
源代码库( .whl, .jar,*.py等)
这些库可以直接发布到S3存储桶中;或者,如果你正在使用容器化的数据应用程序,所有应用所需的资源可以写入容器文件系统层。
配置(app.properties,spark.conf)
应用配置可以通过Kubernetes的ConfigMaps传递给应用程序,或者通过传统Spark应用的
spark.conf或spark.properties进行提供,或者以任何你支持的配置类型进行传递。重要的是,对于每个版本(例如示例中的v1.0.0),所有资源都是自包含的。这种模式使得如果出现错误(我们都犯错误),可以轻松回滚到“最后”一个版本,而不会破坏检查点(保持正常运行的版本)。流处理检查点(_checkpoints)
此集合包含有状态应用程序的元数据(结构化流处理或其他)。例如,如果我们的上游是另一个Delta表,
_checkpoints将包含最后一次从Delta读取的版本(存储池版本)以及接收信息,包括最后一次“观察到”的提交版本。表元数据和物理文件
Delta表是数据产品的一部分,以减少管理所需的策略、文件和角色数量,使得团队能够在湖屋中操作。
所有应用资源都使用简单的命名空间模式来定位,S3前缀格式为
{catalog}/{database_or_schema}/_apps/{app_name}/*,并且所有版本化资源和资产都包含在语义版本化发布(如v1.0.0)中。当我们将持续集成和持续交付(CI/CD)与包含数据应用的GitHub存储库连接时,应用的版本可以与Git发布的Git标签进行关联。这还使得在出现故障时能够自动回滚到当前发布版本的前一个版本。Delta表的实际配置
接下来,我们来看实际的Delta表。我们的数据应用的输出表位于与数据应用相同的相对路径下。数据应用和表的共同父目录是特定目录中的数据库(或模式)。但在某些情况下,这种模式可能不可行,特别是当数据应用从多个bronze表读取并生成一个silver级别的输出表时。
对于我们的应用配置,以Spark为例,我们可以设置配置属性
spark.sql.warehouse.dir=s3://com.common_foods.prod/common_foods,以使我们的应用程序能够读取或写入包含在common_foods目录下的表。
数据资产和策略即代码
我们可以通过使用常见的访问模式简化湖屋的安全性和治理。例如,引入Amazon S3访问授权(Amazon S3 Access Grants):这种抽象简化了角色管理以及在传统S3存储桶中委派SQL风格的GRANT权限。
注意 以下部分将以高层次概述如何使用Amazon S3访问授权。本部分假设读者具有使用Amazon S3和理解策略管理工作的经验。
创建一个S3存储桶
S3存储桶将作为封装我们生产湖屋的容器。通过使用Amazon CLI(如示例12-2所示),我们设置存储桶并将其命名为production.v1。
示例12-2:设置湖屋的S3存储桶
aws s3api create-bucket \
--bucket com.dldgv2.production.v1 \
--region us-west-1 \
--create-bucket-configuration LocationConstraint=us-west-1
成功设置存储桶后,会返回存储桶的位置信息。这意味着我们已经获得了一个唯一的ARN(Amazon资源名称),例如:arn:aws:s3:::com.dldgv2.production.v1。
创建S3访问授权实例
S3访问授权实例是一个容器,用于逻辑地分组一个或多个注册的S3位置,并定义谁对每个位置的S3数据拥有何种访问级别的授权。每个AWS账户在每个AWS区域内都有一个访问授权实例——创建授权实例的过程如示例12-3所示。这意味着即使S3存储桶允许全局访问,区域性的数据访问控制仍然会得到遵守。
示例12-3:创建S3访问授权实例
% ACCOUNT_ID="123456789012" && \
aws s3control create-access-grants-instance \
--account-id $ACCOUNT_ID
创建新授权实例的结果如下:
{
"CreatedAt": "2024-01-15T22:54:18.587000+00:00",
"AccessGrantsInstanceId": "default",
"AccessGrantsInstanceArn": "arn:aws:s3:us-west-1:123456789012:access-grants/default"
}
现在,我们已经在us-west-1区域设置了S3存储桶和访问授权实例,接下来我们可以创建一个IAM角色和信任策略,用于使用S3访问授权。
创建信任策略
必须创建一个信任策略,允许AWS服务(由access-grants.s3.amazon.com标识)使用GetDataAccess操作生成临时IAM凭证,以访问S3资源。信任策略如示例12-4所示。
示例12-4:创建trust-policy.json文件
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "access-grants.s3.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:SetSourceIdentity",
"sts:SetContext"
]
}
]
}
接下来执行以下命令:
% aws iam create-role --role-name s3ag-location-role \
--assume-role-policy-document file://trust-policy.json
创建S3数据访问策略
最后一步是创建一个策略,授予对S3存储桶前缀的读取和读写权限。
% aws iam put-role-policy --role-name s3ag-location-role \
--policy-name s3ag-location-role --policy-document file://iam-policy.json
iam-policy.json文件在本书的GitHub材料中提供。
现在,我们已经设置好了S3访问授权,接下来我们可以简化如何管理对湖屋资源的读取、读写权限,甚至是管理员级别的权限。
在角色级别应用策略
接下来,我们将在策略中应用RBAC(基于角色的访问控制)原理。这使我们能够提供通用的规则来强制执行对一组资源的访问控制。在本例中,资源是位于我们S3存储桶中的Delta Lake表。
读取权限
这将授权对资源的只读权限,或查看给定数据资产的元数据的能力,包括表的属性、所有权、数据源和其他相关数据。此权限是查看表内行级数据、列出存储桶前缀(文件系统路径)中的资源,或读取表级元数据所必需的。示例12-5展示了如何使用SQL授权启用我们的analystRole角色的读取权限。
示例12-5:应用Amazon S3访问授权读取策略
$ export ACCOUNT_ID="123456789012"
aws s3control create-access-grant \
--account-id $ACCOUNT_ID \
--access-grants-location-id default \
--access-grants-location-configuration S3SubPrefix="warehouse/gold/analysis/*" \
--permission READ \
--grantee GranteeType=IAM,GranteeIdentifier=arn:aws:iam::$ACCOUNT_ID:role/analystRole
此示例展示了使用访问授权授予Amazon S3权限的简化方法。
读写权限
除了读取权限所提供的操作,写入权限还增加了修改功能,允许角色(身份)插入(写入)新数据、更新表元数据并从表中删除行。示例12-6展示了简单的读写策略。
示例12-6:应用Amazon S3访问授权读写策略
$ export ACCOUNT_ID="123456789012"
export GRANT_ROLE="role/developerRole"
aws s3control create-access-grant \
--account-id $ACCOUNT_ID \
--access-grants-location-id default \
--access-grants-location-configuration S3SubPrefix="warehouse/gold/analysis/*" \
--permission READWRITE \
--grantee GranteeType=IAM,GranteeIdentifier=arn:aws:iam::$ACCOUNT_ID:$GRANT_ROLE
管理员权限
除了读写权限所管理的功能外,管理员角色还授权一个角色创建或删除特定位置的数据资产。例如,通常会将破坏性操作限制为仅由服务主体执行;类似地,创建资源通常也意味着额外的协调工作来管理和监控资源。由于无头用户只能代表用户操作,这意味着他们只能运行已存在的工作流和命令,并执行已定义的操作和任务。换句话说,服务主体可以基于某些外部事件触发特定操作,从而减少意外操作的风险。最好使用传统的IAM策略来控制对创建和销毁湖仓资源位置的访问。
RBAC的局限性
当然,单纯使用角色来管理访问存在局限性;主要的情况是,角色数量会激增。这可以被视为“蔓延”,它是成功的一个意外副作用。说实话,如果只有四个业务线,并且你有四个支持角色(开发人员、分析师、科学家、业务人员),那么你最多需要处理4 × 4 × n的情况(n是每个业务线中需要特殊规则来管理访问的表数量)。那么当你从四个业务线增加到二十个时会发生什么?五十个呢?正是这些“假设”决定了接下来该怎么做。如果幸运的话,公司已经蓬勃发展,我们雇佣了合适的人才,并成功维持了一个健全的工程纪律和实践,那么我们可以开始转向基于属性的访问控制(ABAC)。这也被称为标签基础的策略,也可以被纳入细粒度访问控制的范畴。
湖仓的细粒度访问控制
使用粗粒度访问控制(即基于允许或拒绝对整个数据资产的读取和写入的访问控制,通常依据层级角色)带来的复杂性积累问题的解决方案是细粒度访问控制。现在有许多新兴技术,通过标签或属性的概念提供细粒度的访问控制。
例如,假设我们有一个Delta Lake表,包含二十列。该表可能包含我们客户的订单信息。每个订单的信息可能对公司内的许多角色都有重要意义,但根据有关客户数据访问的章程和规则,访问与订单相关的用户信息可能不符合合规要求。与其将整个表标记为“黄色”或“红色”进行分类,不如直接对列进行标记(使用元数据),以标明该列是否可以被读取,或者是否应在公共访问时进行屏蔽或置为null。
示例12-7中的SQL展示了如何在Databricks中使用Unity Catalog实现动态屏蔽。为了查看存储在user结构中的数据,查询订单数据的用户或服务主体必须属于consumer_privileged帐户组,并且此时user结构本身必须被标记为pii(个人可识别信息)。
示例12-7:使用动态视图和标签进行细粒度访问控制
-- SQL
CREATE VIEW consumer.prod.orders_redacted AS
SELECT
order_id,
region,
items,
amount,
CASE
WHEN has_tag_value('pii')
AND is_account_group_member('consumer_privileged')
THEN user
ELSE named_struct(
'user_id', sha1(user.user_id), 'email', null, 'age', null)
AS user
END
FROM consumer.prod.orders
虽然示例12-7中的SQL为我们提供了一个起点,来选择性地屏蔽数据,但该示例使用了has_tag_value函数和is_account_group_member函数,而这两个函数并不向公众开放。此外,若没有集成的通用规则管理支持,创建和维护动态视图可能随着时间推移变得繁琐。然而,值得注意的是,一个简单的解决方案是通过视图向公众提供对物理表的访问,视图中会明确屏蔽任何标记为PII的数据,同时继续使用更简单的粗粒度访问控制限制对底层物理表的直接访问。这是一个不错的权宜之计,可以仅通过开源工具实现。
总结
我们如何管理、保护和存储湖屋中的珍贵资产可以是复杂的,也可以是简单的;这一切取决于规模和大小(或表格及其他数据资产的数量),以及在何时意识到需要更完整的治理解决方案。无论处于旅程的哪个阶段,都应该从小做起——首先在桶级别创建数据目录的分离,将所有可访问的数据与高度敏感的数据隔离开来。在解决方案中逐步加入同步需求的方式,既要考虑人们从数据中需要什么,也要考虑系统和服务从数据中需要什么,并将这些因素整合到谁、什么、何时的策略中。
在下一章,我们将继续探讨元数据管理、数据流和数据血统,并总结本章的内容。