MongoDB认证与授权

Posted lqding1980

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongoDB认证与授权相关的知识,希望对你有一定的参考价值。

MongoDB认证与授权

目录

[toc]

要想了解MongoDB的权限必须先了解如下一些关键字:

  • user:
    用户,用于提供客户端连接MongoDB的认证账户;
  • role:
    角色,数据权限的集合,创建用户的时候必须要指定对应的角色,否则用户无法操作数据库;
  • resource:
    资源,包括database或collection 也可以是database和collection的组合;
    {db:<db>, collection:<collection>}
  • actions:
    权限操作,定义了 user 能够对 resource document 执行的操作;
    如 增、删、改、查;
  • privilege:
    权限,privilege 是一组 resource 和 action的组合,对资源拥有什么操作称为权限;
  • authenticationDatabase:
    认证库,及创建角色或用户时所在的库;
    如,在admin下创建MongoDB用户那么登录的时候需要指定认证库 admin;
    在 test 库下创建的用户登录的时候指定认证库 test;

权限认证

MondoDB单实例认证

MongodDB存储所有的用户信息在admin数据库的集合system.users中,保存数据库、密码和数据库信息。MongoDB默认不启用权限认证,只要能连接到服务器,就可连接到mongod。
若要启用安全认证,需要更改配置文件Authorization,也可简写为 auth。或者在命令行启动MongoDB时加上 -auth参数启动,这样当MongoDB启动后就需要用户和密码进行认证了。

这是老版本MongoDB2.x中:

vim /etc/mongod.conf
auth = true

MongoDB3.x中:

vim /etc/mongod.conf
security:
    authorization:enabled

但是,不使用用户名和密码依然可以连接到数据库。但是将没有权限查看数据库。

连接到数据库后,可以使用db.auth命令认证用户:

mongo
use admin
db.auth("user","pwd")

或直接 mongo 127.0.0.1/admin -u user -p 来连接数据库。

MongoDB副本集认证

如果在副本集机制下开启了 -auth 认证,那么此时MongoDB副本集状态就会变成不健康状态,这就需要另外一个认证方式 KeyFile
简单来说 KeyFile 就是用在副本集群间开启认证的情况下需要的另一种认证方式,用来验证集群间身份的。

在各个节点的配置文件中加入KeyFile(600):

vim /etc/mongod.conf

security:
    authorization:enabled
    KeyFile:/path/.KeyFile

角色管理

MondoDB支持基于角色的访问控制(RBAC)来管理对MongoDB系统的访问。一个用户可以被授权一个或多个角色以决定该用户对数据库资源和操作的访问权限。在权限以外,用户是无法访问系统的。
数据库角色在创建用户的role参数中设置。角色分为內建角色和自定义角色。

內建角色

MongoDB內建角色包括以下几类:

数据库读写角色

read:允许用户读取指定数据库;
readWrite:允许用户读写指定数据库;

数据库管理员角色

dbAdmin

允许用户进行索引创建、删除,查看统计或访问system.profile,但没有角色和用户管理的权限;

userAdmin

提供了在当前数据库中创建和修改角色和用户的能力;

包含如下action

dbOwner

提供对数据库执行任何操作的能力。这个角色组合了readWrite、dbAdmin和userAdmin角色授权的特权;

集群管理角色

hostManager:提供监视和管理服务器的能力;
clusterManager:在集群上提供管理和监视操作。可以访问配置和本地数据库,这些数据库分别用于分片和复制;
clusterMonitor:提供对监控工具的只读访问;
clusterAdmin:提供最强大的集群管理访问(副本集、分片、主从等)。组合了clusterManager、clusterMonitor和hostManager角色的能力,还提供了dropDatabase操作;

备份恢复角色

backup:提供备份数据所需的能力;
restore: 提供使用mongorestore恢复数据的能力;

所有数据库角色

readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限;
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限;
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限;
dbAdminAnyDataBase:只在admin数据库中可用,赋予用户所有数据库的adAdmin权限;

超级用户角色

root:超级权限,只能针对admin库;

内部角色

__system:提供对数据库中任何对象的任何操作的特权;

自定义角色

MongoDB内置角色一般来说都是够用的,但当内置角色不满足需求时就可以自定义角色了。使用 db.createRole() 方法来自定义角色。
只能在 admin库 中创建角色;

