有办法限制MongoDB的普通用户的建表权限么?
有办法限制MongoDB的普通用户的建表权限么?

有办法限制MongoDB的普通用户的建表权限么?

需求背景

我们有一个需求,就是希望能够限制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"
      ]
    }
  ]
)

从而来实现控制用户的建表权限的需求。