在互联网公司开发过程中,我们常常会遇到,一些一开始没考虑到的场景,等到上线或者服务运行一段时间之后,发现有些东西没做好,需要做一些优化重构啥的。
这些场景包括,某些服务密码配置过于简单(或者没配置),敏感数据没有脱敏(转移),代码没有足够测试用例,日常服务爆出漏洞需要升级修复等等。在优化过程中,我们都希望做到零宕机平滑迁移,以此把服务影响时间降到最低。
今天我说的就是这里场景的一种,mongo实现零重启添加访问控制。
写在前面
本文是在 Ubuntu:16.04, mongo 3.4版本进行
要求:您的副本集可以在现有的primary成员之后(比如宕机)选择一个新的primary。
mongo集群实现零停机添加「身份认证」,需要版本是在mongo 3.4以上版本,原因是mongo在3.4的时候加入了--transitionToAuth 参数,本文主要是通过这个参数做到零停机进行升级认证的。
我们这里以3个节点副本集为例。
创建一个用户管理员
链接到primary进行创建 userAdminAnyDatabase 权限的用户
admin = db.getSiblingDB("admin") admin.createUser( { user: "yourname1", pwd: "changeme1", roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] } )
在完成此过程后,任何管理副本集合中的用户的客户端都必须作为该用户进行身份验证,或者具有类似权限的用户。
创建集群管理员
连接到primary节点,创建一个具有clusterAdmin角色的用户。clusterAdmin角色授予对复制操作的访问权,例如配置副本集。
db.getSiblingDB("admin").createUser( { "user" : "yourname2", "pwd" : "changeme2", roles: [ { "role" : "clusterAdmin", "db" : "admin" } ] } )
创建客户端应用链接的用户
创建用户允许客户端程序与副本级交互。完成这一步客户端需要通过对应帐号密码来进行链接副本级。
这里面我们需要注意使用readWrite权限对数据进行操作,对特定的数据库(如yourdb)密码建议设置较为复杂来加强系统安全性,这里建议用1password进行生成管理。
db.getSiblingDB("yourdb").createUser( { "user" : "yourname_client", "pwd" : "changeme2", roles: [ { "role" : "readWrite", "db" : "yourdb" } ] } )
客户端认证yourdb可以对其进行读写。
更新客户端应用代码
这一步里面,副本级链接并没有强制要求认证,但是客户端应用程序依然可以通过认证的帐号密码俩进行链接副本级。
这里我们假设你的副本级 replia set 为 yourRepl 进行测试
mongo -u yourname_client -password changeme2 -authenticationDatabase yourdb —host yourRepl/mongo1.example.net:27017, mongo2.example.net:27017, mongo3.example.net:27017
可以链接成功,然后更新客户端代码,发布上线。
创建密钥文件
openssl rand -base64 756 > <path-to-keyfile><path-to-keyfile>
这里面保证上面这个keyfile,需要mongodb(你启动mongod) 用户可以访问
通过keyfile认证方式,副本级中的每个mongod实例都会使用keyfile的内容作为密码去认证其他成员。只有正确的mongo实例拥有正确的keyfile可以加入副本级。
然后复制keyfile到每一个副本级
添加transitionToAuth,重启实例
注意:在重启之前保证配置文件中有以下配置
security: keyFile: <path-to-keyfile> transitionToAuth: true # 这个配置很重要replication: replSetName: <replicaSetName>
-
先重启secondary 或arbiter
sudo service mongod restart
-
在重启针对primary节点需要
rs.stepDown()
一个原则,保持primary在线
去掉transitionToAuth,重启实例
注意:在重启之前保证配置文件中有以下配置
security: keyFile: <path-to-keyfile> replication: replSetName: <replicaSetName>
-
先重启secondary 或arbiter
sudo service mongod restart
-
重启primary节点需要
rs.stepDown()
至此所有的集群认证已经添加完毕,所有客户端也需要进行认证才能进行链接。
我们这种「边开飞机,边换引擎」方式到此就已经完成了。