use admin
db.createRole(
    {
      role: "<name>",
      privileges: [
         { resource: { <resource> }, actions: [ "<action>", ... ] },
         ...
      ],
      roles: [
         { role: "<role>", db: "<database>" } | "<role>",
          ...
      ],
      authenticationRestrictions: [
        {
          clientSource: ["<IP>" | "<CIDR range>", ...],
          serverAddress: ["<IP>" | "<CIDR range>", ...]
        },
        ...
      ]
    }
)

权限由资源和action组合而成

resource

mongodb中resource分为如下几类

数据库或集合

语法:

{ db: <database>, collection: <collection> }

指定数据库集合

{ db: "products", collection: "inventory" }

指定数据库

{ db: "products", collection: "" }

跨库指定集合

 { db: "", collection: "inventory" }

指定所有库所有集合

 { db: "", collection: "" }
集群资源
{ cluster : true }
任意资源
{ anyResource: true }

action

读写action
  • find
  • insert
  • remove
  • update
  • bypassDocumentValidation
  • useUUID
数据库管理action
  • changeCustomData
  • changeOwnCustomData
  • changeOwnPassword
  • changePassword
  • createCollection
  • createIndex
  • createRole
  • createUser
  • dropCollection
  • dropRole
  • dropUser
  • enableProfiler
  • grantRole
  • killCursors
  • killAnyCursor
  • revokeRole
  • setAuthenticationRestriction
  • unlock
  • viewRole
  • viewUser

操作角色

创建角色

自定义一个角色,角色拥有任意数据库上的赋予、收回、查看角色的权限

use admin
db.createRole(
  {
      role: "grantRevokeRoleAnyDB",
      privileges: [
          { resource :{ db: "", collection: ""}, actions: ["grantRole", "revokeRole", "viewRole"] }
      ],
      roles: []
  }
)
查看角色
  • db.getRole()
admin@undefined$ db.getRoles()
[
        {
                "role" : "grantRevokeRoleAnyDB",
                "db" : "admin",
                "isBuiltin" : false,
                "roles" : [ ],
                "inheritedRoles" : [ ]
        }
]
  • db.system.roles.find()
admin@undefined$ db.system.roles.find().pretty()
{
        "_id" : "admin.grantRevokeRoleAnyDB",
        "role" : "grantRevokeRoleAnyDB",
        "db" : "admin",
        "privileges" : [
                {
                        "resource" : {
                                "db" : "",
                                "collection" : ""
                        },
                        "actions" : [
                                "grantRole",
                                "revokeRole",
                                "viewRole"
                        ]
                }
        ],
        "roles" : [ ]
}
角色继承
-- 语法
db.grantRolesToRole( "<rolename>", [ <roles> ], { <writeConcern> } )

roles字段,可以指定内置角色,也可以是自定义角色

role有两种方式:

  • 只指定角色,比如read,那角色默认作用的数据库为运行如上命令所在的数据库
  • 指定db和角色
db.grantRolesToRole("grantRevokeRoleAnyDB",["read"])
db.grantRolesToRole("grantRevokeRoleAnyDB",[{role: "readWrite", db:"test"}])  #这里的db不能指定为""
# 查看
db.getRoles()
[
        {
                "role" : "grantRevokeRoleAnyDB",
                "db" : "admin",
                "isBuiltin" : false,
                "roles" : [
                        {
                                "role" : "read",
                                "db" : "admin"
                        },
                        {
                                "role" : "readWrite",
                                "db" : "test"
                        }
                ],
                "inheritedRoles" : [
                        {
                                "role" : "read",
                                "db" : "admin"
                        },
                        {
                                "role" : "readWrite",
                                "db" : "test"
                        }
                ]
        }
]
# 通过getRoles函数,看不到了role自定义的权限
# 使用db.system.roles.find()
db.system.roles.find().pretty()
{
        "_id" : "admin.grantRevokeRoleAnyDB",
        "role" : "grantRevokeRoleAnyDB",
        "db" : "admin",
        "privileges" : [
                {
                        "resource" : {
                                "db" : "",
                                "collection" : ""
                        },
                        "actions" : [
                                "grantRole",
                                "revokeRole",
                                "viewRole"
                        ]
                }
        ],
        "roles" : [
                {
                        "role" : "read",
                        "db" : "admin"
                },
                {
                        "role" : "readWrite",
                        "db" : "test"
                }
        ]
}
角色回收

