|
本文讨论MonDB数据库安全内容,安全加固包括操作操作系统级别和数据库级别的安全,安全加固的原则是尽量安全,但是不能影响性能。
MonDB集群拓扑如下:
拓扑说明:
1. 上图拓扑包括三个副本集,分别构成三个分片,各副本集端口分别为10000,10001,10002
2. 三台服务器上各包括一个配置服务器,端口均为20000
3. 三台服务器上都有一个mongos进程,端口号均为30000。
4. 客户端可以访问三个mongos进程,但是不能单独访问分片
安全加固包含如下内容:
1. 启动数据库实例时指定端口,禁用HTTP,指定mongos和mongod的监听IP。
2. 用操作系统或者硬件防火墙阻止未知主机对数据库各种组件的访问
3. 不要让数据库运行在公用网络上,应该单独设计一个网段
4. 进行安全认证
5. 账户权限最小化
6. Linux自身安全
1 启动时指定安全选项
1.1 指定端口
如果不指定端口,普通实例启动后使用27017端口,带有—shardsvr选项的实例会使用27018端口,带有—configsvr选项的实例会启用27019端口,各个进程又会启用一个端口比自己大1000的http进程,用于通过网页查看状态。使用—nohttpinterface选项可以禁止http进程。
1.2 使用--bind_ip选项
这个选项可以限制监听接口,在服务器多接口情况下适用。
综上所述,可以按照下列命令启动实例
以54上的配置服务器为例:
[iyunv@54 ~]# numactl --interleave=all mongod --dbpath /mongodb/scheme2/config/data \
--configsvr --port 20000 --logpath /mongodb/scheme2/config/logs/config.log \
--fork --directoryperdb --nohttpinterface \
--bind_ip=127.0.0.1,192.168.69.54
集群中所有mongs和mongod都应该按照上面选项启动。
2 操作系统防火墙配置
本例,三台机器之间的10000,10001,100002,200000,300000端口是相互信任的,客户端也应该可以访问mongos的30000端口。
假设客户端运营平台ip为192.168.69.46,为实现需求,配置规则如下:
以192.168.69.54为例,修改防火墙配置文件:
/etc/sysconfig/iptables
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -s 192.168.69.54,192.168.69.55,192.168.69.56 -m state --state NEW -m tcp -p tcp --dport 10000 -j ACCEPT
-A INPUT -s 192.168.69.54,192.168.69.55,192.168.69.56 -m state --state NEW -m tcp -p tcp --dport 10001 -j ACCEPT
-A INPUT -s 192.168.69.54,192.168.69.55,192.168.69.56 -m state --state NEW -m tcp -p tcp --dport 10002 -j ACCEPT
-A INPUT -s 192.168.69.54,192.168.69.55,192.168.69.56 -m state --state NEW -m tcp -p tcp --dport 20000 -j ACCEPT
-A INPUT -s 192.168.69.46,192.168.69.54,192.168.69.55,192.168.69.56 -m state --state NEW -m tcp -p tcp --dport 30000 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
修改完成后启动防火墙:
[iyunv@56 ~]# service iptables save
[iyunv@56 ~]# service iptables start
[iyunv@56 ~]# service ip6tables start
3 认证与授权功能
3.1 单实例认证
启动时启用--auth选项
1. 启动实例:
numactl --interleave=all mongod --port 40000 \
--dbpath=/mongodb/scheme2/sin/data \
--logpath=/mongodb/scheme2/sin/logs/sin.log --logappend --fork --directoryperdb \
--bind_ip=127.0.0.1,192.168.69.54 --nohttpinterface \
--auth
2. 使用本地例外方式登录数据库
[iyunv@54 ~]# mongo --port 40000
MongoDB shell version: 2.4.4
connecting to: 127.0.0.1:40000/test
>
注意:本地例外方式类似oracle操作系统认证方式,登录后具备所有权限。在没有建立帐号时,需要使用本地例外方式登录。可以用下面选项关闭本地例外认证方式:
--setParameter enableLocalhostAuthBypass=0
3. 创建系统管理员用户(角色为userAdminAnyDatabase或者userAdmin)
默认条件下,超级管理员只能用于帐号管理,不能进行其他数据库操作,可以通过自己给自己授权实现。生产环境中的管理员,如果某个帐号包含了角色userAdminAnyDatabase或者userAdmin,就应该仅仅用于帐号和角色管理,不应该再授予别的角色了。
我们首先就要建立一个超级管理员,然后再用超级管理员建立其他帐号:
(1) 建立超级管理员帐号:
> db= db.getSiblingDB('admin')
> db.addUser({ user: "superman",
pwd: "talent",
roles: [ "userAdminAnyDatabase"] } ) --创建第一个账户时候,指定角色是超级管理员
{
"user" : "superman",
"pwd" : "a6de521abefc2fed4f5876855a3484f5",
"roles" : [
"userAdminAnyDatabase"
],
"_id" : ObjectId("51fa3108a0e7aeded08baf35")
}
(2)为帐号启用admin数据库认证,这样他就可以操作admin数据库了。
> db.auth("superman","talent")
> db.system.users.find().pretty();
{
"_id" : ObjectId("51fa3108a0e7aeded08baf35"),
"user" : "test",
"pwd" : "a6de521abefc2fed4f5876855a3484f5",
"roles" : [
"userAdminAnyDatabase"
]
}
>
(4)使用用刚才的超级帐号登录数据库(admin),
[iyunv@54 ~]# mongo localhost:40000/admin -u superman -p superman
现在,我们就可以为其他数据库添加用户了:
> use test
switched to db test
> db.addUser("supermantest","supermantest")
{
"user" : "supermantest",
"readOnly" : false,
"pwd" : "489151cf34eaf7473ff69a18acb36a49",
"_id" : ObjectId("51fa618b49713cce4ee1d94b")
}
授予这个用户的权限:(必须要,否则无法进行读写操作)
> db.auth("supermantest","supermantest")
1
(5)现在可以用新用户登录并且操作test数据库了
4.关闭本地例外登录方式
一旦拥有了超级管理员,就可以考虑关闭本地例外方式登录了
方法如下:
重启数据库,启动时候加上--setParameter enableLocalhostAuthBypass=0即可,这样登录的话就必须要用账户认证了
5.删除用户
删除用户要针对某个数据库进行删除
> use test
switched to db test
> db.removeUser("superman11111")
6.修改用户密码
普通用户只能修改自己的密码,userAdmin角色帐号可以修改其他用户密码
例如:
[iyunv@55 ~]# mongo 192.168.69.54:40000/admin -u superman -p superman
MongoDB shell version: 2.4.4
connecting to: 192.168.69.54:40000/admin
> use test
switched to db test
> db.changeUserPassword("supermantest","talent")
>
3.2 副本集成员认证
副本集之间的认证可以通过keyFile实现
KeyFile文件必须满足条件:
(1)至少6个字符,小于1024字节
(2)认证时候不考虑文件中空白字符
(3)连接到副本集的成员和mongos进成的keyfile文件内容必须一样
(4)必须是base64编码,但是不能有等号
(5)文件权限必须是x00,也就是说,不能分配任何权限给group成员和other成员
以副本集sh0为例:
1.生成keyFile文件:
在54上执行:
[iyunv@54 ~]# openssl rand -base64 100 > /mongodb/scheme2/keyfile0 --文件内容采base64编码,一共100个字符
2.修改文件权限:
[iyunv@54 ~]# chmod600 /mongodb/scheme2/keyfile0
把生成的文件拷贝到副本集剩余各台机器上,存放的目录可以不一样,注意权限。
3.三台机器启动时指定--keyFile选项
numactl --interleave=all mongod --replSet sh0 --port 10000 \
--dbpath=/mongodb/scheme2/sh0/data --logpath=/mongodb/scheme2/sh0/logs/sh0.log \
--logappend --fork --directoryperdb --bind_ip=127.0.0.1,192.168.69.54 --nohttpinterface \
--keyFile=/mongodb/scheme2/keyfile0
这样,没有这个文件的机器就无法加入副本集,Sh1和sh2副本集的操作类似。
开启了keyFile,隐含就开启了auth,这个时候连接副本集就需要进行认证了,否则只能通过本地例外方式操作数据库。
3.3 副本集+分片环境下的认证
结合上面的两种环境的认证方式,可以实现副本集+分片环境中安全认证,需要注意以下几点
1.在分片集群环境中,副本集内成员之间需要用keyFile认证,mongos与配置服务器,副本集之间也要keyFile认证,集群所有mongod和mongos实例使用内容相同的keyFile文件。
2.进行初始化,修改副本集时,都从本地例外登录进行操作
3.由于启用了认证,需要建立一个管理员帐号,才能从远程登录。建立管理员帐户,利用管理员账户从远程登录后,需要建立一个可以操作某个数据库的用户,客户端就用这个用户访问数据库。
4.分片集群中的管理员帐号需要具备配置服务器中admin和config数据库的读写权限,才能进行分片相关操作
5.集群中每个分片有自己的admin数据库,存储了集群的各自的证书和访问权限。如果需要单独远程登录分片,可以按照3.2的办法建立用户
相关操作如下:
1.启动集群中的配置服务器,路由进程和副本集,每个进程都要指定KeyFile文件,而且每个进程的keyfile内容相同,详细操作见3.2。
2.初始化副本集。
3. 连接mongos,为集群建立管理员帐号和普通帐号,步骤如下;
(1)建立管理员帐号
管理员需要具备对集群中配置服务器的读写权限,这些权限包括:
建立新的普通管理员,用于客户端连接集群中的数据库;
分片相关权限,例如查看分片状态,启用分片,设置片键等操纵。
首先用本地例外方式登录,建立管理员帐号:
[iyunv@54 ~]# mongo --port 30000
mongos> use admin
db.addUser( { user: "superman",
pwd: "superman",
roles: [ "clusterAdmin","userAdminAnyDatabase","dbAdminAnyDatabase","readWriteAnyDatabase" ] } )
mongos> db.auth("superman","superman")
mongos> use config
switched to db config
mongos> db.addUser( { user: "superman",
pwd: "superman",
roles: [ "clusterAdmin","userAdminAnyDatabase","dbAdminAnyDatabase","readWriteAnyDatabase" ] } )
mongos> db.auth("superman","superman")
(2)用上面建立的管理员帐号登录mongos进程,对数据库(比如test)启用分片,设置集合片键。
(3)用管理员账户登录,建立新账户,让他可以读写数据库test
[iyunv@54 ~]# mongolocalhost:30000/admin -u superman -p superman
mongos> use test
switched to db test
mongos> db.addUser("test","test")
{
"user" : "test",
|
|