seemebaby 发表于 2015-11-11 10:28:01

MongoDB数据库安全解决方案

本文讨论MonDB数据库安全内容,安全加固包括操作操作系统级别和数据库级别的安全,安全加固的原则是尽量安全,但是不能影响性能。
MonDB集群拓扑如下:




图1 集群拓扑
拓扑说明:
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上的配置服务器为例:
# numactl --interleave=allmongod --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
:FORWARD ACCEPT
:OUTPUT ACCEPT
-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
修改完成后启动防火墙:
# service iptables save
# serviceiptables start
# service ip6tables start


3 认证与授权功能

3.1 单实例认证

启动时启用--auth选项
1. 启动实例:
numactl --interleave=allmongod   --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. 使用本地例外方式登录数据库
# 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),
#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角色帐号可以修改其他用户密码
例如:
# 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上执行:
# openssl rand -base64 100 > /mongodb/scheme2/keyfile0 --文件内容采base64编码,一共100个字符
2.修改文件权限:
# 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)建立管理员帐号
管理员需要具备对集群中配置服务器的读写权限,这些权限包括:
建立新的普通管理员,用于客户端连接集群中的数据库;
分片相关权限,例如查看分片状态,启用分片,设置片键等操纵。
首先用本地例外方式登录,建立管理员帐号:
# 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
# mongolocalhost:30000/admin -u superman -p superman
mongos> use test
switched to db test
mongos> db.addUser("test","test")
{
      "user" : "test",
      "readOnly" : false,
      "pwd" : "a6de521abefc2fed4f5876855a3484f5",
      "_id" : ObjectId("51fb5d4ecaa5917203f37f63")
}
mongos> db.auth("test","test")
1
(4)用新帐号test登录,操作数据库test
# mongo localhost:30000/test -u test -p test            
MongoDB shell version: 2.4.4
connecting to: localhost:30000/test
> for(var i = 1; i < 100000; i&#43;&#43; ) db.test.insert( { x:i, C_ID:i } );



说明:为分片集群启用认证后,本地例外方式登录由于只具备admin数据库读写权限,无法进行分片操作。对本例来讲,添加分片,查看分片状态等操作都需要用superman帐号登录才行。执行数据库test操作用test帐号,这个帐号就是提供给客户端的帐号。




4 Linux自身安全加固

Linux自身安全加固包含一下几个方面:
1.         网络安全
2.         服务安全
3.         文件系统安全
4.         账户安全
5.         帐号资源限制

4.1 网络安全

网络安全包括如下几个部分:


4.1.1 关闭不必要的端口


关闭端口可以通过linux的防火墙来实现,本集群系统中各台机器使用的mongodb端口要相互开放,22端口要开放给管理区域。第二章已经说明了其用法


4.1.2 不设置默认路由


内网运行的linux都不应该设置默认路由,只要管理区域和web服务器可以访问数据库即可
以本集群环境为例
不添加网关,只要机器与73网段互通,当前路由如下:
# route
Kernel IP routing table
Destination   Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.69.0    *               255.255.255.0   U   0      0      0 eth1
link-local      *               255.255.0.0   U   1002   0      0 eth1
default         192.168.69.1    0.0.0.0         UG    0      0      0 eth1
现在要做的是,删掉默认路由,添加一条到192.168.73.0网段的静态路由即可
# route add -net 192.168.73.0/24 gw 192.168.69.1 dev eth1
# route del default
如果要使重启继续生效,执行如下操作:
(1)打开网卡配置文件:/etc/sysconfig/network-scripts/ifcfg-eth1,注释掉网关部分(网关配置有时候可能会写到/etc/sysconfig/network)
(2)把上面添加静态路由的语句写入开机启动文件/etc/rc.local。


4.1.3禁用ipv6

如果环境不需要ipv6,就把它禁掉
(1)         编辑文件/etc/sysconfig/network,加入如下两行
NETWORKING_IPV6=no
IPV6INIT=no
(2)         修改ipv6模块配置文件,把ipv6模块禁用掉:
echo&quot;options ipv6 disabled=1&quot; > /etc/modprobe.d/ipv6.conf
或者用 echo&quot;install ipv6 /bin/true&quot; > /etc/modprobe.d/ipv6.conf
(3)         重启系统

4.2 服务安全

服务安全包括关闭不必要的和服务,优化ssh服务,以非root帐号运行数据库。


4.2.1 关闭不必要的服务

安装完成后,如果安装了桌面,linux将会以运行级5运行。如果不需要用桌面,不建议安装,在安装系统时候,选择基础安装,然后选择部分开发包和system-config界面即可。重启后,linux将会以运行级别3运行。可以查看/etc/inittab文件确认
找到id:3:initdefault:部分,确认红色数字是3。
进入命令行,使用如下命令关闭不必要的服务:
# export LANG=&quot;zh_CN.UTF-8&quot;
# ntsysv      ---打开系统服务设置窗口


只需要保留如下服务:
Cpupeed,crond,iptables,network, irqbalance,ssh, rsyslog,udev-post, messagebus, sysstat


4.2.2 SSH服务修改

(1)默认ssh服务是22端口,可以修改:
打开/etc/ssh/sshd_config,找到#Port 22部分,去除#,修改为Port28,同时设置28为防火墙信任端口。

(2)禁用root帐号sshd登录:
找到ssh服务配置文件/etc/ssh/sshd_config,找到#PermitRootLoginyes部分,修改为PermitRootLogin no,重启ssh服务。接下来用mongod登录登录然后切换到root。


4.2.3 以非root帐号运行数据库

不要以root账户运行软件,因为这样会造成软件运行权限过大,威胁系统自身安全。同时,也不方便对帐号资源进行限制。
1. 配置mongod用户
# groupadd mongod
# groupadd mongod
# useradd -d /mongodb -g mongod mongod
# chown -R mongod.mongod /mongodb
# su - mongod
-bash-4.1$ vi .bash_profile
export PATH
# .bash_profile


# Get the aliases and functions
if [ -f ~/.bashrc ]; then
      . ~/.bashrc
fi


# User specific environment and startup programs


PATH=$PATH:$HOME/bin


export PATH=$PATH:/mongodb/bin
2.切换到mongod账户,进行数据库建立和集群相关操作。


4.3 文件系统安全

Linux默认文件权限为644,文件夹权限是755,无特殊需要不要修改。在使用mondb时候,如果遇到权限问题,不要把权限设置为777,一般设置为700,保证账户mongod具备一定权限即可。如果要求每个新建立的帐号权限都是600,可以用下列命令实现(集群中keyFile文件权限就必须是x00)
oracle[~]$umask007

4.4 帐号安全
安装linux时,一般会要求设置一个帐号,只有新建立的帐号和root帐号具备登录资格,不要使用系统保留帐号登录系统。在mongodb集群环境中,每台操作系统都应该只允许mongod和root启动shell。
帐号口令应该满足一定复杂度:包含大小写字母,数字和特殊字符。
为了更安全,可以不用帐号密码认证,而是启用ssh公钥和私钥认证,以securecrt配置方法为例:

1. shd服务设置:
打开配置文件/etc/ssh/sshd_config,修改已有的配置,确保有如下几行
StrictModes no
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile      /root/.ssh/authorized_keys
PermitEmptyPasswords yes
PasswordAuthentication no

2.SecureCRT设置
会话属性-> Authentiation -> Public Key -> Properties ->Create Identity File ->RSA(选择RSA加密算法) -> Set Passphrase (设置密码,保护公钥)-> Done
完成时会在指定目录(一般是C:\Users\’username’\Documents)生成两个文件,默认名称为:私钥Identity和公钥Identity.pub。

3.将公钥Identity.pub传到Linux服务器的/root/.ssh/,将SSH2兼容格式的公钥转换成为Redhat兼容格式。
[~/.ssh]#ssh-keygen -i -f/root/.ssh/Identity.pub>/root/.ssh/authorized_keys
[~/.ssh]#chmod 600/root/.ssh/authorized_keys

4. 使用SecureCRT登录服务器首先设置登录模式为PublicKey,并选择刚刚创建的公钥文件Identity.pub。
重启Linux服务器的sshd服务。
页: [1]
查看完整版本: MongoDB数据库安全解决方案