亚马逊AWS官方博客

Amazon DocumentDB(兼容 MongoDB)推出基于角色的访问控制

Original URL: https://aws.amazon.com/blogs/database/introducing-role-based-access-control-for-amazon-documentdb-with-mongodb-compatibility/

 

Amazon DocumentDB(兼容 MongoDB)是一款快速、可扩展、高度可用且完全托管的文档数据库服务,它支持 MongoDB 3.6 工作负载。在 Amazon DocumentDB 上,您可以使用与目前相同的 MongoDB 应用程序代码、驱动程序和工具来运行、管理和扩展工作负载,无需关心底层基础设施。

Amazon DocumentDB 现已增加支持基于角色的访问控制 (RBAC)。借助 RBAC,您可以向用于授予一个或多个预定义的角色(例如 readreadWrite 或 dbOwner),从而确定用户有权在一个或多个数据库上执行的操作。RBAC 的一个常见使用案例是在单个应用程序上强制执行最小权限访问原则。另一个常见的使用案例是构建多租户应用程序。多租户应用程序是指服务多个客户的软件和硬件部署。对于 Amazon DocumentDB,多租户应用程序的一个例子是每个客户(或租户)都有权访问集群中自己的数据库。

本文介绍了 Amazon DocumentDB 中的 RBAC 概念和功能,演示了两个使用案例,并讨论了构建具有 RBAC 功能的多租户应用程序时的设计注意事项。有关新增 RBAC 功能的更多信息,请参阅文档中的基于角色的访问控制(内置角色)

概念

Amazon DocumentDB 使用了下列关键的 RBAC 概念:

  • 用户 – 可以进行身份验证并执行操作的具名实体
  • 密码 – 用于验证用户身份的秘密口令
  • 角色 – 授权用户在一个或多个数据库上执行操作的称谓
  • 管理数据库 – 用于向用户授予权限的特殊数据库
  • 数据库 (DB) – 集群中包含集合的命名空间

以下代码创建了一个名为 app 的用户,密码为 abc123,它具有 foo 数据库的 read 权限(本文中提供的示例用户名和密码仅供演示之用,您应始终选择使用强密码):

db.createUser({user: "app", pwd: "abc123", roles: [{role: "read", db: "foo"}]})

您可以通过 show users 命令列出集群中的现有用户和角色。以下代码显示了对于创建的用户,此命令的输出:

{
	"_id" : "app",
	"user" : "app",
	"db" : "admin",
	"roles" : [
		{
			"db" : "foo",
			"role" : "read"
		}
	]
}

所有角色信息都存储在一个名为 admin 的特殊数据库中。在此示例代码中,您可以看到用户 app 位于 admin 数据库中,具有 foo 数据库的 read 角色。

RBAC 使用案例

为了演示 RBAC 的工作原理,本文演示了两个常见的 RBAC 使用案例:在当个应用程序中强制执行最小权限访问原则以及在单个 Amazon DocumentDB 集群上启用多租户应用程序。

强制执行最小权限原则

应用程序经常会将单个 Amazon DocumentDB 集群作为数据存储使用,但有多个用户需要具有执行特定操作的授权。一些用户可能需要读取和写入数据,而另一些用户则可能只需要读取权限。最小权限原则是一项基础性的安全控制手段;您可以使用 RBAC 来执行此原则,将用户的访问权限限制在履行其职能所需的范围。本文演示了一个具有三个应用程序用户(appAdminappUser 和 analytics)的使用案例。根据用户必须履行的职能,每个用户都拥有不同的角色。下图概括了这些角色。

第一个用户 (appAdmin) 是应用程序的管理员,需要在任何数据库中创建索引、添加用户以及读取和写入数据。为此用户分配了 dbAdminAnyDatabasereadWriteAnyDatabase 和 clusterAdmin 角色。要创建 appAdmin 用户并授予需要的角色,请输入以下代码(为了创建这些用户,您必须以具有 root 角色的用户身份在集群上验证身份):

db.createUser( { user: "appAdmin", pwd: "abc123",  roles: [{"db":"admin", "role":"dbAdminAnyDatabase" }, {"db":"admin", "role":"readWriteAnyDatabase"}, {"db":"admin", "role":"clusterAdmin"}]})

