使用基于角色的访问控制进行数据库访问
您可以使用 Amazon DocumentDB(与 MongoDB 兼容)中的基于角色的访问控制(RBAC)限制用户可以对数据库执行的操作的访问权限。RBAC 的原理是向用户授予一个或多个角色。这些角色决定了用户可以对数据库资源执行的操作。Amazon DocumentDB 目前既支持限定在数据库级别的内置角色(例如read
、readWrite
、readAnyDatabase
、clusterAdmin
),也支持限定为特定操作的用户定义角色和精细资源(例如基于您的要求的集合)。
RBAC 的常见使用案例包括通过创建对集群中数据库具有只读访问权限的用户来强制执行最低权限,以及允许单个用户访问集群中给定数据库的多租户应用程序设计。
注意
所有在 2020 年 3 月 26 日之前创建的新用户都已被授予 dbAdminAnyDatabase
、readWriteAnyDatabase
和 clusterAdmin
角色。建议您重新评估所有现有用户并根据需要修改角色,以便为您的集群强制执行最低权限。
RBAC 概念
以下是与基于角色的访问控制相关的重要术语和概念。有关 Amazon DocumentDB 用户的更多信息,请参阅 管理 Amazon DocumentDB 用户。
-
用户 可进行身份验证以访问数据库并执行操作的单个实体。
-
密码 用于对用户进行身份验证的密钥。
-
角色 授权用户对一个或多个数据库执行操作。
-
管理数据库 用户在其中存储并已得到授权的数据库。
-
数据库 (
db
) 集群中包含用于存储文档的集合的命名空间。
以下命令创建名为 sample-user
的用户。
db.createUser({user: "sample-user", pwd: "abc123", roles: [{role: "read", db: "sample-database"}]})
在本示例中:
-
user: "sample-user"
表示用户名。 -
pwd: "abc123"
表示用户密码。 -
role: "read", "db: "sample-database"
表示用户sample-user
将在sample-database
中具有读取权限。
以下示例显示您为用户 sample-user
指定 db.getUser(sample-user)
后的输出。在此示例中,用户 sample-user
驻留在 admin
数据库中,但具有 sample-database
数据库的读取角色。
在创建用户时,如果在指定角色时省略 db
字段,则 Amazon DocumentDB 会隐式地将该角色归属于发出连接的数据库。例如,如果您的连接是针对数据库 sample-database
发出的,并且您运行以下命令,则用户 sample-user
将在 admin
数据库中创建并具有对数据库 sample-database
的 readWrite
权限。
db.createUser({user: "sample-user", pwd: "abc123", roles: ["readWrite"]})
此操作的输出将类似于下文。
{
"user":"sample-user",
"roles":[
{
"db":"sample-database",
"role":"readWrite"
}
]
}
创建具有跨所有数据库范围的角色的用户(例如,readAnyDatabase
)需要在创建用户时处于 admin
数据库的上下文,或者在创建用户时明确指定角色的数据库。要针对 admin
数据库发出命令,可以使用命令 use admin
。有关更多信息,请参阅 通用命令。
RBAC 内置角色入门
为帮助您掌握基于角色的访问控制,本部分将向您介绍通过为三个用户创建具有不同职能的角色来强制执行最低权限的示例方案。
-
user1
是一位新上任的经理,需要能够查看和访问集群中的所有数据库。 -
user2
是一位新员工,只需访问同一集群中的一个数据库sample-database-1
。 -
user3
是现有员工,需要查看和访问同一集群中其以前无权访问的不同数据库sample-database-2
。
在这之后,user1
和 user2
都离开了公司,所以必须撤销他们的访问权限。
要创建用户和授予角色,进入集群用于进行身份验证的用户必须具有可以为 createUser
和 grantRole
执行操作的关联角色。例如,角色 admin
和 userAdminAnyDatabase
都可以授予执行上述功能的权限。有关每个角色的操作,请参阅使用基于角色的访问控制进行数据库访问。
注意
在 Amazon DocumentDB 中,所有用户和角色操作(例如,create
、get
、drop
、grant
、revoke
等等)都在 admin
数据库中隐式执行,无论您是否对 admin
数据库发出命令。
首先,要了解集群中的当前用户和角色,可以运行 show users
命令,如以下示例所示。您将看到两个用户,即集群的 serviceadmin
和主用户。这两个用户始终存在,无法将它们删除。有关更多信息,请参阅 管理 Amazon DocumentDB 用户。
show users
对于 user1
,使用以下命令创建具有对整个集群中所有数据库的读写访问权限的角色。
db.createUser({user: "user1", pwd: "abc123", roles: [{role: "readWriteAnyDatabase", db: "admin"}]})
此操作的输出将类似于下文。
{
"user":"user1",
"roles":[
{
"role":"readWriteAnyDatabase",
"db":"admin"
}
]
}
对于 user2
,使用以下命令创建对数据库 sample-database-1
具有只读访问权限的角色。
db.createUser({user: "user2", pwd: "abc123", roles: [{role: "read", db: "sample-database-1"}]})
此操作的输出将类似于下文。
{
"user":"user2",
"roles":[
{
"role":"read",
"db":"sample-database-1"
}
]
}
要模拟 user3
是现有用户的方案,请先创建用户 user3
,然后将新角色分配给 user3
。
db.createUser({user: "user3", pwd: "abc123", roles: [{role: "readWrite", db: "sample-database-1"}]})
此操作的输出将类似于下文。
{ "user":"user3", "roles":[ { "role":"readWrite", "db":"sample-database-1" } ] }
现在已创建了用户 user3
,请为 user3
分配可对 sample-database-2
进行 read
的角色。
db.grantRolesToUser("user3", [{role: "read", db: "sample-database-2"}])
最后,user1
和 user2
都离开了公司,需要撤销他们对集群的访问权限。您可以通过删除用户来执行此操作,如下所示。
db.dropUser("user1") db.dropUser("user2")
要确保所有用户都具有适当角色,可使用以下命令列出所有用户。
show users
此操作的输出将类似于下文。
{
"_id":"serviceadmin",
"user":"serviceadmin",
"db":"admin",
"roles":[
{
"db":"admin",
"role":"root"
}
]
}
{
"_id":"master-user",
"user":"master-user",
"db":"admin",
"roles":[
{
"db":"admin",
"role":"root"
}
]
}
{
"_id":"user3",
"user":"user3",
"db":"admin",
"roles":[
{
"db":"sample-database-2",
"role":"read"
},
{
"db":"sample-database-1",
"role":"readWrite"
}
]
}
RBAC 用户定义角色入门
为了帮助您开始使用用户定义的角色,本节将带您了解通过为具有不同工作功能的三个用户创建角色来强制执行最低权限的示例场景。
在本例中,以下条件适用:
-
user1
是一位新上任的经理,需要能够查看和访问集群中的所有数据库。 -
user2
是一位新员工,只需要对同一集群中的一个数据库sample-database-1
执行“查找”操作。 -
user3
是现有员工,需要查看和访问不同数据库sample-database-2
中的特定集合 col2,而他们以前在同一集群中无法访问该集合。 -
对于
user1
,使用以下命令创建具有对整个集群中所有数据库的读写访问权限的角色。
db.createUser( { user: "user1", pwd: "abc123", roles: [{role: "readWriteAnyDatabase", db: "admin"}] } )
此操作的输出将类似于下文。
{ "user":"user1", "roles":[ { "role":"readWriteAnyDatabase", "db":"admin" } ] }
对于 user2
,使用以下命令创建一个对数据库 sample-database-1
中所有集合具有“查找”权限的角色。请注意,此角色将确保任何关联用户只能运行查找查询。
db.createRole( { role: "findRole", privileges: [ { resource: {db: "sample-database-1", collection: ""}, actions: ["find"] }], roles: [] } )
此操作的输出将类似于下文。
{ "role":"findRole", "privileges":[ { "resource":{ "db":"sample-database-1", "collection":"" }, "actions":[ "find" ] } ], "roles":[ ] }
接下来,创建用户(user2
)并将最近创建的角色 findRole
附加到该用户。
db.createUser( { user: "user2", pwd: "abc123", roles: [] }) db.grantRolesToUser("user2",["findRole"])
为了模拟 user3
是现有用户的场景,首先创建用户 user3
,然后创建一个名为 collectionRole 的新角色,我们将在下一步中分配到 user3
。
现在,您可以分配新角色到 user3
。此新角色将允许user3
插入、更新、删除和查找sample-database-2
中一个特定集合 col2 的访问权限。
db.createUser( { user: "user3", pwd: "abc123", roles: [] }) db.createRole( { role: "collectionRole", privileges: [ { resource: {db: "sample-database-2", collection: "col2"}, actions: ["find", "update", "insert", "remove"] }], roles: [] } )
此操作的输出将类似于下文。
{ "role":"collectionRole", "privileges":[ { "resource":{ "db":"sample-database-2", "collection":"col2" }, "actions":[ "find", "update", "insert", "remove" ] } ], "roles":[ ] }
现在已创建了用户 user3
,你可以位角色 collectionFind
分配 user3
。
db.grantRolesToUser("user3",["collectionRole"])
最后,user1
和 user2
都离开了公司,需要撤销他们对集群的访问权限。您可以通过删除用户来执行此操作,如下所示。
db.dropUser("user1") db.dropUser("user2")
要确保所有用户都具有适当角色,可使用以下命令列出所有用户。
show users
此操作的输出将类似于下文。
{ "_id":"serviceadmin", "user":"serviceadmin", "db":"admin", "roles":[ { "db":"admin", "role":"root" } ] } { "_id":"master-user", "user":"master-user", "db":"admin", "roles":[ { "db":"admin", "role":"root" } ] } { "_id":"user3", "user":"user3", "db":"admin", "roles":[ { "db":"admin", "role":"collectionRole" } ] }
以用户身份连接到 Amazon DocumentDB
在连接到 Amazon DocumentDB 集群时,需要在特定数据库的上下文中进行连接。默认情况下,如果未在连接字符串中指定数据库,则会在 test
数据库上下文中自动连接到集群。所有集合级别命令(如 insert
和 find
)都是针对 test
数据库中的集合发出的。
要查看您所在上下文或者换句话说,对其发出命令的数据库,请在 mongo shell 中使用 db
命令,如下所示。
查询:
db
输出:
test
尽管默认连接可能位于 test
数据库的上下文中,但这并不一定意味着与连接关联的用户有权对 test
数据库执行操作。在上述示例方案中,如果您用于进行身份验证的用户 user3
是具有对 sample-database-1
数据库的 readWrite
权限的角色,则连接的默认上下文是 test
数据库。但是,如果您尝试将文档插入 test
数据库中的集合中,您将收到 Authorization failure (授权失败) 错误消息。这是因为该用户未获得对该数据库执行该命令的授权,如下所示。
查询:
db
输出:
test
查询:
db.col.insert({x:1})
输出:
WriteCommandError({ "ok" : 0, "code" : 13, "errmsg" : "Authorization failure" })
如果您将连接上下文更改为 sample-database-1
数据库,则可以写入到集合中,因为该用户具有执行此操作的授权。
查询:
use sample-database-1
输出:
switched to db sample-database-1
查询:
db.col.insert({x:1})
输出:
WriteResult({ "nInserted" : 1})
使用特定用户对集群进行身份验证时,还可以在连接字符串中指定数据库。如果这样做,则用户在通过 admin
数据库的身份验证后,不再需要执行 use
命令。
以下连接字符串根据 admin
数据库对用户进行身份验证,但连接上下文则是 sample-database-1
数据库。
mongo "mongodb://user3:abc123@sample-cluster.node.us-east-1.docdb.amazonaws.com:27017/sample-database-2"
通用命令
本节提供在 Amazon DocumentDB 中使用基于角色的访问控制的常用命令示例。您必须位于 admin
数据库的上下文中,才能创建和修改用户和角色。您可以使用 use admin
命令切换到 admin
数据库。
注意
对用户和角色的修改将隐式发生在 admin
数据库中。创建具有跨所有数据库范围的角色的用户(例如,readAnyDatabase
)需要在创建用户时处于 admin
数据库上下文(即 use
admin
),或者在创建用户时明确指定角色的数据库(如本节的示例 2 所示)。
示例 1:创建对数据库 foo
具有 read
角色的用户。
db.createUser({user: "readInFooBar", pwd: "abc123", roles: [{role: "read", db: "foo"}]})
此操作的输出将类似于下文。
{
"user":"readInFooBar",
"roles":[
{
"role":"read",
"db":"foo"
}
]
}
示例 2:创建具有所有数据库的读取访问权限的用户。
db.createUser({user: "readAllDBs", pwd: "abc123", roles: [{role: "readAnyDatabase", db: "admin"}]})
此操作的输出将类似于下文。
{
"user":"readAllDBs",
"roles":[
{
"role":"readAnyDatabase",
"db":"admin"
}
]
}
示例 3:向新数据库的现有用户授予 read
角色。
db.grantRolesToUser("readInFooBar", [{role: "read", db: "bar"}])
示例 4:更新用户的角色。
db.updateUser("readInFooBar", {roles: [{role: "read", db: "foo"}, {role: "read", db: "baz"}]})
示例 5:撤销用户对数据库的访问权限。
db.revokeRolesFromUser("readInFooBar", [{role: "read", db: "baz"}])
示例 6:描述内置角色。
db.getRole("read", {showPrivileges:true})
此操作的输出将类似于下文。
{
"role":"read",
"db":"sample-database-1",
"isBuiltin":true,
"roles":[
],
"inheritedRoles":[
],
"privileges":[
{
"resource":{
"db":"sample-database-1",
"collection":""
},
"actions":[
"changeStream",
"collStats",
"dbStats",
"find",
"killCursors",
"listCollections",
"listIndexes"
]
}
],
"inheritedPrivileges":[
{
"resource":{
"db":"sample-database-1",
"collection":""
},
"actions":[
"changeStream",
"collStats",
"dbStats",
"find",
"killCursors",
"listCollections",
"listIndexes"
]
}
}
示例 7:从集群中删除用户。
db.dropUser("readInFooBar")
此操作的输出将类似于下文。
true
示例 8:创建对特定集合具有读写权限的角色
db.createRole( { role: "collectionRole", privileges: [ { resource: {db: "sample-database-2", collection: "col2"}, actions: ["find", "update", "insert", "remove"] }], roles: [] } )
此操作的输出将类似于下文。
{ "role":"collectionRole", "privileges":[ { "resource":{ "db":"sample-database-2", "collection":"col2" }, "actions":[ "find", "update", "insert", "remove" ] } ], "roles":[ ] }
示例 9:创建用户并分配用户定义角色
db.createUser( { user: "user3", pwd: "abc123", roles: [] }) db.grantRolesToUser("user3",["collectionRole"])
示例 10:向用户定义角色授予其他权限
db.grantPrivilegesToRole( "collectionRole", [ { resource: { db: "sample-database-1", collection: "col1" }, actions: ["find", "update", "insert", "remove"] } ] )
示例 11:删除用户定义角色的权限
db.revokePrivilegesFromRole( "collectionRole", [ { resource: { db: "sample-database-1", collection: "col2" }, actions: ["find", "update", "insert", "remove"] } ] )
示例 12:更新现有用户定义角色
db.updateRole( "collectionRole", { privileges: [ { resource: {db: "sample-database-3", collection: "sample-collection-3"}, actions: ["find", "update", "insert", "remove"] }], roles: [] } )
功能差异
在 Amazon DocumentDB 中,用户和角色定义存储在 admin
数据库中,而且根据 admin
数据库对用户进行身份验证。此功能与 MongoDB 社区版不同,但与 MongoDB Atlas 一致。
Amazon DocumentDB 还支持变更流,该功能提供按时间顺序排列的更改事件,这些事件在您的集集群合中发生。listChangeStreams
操作应用于集群级别(即跨所有数据库),modifyChangeStreams
操作可以应用于数据库级别和集群级别。
限制
下表包含 Amazon DocumentDB 中基于角色的访问控制的限制。
描述 | 限制 |
---|---|
每个集群的用户数 | 1000 |
与用户关联的角色数 | 1000 |
用户定义角色数 | 100 |
与权限关联的资源数 | 100 |
使用基于角色的访问控制进行数据库访问
借助基于角色的访问控制,您可以创建一个用户并向其授予一个或多个角色,以确定该用户可以在数据库或集群中执行哪些操作。
以下是 Amazon DocumentDB 中目前支持的内置角色的列表。
注意
在 Amazon DocumentDB 4.0 和 5.0 中,ListCollection
和 ListDatabase
命令可以选择使用 authorizedCollections
和 authorizedDatabases
参数列出用户有权访问分别需要 listCollections
和 listDatabase
角色的集合和数据库。此外,用户现在可以在不需要 KillCursor
角色的情况下终止自己的游标。