某个晴朗的工作日,我正在自己的工位上勤勤恳恳的工(hua)作(shui),此时总监突然微信我:“小刘,这会儿工作忙吗?”,我当下后背就是一凉,慌忙回复到:“总监,我这会儿闲的很,哦不,是忙的很”。沉默了2秒之后,总监继续说到:“…这样啊,我这儿有个任务交给你,公司有两台服务器的mongo没有做安全配置,你去给它们加上”
虽然没有给mongo做过安全配置,但是身为Google小能手的我,很快就找到了相应的教程,熟练的开始抄起了作业。理想是美好的,现实却很残酷,配置过程中踩坑不断,本篇中会将这些坑都一一记录下来,防止以后踩坑历史重演:)
建议可以先看看官方文档:Mongo Enable Access Control
网上也有很多中文翻译,比如:MongoDB 设置用户名密码登录
具体的配置我在这里简单的说一下:
首先,进入mongo终端(此时还没有认证);
之后,选择使用mongo自带的admin
表,该表是用来管理mongo账户的;
为mongo数据库添加账户
>> use admin
>> db.createUser(
{
user: "Admin",
pwd: "admin_password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
在使用配置文件启动的情况下,需要在配置文件中加上这么一句:
security:
authorization: enabled
重启mongo后,认证功能便会打开,我们有两种方式继续使用mongo客户端
>> use admin
>> db.auth("Admin", "admin_password") # 之前配置的账户密码
1 # 返回1表示认证成功,我们就可以继续像平时那样继续操作了
mongo --port 27017 --authenticationDatabase "admin" -u "Admin" -p "admin_password"
其中稍微需要注意一下的就这个authenticationDatabase
参数
Authentication Database
When adding a user, you create the user in a specific database. This database is the authentication database for the user.
A user can have privileges across different databases; that is, a user’s privileges are not limited to their authentication database. By assigning to the user roles in other databases, a user created in one database can have permissions to act on other databases. For more information on roles, see Role-Based Access Control.
The user’s name and authentication database serve as a unique identifier for that user. That is, if two users have the same name but are created in different databases, they are two separate users. If you intend to have a single user with permissions on multiple databases, create a single user with roles in the applicable databases instead of creating the user multiple times in different databases.
简单来说,authenticationDatabase
就是用来做认证的那个数据库,这里就是admin这个库,我们也可以为其他每个数据库单独建立账户,后面的-u
和-p
分别是用户名和密码。
这就是为mongo添加安全认证的步骤,整个过程看起来很简单,而然其中有些坑不容易被发现,一不小心就会出问题(血泪警告)。
如果此前你的mongo中已经配置了service启动(即通过systemctl start mongod
启动mongo服务),并且service中user配置的不是root(通常会另设置一个专门的用户,比如mongod
)
那么,你在根据mongo官方文档进行账户配置的时候就会发生权限问题(包括很多参考官方文档的博客中没有详细提及)
官方文档会提示你通过mongod
启动一个mongo服务,然后在启动一个mongo的终端进行上述的配置过程。
然而当你按照官方文档的步骤做完配置之后,在以systemctl restart mongo
启动时,就会疯狂报错,突然间的报错可能会让你猝不及防,这个时候就非常非常非常的推荐看日志!
# 查看mongo启动日志, 通常是这个路径,如果不知道路径在哪儿,可以查看配置文件
tail -f /var/log/mongodb/mongod.log
报错信息没来得及截图就不放了 = =,基本可以确定是权限问题。原因是你在root用户下启动mongo服务后,部分日志文件的权限就被改为root,当你后面在想用systemctl
启动时,就会疯狂权限错误。
我们可以看看service文件是如果配置的,使用systemctl status mongo
查看一下当前服务的运行状态和service
配置文件的路径,像这样
在这里面我们可以查看mongo的service配置路径,如果启动不成功,也可以在这个命令下看到基本的报错信息。
查看一下mongod.service
[Unit]
Description=High-performance, schema-free document-oriented database
After=network.target
Documentation=https://docs.mongodb.org/manual
[Service]
User=mongod
Group=mongod
Environment="OPTIONS=-f /etc/mongod.conf"
ExecStart=/usr/bin/mongod $OPTIONS
ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb
ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb
ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb
PermissionsStartOnly=true
PIDFile=/var/run/mongodb/mongod.pid
Type=forking
# file size
LimitFSIZE=infinity
# cpu time
LimitCPU=infinity
# virtual memory size
LimitAS=infinity
# open files
LimitNOFILE=64000
# processes/threads
LimitNPROC=64000
# locked memory
LimitMEMLOCK=infinity
# total threads (user+kernel)
TasksMax=infinity
TasksAccounting=false
# Recommended limits for for mongod as specified in
# http://docs.mongodb.org/manual/reference/ulimit/#recommended-settings
其中,user
和group
是用来表示运行服务的用户,如果你以root权限启动了mongo,再使用service
启动时,会出现无法运行数据无法写入的情况。需要手动更改出现Permission denied
的文件,下面列出几个,可以检查一下,这些在mongo配置文件中也能找到(如果没有就创建并修改用户权限)
/var/run/mongodb/mongod.pid # 进程文件
/var/lib/mongodb # 数据库存储路径
/var/log/mongodb # 日志路径
# 修改权限
sudo chown -R mongodb:mongodb 文件路径
至此,一系列全七八糟的权限问题就解决了。
上面的问题说完了,接下来可以开开心心的完成任务了,通过认证打开mongo终端一看,刷刷刷弹出来一堆错误,又来??!!
错误信息大致如下:
No primary detected for set xxx
No primary detected for set xxx
No primary detected for set xxx
No primary detected for set xxx
No primary detected for set xxx
No primary detected for set xxx
这里再次友情推荐,查mongo日志!
# 查看mongo日志
tail -f /var/log/mongodb/mongod.log
发现日志中报错信息如下
MongoDB not authorized on admin to execute command { replSetGetStatus: 1.0 }
原来又是权限 = =,这次是mongo集群的权限配置有问题,无法执行集群相关命令,这里回顾一下创建mongo账户时的语句
db.createUser(
{
user: "Admin",
pwd: "admin_password",
# 这里roles已经是超级用户,但是对于集群来说,权限的级别还是不够
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
确实是有个roles权限的设置,最终想到是我们的Admin
账号没有集群管理的权限,那么对症下药,给Admin
添加集群权限。
进入mongo终端(不想看到疯狂报错,可以先关了认证),执行以下命令
>> db.grantRolesToUser("Admin", ["clusterAdmin"])
由于复制集之间的互联也是需要验证的,所以还要配置keyfile
来满足这个需求,如果配置认了认证 ,投票节点需要通过证书的形式与复制集中的其他节点进行认证。MongoDB的身份认证过程是加密的。
keyfile
的配置可以参考这篇博客
我们这里就直接贴出配置完的结果把,还记得之前mongo中配置的security
吗?我们修改一下
security:
keyFile: /var/lib/mongo/mongo_key_file # 这个就是生成keyfile!
authorization: enabled
注意,每个节点都需要进行配置哦~
mongo的权限分的很多很细,这里不多做解释了,通过这篇博客可以进行更进一步的了解~
权限的配置十分细碎,Admin
账户已经有了
clusterAdmin
userAdminAnyDatabase
两大角色
看似已经覆盖到常用的权限,然而你还是可能会遇到not authorized on admin to execute command xxx
的情况,比我我后端系统权限都配置好了,然后系统连接数据库的时候还是报了
not authorized on admin to execute command currentOp
的错误,我也是醉了。
如果完全弄清楚角色配置比较麻烦,最简单粗暴的办法,可以直接为账户配置最高级的root权限,像这样
>> db.grantRolesToUser("Admin", ["root"])
至此,mongo的账户配置算是完成了,总监点了点头,露出了满意的微笑~
如果这篇文章还没能解决你的问题,欢迎留言一起讨论~笔芯~
Mongo Enable Access Control
mongodb 3.4.3 Permission denied wiredtiger_kv_engine.cpp 267 error
mongodb 3.4复制集配置
MongoDB开启访问控制后currentOp出错