第二个用户 (appUser) 是主要应用程序用户,需要具有产品数据库的读取和写入权限。要创建 appUser 用户并授予需要的权限,请输入以下代码:

db.createUser( { user: "appUser", pwd: "abc124",  roles: [ { role: "readWrite", db: "products"}]})

第三个用户 (analytics) 用于一个分析应用程序,仅需要从 products 数据库读取数据。要创建 analytics 用户并授予需要的权限,请输入以下代码:

db.createUser( { user: "analytics", pwd: "abc125",  roles: [ { role: "read", db: "products"}]})

您可以使用下面的 CLI 命令,以 appUser 用户身份连接到您的集群并验证身份:

mongo "mongodb://appUser:abc124@<clusterName>.us-east-1.docdb.amazonaws.com:27017/"

如果您未在连接字符串中指定特定的数据库,则您将默认以该用户身份在 test 数据库上验证身份。由于您的应用程序位于产品数据库中,您可以使用 use 语句将连接上下文切换到产品数据库。请参见以下代码:

use products

您现在可以在产品目录上执行读取和写入操作。要向目录集插入少量的文档,请输入以下代码:

db.catalog.insertMany([
{ "_id":1, "name":"banana", "inventory": 10},
{ "_id":2, "name":"passion fruit", "inventory": 22},
{ "_id":3, "name":"pink laddy apple", "inventory": 78},
])

您将收到以下输出:

{ "acknowledged" : true, "insertedIds" : [ 1, 2, 3 ] }

您现在可以查询数据以找到特定种类的水果。例如,如果您要检查当前的百香果库存,请输入以下代码:

db.catalog.find({"name": "passion fruit"})

您将收到以下输出:

{ "_id" : 2, "name" : "passion fruit", "inventory" : 22 }

然后注销 appUser 身份。请参见以下代码:

db.logout()

您将收到以下输出:

{ "ok" : 1 }

发出注销命令后,您仍然保持 Amazon DocumentDB 集群的连接,但不再以任何用户身份验证身份。您现在可以使用 analytics 用户身份来验证身份,该用户仅拥有产品数据库的读取权限。请参见以下代码:

db.auth("analytics", "abc125")

由于您验证身份时使用的是只读角色,因此您可以读取数据。请参见以下代码:

db.catalog.find({"name": "passion fruit"})

您将收到以下输出:

{ "_id" : 2, "name" : "passion fruit", "inventory" : 22 }

但您无权写入数据。例如,以下代码尝试插入新数据:

db.catalog.insert({"name": "lemons", "quantity": 99})

您将收到以下输出:

WriteResult({ "writeError" : { "code" : 13, "errmsg" : "Authorization failure" } })

多租户应用程序

在第二个使用案例中,您使用一个数据库来支持游戏开发应用程序。为了优化成本,您使用了一个多租户集群,每个游戏开发人员都有权访问集群中自己的数据库。有四个游戏开发工作室在您的游戏平台上注册:bigCowraceCarxQuest 和 bounce。为了向这些客户授予对其数据的访问权限,您创建了四个数据库管理员用户:每个客户一名用户。每个管理员用户都可以管理自己的游戏数据库。下图概括了这些用户角色。

在以具有整个 DocumentDB 集群的管理员角色的用户身份登录后,您可以创建每个游戏数据库的管理员用户,并且可以分配集群内特定数据库的相关角色。请参见以下代码:

db.createUser( { user: "bigCowAdmin", pwd: "abc123",  roles: [ { role: "dbOwner", db: "bigCow"}]})
db.createUser( { user: "raceCarAdmin", pwd: "def456",  roles: [ { role: "dbOwner", db: "raceCar"}]})
db.createUser( { user: "xQuestAdmin", pwd: "ghi789",  roles: [ { role: "dbOwner", db: "xQuest"}]})
db.createUser( { user: "bounceAdmin", pwd: "jkl012",  roles: [ { role: "dbOwner", db: "bounce"}]})

