chroot MySQL on CentOS

网上有各种chroot资料,但是似乎没有完整明确的chroot MySQL的介绍,结合工作,将我进行chroot MySQL的方法说明一下。

因为Linux发行版本众多,首先说明运行环境:CentOS 5.9, MySQL 5.5,所有chroot环境下的文件都从父环境拷贝过来,适用于无网络或网络受限环境下的安全加固。

chroot的作用不做过多介绍,部分内容可以参考我以前翻译的博文《Unix chroot最佳实践》。

在CentOS下,MySQL服务调用关系大概是/etc/init.d/mysql==>/etc/init.d/mysql-real==>/usr/bin/mysqld_safe,当然这只是最主要的一条线。其实,如果不使用service命令或者/etc/init.d/mysql来启停服务的话, 我们运行MySQL只需要下面的命令:

/usr/bin/mysqld_safe --datadir="/var/lib/mysql" --pid-file="/var/lib/mysql/mysqld.pid" 

启动后就可以使用mysql命令来操作数据库了。

选择在哪一个点来做chroot直接决定了难易程度,理论上来说,chroot环境越小越好,也就是在调用关系的越后面越好,因为越往前,需要放到chroot监狱中的东西也就越多。但是发现这种方案直接导致工作量成倍增加,因为越往后,脚本的分支越多,需要处理的点也就越多,潜在的问题也会越多,这需在安全和成本之间做个妥协。最终,我选择直接在/etc/init.d/mysql中进行chroot。

CentOS的chroot命令很简单:chroot NEWROOT [COMMAND...],第一个参数是chroot的路径,第二个参数是要执行的命令,默认第二个参数是sh -i。

详细步骤说明如下:

1.建立chroot环境下的目录结构

选择/var/chroot/mysql作为根目录,参照父环境,将顶层目录依次建立起来,包括:/etc, /bin, /sbin, /tmp/, /dev, /lib64, /usr, /var,用到的次级目录后面会有介绍。完成后目录结构下图所示:

chroot MySQL on CentOS_第1张图片

2.拷贝MySQL所需的系统文件

这一步可能因系统而异,下面列出的大部分都是在验证过程中通过错误信息逐步加进去的。根据chroot最佳实践,chroot监狱要越小越好,切忌将所有库文件及可执行文件一股脑全部复制过来,因为这些程序很可能被黑客所利用,降低了系统安全性。

依赖的库文件如下,库文件可以使用ldd命令查询得到:

/lib64/libtermcap.so.2 /lib64/librt.so.1 /lib64/libdl.so.2 /lib64/libssl.so.6 /lib64/libcrypto.so.6 /lib64/libpthread.so.0 /lib64/libcrypt.so.1 /lib64/libnsl.so.1 /lib64/libm.so.6 /lib64/libgcc_s.so.1 /lib64/libc.so.6 /lib64/ld-linux-x86-64.so.2 /lib64/libcom_err.so.2 /lib64/libresolv.so.2 /lib64/libkeyutils.so.1 /lib64/libselinux.so.1 /lib64/libsepol.so.1 /lib64/libnss_compat.so.2 /lib64/libnss_files.so.2 /usr/lib64/libz.so.1 /usr/lib64/libaio.so.1 /usr/lib64/libstdc++.so.6 /usr/lib64/libgssapi_krb5.so.2 /usr/lib64/libkrb5.so.3 /usr/lib64/libk5crypto.so.3 /usr/lib64/libkrb5support.so.0 /var/chroot/mysql/usr/lib64/以及/usr/lib64/mysql目录下全部文件。

可执行文件被MySQL脚本调用,包括:

/sbin/pidof /bin/sh /bin/hostname /bin/basename /bin/sleep /bin/nice /bin/sed /bin/cut /bin/touch /bin/chown /usr/bin/wc /bin/rm /bin/date /bin/grep /bin/chmod /bin/cat /usr/bin/expr /usr/bin/test /usr/bin/dirname /usr/bin/innochecksum /usr/bin/perror /usr/bin/replace /usr/bin/resolve_stack_dump /usr/bin/resolveip /usr/sbin/mysqld以及 /usr/bin/下所有已my开头的文件。