db.revokeRolesfromRole()

与角色继承用法一样

db.revokeRolesFromRole("grantRevokeRoleAnyDB",["read"])
db.system.roles.find().pretty()
{
        "_id" : "admin.grantRevokeRoleAnyDB",
        "role" : "grantRevokeRoleAnyDB",
        "db" : "admin",
        "privileges" : [
                {
                        "resource" : {
                                "db" : "",
                                "collection" : ""
                        },
                        "actions" : [
                                "grantRole",
                                "revokeRole",
                                "viewRole"
                        ]
                }
        ],
        "roles" : [
                {
                        "role" : "readWrite",
                        "db" : "test"
                }
        ]
}

db.revokeRolesFromRole("grantRevokeRoleAnyDB",[{db: "test", role:"readWrite"}])
db.system.roles.find().pretty()
{
        "_id" : "admin.grantRevokeRoleAnyDB",
        "role" : "grantRevokeRoleAnyDB",
        "db" : "admin",
        "privileges" : [
                {
                        "resource" : {
                                "db" : "",
                                "collection" : ""
                        },
                        "actions" : [
                                "grantRole",
                                "revokeRole",
                                "viewRole"
                        ]
                }
        ],
        "roles" : [ ]
}

用户管理

创建用户

db.createUser({
    user:"xxx",
    pwd:"xxxx",
    roles:[{    #指定角色名称,以及作用于何数据库
        role:"xxx", db:"xxxx"
    }]
})

查看用户

  • db.getUsers()

​ 获取当前认证库下的所有用户

test@undefined$ db
test
test@undefined$ db.getUsers()
[
        {
                "_id" : "test.user1",
                "userId" : UUID("26cb7625-8f2f-421d-95e4-15e6150e969b"),
                "user" : "user1",
                "db" : "test",
                "roles" : [
                        {
                                "role" : "read",
                                "db" : "test"
                        }
                ],
                "mechanisms" : [
                        "SCRAM-SHA-1",
                        "SCRAM-SHA-256"
                ]
        }
]
test@undefined$ use admin
switched to db admin
admin@undefined$ db.getUsers()
[
        {
                "_id" : "admin.root",
                "userId" : UUID("c80ec145-da32-4192-bd23-4639da5e6d91"),
                "user" : "root",
                "db" : "admin",
                "roles" : [
                        {
                                "role" : "userAdminAnyDatabase",
                                "db" : "admin"
                        }
                ],
                "mechanisms" : [
                        "SCRAM-SHA-1",
                        "SCRAM-SHA-256"
                ]
        }
]
  • db.getUser("user")

​ 获取当前认证库下指定用户

#再创建一个用户
test@undefined$ db.createUser({
...   user: "user2",
...   pwd: "password2",
...   roles: [ { role: "read", db: "test" } ]
... })
Successfully added user: {
        "user" : "user2",
        "roles" : [
                {
                        "role" : "read",
                        "db" : "test"
                }
        ]
}
# test 库下有两个用户
test@undefined$ db.getUsers()
[
        {
                "_id" : "test.user1",
                "userId" : UUID("26cb7625-8f2f-421d-95e4-15e6150e969b"),
                "user" : "user1",
                "db" : "test",
                "roles" : [
                        {
                                "role" : "read",
                                "db" : "test"
                        }
                ],
                "mechanisms" : [
                        "SCRAM-SHA-1",
                        "SCRAM-SHA-256"
                ]
        },
        {
                "_id" : "test.user2",
                "userId" : UUID("756272ed-a8ff-4333-bee2-7998454e4f15"),
                "user" : "user2",
                "db" : "test",
                "roles" : [
                        {
                                "role" : "read",
                                "db" : "test"
                        }
                ],
                "mechanisms" : [
                        "SCRAM-SHA-1",
                        "SCRAM-SHA-256"
                ]
        }
]
# 获取指定用户
test@undefined$ db.getUser("user2")
{
        "_id" : "test.user2",
        "userId" : UUID("756272ed-a8ff-4333-bee2-7998454e4f15"),
        "user" : "user2",
        "db" : "test",
        "roles" : [
                {
                        "role" : "read",
                        "db" : "test"
                }
        ],
        "mechanisms" : [
                "SCRAM-SHA-1",
                "SCRAM-SHA-256"
        ]
}
  • db.system.users.find()

    获取所有用户信息

