前面几篇BLOG介绍了PostgreSQL 数据传输的加密. 数据传输加密可以防止数据在传输过程中泄露.
本篇主要介绍一下数据存储的加密.
存储加密的好处是, 不用担心因为硬盘被盗导致的数据泄露.
存储加密的方法很多, 有些硬件厂商就提供了硬件层面的加密.
本文主要介绍一下Linux下面的卷加密的软件cryptsetup.
还有很多其他加密手段请参考本文末尾wiki.
需要用到
cryptsetup-luks-1.0.3-8.el5这个包.
[root@db-172-16-3-33 postgresql-9.3beta1]# which cryptsetup
/sbin/cryptsetup
[root@db-172-16-3-33 postgresql-9.3beta1]# rpm -qf /sbin/cryptsetup
cryptsetup-luks-1.0.3-8.el5
cryptsetup-luks-1.0.3-8.el5
[root@db-172-16-3-33 postgresql-9.3beta1]# rpm -ql cryptsetup-luks-1.0.3-8.el5
/sbin/cryptsetup
/usr/lib64/libcryptsetup.so.0
/usr/lib64/libcryptsetup.so.0.0.0
/usr/share/doc/cryptsetup-luks-1.0.3
/usr/share/doc/cryptsetup-luks-1.0.3/AUTHORS
/usr/share/doc/cryptsetup-luks-1.0.3/COPYING
/usr/share/doc/cryptsetup-luks-1.0.3/ChangeLog
/usr/share/doc/cryptsetup-luks-1.0.3/INSTALL
/usr/share/doc/cryptsetup-luks-1.0.3/NEWS
/usr/share/doc/cryptsetup-luks-1.0.3/README
/usr/share/locale/de/LC_MESSAGES/cryptsetup-luks.mo
/usr/share/man/man8/cryptsetup.8.gz
注意本例是磁盘级加密, 不是文件系统加密, 也不是文件级的加密.
Linux Unified Key Setup or LUKS is a disk-encryption specification
[举例]
使用/dev/mapper/vgdata01-lv01这个设备作为加密设备.
[root@db-172-16-3-33 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/cciss/c0d0p1 29G 16G 12G 57% /
tmpfs 6.9G 0 6.9G 0% /dev/shm
/dev/mapper/vgdata01-lv03
135G 35G 93G 28% /pgdata/digoal/1921/data03
/dev/mapper/vgdata01-lv04
135G 69G 59G 54% /pgdata/digoal/1921/data04
/dev/mapper/vgdata01-lv05
135G 85G 44G 66% /pgdata/digoal/1921/data05
[root@db-172-16-3-33 ~]# lvs
LV VG Attr LSize Origin Snap% Move Log Copy% Convert
lv03 vgdata01 -wi-ao 136.70G
lv04 vgdata01 -wi-ao 136.70G
lv05 vgdata01 -wi-ao 136.70G
lv06 vgdata01 -wi-a- 99.40G
1. 方法1 : 使用密钥文件解密
随便找一个文件即可. 但是权限最好弄成400.
新建一个device mapper设备.
查看新建好的dm设备状态.
通过/dev/mapper/cry_test1新建文件系统.
修改/etc/fstab
使用mount -a可以挂载
重启服务器, 无法自动 挂载/mnt, 原因 :
[root@db-172-16-3-33 ~]# pwd
/root
[root@db-172-16-3-33 ~]# chmod 400 ssl.dmp
-r-------- 1 root root 6838 May 22 17:29 ssl.dmp
新建一个device mapper设备.
[root@db-172-16-3-33 ~]# cryptsetup create cry_test1 /dev/mapper/vgdata01-lv06 --cipher aes-cbc-essiv:sha256 --key-file ./ssl.dmp
查看新建好的dm设备状态.
[root@db-172-16-3-33 ~]# cryptsetup status cry_test1
/dev/mapper/cry_test1 is active:
cipher: aes-cbc-essiv:sha256
keysize: 256 bits
device: /dev/mapper/vgdata01-lv06
offset: 0 sectors
size: 208453632 sectors
mode: read/write
通过/dev/mapper/cry_test1新建文件系统.
[root@db-172-16-3-33 ~]# mkfs.ext4 /dev/mapper/cry_test1
修改/etc/fstab
vi /etc/fstab
/dev/mapper/cry_test1 /mnt ext4 defaults,noatime,nodiratime 0 0
使用mount -a可以挂载
mount -a
df -h
/dev/mapper/cry_test1
98G 188M 93G 1% /mnt
[root@db-172-16-3-33 ~]# cd /mnt
[root@db-172-16-3-33 mnt]# ll
total 16
drwx------ 2 root root 16384 May 23 16:17 lost+found
[root@db-172-16-3-33 mnt]# dd if=/dev/zero of=./test.img bs=1024k count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.930429 seconds, 1.2 GB/s
[root@db-172-16-3-33 mnt]# ll
total 1048592
drwx------ 2 root root 16384 May 23 16:17 lost+found
-rw-r--r-- 1 root root 1073741824 May 23 16:25 test.img
重启服务器, 无法自动 挂载/mnt, 原因 :
mount: special device /dev/mapper/cry_test1 does not exist
但是系统能正常进入.
解决办法是编写/etc/crypttab
格式 :
dm-name devic-name keyfile option1=val1,option2=val2,...
详见man crypttab
例如我这里写的是 :
再次重启, 自动挂载成功.
密钥文件非常重要, 如果与磁盘一起丢失了, 那么也是可以被挂载的.
cry_test1 /dev/mapper/vgdata01-lv06 /root/ssl.dmp cipher=aes-cbc-essiv:sha256
再次重启, 自动挂载成功.
[root@db-172-16-3-33 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/cciss/c0d0p1 29G 16G 12G 56% /
tmpfs 6.9G 0 6.9G 0% /dev/shm
/dev/mapper/cry_test1
98G 1.2G 92G 2% /mnt
密钥文件非常重要, 如果与磁盘一起丢失了, 那么也是可以被挂载的.
2. 方法2 :
当然也可以不使用密钥文件进行解密, 使用passphrase也是可以的.
[root@db-172-16-3-33 ~]# umount /mnt
[root@db-172-16-3-33 ~]# cryptsetup remove cry_test1
[root@db-172-16-3-33 ~]# cryptsetup create cry_test1 /dev/mapper/vgdata01-lv06 --cipher aes-cbc-essiv:sha256
Enter passphrase:
假设输入digoal
需要重新格式化 :
[root@db-172-16-3-33 ~]# mkfs.ext4 /dev/mapper/cry_test1
mount -a
[root@db-172-16-3-33 ~]# cd /mnt
[root@db-172-16-3-33 mnt]# ll
total 16
drwx------ 2 root root 16384 May 23 16:48 lost+found
[root@db-172-16-3-33 mnt]# touch abc
使用passphrase解密, 在系统重启后无法自动挂载, 原因和前面一样, 需要在系统进入后新建这个dm设备.
可能是crypttab格式不正确.
如果重启后出现挂载失败的话, 需要重新创建一下设备, 但是注意密码要输正确, 否则挂载时会报fs类型不正确.
重新创建, 输入正确的密码即可.
[root@db-172-16-3-33 ~]# mount -a
mount: special device /dev/mapper/cry_test1 does not exist
[root@db-172-16-3-33 ~]# cryptsetup create cry_test1 /dev/mapper/vgdata01-lv06 --cipher aes-cbc-essiv:sha256
Enter passphrase:
输入正确的密码.
输入密码错误并不会破坏数据. 重新创建并输入正确即可.
[root@db-172-16-3-33 ~]# mount -a
[root@db-172-16-3-33 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/cciss/c0d0p1 29G 16G 12G 56% /
tmpfs 6.9G 0 6.9G 0% /dev/shm
/dev/mapper/vgdata01-lv03
135G 35G 93G 28% /pgdata/digoal/1921/data03
/dev/mapper/vgdata01-lv04
135G 69G 59G 54% /pgdata/digoal/1921/data04
/dev/mapper/vgdata01-lv05
135G 85G 44G 66% /pgdata/digoal/1921/data05
/dev/mapper/cry_test1
98G 188M 93G 1% /mnt
3. 方法3
cryptsetup还支持LUKS, Linux Unified Key Setup扩展.
使用方法与上面两种方法类似.
创建一个加密设备
新建dm设备 :
初始化文件系统 :
为了能够启动系统时可以自动挂载, 为这个设备添加key文件.
在添加2个钥匙
[root@db-172-16-3-33 ~]# cryptsetup luksFormat /dev/mapper/vgdata01-lv06 --cipher aes-cbc-essiv:sha256
WARNING!
========
This will overwrite data on /dev/mapper/vgdata01-lv06 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase:
输入digoal
Verify passphrase:
输入digoal
Command successful.
新建dm设备 :
[root@db-172-16-3-33 ~]# cryptsetup luksOpen /dev/mapper/vgdata01-lv06 lukstest1
Enter LUKS passphrase for /dev/mapper/vgdata01-lv06:
输入digoal
key slot 0 unlocked.
Command successful.
初始化文件系统 :
[root@db-172-16-3-33 ~]# mkfs.ext4 /dev/mapper/lukstest1
为了能够启动系统时可以自动挂载, 为这个设备添加key文件.
[root@db-172-16-3-33 ~]# cryptsetup luksAddKey /dev/mapper/vgdata01-lv06 /root/dscn1068.jpg
Enter any LUKS passphrase: 输入digoal
Verify passphrase: 输入digoal
key slot 0 unlocked.
Command successful.
在添加2个钥匙
[root@db-172-16-3-33 ~]# cryptsetup luksAddKey /dev/mapper/vgdata01-lv06 /root/pwdfile
Enter any LUKS passphrase: 输入digoal
Verify passphrase: 输入digoal
key slot 0 unlocked.
Command successful.
[root@db-172-16-3-33 ~]# cryptsetup luksAddKey /dev/mapper/vgdata01-lv06 /root/ssl.dmp
Enter any LUKS passphrase: 输入digoal
Verify passphrase: 输入digoal
key slot 0 unlocked.
Command successful.
最多可以添加8个密钥.
查看luks设备信息 :
vi /etc/crypttab, 任意一把钥匙都可以
如果你觉得现在系统可能被入侵了, 可以赶紧在系统中锁定这个加密设备 :
锁定后, 要再挂载的话, 需要重新OPEN这个设备.
[root@db-172-16-3-33 ~]# cryptsetup luksDump /dev/mapper/vgdata01-lv06
LUKS header information for /dev/mapper/vgdata01-lv06
Version: 1
Cipher name: aes
Cipher mode: cbc-essiv:sha256
Hash spec: sha1
Payload offset: 1032
MK bits: 128
MK digest: eb b0 d4 31 d1 60 99 2c af db cf 72 b0 21 46 ca 7b f5 07 3a
MK salt: 8c b2 3b 09 ae fd a9 ef 10 87 d7 e2 e8 61 68 44
7d 61 bc b0 17 19 e4 a5 01 f4 0a 4d ab 2e 7d 40
MK iterations: 10
UUID: ed3427a4-8cc5-4b45-907e-a0b81c562f69
Key Slot 0: ENABLED
Iterations: 587148
Salt: 4e 90 49 da 53 60 dc 39 c2 26 93 83 7a 93 c8 b6
35 b6 28 62 76 a5 c7 1c f6 dc 96 5f f3 bb 89 d7
Key material offset: 8
AF stripes: 4000
Key Slot 1: ENABLED
Iterations: 589389
Salt: ce e2 9f 5f 27 e6 da 94 f8 9b 6d 91 ab b9 d8 7b
11 c9 99 57 fc 43 00 42 3f 17 b5 be 95 11 15 d7
Key material offset: 136
AF stripes: 4000
Key Slot 2: ENABLED
Iterations: 582465
Salt: b2 8d 38 84 0c 72 21 56 f4 38 a0 64 f1 be a6 8e
e2 88 f0 dd 4c fd 4f 01 c3 c9 53 c8 e3 4a 0f 7c
Key material offset: 264
AF stripes: 4000
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED
自动挂载 :
vi /etc/fstab
/dev/mapper/lukstest1 /mnt ext4 defaults,noatime,nodiratime 0 0
vi /etc/crypttab, 任意一把钥匙都可以
lukstest1 /dev/mapper/vgdata01-lv06 /root/pwdfile cipher=aes-cbc-essiv:sha256
如果你觉得现在系统可能被入侵了, 可以赶紧在系统中锁定这个加密设备 :
[root@db-172-16-3-33 ~]# umount /mnt
[root@db-172-16-3-33 ~]# cryptsetup luksClose lukstest1
锁定后, 要再挂载的话, 需要重新OPEN这个设备.
[root@db-172-16-3-33 ~]# mount -a
mount: special device /dev/mapper/lukstest1 does not exist
[root@db-172-16-3-33 ~]# cryptsetup luksOpen /dev/mapper/vgdata01-lv06 lukstest1
Enter LUKS passphrase for /dev/mapper/vgdata01-lv06: 这里就要输入passphrase了.
key slot 0 unlocked.
Command successful.
[root@db-172-16-3-33 ~]# mount -a
简单的测试一下加密前后的性能 :
加密前 :
加密后 :
pg93@db-172-16-3-33-> pg_test_fsync
5 seconds per test
O_DIRECT supported on this platform for open_datasync and open_sync.
Compare file sync methods using one 16kB write:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync n/a
fdatasync 3078.659 ops/sec 325 usecs/op
fsync 122.920 ops/sec 8135 usecs/op
fsync_writethrough n/a
open_sync 3159.457 ops/sec 317 usecs/op
Compare file sync methods using two 16kB writes:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync n/a
fdatasync 2183.032 ops/sec 458 usecs/op
fsync 119.158 ops/sec 8392 usecs/op
fsync_writethrough n/a
open_sync 82.511 ops/sec 12120 usecs/op
Compare open_sync with different write sizes:
(This is designed to compare the cost of writing 16kB
in different write open_sync sizes.)
1 * 16kB open_sync write 3159.608 ops/sec 316 usecs/op
2 * 8kB open_sync writes 82.715 ops/sec 12090 usecs/op
4 * 4kB open_sync writes 75.105 ops/sec 13315 usecs/op
8 * 2kB open_sync writes 76.498 ops/sec 13072 usecs/op
16 * 1kB open_sync writes 66.042 ops/sec 15142 usecs/op
Test if fsync on non-write file descriptor is honored:
(If the times are similar, fsync() can sync data written
on a different descriptor.)
write, fsync, close 130.770 ops/sec 7647 usecs/op
write, close, fsync 134.353 ops/sec 7443 usecs/op
Non-Sync'ed 16kB writes:
write 162297.029 ops/sec 6 usecs/op
加密后 :
pg93@db-172-16-3-33-> pg_test_fsync
5 seconds per test
O_DIRECT supported on this platform for open_datasync and open_sync.
Compare file sync methods using one 16kB write:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync n/a
fdatasync 1659.743 ops/sec 603 usecs/op
fsync 40.495 ops/sec 24694 usecs/op
fsync_writethrough n/a
open_sync 1986.934 ops/sec 503 usecs/op
Compare file sync methods using two 16kB writes:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync n/a
fdatasync 810.707 ops/sec 1233 usecs/op
fsync 44.788 ops/sec 22327 usecs/op
fsync_writethrough n/a
open_sync 82.907 ops/sec 12062 usecs/op
Compare open_sync with different write sizes:
(This is designed to compare the cost of writing 16kB
in different write open_sync sizes.)
1 * 16kB open_sync write 1892.044 ops/sec 529 usecs/op
2 * 8kB open_sync writes 85.417 ops/sec 11707 usecs/op
4 * 4kB open_sync writes 57.790 ops/sec 17304 usecs/op
8 * 2kB open_sync writes 66.311 ops/sec 15080 usecs/op
16 * 1kB open_sync writes 66.290 ops/sec 15085 usecs/op
Test if fsync on non-write file descriptor is honored:
(If the times are similar, fsync() can sync data written
on a different descriptor.)
write, fsync, close 43.325 ops/sec 23082 usecs/op
write, close, fsync 40.256 ops/sec 24841 usecs/op
Non-Sync'ed 16kB writes:
write 162096.790 ops/sec 6 usecs/op
从测试结果来看, 性能下降比较厉害.
[参考]
2. man cryptsetup
man crypttab