需求背景
我们有一个需求,就是希望能够限制MongoDB应用的业务用户的建集合权限,目的是希望研发在新增集合时能够通知到DBA,DBA能够介入到整个应用开发流程,防止研发人员设计出一些低性能的表结构,偷偷摸摸上了新表新功能,等到真正上线之后才暴漏出真正的问题, 后期优化成本剧增,如果能将风险控制在功能上线前,将会避免很多的麻烦。 下面是我们创建普通业务用户的命令,readWrite其实包含了很多的权限,是一个比较宽的权限。
use appdb
db.createUser({ user: "appdb", pwd: "appdb_pwd",
roles: [{ role: "readWrite", db: "appdb" }]
})
但是MongoDB是一个schema-less的数据库,用户在insert集合的时候如果集合不存在的话会自动创建集合
目前来看好像没办法实现我们想要的需求?
实际上这个需求可以使用MongoDB集合级别的权限控制来实现
创建初始化用户, 用户只有mydb库的只读权限
use appdb
db.createUser({ user: "appdb",
pwd: "appdb_pwd",
roles: [{ role: "read", db: "appdb" }]
})
/*创建角色, 这里collection不能设置空"",空表示对所有collection都有权限 */
db.createRole({
role: "db_role",
privileges: [
{
resource: { db: "appdb", collection: "tmp_table" },
actions: [
"find",
"insert",
"remove",
"update",
"collStats",
"createIndex",
"dbHash",
"dbStats",
"dropIndex",
"killCursors",
"listCollections",
"listIndexes"
]
}
],
roles: []
})
/* 将这个角色授权给用户 */
db.grantRolesToUser("appdb", [
{ role: "db_role", db:"appdb" }
])
通过工单系统添加表
如下是添加了一个user_role_info表, appdb用户就能对user_role_info表做正常的DML了,每加一个表就做以下的步骤。
/*授权*/
db.grantPrivilegesToRole(
"db_role",
[
{
resource: { db: "appdb", collection: "user_role_info" },
actions: [
"find",
"insert",
"remove",
"update",
"collStats",
"createIndex",
"dbHash",
"dbStats",
"dropIndex",
"killCursors",
"listCollections",
"listIndexes"
]
}
]
)
/*提前创建空集合,用show collections命令可以看到集合名*/
db.createCollection("user_role_info");
如果有需要可以通过validator功能限制字段其他属性
/*最简单的demo*/
db.createCollection("user_role_info", {
validator: { $jsonSchema: {
bsonType: "object",
required: [ "user_id"],
properties: {
user_id: {
bsonType: "int",
description: "must be a integer and is required"
},
email: {
bsonType : "string",
pattern : "@test\.com$",
description: "must be a string and match the regular expression pattern"
},
status: {
enum: [ "Unknown", "Incomplete" ],
description: "can only be one of the enum values"
}
}
} }
})
优化
上面每一次都要授很多权限,略显繁琐,其实可以更简化一下,既然insert权限控制了集合的create权限,我们可以预先给用户分配所有表上的除了insert之外的所有权限,后续添加表时只需要授insert权限即可。
/*授权*, 集合名为空""表示所有的表/
db.grantPrivilegesToRole(
"db_role",
[
{
resource: { db: "appdb", collection: "" },
actions: [
"find",
"remove",
"update",
"collStats",
"createIndex",
"dbHash",
"dbStats",
"dropIndex",
"killCursors",
"listCollections",
"listIndexes"
]
}
]
)
此时再按需增加一个一个的业务表。
db.grantPrivilegesToRole(
"db_role",
[
{
resource: { db: "appdb", collection: "user_role_info" },
actions: [
"insert"
]
}
]
)
从而来实现控制用户的建表权限的需求。