基于ZFS和GnuPG的安全远程备份方案

需求及方案

这事的需求是这样的,公司服务器上有一些数据需要备份,主要是数据库和一些共享文件,早年是通过磁带机备份, 然后离线保存磁带实现的,但是这个方法实在是很麻烦,而且用了几年以后,一盘磁带已经装不下所有备份了,再说那个老型号的磁带机已经过保可以报废了,所以 前年的时候重新搞了一个远程备份方案,用了一年多,基本靠谱,最近稍微调整一下顺便作个记录。

基本方案是这样:

在本地备份服务器上将所有数据压缩打包加密,通过互联网传到远程服务器上保存。因为远程服务器在外地分公司那边,那边的同事是没有权限访问这些备份数据的,而且那边的机房环境也不能保障安全,加上传输过程是通过互联网,所以数据安全是很重要的。

虽然通过rsync over SSH可以解决互联网传输中的安全问题,但远程保存的安全性还是需要保证,所以加密是必须的。

具体实现

首先是本地备份服务器的搭建。

因 为源数据都是需要被Windows访问的,所以这个备份服务器必须是可以通过网络被Windows使用的。因为原本共享数据就是在FreeBSD上通过 Samba提供的,所以最初的备份方案中也是让备份服务器通过共享给数据库服务器,让它备份过来,但是在Windows上这么搞其实是很麻烦的(因为默认 的system用户不能访问共享)。

后来因为搞了这个《用FreeBSD10搭建基于ZFS的iSCSI服务 》,所以现在是通过iSCSI来为Windows提供存储服务,比共享好得多,而且高版本的Windows自带Initiator,用起来还是相当方便的。

之 所以要用FreeBSD做备份,当然是因为ZFS。我讨厌Windows那个垃圾说过了很多次了,除了业务应用必须用Windows以外,我都换成了 FreeBSD或Linux——比如远程备份服务器就是CentOS,这是因为分公司那边的IT同事除了Windows就只会这个,不然我肯定也是要搞成 FreeBSD的。

本地备份系统结构大体如下:

共享服务器(FreeBSD+ZFS+Samba) <=> 备份服务器(FreeBSD+ZFS+iSCSI) <=> 业务服务器(Windows)

共享服务器通过Samba共享出一个ZFS,这个ZFS启用dedup以节约空间改善性能(启用压缩当然更节约一些,但性能有影响)。本机上通过对ZFS做每日快照实现本地快速备份。每周将最新快照完全打包发送到备份服务器(内网rsync)。

备 份服务器上通过iSCSI向业务服务器提供一个ZFS,这个ZFS启用压缩以节约空间,因为某弱智数据库备份时都不会做压缩的(不知道新版本有没有改 过),业务服务器将这个ZFS格式化为一个NTFS盘做备份盘,然后数据库每周做完全备份,每天做增量备份,都放在这个备份盘里。

备份逻辑是这样,因为数据量太大,远程备份需要时间很长,只能放在周末,每周执行一次,每日备份如上面所说,只在本地进行。

所 以,每周在共享备份和数据库备份完成以后,备份服务器对那个备份用的iSCSI ZFS作快照,并完全打包与共享备份的打包的快照文件一起加密后发送到远程服务器。因为是在本地加密,远程服务器没有密钥,无法知道备份文件的内容,只能 简单保存文件。即使有人非法获得这个打包的备份文件也无法解密出其中内容。

恢复备份的方法是这样:

万一本地系统完全故障或受 到不可抗力灾害,可以立即在一台新安装的FreeBSD服务器上把备份文件从远程服务器上传回来,再用备份的密钥解密,再恢复出两个ZFS快照(一个 Samba共享,一个iSCSI target,前者可以直接访问其中的文件,后者需要通过Initiator连接并mount为NTFS盘),即可恢复原来的备份内容。

至于本地的日常恢复就更简单了,直接回滚或克隆一下快照即可。

附:应对加密病毒的大杀器——ZFS快照

去年有个厉害的病毒叫CryptoLocker,它的做法是感染后用高强度加密你Windows电脑里的所有文件(当然包括可以通过共享访问到的),杯具在于因为文件还在,你无法通过恢复被删除文件的方式找回,但是因为被加密,你也无法打开,结果就是除了给对方付钱取得解密私钥以外,没有其它办法——除非有备份。

但是备份也有困难,一般来说除了源码会作版本控制方式的备份以外,一般文件很少有人会做,长时间的备份又意义不大,但是频繁做备份又成本太高。

所以你需要ZFS快照,快照就是一种对文件系统级的版本控制,无论当前文件被破坏成什么样,你都可以通过回滚快照或作快照克隆的方式恢复之前任意一个快照的备份,而快照本身又是一种差异备份,其备份成本是很低的,不论是创建还是回滚或克降,速度也都是非常快的。

你值得拥有!

GnuPG的使用

这个方案中用到的ZFS上面和我以前的文章都介绍过很多了,这里再简单介绍一下GPG:

全名叫:The GNU Privacy Guard, 是一个安全的加解密工具。除了可以给文件加解密以外,它还有邮件插件,可以装在邮件客户端里给邮件加密或加签名,防止邮件在传输过程中泄密或被修改。相比 普通的加密工具(比如压缩软件自带的加密功能)来说,它具有更高的安全性(默认密钥长达2048位,最长支持4096位),并且是非对称加密(在邮件加密 中很重要)。

