3.安全认证

3.1 MongoDB的用户和角色权限简介

默认情况下,MongoDB实例启动运行时是没有启用用户访问权限控制的,也就是说,在实例本机服务器上都可以随意连接到实例进行各种操作,MongoDB不会对连接客户端进行用户验证,这是非常危险的。

mongodb官网上说,为了能保障mongodb的安全可以做以下几个步骤:
1)使用新的端口,默认的27017端口如果一旦知道了ip就能连接上,不太安全。
2)设置mongodb的网络环境,最好将mongodb部署到公司服务器内网,这样外网是访问不到的。公司内部访问使用vpn等。
3)开启安全认证。认证要同时设置服务器之间的内部认证方式,同时要设置客户端连接到集群的账号密码认证方式。

为了强制开启用户访问控制(用户验证),则需要在MongoDB实例启动时使用选项 --auth 或在指定启动配置文件中添加选项 auth=true 。
在开始之前需要了解一下概念

1)启用访问控制:
MongoDB使用的是基于角色的访问控制(Role-Based Access Control,RBAC)来管理用户对实例的访问。
通过对用户授予一个或多个角色来控制用户访问数据库资源的权限和数据库操作的权限,在对用户分配角色之前,用户无法访问实例。
在实例启动时添加选项 --auth 或指定启动配置文件中添加选项 auth=true 。

2)角色:
在MongoDB中通过角色对用户授予相应数据库资源的操作权限,每个角色当中的权限可以显式指定,也可以通过继承其他角色的权限,或者两都都存在的权限。

3)权限:
权限由指定的数据库资源(resource)以及允许在指定资源上进行的操作(action)组成。

  1. 资源(resource)包括:数据库、集合、部分集合和集群;
  2. 操作(action)包括:对资源进行的增、删、改、查(CRUD)操作。

在角色定义时可以包含一个或多个已存在的角色,新创建的角色会继承包含的角色所有的权限。在同一个数据库中,新创建角色可以继承其他角色的权限,在 admin 数据库中创建的角色可以继承在其它任意数据库中角色的权限。

关于角色权限的查看,可以通过如下命令查询(了解):

// 查询所有角色权限(仅用户自定义角色) 
> db.runCommand({ rolesInfo: 1 }) 
// 查询所有角色权限(包含内置角色) 
> db.runCommand({ rolesInfo: 1, showBuiltinRoles: true })