test@undefined$ use admin
switched to db admin
admin@undefined$ db.system.users.find().pretty()
{
        "_id" : "admin.root",
        "userId" : UUID("c80ec145-da32-4192-bd23-4639da5e6d91"),
        "user" : "root",
        "db" : "admin",
        "credentials" : {
                "SCRAM-SHA-1" : {
                        "iterationCount" : 10000,
                        "salt" : "cdKArk1NhxpvFmvTvKCItA==",
                        "storedKey" : "HUo9S9XjOB8m3d8ZXFFxPjqAK5Q=",
                        "serverKey" : "rGnwDfRi/z2jfiGkwWWsUTPkGkQ="
                },
                "SCRAM-SHA-256" : {
                        "iterationCount" : 15000,
                        "salt" : "KagWAruayVEUbNf5l0dOenrXb05HqtRIXs6CkA==",
                        "storedKey" : "5le156+HTjcN3VzXIaEypi3pZ7RSDy0fDpDRyW5B1N8=",
                        "serverKey" : "iTjmBP/wP5drO2rE1IM+GvIEfuDDUM3IvGhjuydI7PI="
                }
        },
        "roles" : [
                {
                        "role" : "userAdminAnyDatabase",
                        "db" : "admin"
                }
        ]
}
{
        "_id" : "test.user1",
        "userId" : UUID("26cb7625-8f2f-421d-95e4-15e6150e969b"),
        "user" : "user1",
        "db" : "test",
        "credentials" : {
                "SCRAM-SHA-1" : {
                        "iterationCount" : 10000,
                        "salt" : "iNKugTh/fVlal5d22vTQlQ==",
                        "storedKey" : "D6TOl2P5v8wboGf12LHr3796J7I=",
                        "serverKey" : "63e+PWI+F5arREp9SsEcHFrWHPY="
                },
                "SCRAM-SHA-256" : {
                        "iterationCount" : 15000,
                        "salt" : "g2rNWPU42wAkcWWrrdZFEM3jCug7puS1tn8CWg==",
                        "storedKey" : "nPXRMJkRmMFP8ytWmACpYCmVnEHV+GIRHA6TKiZLmPY=",
                        "serverKey" : "rxu1f4Bi8JJxFpWJZa8OwRog0eVzFHYraFAyMIf+iVE="
                }
        },
        "roles" : [
                {
                        "role" : "read",
                        "db" : "test"
                }
        ]
}
{
        "_id" : "test.user2",
        "userId" : UUID("756272ed-a8ff-4333-bee2-7998454e4f15"),
        "user" : "user2",
        "db" : "test",
        "credentials" : {
                "SCRAM-SHA-1" : {
                        "iterationCount" : 10000,
                        "salt" : "DmLYgaL4oc8HE3qZghrjYQ==",
                        "storedKey" : "uPUI6RayJpNasyRVvQSuCvoxYXc=",
                        "serverKey" : "PbpZfK2UgCphoa8pkGCtGN69mjk="
                },
                "SCRAM-SHA-256" : {
                        "iterationCount" : 15000,
                        "salt" : "EyRe0aaqeUmOUZKSMu8kEqOqzqBKY4Enw7tnhg==",
                        "storedKey" : "Rill2kRC3rELi0uu4M8Efjeny6KbDs2g8so+35cEk2M=",
                        "serverKey" : "7yEHeydWZl5Hlnrj6ZnABEnD2JVB05W+2nUsal2P5aA="
                }
        },
        "roles" : [
                {
                        "role" : "read",
                        "db" : "test"
                }
        ]
}

用户角色管理

赋予角色

创建用户时,可以不指定角色。

db.createUser(
...   {
...     user: "user1",
...     pwd: "password1",
...     roles: []
...   }
... )
Successfully added user: { "user" : "user1", "roles" : [ ] }

创建完用户后,可以授予用户角色

db.grantRolesToUser(
...   "user1",
...   [{ role: "read", db: "test"}]
... )

db.getUser("user1")
{
        "_id" : "admin.user1",
        "userId" : UUID("62952ca2-5c70-464e-ba0a-6176101649f7"),
        "user" : "user1",
        "db" : "admin",
        "roles" : [
                {
                        "role" : "read",
                        "db" : "test"
                }
        ],
        "mechanisms" : [
                "SCRAM-SHA-1",
                "SCRAM-SHA-256"
        ]
}