配置文件包括:/etc/hosts, /etc/my.cnf, /etc/passwd, /etc/group,这里要注意,passwd和group文件需要将除mysql用户和组以外的内容全部删除。

其实这一步完成后,就可以执行chroot命令,使用shell进入chroot环境了,当然只能使用已经复制过来的系统命令。因为没有ls,所有你就看不了目录内容,调试的时候可以多拷贝一些系统命令过来,通过命令行直接启动mysql,看错误提示,进行修改。

3. 拷贝父系统上的其他文件

因为从/etc/init.d/mysql就开始chroot,所以后面用到的脚本都要拷贝过来,如/etc/init.d/mysql-real。

还有MySQL的数据文件,在父系统的/var/lib/mysql目录中。

4.建立设备文件

到目前为止,发现只需要建立/dev/null就可以

mknod -m 666 /var/chroot/mysql/dev/null c 1 3

5.参考父系统修改文件系统权限及属主

这里可以根据安全需要进一步收紧权限。

6.修改/etc/init.d/mysql,调用chroot命令

#!/bin/bash
REALSCRIPT=/etc/init.d/mysql-real
ARGS=''

# don't double-start, as mysql kills the pid file
if [ "$1" = "start" ]; then
        /usr/sbin/chroot /var/chroot/mysql $REALSCRIPT status >/dev/null 2>/dev/null
        if [ $? -eq 0 ]; then
                /usr/sbin/chroot /var/chroot/mysql $REALSCRIPT status
                exit $?
        fi
fi

# pass additional parameter to mysql on start / restart
if [ "$1" = "start" ]\
        ||[ "$1" = "restart" ]\
        ||[ "$1" = "reload" ]\
; then
        # reverting additional argument
        ARGS="--max_allowed_packet=128M $ARGS"
        :
fi

/usr/sbin/chroot /var/chroot/mysql $REALSCRIPT $1 $ARGS

这一步完成后,如果没什么问题,我们已经可以通过"service mysql start"来启动mysql,使其运行在chroot环境下。但是你会发现当你用mysql来试图连接数据库时却返回“ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)”的错误。这是因为mysql客户端程序会默认读取my.cnf中的sock配置来连接数据库,而我们配的是/var/lib/mysql/mysql.sock,很明显,mysql运行在chroot环境中,在父环境的/var/lib/mysql目录中并没有sock文件,怎么办呢?建立软链接,当然你也可以指定socket参数。搞定!

在chroot环境下使用软链接时注意,只能将chroot监狱中的文件链接到外面,而不能反过来,反过来的话在chroot监狱中是无法读取的。

这种方案除了修改了/etc/init.d/mysql脚本外,其他配置文件和脚本都不需要修改,工作量应该是最小的。但是这种方案的安全性如何呢?自己不是黑客,没有尝试过,以后如果发现有漏洞的话会即使更新本文。但上次一个安全专家确实给我们演示过通过一个安全性不强的MySQL攻入系统,获得root权限,他怎么做到的呢?不好意思,都忘了。

再简单介绍一下如何判断应用程序是否被成功chroot,找一下男人(man),有这么一说:

/proc/[pid]/root
              UNIX and Linux support the idea of a per-process root of the filesystem, set by the chroot(2) system call.  This file is a symbolic link that points to the process's root directory, and behaves in the same way as exe, and fd/*.
说白了就是你先用ps找到应用程序的PID,然后查看/proc/[pid]/root这个文件,如果是"/",说明你没有chroot成功,反之,可能搞定了。我的环境下



如果有高手路过,请不吝赐教如何验证chroot环境下mysql的安全性,叩谢。


你可能感兴趣的:(mysql,系统安全,chroot)