// 查询当前数据库中的某角色的权限 
> db.runCommand({ rolesInfo: "" }) 
// 查询其它数据库中指定的角色权限 
> db.runCommand({ 
   rolesInfo: { 
       role: "",
       db: "" 
   } 
} 
// 查询多个角色权限 
> db.runCommand( {
       rolesInfo: [ "", 
            { role: "", 
              db: "" }, ... ] 
} )

示例:
查看所有内置角色:

> db.runCommand({ rolesInfo: 1, showBuiltinRoles: true }) 
{ 
    "roles" : [ 
      { 
        "role" : "__queryableBackup", 
        "db" : "admin", 
        "isBuiltin" : true, 
        "roles" : [ ],
        "inheritedRoles" : [ ] 
     },{ 
        "role" : "__system", 
        "db" : "admin", 
        "isBuiltin" : true, 
        "roles" : [ ], 
        "inheritedRoles" : [ ] 
     },{ 
        "role" : "backup", 
        "db" : "admin", 
        "isBuiltin" : true, 
        "roles" : [ ], 
        "inheritedRoles" : [ ] 
      },{ 
        "role" : "clusterAdmin", 
        "db" : "admin", 
        "isBuiltin" : true, 
        "roles" : [ ], 
        "inheritedRoles" : [ ] 
       },{ 
        "role" : "clusterManager",
        "db" : "admin", 
        "isBuiltin" : true, 
        "roles" : [ ], 
        "inheritedRoles" : [ ] 
       },{ 
         "role" : "clusterMonitor", 
         "db" : "admin", 
         "isBuiltin" : true, 
         "roles" : [ ], 
         "inheritedRoles" : [ ] 
       },{ 
         "role" : "dbAdmin", 
         "db" : "admin", 
         "isBuiltin" : true, 
         "roles" : [ ], 
         "inheritedRoles" : [ ] 
       },{ 
         "role" : "dbAdminAnyDatabase", 
         "db" : "admin", 
         "isBuiltin" : true, 
         "roles" : [ ], 
         "inheritedRoles" : [ ] 
       },{ 
         "role" : "dbOwner", 
         "db" : "admin", 
         "isBuiltin" : true, 
         "roles" : [ ], 
         "inheritedRoles" : [ ] 
       },{ 
         "role" : "enableSharding", 
         "db" : "admin", 
          "isBuiltin" : true, 
          "roles" : [ ], 
          "inheritedRoles" : [ ] 
        },{ 
          "role" : "hostManager",
          "db" : "admin", 
          "isBuiltin" : true, 
          "roles" : [ ], 
          "inheritedRoles" : [ ] 
        },{ 
          "role" : "read", 
          "db" : "admin", 
          "isBuiltin" : true, 
          "roles" : [ ], 
          "inheritedRoles" : [ ] 
        },{ 
          "role" : "readAnyDatabase", 
          "db" : "admin",
          "isBuiltin" : true,
          "roles" : [ ], 
          "inheritedRoles" : [ ] 
        },{ 
          "role" : "readWrite", 
          "db" : "admin", 
          "isBuiltin" : true, 
          "roles" : [ ], 
          "inheritedRoles" : [ ] 
        },{ 
         "role" : "readWriteAnyDatabase", 
         "db" : "admin", 
         "isBuiltin" : true, 
         "roles" : [ ], 
         "inheritedRoles" : [ ] 
        },{ 
         "role" : "restore", 
         "db" : "admin", 
         "isBuiltin" : true,
         "roles" : [ ], 
         "inheritedRoles" : [ ] 
       },{ 
         "role" : "root", 
         "db" : "admin", 
         "isBuiltin" : true, 
         "roles" : [ ], 
         "inheritedRoles" : [ ] 
       },{ 
          "role" : "userAdmin", 
          "db" : "admin", 
          "isBuiltin" : true, 
          "roles" : [ ], 
          "inheritedRoles" : [ ] 
       },{ 
          "role" : "userAdminAnyDatabase", 
          "db" : "admin", 
          "isBuiltin" : true,
          "roles" : [ ], 
          "inheritedRoles" : [ ] 
        } 
     ],
"ok" : 1
 }

常用的内置角色:

  • 数据库用户角色:read、readWrite;
  • 所有数据库用户角色:readAnyDatabase,readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
  • 数据库管理角色:dbAdmin、dbOwner、userAdmin;
  • 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
  • 备份恢复角色:backup、restore;
  • 超级用户角色:root
  • 内部角色:system

角色说明:

image.png

3.2 单实例环境

目标:对单实例的MongoDB服务开启安全认证,这里的单实例指的是未开启副本集或分片的MongoDB
实例。
3.2.1 关闭已开启的服务(可选)
增加mongod的单实例的安全认证功能,可以在服务搭建的时候直接添加,也可以在之前搭建好的服务上添加。

本文使用之前搭建好的服务,因此,先停止之前的服务
停止服务的方式有两种:快速关闭和标准关闭,下面依次说明:
(1)快速关闭方法(快速,简单,数据可能会出错)
目标:通过系统的kill命令直接杀死进程:

杀完要检查一下,避免有的没有杀掉。

#通过进程编号关闭节点
 kill -2 54410

【补充】
如果一旦是因为数据损坏,则需要进行如下操作(了解):
1)删除lock文件:

rm -f /mongodb/single/data/db/*.lock 

2)修复数据:

/usr/local/mongodb/bin/mongod --repair --dbpath=/mongodb/single/data/db

(2)标准的关闭方法(数据不容易出错,但麻烦):
目标:通过mongo客户端中的shutdownServer命令来关闭服务
主要的操作步骤参考如下:

//客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。 
mongo --port 27017 
//#切换到admin库
use admin 
//关闭服务 
db.shutdownServer()

3.2.2 添加用户和权限
(1)先按照普通无授权认证的配置,来配置服务端的配置文件 /mongodb/single/mongod.conf :
(参考,复用之前课程的)

 systemLog: 
    #MongoDB发送所有日志输出的目标指定为文件 
    destination: file 
    #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径 
    path: "/mongodb/single/log/mongod.log" 
    #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
    logAppend: true 
 storage: 
    #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。 
    dbPath: "/mongodb/single/data/db" 
    journal: 
    #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true 
 processManagement: 
     #启用在后台运行mongos或mongod进程的守护进程模式。 
    fork: true 
    #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
    pidFilePath: "/mongodb/single/log/mongod.pid" 
 net:
    #服务实例绑定的IP 
    bindIp: localhost,192.168.0.2
    #绑定的端口 
    port: 27017 

(2)按之前未开启认证的方式(不添加 --auth 参数)来启动MongoDB服务:

/usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf

提示:
在操作用户时,启动mongod服务时尽量不要开启授权。
(3)使用Mongo客户端登录:

/usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017 

(4)创建两个管理员用户,一个是系统的超级管理员 myroot ,一个是admin库的管理用户
myadmin :

//切换到admin库 
> use admin 
//创建系统超级用户 myroot,设置密码123456,设置角色root 
//> db.createUser({user:"myroot",pwd:"123456",roles:[ { "role" : "root", "db" : "admin" } ]}) 
//或 
> db.createUser({user:"myroot",pwd:"123456",roles:["root"]})
Successfully 
 added user: { 
       "user" : "myroot",
       "roles" : [ "root" ] 
 } 
//创建专门用来管理admin库的账号myadmin,只用来作为用户权限的管理 
> db.createUser({user:"myadmin",pwd:"123456",roles: 
[{role:"userAdminAnyDatabase",db:"admin"}]}) 
Successfully added user: {
    "user" : "myadmin", 
    "roles" : [ { 
      "role" : "userAdminAnyDatabase", 
      "db" : "admin" } ] 
}
//查看已经创建了的用户的情况: 
> db.system.users.find()
{ "_id" : "admin.myroot", "userId" : UUID("9a0a698c-73ad-4c45-8f33- e8a90d3ad689"), "user" : "myroot", "db" : "admin", "credentials" : { "SCRAM-SHA- 1" : { "iterationCount" : 10000, "salt" : "4tXXi9g9wMlrR32e+NleyA==", "storedKey" : "78EXQoWeA6lLYTTzcQrtJuWLcmg=", "serverKey" : "xwze/lGcQ7FI5cSFoilY4CW4Wks=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "+Hq2Y6PiNFkDEBYFertTaZSWI9FqbkYGdHaFkg==", "storedKey" : "gUZ5Wyl7dsjtu77Isw2dsJ+Ck4fKiKZteUh/CuJoQj4=", "serverKey" : "4WiBApuB435LNPP49DxKwJ+YGcRaWZNvEq/Ibkr5Lxo=" } }, 
"roles" : [ { "role" : "root", "db" : "admin" } ] } 
{ "_id" : "admin.myadmin", "userId" : UUID("be9c832e-f894-4ffd-b76b- 62940707aab2"), "user" : "myadmin", "db" : "admin", "credentials" : { "SCRAM- SHA-1" : { "iterationCount" : 10000, "salt" : "KIIoSNfp5kTgpUExtTKDTA==", "storedKey" : "39509XHQiWi8HWLc6qMDf13WcSs=", "serverKey" : "zKkJAKH3HgPL35/a6hkhBaCD1WE=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "v76GZgBAKsWNewB7mo6dhSE59ME3HFJ5T9UXlQ==", "storedKey" : "CwHtBiww04Y0hycHKqq4VIS5QnnuAne59+iPFooIhkk=", "serverKey" : "HQk3RTSWDABGwxYPEiEC2+iK/rGTL6ROAD0HQEJI0F8=" } }, 
"roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] } 
//删除用户 
> db.dropUser("myadmin") 
true 
> db.system.users.find() 
//修改密码 
> db.changeUserPassword("myroot", "123456")

提示:
1)本案例创建了两个用户,分别对应超管和专门用来管理用户的角色,事实上,你只需要一个用户即可。如果你对安全要求很高,防止超管泄漏,则不要创建超管用户。
2)和其它数据库(MySQL)一样,权限的管理都差不多一样,也是将用户和权限信息保存到数据库对应的表中。Mongodb存储所有的用户信息在admin 数据库的集合system.users中,保存用户名、密码
和数据库信息。
3)如果不指定数据库,则创建的指定的权限的用户在所有的数据库上有效,如 {role: "userAdminAnyDatabase", db:""}

(5)认证测试
测试添加的用户是否正确

//切换到admin 
> use admin 
//密码输错 
> db.auth("myroot","12345") 
Error: Authentication failed. 0
//密码正确 
> db.auth("myroot","123456") 
1 

(6)创建普通用户
创建普通用户可以在没有开启认证的时候添加,也可以在开启认证之后添加,但开启认证之后,必须使用有操作admin库的用户登录认证后才能操作。底层都是将用户信息保存在了admin数据库的集合system.users中。

//创建(切换)将来要操作的数据库articledb, 
> use articledb 
switched to db articledb 
//创建用户,拥有articledb数据库的读写权限readWrite,密码是123456 
> db.createUser({user: "bobo", pwd: "123456", roles: [{ role: "readWrite", db: "articledb" }]}) 
//> db.createUser({user: "bobo", pwd: "123456", roles: ["readWrite"]}) 
Successfully added user: { 
   "user" : "bobo", 
   "roles" : [ {
       "role" : "readWrite", 
      "db" : "articledb" } ] 
}
//测试是否可用 
> db.auth("bobo","123456") 
1

提示:
如果开启了认证后,登录的客户端的用户必须使用admin库的角色,如拥有root角色的myadmin用户,再通过myadmin用户去创建其他角色的用户

3.2.3 服务端开启认证和客户端连接登录
(1)关闭已经启动的服务
1)使用linux命令杀死进程:

[root@bobohost single]# ps -ef |grep mongo 
root 23482 1 0 08:08 ? 00:00:55 /usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf 
[root@bobohost single]# kill -2 23482 

2)在mongo客户端中使用shutdownServer命令来关闭。

> db.shutdownServer() 
shutdown command only works with the admin database; try 'use admin' 
> use admin 
switched to db admin 
> db.shutdownServer() 
2019-08-14T11:20:16.450+0800 E QUERY [js] Error: shutdownServer failed: { 
"ok" : 0, 
"errmsg" : "shutdown must run from localhost when running db without auth", 
"code" : 13,
 "codeName" : "Unauthorized"
} : 
_getErrorWithCode@src/mongo/shell/utils.js:25:13 
DB.prototype.shutdownServer@src/mongo/shell/db.js:453:1
 @(shell):1:1

需要几个条件:

  • 必须是在admin库下执行该关闭服务命令。
  • 如果没有开启认证,必须是从localhost登陆的,才能执行关闭服务命令。
  • 非localhost的、通过远程登录的,必须有登录且必须登录用户有对admin操作权限才可以。

(2)以开启认证的方式启动服务
有两种方式开启权限认证启动服务:一种是参数方式,一种是配置文件方式。
1)参数方式
在启动时指定参数 --auth ,如:

mongod -f /mongodb/single/mongod.conf --auth 

2)配置文件方式
在mongod.conf配置文件中加入:
vim /mongodb/single/mongod.conf

security: 
   #开启授权认证 
   authorization: enabled

启动时可不加 --auth 参数:

mongod -f /mongodb/single/mongod.conf 

(3)开启了认证的情况下的客户端登录
有两种认证方式,一种是先登录,在mongo shell中认证;一种是登录时直接认证。
1)先连接再认证

[root@bobohost bin]# mongo --host 192.168.1.114 --port 27017 
MongoDB shell version v4.0.10 
connecting to: mongodb://180.76.159.126:27017/?gssapiServiceName=mongodb 
Implicit session: session { "id" : UUID("53fef661-35d6-4d29-b07c-020291d62e1a") }
MongoDB server version: 4.0.10 >

提示:
开启认证后再登录,发现打印的日志比较少了。
相关操作需要认证才可以:
查询admin库中的system.users集合的用户:

> use admin 
switched to db admin 
> db.system.users.find() 
Error: error: { "ok" : 0, "errmsg" : "command find requires authentication", "code" : 13, "codeName" : "Unauthorized" }
> db.auth("myroot","123456") 
1
> db.system.users.find()

查询articledb库中的comment集合的内容:

> use articledb switched to db articledb 
> db.comment.find() 
Error: error: { "ok" : 0, "errmsg" : "not authorized on articledb to execute command { find: \"comment\", filter: {}, lsid: { id: UUID(\"53fef661-35d6-4d29-b07c- 020291d62e1a\") }, $db: \"articledb\" }", "code" : 13, "codeName" : "Unauthorized" }
> db.auth("bobo","123456") 
1
> db.comment.find() 
Error: error: { "ok" : 0, "errmsg" : "too many users are authenticated", "code" : 13, "codeName" : "Unauthorized" }

提示:
这里可能出现错误,说是太多的用户正在认证了。因为我们确实连续登录了两个用户了。
解决方案:退出shell,重新进来登录认证。

> exit 
bye
[root@bobohost bin]# ./mongo --host 180.76.159.126 --port 27017
MongoDB shell version v4.0.10 
connecting to: mongodb://180.76.159.126:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("329c1897-566d-4231-bcb3-b2acda301863") }
MongoDB server version: 4.0.10 
> db.auth("bobo","123456") 
Error: Authentication failed. 0
> use articledb 
switched to db articledb 
> db.auth("bobo","123456") 
1
> db.comment.find() 
> 

2)连接时直接认证
对admin数据库进行登录认证和相关操作:

[root@bobohost ~]# /usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017 --authenticationDatabase admin -u myroot -p 123456 
MongoDB shell version v4.0.10 connecting to: mongodb://180.76.159.126:27017/? authSource=admin&gssapiServiceName=mongodb 
Implicit session: session { "id" : UUID("f959b8d6-6994-44bc-9d35-09fc7cd00ba6") }
MongoDB server version: 4.0.10 
Server has startup warnings: 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] ** WARNING: 
You are running this process as the root user, which is not recommended. 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] 
2019-09-10T15:23:40.102+0800 I CONTROL[initandlisten] ** WARNING: 
/sys/kernel/mm/transparent_hugepage/enabled is 'always'. 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] ** WARNING: 
/sys/kernel/mm/transparent_hugepage/defrag is 'always'. 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 
2019-09-10T15:23:40.102+0800 I CONTROL [initandlisten] 
> show dbs; 
admin 0.000GB 
articledb 0.000GB 
config 0.000GB
local 0.000GB 

对articledb数据库进行登录认证和相关操作:

[root@bobohost bin]# /usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017 --authenticationDatabase articledb -u bobo -p 123456 
MongoDB shell version v4.0.10 connecting to: mongodb://180.76.159.126:27017/? authSource=articledb&gssapiServiceName=mongodb 
Implicit session: session { "id" : UUID("e5d4148f-373b-45b8-9cff-a927ce617100") }
MongoDB server version: 4.0.10 
> use articledb 
switched to db articledb 
> db.comment.find()

提示:

  • -u :用户名
  • -p :密码
  • --authenticationDatabase :指定连接到哪个库。当登录是指定用户名密码时,必须指定对应的数据库!

3.2.4 SpringDataMongoDB连接认证
使用用户名和密码连接到 MongoDB 服务器,你必须使用
'username:password@hostname/dbname' 格式,'username'为用户名,'password' 为密码。
目标:使用用户bobo使用密码 123456 连接到MongoDB 服务上。
application.yml:

 spring: 
   #数据源配置 
   data: 
      mongodb: 
      # 主机地址 
      # host: 180.76.159.126 
      # 数据库 
      # database: articledb 
      # 默认端口是27017 
      # port: 27017 
      #帐号 
      # username: bobo 
      #密码 
      # password: 123456 
      #单机有认证的情况下,也使用字符串连接 
     uri: mongodb://bobo:[email protected]:27017/articledb

提示:
分别测试用户名密码正确以及不正确的情况。

3.3 副本集环境

3.3.1 前言
对于搭建好的mongodb副本集,为了安全,启动安全认证,使用账号密码登录。
副本集环境使用之前搭建好的,架构如下:

image.png

对副本集执行访问控制需要配置两个方面:
1)副本集和共享集群的各个节点成员之间使用内部身份验证,可以使用密钥文件或x.509证书。密钥文件比较简单,本文使用密钥文件,官方推荐如果是测试环境可以使用密钥文件,但是正式环境,官方推荐x.509证书。原理就是,集群中每一个实例彼此连接的时候都检验彼此使用的证书的内容是否相同。只有证书相同的实例彼此才可以访问
2)使用客户端连接到mongodb集群时,开启访问授权。对于集群外部的访问。如通过可视化客户端,或者通过代码连接的时候,需要开启授权。

在keyfile身份验证中,副本集中的每个mongod实例都使用keyfile的内容作为共享密码,只有具有正确密钥文件的mongod或者mongos实例可以连接到副本集。密钥文件的内容必须在6到1024个字符之间,并且在unix/linux系统中文件所有者必须有对文件至少有读的权限。

3.3.2 关闭已开启的副本集服务(可选)
增加副本集的安全认证和服务鉴权功能,可以在副本集搭建的时候直接添加,也可以在之前搭建好的副本集服务上添加。
本文使用之前搭建好的副本集服务,因此,先停止之前的集群服务

停止服务的方式有两种:快速关闭和标准关闭,下面依次说明:
(1)快速关闭方法(快速,简单,数据可能会出错)
目标:通过系统的kill命令直接杀死进程:
依次杀死仲裁者、副本节点、主节点,直到所有成员都离线。建议主节点最后kill,以避免潜在的回滚。
杀完要检查一下,避免有的没有杀掉。

#通过进程编号关闭节点 
kill -2 54410

【补充】
如果一旦是因为数据损坏,则需要进行如下操作(了解):
1)删除lock文件:

rm -f /mongodb/replica_sets/myrs_27017/data/db/*.lock \
/mongodb/replica_sets/myrs_27018/data/db/*.lock \
/mongodb/replica_sets/myrs_27019/data/db/mongod.lock \

2)依次修复数据:

/usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/replica_sets/myrs_27017/data/db
/usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/replica_sets/myrs_27018/data/db
/usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/replica_sets/myrs_27019/data/db

(2)标准的关闭方法(数据不容易出错,但麻烦):
目标:通过mongo客户端中的shutdownServer命令来依次关闭各个服务
关闭副本集中的服务,建议依次关闭仲裁节点、副本节点、主节点。主要的操作步骤参考如下:

//客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。 
mongo --port 27017 
//告知副本集说本机要下线
 rs.stepDown()
 //#切换到admin库 
use admin 
//关闭服务 
db.shutdownServer()

3.3.3 通过主节点添加一个管理员帐号
只需要在主节点上添加用户,副本集会自动同步。
开启认证之前,创建超管用户:myroot,密码:123456
通过进程编号关闭节点

myrs:PRIMARY> use admin 
switched to db admin 
myrs:PRIMARY> db.createUser({user:"myroot",pwd:"123456",roles:["root"]}) 
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }

详细操作详见单实例环境的 添加用户和权限 的相关操作。
提示:
该步骤也可以在开启认证之后,但需要通过localhost登录才允许添加用户,用户数据也会自动同步到本集。
后续再创建其他用户,都可以使用该超管用户创建。

3.3.4 创建副本集认证的key文件
第一步:生成一个key文件到当前文件夹中。
可以使用任何方法生成密钥文件。例如,以下操作使用openssl生成密码文件,然后使用chmod来更改文件权限,仅为文件所有者提供读取权限

[root@bobohost ~]# openssl rand -base64 90 -out ./mongo.keyfile 
[root@bobohost ~]# chmod 400 ./mongo.keyfile 
[root@bobohost ~]# ll mongo.keyfile 
-r--------. 1 root root 122 8月 14 14:23 mongo.keyfile

提示:
所有副本集节点都必须要用同一份keyfile,一般是在一台机器上生成,然后拷贝到其他机器上,且必须有读的权限,否则将来会报错:

permissions on /mongodb/replica_sets/myrs_27017/mongo.keyfile are too open

一定要保证密钥文件一致,文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置,都放到和配置文件一起的目录中。
这里将该文件分别拷贝到多个目录中:

[root@bobohost ~]# cp mongo.keyfile /mongodb/replica_sets/myrs_27017 
[root@bobohost ~]# cp mongo.keyfile /mongodb/replica_sets/myrs_27018 
[root@bobohost ~]# cp mongo.keyfile /mongodb/replica_sets/myrs_27019

3.3.5 修改配置文件指定keyfile
分别编辑几个服务的mongod.conf文件,添加相关内容:

security: 
#KeyFile鉴权文件 
   keyFile: /mongodb/replica_sets/myrs_27017/mongo.keyfile 
   #开启认证方式运行 
   authorization: enabled

/mongodb/replica_sets/myrs_27018/mongod.conf

security: 
   #KeyFile鉴权文件 
   keyFile: /mongodb/replica_sets/myrs_27018/mongo.keyfile
   #开启认证方式运行 
   authorization: enabled

/mongodb/replica_sets/myrs_27019/mongod.conf

security: 
   #KeyFile鉴权文件 
   keyFile: /mongodb/replica_sets/myrs_27019/mongo.keyfile 
   #开启认证方式运行 
   authorization: enabled

3.3.6 重新启动副本集
如果副本集是开启状态,则先分别关闭关闭复本集中的每个mongod,从次节点开始。直到副本集的所有成员都离线,包括任何仲裁者。主节点必须是最后一个成员关闭以避免潜在的回滚。

#通过进程编号关闭三个节点 
kill -2 54410 54361 54257

分别启动副本集节点:

/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf 
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf 
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf

查看进程情况:

[root@bobohost replica_sets]# ps -ef |grep mongod 
root 62425 1 5 14:43 ? 00:00:01 /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf 
root 62495 1 7 14:43 ? 00:00:01 /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf 
root 62567 1 11 14:43 ? 00:00:01 /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf

3.3.7 在主节点上添加普通账号

#先用管理员账号登录 
#切换到admin库 
use admin 
#管理员账号认证 
db.auth("myroot","123456") 
#切换到要认证的库 
use articledb 
#添加普通用户 
db.createUser({user: "bobo", pwd: "123456", roles: ["readWrite"]})

重新连接,使用普通用户bobo重新登录,查看数据。
注意:也要使用rs.status()命令查看副本集是否健康。

3.3.8 SpringDataMongoDB连接副本集
使用用户名和密码连接到 MongoDB 服务器,你必须使用
'username:password@hostname/dbname' 格式,'username'为用户名,'password' 为密码。
目标:使用用户bobo使用密码 123456 连接到MongoDB 服务上。
application.yml:

 spring: 
 #数据源配置
   data: 
     mongodb:
     #副本集有认证的情况下,字符串连接 
     uri: mongodb://bobo:[email protected]:27017,180.76.159.126:27018,180.76.159.126:2 7019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs

3.4 分片集群环境(扩展)

3.4.1 关闭已开启的集群服务(可选)
分片集群环境下的安全认证和副本集环境下基本上一样。
但分片集群的服务器环境和架构较为复杂,建议在搭建分片集群的时候,直接加入安全认证和服务器间的鉴权,如果之前有数据,可先将之前的数据备份出来,再还原回去。

本文使用之前搭建好的集群服务,因此,先停止之前的集群服务
停止服务的方式有两种:快速关闭和标准关闭,下面依次说明:
(1)快速关闭方法(快速,简单,数据可能会出错)
目标:通过系统的kill命令直接杀死进程:

依次杀死mongos路由、配置副本集服务,分片副本集服务,从次节点开始。直到所有成员都离线。副本集杀的时候,建议先杀仲裁者,再杀副本节点,最后是主节点,以避免潜在的回滚。杀完要检查一
下,避免有的没有杀掉。

#通过进程编号关闭节点 
kill -2 54410

【补充】
如果一旦是因为数据损坏,则需要进行如下操作(了解):
1)删除lock文件:

rm -f /mongodb/sharded_cluster/myshardrs01_27018/data/db/*.lock\ 
/mongodb/sharded_cluster/myshardrs01_27118/data/db/*.lock \
/mongodb/sharded_cluster/myshardrs01_27218/data/db/mongod.lock \
/mongodb/sharded_cluster/myshardrs02_27318/data/db/mongod.lock \ 
/mongodb/sharded_cluster/myshardrs02_27418/data/db/mongod.lock \
/mongodb/sharded_cluster/myshardrs02_27518/data/db/mongod.lock \ 
/mongodb/sharded_cluster/myconfigrs_27019/data/db/mongod.lock \ 
/mongodb/sharded_cluster/myconfigrs_27119/data/db/mongod.lock \ 
/mongodb/sharded_cluster/myconfigrs_27219/data/db/mongod.lock

2)依次修复数据:

 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myshardrs01_27018/data/db 
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myshardrs01_27118/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myshardrs01_27218/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myshardrs02_27318/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myshardrs02_27418/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myshardrs02_27518/data/db 
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myconfigrs_27019/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myconfigrs_27119/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/myconfigrs_27219/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/mymongos_27017/data/db
 /usr/local/mongodb/bin/mongod --repair -- dbpath=/mongodb/sharded_cluster/mymongos_27117/data/db
 

(2)标准的关闭方法(数据不容易出错,但麻烦):
目标:通过mongo客户端中的shutdownServer命令来依次关闭各个服务
关闭分片服务器副本集中的服务,建议依次关闭仲裁节点、副本节点、主节点。主要的操作步骤参考如下:

//客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。 
mongo --port 27018 
//告知副本集说本机要下线 
rs.stepDown() 
//#切换到admin库 
use admin 
//关闭服务 
db.shutdownServer()

关闭配置服务器副本集的服务,建议依次关闭副本节点、主节点。主要的操作步骤参考如下:

//客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。 
mongo --port 27019 
//告知副本集说本机要下线 
rs.stepDown() 
//#切换到admin库 
use admin 
//关闭服务 
db.shutdownServer()

关闭路由服务器的服务,建议依次关闭两个路由节点。主要的操作步骤参考如下:

//客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。 
mongo --port 27017 
//告知副本集说本机要下线 
rs.stepDown() 
//#切换到admin库 
use admin 
//关闭服务 
db.shutdownServer()

3.4.2 创建副本集认证的key文件
第一步:生成一个key文件到当前文件夹中。
可以使用任何方法生成密钥文件。例如,以下操作使用openssl生成密码文件,然后使用chmod来更改文件权限,仅为文件所有者提供读取权限

[root@bobohost ~]# openssl rand -base64 90 -out ./mongo.keyfile [root@bobohost ~]# chmod 400 ./mongo.keyfile 
[root@bobohost ~]# ll mongo.keyfile 
-r--------. 1 root root 122 8月 14 14:23 mongo.keyfile

提示:
所有副本集节点都必须要用同一份keyfile,一般是在一台机器上生成,然后拷贝到其他机器上,且必须有读的权限,否则将来会报错: permissions on

/mongodb/replica_sets/myrs_27017/mongo.keyfile are too open 

一定要保证密钥文件一致,文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置,都放到和配置文件一起的目录中。
这里将该文件分别拷贝到多个目录中:

echo '/mongodb/sharded_cluster/myshardrs01_27018/mongo.keyfile 
/mongodb/sharded_cluster/myshardrs01_27118/mongo.keyfile 
/mongodb/sharded_cluster/myshardrs01_27218/mongo.keyfile
/mongodb/sharded_cluster/myshardrs02_27318/mongo.keyfile
 /mongodb/sharded_cluster/myshardrs02_27418/mongo.keyfile
 /mongodb/sharded_cluster/myshardrs02_27518/mongo.keyfile
 /mongodb/sharded_cluster/myconfigrs_27019/mongo.keyfile
 /mongodb/sharded_cluster/myconfigrs_27119/mongo.keyfile
 /mongodb/sharded_cluster/myconfigrs_27219/mongo.keyfile
 /mongodb/sharded_cluster/mymongos_27017/mongo.keyfile
 /mongodb/sharded_cluster/mymongos_27117/mongo.keyfile' | xargs -n 1 cp -v /root/mongo.keyfile

3.4.3 修改配置文件指定keyfile
分别编辑几个服务的mongod.conf文件,添加相关内容:

/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf

 security: 
    #KeyFile鉴权文件 
   keyFile: /mongodb/sharded_cluster/myshardrs01_27018/mongo.keyfile 
   #开启认证方式运行 
   authorization: enabled

/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf

 security: 
   #KeyFile鉴权文件 
   keyFile: /mongodb/sharded_cluster/myshardrs01_27118/mongo.keyfile 
   #开启认证方式运行 
   authorization: enabled

/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf

 security: 
    #KeyFile鉴权文件 
    keyFile: /mongodb/sharded_cluster/myshardrs01_27218/mongo.keyfile 
    #开启认证方式运行 
    authorization: enabled

/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf

 security: 
    #KeyFile鉴权文件 
    keyFile: /mongodb/sharded_cluster/myshardrs02_27318/mongo.keyfile 
    #开启认证方式运行 
    authorization: enabled

/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf

 security:
    #KeyFile鉴权文件 
    keyFile: /mongodb/sharded_cluster/myshardrs02_27418/mongo.keyfile 
    #开启认证方式运行 
    authorization: enabled

/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf

security: #KeyFile鉴权文件 keyFile: /mongodb/sharded_cluster/myshardrs02_27518/mongo.keyfile #开启认证方式运行 authorization: enabled

/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf

security: #KeyFile鉴权文件 keyFile: /mongodb/sharded_cluster/myconfigrs_27019/mongo.keyfile #开启认证方式运行 authorization: enabled

/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf

 security: 
    #KeyFile鉴权文件 
    keyFile: /mongodb/sharded_cluster/myconfigrs_27119/mongo.keyfile 
   #开启认证方式运行 
   authorization: enabled

/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf

 security: 
    #KeyFile鉴权文件 
   keyFile: /mongodb/sharded_cluster/myconfigrs_27219/mongo.keyfile 
   #开启认证方式运行 
   authorization: enabled

/mongodb/sharded_cluster/mymongos_27017/mongos.conf

 security: 
    #KeyFile鉴权文件 
    keyFile: /mongodb/sharded_cluster/mymongos_27017/mongo.keyfile

/mongodb/sharded_cluster/mymongos_27117/mongos.conf

 security: 
    #KeyFile鉴权文件 
    keyFile: /mongodb/sharded_cluster/mymongos_27117/mongo.keyfile

mongos比mongod少了authorization:enabled的配置。原因是,副本集加分片的安全认证需要配置两方面的,副本集各个节点之间使用内部身份验证,用于内部各个mongo实例的通信,只有相同keyfile
才能相互访问。所以都要开启 keyFile:
/mongodb/sharded_cluster/mymongos_27117/mongo.keyfile 。
然而对于所有的mongod,才是真正的保存数据的分片。mongos只做路由,不保存数据。所以所有的mongod开启访问数据的授权authorization:enabled。这样用户只有账号密码正确才能访问到数据。

3.3.4 重新启动节点
必须依次启动配置节点、分片节点、路由节点:

/usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
/usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myconfigrs_27119/mongod.conf 
/usr/local/mongodb/bin/mongod -f 
/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf 

/usr/local/mongodb/bin/mongod -f 
/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf 
/usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27118/mongod.conf 
/usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs01_27218/mongod.conf 

/usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27318/mongod.conf 
/usr/local/mongodb/bin/mongod -f /mongodb/sharded_cluster/myshardrs02_27418/mongod.conf

注意:
这里有个非常特别的情况,就是启动顺序。先启动配置节点,再启动分片节点,最后启动路由节点。

如果先启动分片节点,会卡住,提示:
about to fork child process, waiting until server is ready for connections
这也许是个bug。原因未知。

3.3.5 创建帐号和认证
客户端mongo,通过localhost登录任意一个mongos路由,

[root@bobohost db]# /usr/local/mongodb/bin/mongo --port 27017

提示:相当于一个后门,只能在admin下添加用户。
创建一个管理员帐号:

mongos> use admin switched to db admin 
mongos> db.createUser({user:"myroot",pwd:"123456",roles:["root"]}) 
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }

提示:如果在开启认证之前已经创建了管理员账号,这里可以忽略
创建一个普通权限帐号:

mongos> use admin switched to db admin 
mongos> db.auth("myroot","123456") 
1
mongos> use articledb switched to db articledb 
mongos> db.createUser({
   user: "bobo", 
   pwd: "123456", 
   roles: [{ role: "readWrite", db: "articledb" }]
   }) 
Successfully added user: { 
   "user" : "bobo", 
   "roles" : [ { 
      "role" : "readWrite", 
      "db" : "articledb" }]
}
mongos> db.auth("bobo","123456") 
1

提示:
通过mongos添加的账号信息,只会保存到配置节点的服务中,具体的数据节点不保存账号信息,因此,分片中的账号信息不涉及到同步问题。
mongo客户端登录mongos路由,用管理员帐号登录可查看分片情况:

mongos> use admin 
switched to db admin 
mongos> db.auth("myroot","123456") 
1
mongos> sh.status()

退出连接,重新连接服务,使用普通权限帐号访问数据:

[root@bobohost db]# /usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017 
MongoDB shell version v4.0.10 connecting to: mongodb://180.76.159.126:27017/?gssapiServiceName=mongodb Implicit session: session { "id" : UUID("6f84fa91-2414-407e-b3ab-c0b7eedde825") }
MongoDB server version: 4.0.10 
mongos> use articledb 
switched to db articledb 
mongos> db.auth("bobo","123456") 
1
mongos> show collections 
comment 
comment2 
mongos> db.comment.count() 
10001

3.3.6 SpringDataMongoDB连接认证
使用用户名和密码连接到 MongoDB 服务器,你必须使用
'username:password@hostname/dbname' 格式,'username'为用户名,'password' 为密码。
目标:使用用户bobo使用密码 123456 连接到MongoDB 服务上。

application.yml:

 spring: 
   #数据源配置 
   data: mongodb: 
   # 分片集群有认证的情况下,字符串连接
   uri: mongodb://bobo:[email protected]:27017,180.76.159.126:27117/articledb

你可能感兴趣的:(3.安全认证)