MongoDB数据库安全解决方案

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

MonDB集群拓扑如下:

 


 

 

集群拓扑

拓扑说明:

1.  上图拓扑包括三个副本集,分别构成三个分片,各副本集端口分别为100001000110002

2.  三台服务器上各包括一个配置服务器,端口均为20000

3.  三台服务器上都有一个mongos进程,端口号均为30000

4.  客户端可以访问三个mongos进程,但是不能单独访问分片

 

安全加固包含如下内容:

1.  启动数据库实例时指定端口,禁用HTTP,指定mongosmongod的监听IP

2.  用操作系统或者硬件防火墙阻止未知主机对数据库各种组件的访问

3. 不要让数据库运行在公用网络上,应该单独设计一个网段

4.  进行安全认证

5.   账户权限最小化

6.   Linux自身安全

 

1  启动时指定安全选项


 

1.1 指定端口


 

如果不指定端口,普通实例启动后使用27017端口,带有—shardsvr选项的实例会使用27018端口,带有—configsvr选项的实例会启用27019端口,各个进程又会启用一个端口比自己大1000http进程,用于通过网页查看状态。使用—nohttpinterface选项可以禁止http进程。

 

1.2 使用--bind_ip选项


 

这个选项可以限制监听接口,在服务器多接口情况下适用。

 

综上所述,可以按照下列命令启动实例

54上的配置服务器为例:

[root@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

集群中所有mongsmongod都应该按照上面选项启动。

 

2  操作系统防火墙配置


 

本例,三台机器之间的1000010001100002200000300000端口是相互信任的,客户端也应该可以访问mongos30000端口。

假设客户端运营平台ip192.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

修改完成后启动防火墙:

[root@56 ~]# service iptables save

[root@56 ~]# service  iptables start

[root@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. 使用本地例外方式登录数据库

[root@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)

[root@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角色帐号可以修改其他用户密码

例如:

[root@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上执行:

[root@54 ~]# openssl rand -base64 100 > /mongodb/scheme2/keyfile0 --文件内容采base64编码,一共100个字符

2.修改文件权限:

[root@54 ~]# chmod 600 /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

这样,没有这个文件的机器就无法加入副本集,Sh1sh2副本集的操作类似。

开启了keyFile,隐含就开启了auth,这个时候连接副本集就需要进行认证了,否则只能通过本地例外方式操作数据库。

 

3.3 副本集+分片环境下的认证


 

 

结合上面的两种环境的认证方式,可以实现副本集+分片环境中安全认证,需要注意以下几点

 

1.在分片集群环境中,副本集内成员之间需要用keyFile认证,mongos与配置服务器,副本集之间也要keyFile认证,集群所有mongodmongos实例使用内容相同的keyFile文件。

2.进行初始化,修改副本集时,都从本地例外登录进行操作

3.由于启用了认证,需要建立一个管理员帐号,才能从远程登录。建立管理员帐户,利用管理员账户从远程登录后,需要建立一个可以操作某个数据库的用户,客户端就用这个用户访问数据库。

4.分片集群中的管理员帐号需要具备配置服务器中adminconfig数据库的读写权限,才能进行分片相关操作

5.集群中每个分片有自己的admin数据库,存储了集群的各自的证书和访问权限。如果需要单独远程登录分片,可以按照3.2的办法建立用户

相关操作如下:

1.启动集群中的配置服务器,路由进程和副本集,每个进程都要指定KeyFile文件,而且每个进程的keyfile内容相同,详细操作见3.2

2.初始化副本集。

3. 连接mongos,为集群建立管理员帐号和普通帐号,步骤如下;

(1)建立管理员帐号

管理员需要具备对集群中配置服务器的读写权限,这些权限包括:

建立新的普通管理员,用于客户端连接集群中的数据库;

分片相关权限,例如查看分片状态,启用分片,设置片键等操纵。

首先用本地例外方式登录,建立管理员帐号:

[root@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

[root@54 ~]# mongo localhost: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

[root@54 ~]# 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++ ) 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网段互通,当前路由如下:

[root@54 ~]# 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网段的静态路由即可

[root@54 ~]# route add -net 192.168.73.0/24 gw 192.168.69.1 dev eth1

[root@54 ~]# 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  "options ipv6 disabled=1" > /etc/modprobe.d/ipv6.conf

或者用 echo  "install ipv6 /bin/true" > /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

进入命令行,使用如下命令关闭不必要的服务:

[mongo_46 ~]# export LANG="zh_CN.UTF-8"

[mongo_46 ~]# 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部分,去除#,修改为Port 28,同时设置28为防火墙信任端口。

 

2)禁用root帐号sshd登录:

找到ssh服务配置文件/etc/ssh/sshd_config,找到#PermitRootLogin yes部分,修改为PermitRootLogin no,重启ssh服务。接下来用mongod登录登录然后切换到root

 

4.2.3 以非root帐号运行数据库


 

不要以root账户运行软件,因为这样会造成软件运行权限过大,威胁系统自身安全。同时,也不方便对帐号资源进行限制。

1. 配置mongod用户

[root@54 mongodb]# groupadd mongod

[root@54 mongodb]# groupadd mongod

[root@54 mongodb]# useradd -d /mongodb -g mongod mongod

[root@54 mongodb]# chown -R mongod.mongod /mongodb

[root@54 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[~]$umask  007

4.4 帐号安全

安装linux时,一般会要求设置一个帐号,只有新建立的帐号和root帐号具备登录资格,不要使用系统保留帐号登录系统。在mongodb集群环境中,每台操作系统都应该只允许mongodroot启动shell

帐号口令应该满足一定复杂度:包含大小写字母,数字和特殊字符。

为了更安全,可以不用帐号密码认证,而是启用ssh公钥和私钥认证,以secure crt配置方法为例:

 

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服务。

展开阅读全文

没有更多推荐了,返回首页