收回角色

db.revokeRolesFromUser(
   "user1",
   [{ role: "read", db: "test"}]
 )

db.getUser("user1")
{
        "_id" : "admin.user1",
        "userId" : UUID("62952ca2-5c70-464e-ba0a-6176101649f7"),
        "user" : "user1",
        "db" : "admin",
        "roles" : [ ],
        "mechanisms" : [
                "SCRAM-SHA-1",
                "SCRAM-SHA-256"
        ]
}

删除用户

db.dropUser("user1")  # 删除当前库下user1用户
db.dropAllUsers()    #删除当前库所有用户

修改密码

db.changeUserPassword("user","new_passwd")

更新用户

db.updateUser( username, update, writeConcern )

语法:

db.updateUser(
   "<username>",
   {
     customData : { <any information> },
     roles : [
       { role: "<role>", db: "<database>" } | "<role>",
       ...
     ],
     pwd: passwordPrompt(),      // Or  "<cleartext password>"
     authenticationRestrictions: [
        {
          clientSource: ["<IP>" | "<CIDR range>", ...],
          serverAddress: ["<IP>", | "<CIDR range>", ...]
        },
        ...
     ],
     mechanisms: [ "<SCRAM-SHA-1|SCRAM-SHA-256>", ... ],
     passwordDigestor: "<server|client>"
   },
   writeConcern: { <write concern> }
)

指定的字段,将完全替换先前的字段值

示例:

在products库里创建appClient01用户

db.createUser(
    {
       user : "appClient01",
       pwd: passwordPrompt(),
       customData : { empID : "12345", badge : "9156" },
       roles : [
           {
             role : "readWrite",
             db: "products"
           },
           {
             role : "read",
             db: "inventory"
           }
       ],
       mechanisms : [         // Starting in MongoDB 4.0
          "SCRAM-SHA-1",
          "SCRAM-SHA-256"
       ],
       authenticationRestrictions : [ {
          clientSource: ["69.89.31.226"],
          serverAddress: ["172.16.254.1"]
       } ]
    }
)

完全替换customData和roles字段

use products
db.updateUser( "appClient01",
{
   customData : { employeeId : "0x3039" },
   roles : [
      { role : "read", db : "assets"  }
   ]
} )
# 查看替换结果
use admin
db.system.users.find({user:"appClient01"}).pretty()
{
        "_id" : "products.appClient01",
        "userId" : UUID("c4309b54-5fbd-49d2-aa79-223f441257e2"),
        "user" : "appClient01",
        "db" : "products",
        "credentials" : {
                "SCRAM-SHA-1" : {
                        "iterationCount" : 10000,
                        "salt" : "/vCAfg09papZ1vcYLEzw+w==",
                        "storedKey" : "L0THU8ODHL8Sg4hv5FrVo3aphZU=",
                        "serverKey" : "c2Q5UpaffvFD2ctwPfRon6OweaA="
                },
                "SCRAM-SHA-256" : {
                        "iterationCount" : 15000,
                        "salt" : "6GIelp+V63thV8Xp2LZRlVVPjG9601jFLlQz0w==",
                        "storedKey" : "fCbnx0NF7BmkUvvJyYqK2dVxt7c32n4eYt96P7d9Xu8=",
                        "serverKey" : "5sqiadkBHSDv42Wc99sH3u2+LpnBm6/Ge9oNt09JweA="
                }
        },
        "authenticationRestrictions" : [
                {
                        "clientSource" : [
                                "69.89.31.226"
                        ],
                        "serverAddress" : [
                                "172.16.254.1"
                        ]
                }
        ],
        "customData" : {
                "employeeId" : "0x3039"
        },
        "roles" : [
                {
                        "role" : "read",
                        "db" : "assets"
                }
        ]
}

可见只修改了customData和roles列

以上是关于MongoDB认证与授权的主要内容,如果未能解决你的问题,请参考以下文章

Mongodb副本集认证授权

MongoDB管理之安全性

mongodb之用户/认证/角色/权限管理

MongoDB未授权访问漏洞复现及docker.mongodb下--auth授权验证

mongo-connector怎么去mongo授权数据库认证

mongodb授权登录