本文是系列文章的第四篇,本系列讨论如何使用多租户模型开发经济有效、安全且可配置的 Web 交付应用程序。这个模型让单一共享应用程序实例能够同时支持多个客户组织(即租户),通过在租户之间共享基础结构和操作资源实现经济有效性目标。
Chang Jie Guo, 研究员, WSO2 Inc
Zhi Hu Wang, 研究工程师, WSO2 Inc
Wen Hao An, 软件工程师, WSO2 Inc
Wei Sun, 研究员, WSO2 Inc
Bo Gao, 研究员, EMC
2009 年 8 月 17 日
简介
在本文中,我们通过一个示例应用程序 EasyOA 讲解如何设计单一实例租户启用体系结构。EasyOA 是一个为小型企业开发的简单的办公自动化应用程序。我们将介绍几种主要共享资源的多租户设计模式。另外,即将发表的一个 developerWorks 文章系列会更详细地讨论本文中的每个主题。
多租户身份验证和授权机制
本节主要解决两个问题:(1) 如何在多租户上下文中设计组织数据的存储/访问模式,实现相应的感知租户的身份验证机制;(2) 如何增强基于 Java Authentication and Authorization Service (JAAS) 的授权机制,让租户能够以隔离的方式访问和定制他们的访问控制列表和特权。
图 1. 多租户身份验证和授权体系结构
这个体系结构用于在多租户应用程序中实现身份验证和授权机制,如图 1 所示,它有四个主要组件。
租户的组织结构和访问控制数据分别存储在 Lightweight Directory Access Protocol (LDAP) 服务器和数据库服务器上,使用多租户树模式和数据模型;
身份验证服务允许租户的用户登录应用程序,在安全会话令牌中维护当前登录用户的租户信息;
授权服务支持在运行时检查当前登录的租户用户的权限;
利用服务支持租户维护和配置自己的组织结构和访问控制数据。
多租户组织结构设计和身份验证过程
当出现新的租户时,给每个租户分配一个惟一的租户 ID 和组织结构的一个子树;组织结构存储在共享的 LDAP 服务器上,按租户 ID 隔离子树。在实践中,子树可以实现为物理子树或虚拟子树。
图 2 到图 4 给出 LDAP 服务器中 EasyOA 的多租户组织结构。
图 2. 虚拟的多租户组织结构树
图 3. LDAP 服务器中 EasyOA 的虚拟组织结构
图 4. 物理多租户组织结构树
图 2 和图 3 是一个虚拟的组织结构实现,采用这种实现的多租户身份验证过程如下:
在登录页面上,租户用户输入自己的用户名和密码,可以通过输入显式地提供租户名称,也可以通过 URL 隐式地提供。在提交时,登录页面把 TenantName 和 UserName 组合成 IBM WebSphere Application Server (WAS) 可以理解的 userSecurityName 字符串,通过 API 或表单调用 WAS 登录模块。
WAS 登录模块调用 WAS LDAP User Registry 执行身份验证,例如,根据 LDAP 中存储的组织结构中与这个租户对应的子树检验用户名/密码。
通过身份验证之后,WAS 登录模块创建一个安全会话令牌,在其中存储当前登录用户的租户和会话信息(Tenant Name、Tenant ID、User Name、User ID、特权等),EasyOA 应用程序的其他模块在运行时可以通过调用身份验证服务 API 访问这个令牌。
在图 4 所示的物理组织结构实现中,每个租户在 LDAP 服务器中有一个专用的子树。在这种情况下,可以使用 WAS v6.1 提供的新的 Virtual Member Manager (VMM) 功能 —— 联合用户存储库。
这个特性可以通过配置把来自多个用户存储库的租户条目映射为单一虚拟存储库,而不需要开发。每个存储库可以是完整的外部存储库,也可以是存储库中的子树(对于 LDAP)。每个存储库的根映射到联合存储库中的一个基条目,这个基条目作为虚拟领域的层次化名称空间中的起点。更多信息请参见 “参考资料” 中的文章 IBM WebSphere Developer Technical Journal: Expand your user registry options with a federated repository in WebSphere Application Server V6.1。
多租户权限数据模型设计和授权过程
图 5 给出一个基于标准 JAAS 规范的灵活的多租户访问控制设计模型。
这些原子特权组合为一个称为 privilegeGroup(特权组)的集合。通过引入新的租户对象,在租户之间隔离角色和用户。按照这个模型,租户管理员可以通过 Utilization Service 灵活地定义自己的角色、角色和特权组的映射关系以及角色和用户的关系。
当用户登录 EasyOA 时,WAS 用户注册插件从 ACL 数据结构获取登录用户拥有的所有原子特权,把它们存储在安全会话令牌中,授权服务 API 和其他 WAS 组件在运行时使用这些信息执行权限检验。
在多租户上下文中访问常用 J2EE 工件
除了身份验证和授权之外,在多租户上下文中还应该隔离(缓存、日志、文件、I/O、全局变量等)和定制(徽标、登录页面、日志样式等)许多常用 J2EE 工件。在本节中,我们介绍一个简单的基于筛选器的机制,它以隐式方式在租户之间隔离和定制这些资源:
图 6. 基于隐式筛选器的隔离机制
在图 6 所示的模式中,当 EasyOA 应用程序要代表一个租户访问某一共享资源时,它只需像传统的单租户应用程序那样发出请求,不需要考虑资源访问/存储的多租户实现细节。但是,并不直接执行这个请求,而是把请求委托给一个通用资源访问模块,这个模块有权访问所有租户的资源。这种机制的关键是,受委托的模块从安全会话令牌中隐式地获取请求者的租户信息,然后根据预先定义的一些规则组合出针对特定租户的筛选器。受委托的模块使用这个筛选器防止用户使用其他租户的资源。
有一些针对不同资源类型的典型的筛选器,例如:
“where tenant_id is xxx” 这样的 SQL 子句
通过 Log4j Appender 使用与租户相关的日志文件和格式
缓存中的业务对象使用与租户相关的前缀
文件夹和文件使用与租户相关的前缀
在配置文件中使用与租户相关的 XML 上下文/范围
在业务规则的 if/then 规则集或决策表中,增加一个表示租户的参数或维
对于租户要定制的那些资源(徽标、登录页面、规则等),可以构建一个存储库,以隔离的方式提取和存储可配置点的元数据。然后,受委托的模块可以使用基于这个存储库的感知租户的配置服务,方便地组合筛选器并访问相应的资源。图 7 和图 8 给出 EasyOA 在这方面使用的机制。
图 7. 支持租户定制登录页面
图 8. 在租户之间隔离静态变量
多租户数据层设计模式
本节讨论与数据层有关的多租户体系结构设计和考虑因素,介绍各种设计模式,包括资源共享、安全隔离和定制方面。更多信息请参见 “参考资料” 中的文章 Data Integration and Composite Business Services, Part 3: Build a multi-tenant data tier with access control and security。
数据层资源共享模式
如图 9 所示,在数据层中有三个资源共享级别:
完全隔离:每个租户使用单独的数据库
部分共享:共享数据库,但是使用单独的模式
完全共享:使用相同的数据库和相同的模式
图 9. 多租户上下文中的数据层资源共享模式
数据层安全隔离模式
在多租户上下文中,安全隔离机制非常重要,必须防止租户非法访问其他租户的数据。对于共享的模式/表,一般有两种访问控制隔离方法,见图 10。
应用程序级访问控制:所有租户共享一个受委托的数据库账户,这个账户有权访问共享表中所有租户的所有数据。使用筛选器(例如 SQL 子句)筛选掉不属于当前租户的数据记录。
DBMS 级访问控制:每个租户通过 lattice-based access control (LBAC) 等 DB2 安全特性,使用专用的账户访问专用的数据库或表/模式。这种方法可以完全消除 SQL 注入攻击的风险。
图 10. 多租户上下文中的数据层安全隔离模式
数据层定制模式
在数据定制方面,多租户应用程序也有多种选择,从复杂的模式定制到简单的字段扩展,这些方法的灵活性各不相同。显然,对于专用数据库或表/模式隔离方法,数据定制不是问题,因为每个租户使用单独的数据库/模式。租户可以直接对自己的数据库/模式修改数据模型,不会影响其他租户。但是,对于共享表/模式隔离方法,只能支持数据字段扩展,这种方法的灵活程度由扩展字段的最大数量决定。对于共享表/模式模型,三种主要的定制模式见图 11 到图 13:
保留的扩展表字段:在每个表中预先定义固定数量的额外数据列,这些列采用通用列类型(比如 varchar)。
动态扩展的子表:构建子表来存储主表记录的所有扩展字段,子表通过记录 ID 列与主表相关联。
XML 扩展表字段:这种方法利用 DB2 v9 提供的新的 XML 特性。所有扩展数据存储在一个 XML 字段中。
图 11. 保留的扩展表字段模式
图 12. 动态扩展的子表模式
图 13. XML 扩展表字段
正如前面提到的,EasyOA 应用程序用来支持大量(数千个)小型公司,每个公司的数据量相当少。因此,EasyOA 使用共享表/模式方法来降低成本。对于这种共享模式,它应用 MDC(多维聚簇)技术改进性能(更多信息见 “参考资料”)。EasyOA 还利用 LBAC 实现 DBMS 级安全性以防止租户之间的非法数据访问。它采用一种混合模式满足定制需求:在每个表中默认保留几个固定的数据字段,但是还支持子表模式。这种方法的优点很显著。它可以为定制需求不多的租户提供出色的性能,同时为需要更多扩展字段的租户提供更强的灵活性。
隔离和定制业务过程的人员/角色选择规则
在业务过程/工作流层,过程模板是最重要的资源。为了支持多租户应用程序开发,有两种处理过程模板的方法:
单独的过程模板模式:在这种模式中,每个租户有一组专用的过程模板。租户的访问请求应该路由或分派到对应的过程模板或实例。这种方法比较容易实现租户级的隔离和定制。但是,它有显著的成本问题。例如,如果应用程序有 20 个 BPEL 过程,它支持 1,000 个租户,那么就会有 20,000 个过程模板。
共享的过程模板模式:所有租户共享同一组过程模板。我们将采用这种方法。它的困难在于如何隔离和定制与共享过程相关联的工件,比如人工任务动词、业务规则和过程骨架。
本节介绍一种用于过程模板和人工任务的人员解析隔离机制,它可以自动、透明地选择与过程启动者属于同一租户的角色/人员。它还支持租户定制自己的人员解析规则,而不会影响其他租户。
在 WebSphere Process Server 中,使用 “动词(Verb)” 执行人工任务或过程的人员/角色选择。在运行时,人员解析插件解析动词的参数并查询底层用户存储库,从而选择适当的角色。WPS 在默认情况下提供三种人员解析插件 System、LDAP 和 UR,还提供 User、Group Members、Search 等标准动词。
但是,在多租户上下文中,如果所有租户共享同一组过程模板,那么标准动词和插件就不适用了,因为它们不理解底层的多租户组织结构和用户存储库。
图 14 从设计时、运行时和管理几方面说明我们解决这个问题的方法:
在构建时,我们提供一组支持多租户的动词和一个相应的多租户人员解析插件,开发人员可以使用它们设计过程模板。
在运行时,这个专门设计的插件首先获取过程实例的启动者的用户 ID 和相应的租户 ID,然后在组织结构中在这个租户的范围内查询人员/角色。注意,这些都是以隐式方式执行的。
在管理方面,通过在一组预定义的规则中做出选择,租户的管理员可以轻松地为任何过程或人工任务定制人员/角色选择规则,而不会影响其他租户。
图 14. 多租户动词和人员解析插件
图 15 和图 16 说明 EasyOA 的过程层,展示使用这种隔离和定制机制的结果。
图 15. 人员/角色选择隔离
图 16. 人员/角色选择定制
结束语
多租户设计模式(使用单一共享应用程序实例同时支持多个租户)对于提高 Web 交付应用程序的经济有效性非常重要。本文讨论了单实例多租户应用程序的体系结构设计,介绍了四个方面的多租户设计模式,包括安全机制、J2EE 工件、数据模型和业务过程。后续文章将提供更多信息。