尽管每个管理员用户都可以在验证身份后管理其数据库,但他们无权对集群中任何其他的数据库执行操作。例如,bigCowAdmin 用户将无法在 xQuest 数据库上执行读取或写入。

为了演示 bigCow 用户尝试向其不拥有访问权限的数据库执行写入的情景,我们首先注销当前用户身份。请参见以下代码:

db.logout()

您将收到以下输出:

{ "ok" : 1 }

您可以使用下面的 mongo 外壳命令,以 bigCowAdmin 用户身份连接到您的集群并验证身份:

mongo "mongodb://bigCowAdmin:abc123@&lt;clusterName&gt;.us-east-1.docdb.amazonaws.com:27017/"

然后将连接上下文切换到 xQuest 数据库。请参见以下代码:

use xQuest

您将收到以下输出:

switched to db xQuest

您可以尝试向 xQuest 数据库中的 foo 集合写入单个文档。请参见以下代码:

db.foo.insert({'x':1})

您将收到以下输出:

WriteResult({ "writeError" : { "code" : 13, "errmsg" : "Authorization failure" } })

与预想的一样,bigCowAdmin 用户无权执行该命令。

尽管您的连接上下文为 xQuest 数据库,但这并不意味着用户可以确认集群中存在该数据库。连接上下文是一种客户端侧的结构,您可以将连接上下文切换到您需要的任何数据库,但这并不意味着存在该数据库或者您拥有该数据库的读取或写入权限。例如,以下代码尝试列出 xQuest 数据库中的集合:

db.runCommand( { listCollections: 1})

您将收到以下输出:

{ "ok" : 0, "errmsg" : "Authorization failure", "code" : 13 }

由于 xQuestAdmin 用户不拥有授权其列出集合的角色,此命令会导致授权失败错误。但如果您将连接上下文切换到 bigCow 数据库,也就是 bigCowAdmin 用户拥有权限的数据库,您将有权在 bigCow 数据库上执行命令。请参见以下代码:

use bigCow

您将收到以下输出:

switched to db bigCow

您现在将获得授权并且可以向 bigCow 数据库的 foo 集合写入数据。请参见以下代码:

db.foo.insert({'x':1})

您将收到以下输出:

WriteResult({ "nInserted" : 1 })

同样,由于 bigCowAdmin 用户具有 dbOwner 角色,您可以列出 bigCow 数据库中的集合。请参见以下代码:

db.runCommand( { listCollections: 1})

您将收到以下输出:

{
	"waitedMS" : NumberLong(0),
	"cursor" : {
		"firstBatch" : [
			{
				"name" : "foo",
				"type" : "collection",
				"options" : {
					"autoIndexId" : true,
					"capped" : false
				},
				"info" : {
					"readOnly" : false
				},
				"idIndex" : {
					"v" : 2,
					"key" : {
						"_id" : 1
					},
					"name" : "_id_",
					"ns" : "bigCow.foo"
				}
			}
		],
		"id" : NumberLong(0),
		"ns" : "bigCow.$cmd.listCollections"
	},
	"ok" : 1
}

多租户应用程序的设计注意事项

构建软件即服务 (SaaS) 应用程序的开发人员经常会希望通过构建多租户应用程序来优化成本。SaaS 开发人员通常会通过 RBAC 等授权安全控制机制来隔离共享计算和存储资源的租户(或客户)。在 Amazon DocumentDB 中,您可以通过按集群或按数据库(使用 RBAC)隔离租户的方式来构建 SaaS 应用程序。这一部分讨论了在集群和数据库级别实施隔离时应注意的事项和权衡的因素,以帮助您评估哪种模式最适合您的应用程序架构。有关实施多租户数据隔离的高级别方法的更多信息,请参阅在 AWS 上构建多租户存储模式的 SaaS 存储策略白皮书。

集群隔离

集群隔离模式中,您通过逻辑的方式将每个租户的数据隔离到单个 Amazon DocumentDB 集群。由于每个租户都拥有不同的专用集群,您可以在所有维度实现完全的租户隔离,包括计算、存储、备份、加密密钥以及产生的成本。

数据库隔离