顺便说一句,GPG在加密前会做一次压缩,所以对于加密后的文件小于源文件的情况请不要感到奇怪。

首先是安装GPG,这个在ports找到gnupg安装之即可,不多说。

注 意:GPG需要额外安装一个输入密码的东西叫pinentry,但是在服务器上装的时候要小心,它有四个选项,分别是TTY、NOCURSES、GTK、 QT,选择后两个GUI版的会把XWin给装了,个人建议选择NOCURSES,比TTY版本好看也可靠,TTY版有时不能正常工作——表现为到需要输入 密码的地方时就报错。

GPG的基本的使用说明可以参考阮一峰的文章《GPG入门教程》。

然后是创建你的密钥——当然,如果你自己以前用过GPG,或者需要在新装的服务器上恢复备份,想继续用以前的密钥也可以直接导入使用。

创建密钥的方式是:

gpg --gen-key

注意:这里输入的密码要记得,这个密码是用于保护私钥的,解密的时候会用到。

之后可以看看已经创建好的密钥(分别是公钥部分和私钥部分):

gpg --list-keys
gpg --list-secret-keys

然后要做一件事情就是把密钥导出备份到安全的地方:

gpg -o username.pub.key --export userid
gpg -o username.key --export-secret-keys userid

以上分别导出公钥(username.pub.key)和私钥(username.key)。因为加密用公钥,解密用私钥,所以公钥丢了无所谓,大不了重新创建一副,但是私钥丢了,以前用这个公钥加密的内容都无法解密。

注意:一定要保管好私钥和私钥密码,一旦丢了你所有加密的内容都无法恢复。

万一需要恢复密钥时,可以重新导入(公钥私钥一样,GPG会自动识别):

gpg --import username.pub.key
gpg --import username.key

但是需要注意的是,导入的KEY默认是不被信任的,每次使用时都会显示一下KEY的指纹并提示你是否需要信任,选择YES后才会继续,所以需要手工将其标记为信任:

gpg --edit-key userid
# 进入交互式操作界面
>trust
# 选择5,无限期信任
# 然后退出编辑即可
>quit

然后先测试一下:

dd if=/dev/urandom of=test.dat bs=1024 count=1024  # 创建一个1M的随机内容文件
md5 test.dat # 原文件校验值,注意FreeBSD是用md5命令,不同于Linux的md5sum
gpg -r userid -o test.gpg -e test.dat  # 指定用userid的公钥加密test.dat,生成test.gpg加密文件

再把加密文件test.gpg解密试试:

gpg -d test.gpg -o test1.dat  # 自动使用加密的userid私钥,如果没有则报错,需要输入私钥密码
md5 test1.dat

输入密码应该就可以解出文件来,对个测试文件作一下MD5校验,确认完全一致说明加密解密功能没有问题。

具体配置

最后配置备份同步方案。

共享部分就不说了,跟一般的Samba配置没什么区别,无非是创建ZFS时加上dedup=on参数。下面说一下那个用于备份的ZFS创建:

zfs create -s -V 1T -b 4k -o compression=on tank/backup

这个ZFS的容量为1T,启用压缩。然后配置为了iSCSI target,具体方法见前文。

在备份服务器上创建一个cron任务,每周执行,运行以下命令(当然应该写到一个脚本里去,而且其中的命令全部要加上绝对路径,cron任务可是没有PATH环境变量的):

TODAY=`date +%Y%m%d`  # 注意命令参数与Linux下不同
zfs snapshot tank/backup@$TODAY
zfs send tank/backup@$TODAY | gpg -r userid -o /path_to_backup/$TODAY.bak -e - # 生成ZFS今天的快照(本身就是压缩过的)并通过管道传给GPG进行加密并保存为$TODAY.bak文件
zfs destroy tank/backup@$TODAY # 之后快照就可以删除了,当然要保留一段时间也可以,自己处理
rsync -e "ssh" /path_to_backup/$TODAY.bak user@remotebackup:~/backup/  # remotebackup为远程备份服务器的域名或IP
#rm $TODAY.bak # 传输成功即可删除备份文件,或者也可以保留一段时间,自己处理

必要的话还可以在其中加入发邮件的功能,以便及时了解备份是否成功——FreeBSD的cron会自动把命令执行结果发送邮件,除非你自己把标准输出和标准错误都重定向到日志文件或其它地方。

恢复备份的命令:

zfs create -s -V 1T -b 4k -o comporession=on tank/backup
gpg -d someday.bak | zfs recv -F tank/backup

当然在解密的时候需要输入私钥密码。

请支持GPG

GPG的作者Werner全职为这个开源项目工作,并为此创建了g10code公司运作此项目,但因为基本没什么盈利,公司目前有一些经营困难(见相关报道),他一度打算关闭公司中止项目,是斯诺登让他看到了隐私保护的意义,所以决定筹钱继续干下去。

详情见《GnuPG and g10code》。

欢迎大家捐款支持这样的有意义的工作,这才是真正的为人民服务。像我这么有钱任性的,才不会告诉你们已经捐了50欧。当然这是去年的事,要是现在捐还可以省不少人民币(欧元汇率跌了好多)。

推送到[go4pro.org]