数据库隔离模式中,每个租户在共享的环境中通过 RBAC 等授权机制来进行隔离。在 Amazon DocumentDB 集群中,您通过将每个租户与一个 Amazon DocumentDB 集群中的一个或多个不同的数据库关联起来,从而实现数据库级别的隔离。

成本优化

使用数据库隔离的方法来构建多租户应用程序,一个优势和主要动机就是能够通过密度来优化成本。根据应用程序和客户保证的不同,您可以允许单个集群的租户数量超额,因为您知道不会所有租户在同一时间都处于活动状态。这种密度可以降低单位租户的成本,让总体解决方案具有更高的经济效益。

性能隔离

在选择多租户应用程序架构时,性能隔离是一个重要的注意事项。在使用集群隔离时,每个租户都拥有一个专属集群,因此也拥有专用的计算资源。这确保了根据租户的要求提供稳定、有保证的服务质量。例如,如果一个租户最初使用一个 r5.large 实例集群,但由于他们的应用程序吞吐量翻了一番,您可以将该集群扩展为使用 r5.xlarge 实例,从而实际上为该租户提供双倍的计算资源。

使用数据库隔离时,租户将会共享 Amazon DocumentDB 集群中的计算资源。这种方法的优点在于您可以在单个集群上实现极高的租户密度,最高可达数百个租户。如果租户的长期加总利用率相对稳定,则您可以为所有租户提供相对稳定的体验。数据库隔离的缺点在于,如果一个或多个租户使用的集群资源数量过高,则可能对其他租户的服务质量产生不利影响(通常被称为吵闹的邻居问题)。选择数据库隔离模式时,承认并考虑吵闹的邻居风险,并为租户设定恰当的预期十分重要。

一个常用的缓解策略是实施服务分级。您可以提供一个基本服务等级,让每个租户都能访问共享集群(并从而暴露吵闹的邻居风险)中的一个数据库。对于需要性能隔离的租户,您可以提供更高的服务等级,让每个租户都拥有自己的集群。

安全隔离

选择多租户方法是的另一个注意事项是安全隔离。Amazon DocumentDB 默认提供静态加密功能,使用单个客户主密钥 (CMK) 来加密集群中的存储卷、备份和快照。如果有租户要求不与其他租户共享存储加密密钥,则您可以使用集群隔离(使用不同的 CMK),也可在应用程序中执行客户端侧加密,并通过 AWS KMS 在客户端侧管理这些密钥。客户端侧加密可以在共享集群环境中提供密钥隔离功能,但会增加复杂度,可能会影响应用程序的性能。

小结

本文介绍了 Amazon DocumentDB 的 RBAC 功能,演示了两个常见的使用案例,并讨论了构建多租户应用程序时的设计注意事项。有关 Amazon DocumentDB 的 RBAC 功能的更多信息,请参阅文档中的基于角色的访问控制(内置角色)

有关 Amazon DocumentDB 的更多信息,请参阅 Amazon DocumentDB 入门或观看 YouTube 视频 Amazon DocumentDB 入门。有关更多信息,请参阅 Ramping up on Amazon DocumentDB (with MongoDB compatibility)。您可以使用您目前用于 MongoDB 的相同应用程序代码、驱动程序和工具,开始针对 Amazon DocumentDB 进行开发。

关于 AWS SaaS Factory


AWS SaaS Factory 为 AWS 合作伙伴网络 (APN) 合作伙伴提供有助于加速和指导其采用 SaaS 交付模型的资源。SaaS Factory 包括用于在 AWS 上构建 SaaS 解决方案的参考架构;可自动部署 AWS 上的关键工作负载的快速入门;以及在 AWS 上构建 SaaS 企业的独家培训机会。鼓励开发 SaaS 解决方案的 APN 技术合作伙伴加入该计划!

了解关于 AWS SaaS Factory 的更多信息

 

本篇作者

Joseph Idziorek

Amazon Web Services公司首席产品经理。

Judah Bernstein

是 Amazon Web Services 的一名高级合作伙伴解决方案架构师,主要负责软件即服务 (SaaS) 产品。

Jeff Duffy

Amazon Web Services公司NoSQL专业高级经理,专注于Amazon DocumentDB相关事务。