加密数据和数据库连接
- 客户端和Master数据库之间的连接可以用SSL加密。这种方式可以通过设置ssl服务器配置参数为on并且编辑pg_hba.conf文件来启用。有关在Greenplum数据库中启用SSL的信息请见Greenplum数据库管理员指南中的“加密客户端/服务器连接”。
- Greenplum数据库4.2.1及以上的版本允许在Greenplum的并行文件分发服务器、gpfdist和Segment主机之间传输SSL加密数据。详见加密gpfdist连接。
- Greenplum数据库集群中主机之间的网络通信可以使用IPsec加密。集群中的每一对主机之间会建立一个认证过的加密的VPN。对IPsec的支持请检查操作系统文档,或者考虑等组织提供的第三方解决方案。
- pgcrypto包中的加密/解密函数保护停留在数据库中的数据。列级的加密可以保护敏感信息,例如口令、社会保险号码或者信用卡号码。例子可以在使用PGP加密表中的数据中找到。
- 加密确保数据只能被拥有解密数据所需密钥的用户看见。
- 加密和解密数据有性能代价,只加密需要加密的数据。
- 在生产系统中实现任何加密解决方案之前先做性能测试。
- 用于生产的Greenplum数据库系统中的服务器证书应该由一个数字证书认证机构(CA)签发,这样客户端可以认证服务器。如果所有的客户端都在该组织本地,这个CA可以是本地的。
- 只要到Greenplum数据库的客户端连接会通过一个不安全的链路,就应该使用SSL加密。
- 对称加密模式(加密和解密使用相同的密钥)比非对称模式具有更好的性能,并且应该在可以安全共享密钥时使用对称模式。
- 使用来自pgcrypto包的函数来加密磁盘上的数据。数据在数据库进程中被加密和解密,因此有必要用SSL来保护客户端连接以避免传输未加密的数据。
- 在ETL数据被载入数据库或者被从数据库中卸载时,使用gpfdists协议来保护ETL数据。请见。
密钥管理
只要使用对称(单私钥)或者非对称(公钥和私钥)加密,就有必要安全地存储主密钥或者私钥。存储加密密钥有很多选项,例如在文件系统上保存、密钥保管库、加密的USB、可信平台模块(TPM)或者硬件安全模块(HSM)。
在规划密钥管理时考虑下列问题:
- 密钥将被存在哪里?
- 密钥何时过期?
- 如何保护密钥?
- 如何访问密钥?
- 如何恢复和收回密钥?
开放Web应用安全性项目(OWASP)提供了一套非常全面的。
Greenplum数据库的pgcrypto包提供了加密数据库中静止数据的函数。管理员可以加密具有敏感信息(例如社会保险号码或信用卡号)的列以提供一个额外的保护层。没有加密密钥的用户无法读取以加密形式存储的数据库数据,并且这些数据也无法从磁盘直接读取。
pgcrypto允许使用对称和非对称加密的PGP加密。对称加密使用同样的密钥加密和解密数据,并且比非对称加密更快。在交换密钥不成问题的环境中它是首选方法。在非对称加密中,公钥被用来加密数据而私钥被用来解密数据。这种模式比对称加密慢一些并且要求更强的密钥。
使用pgcrypto总是会带来性能和可维护性的代价。有必要只对需要加密的数据使用加密。还有,要记住用户无法通过索引加密数据来搜索它们。
在用户实现数据库内加密之前,考虑下列PGP限制。
- 不支持签名。这还意味着不会检查加密子密钥是否属于主密钥。
- 不支持将加密密钥作为主密钥。这种做法通常是不被鼓励的,因此这一限制应该不是问题。
- 不支持多个子密钥。这可能看起来像一个问题,因为这是一种常见的做法。在另一方面,用户不应将其常规GPG/PGP密钥用于pgcrypto,而是要创建新的密钥,因为使用场景不同。
Greenplum数据库默认用zlib编译,这允许PGP加密函数在加密数据之前先压缩数据。在编译有OpenSSL时,将会有更多算法可用。
因为pgcrypto函数运行在数据库服务器内部,数据和口令是以明文形式在pgcrypto和客户端应用之间移动。为了最好的安全性,用户应该使用本地连接或者使用SSL连接,并且用户应该信任系统管理员和数据库管理员。
Greenplum数据库默认没有安装pgcrypto包。用户可以从Pivotal Network下载一个pgcrypto包,并且使用Greenplum包管理器(gppkg)在集群中安装pgcrypto。
pgcrypto会根据主PostgreSQL配置脚本的发现配置自身。
当编译有zlib时,pgcrypto加密函数能在加密前压缩数据。
pgcrypto拥有从基本内建函数到高级内建函数的多个加密级别。下面的表格展示了支持的加密算法。
创建PGP密钥
要在Greenplum数据库中使用PGP非对称加密,用户必须首先创建公私钥并且安装它们。
作为root,执行下列命令并且从菜单选择选项1:
如下例所示,回应提示并且遵循其指导:
What keysize do you want? (2048) Press enter to accept default key size
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 365
Key expires at Wed 13 Jan 2016 10:35:39 AM PST
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: John Doe
Email address: jdoe@email.com
Comment:
You selected this USER-ID:
"John Doe <jdoe@email.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.
(For this demo the passphrase is blank.)
can't connect to `/root/.gnupg/S.gpg-agent': No such file or directory
You don't want a passphrase - this is probably a *bad* idea!
I will do it anyway. You can change your passphrase at any time,
using this program with the option "--edit-key".
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key 2027CC30 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdbgpg:
3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: next trustdb check due at 2016-01-13
pub 2048R/2027CC30 2015-01-13 [expires: 2016-01-13]
Key fingerprint = 7EDA 6AD0 F5E0 400F 4D45 3259 077D 725E 2027 CC30
uid John Doe <jdoe@email.com>
sub 2048R/4FD2EFBB 2015-01-13 [expires: 2016-01-13]
通过输入下列命令来列出PGP密钥:
gpg --list-secret-keys
/root/.gnupg/secring.gpg
------------------------
sec 2048R/2027CC30 2015-01-13 [expires: 2016-01-13]
uid John Doe <jdoe@email.com>
ssb 2048R/4FD2EFBB 2015-01-13
2027CC30是公钥并且将被用来加密数据库中的数据。4FD2EFBB是私钥并且将被用来解密数据。
使用下列命令导出密钥:
更多有关PGP加密函数的信息请见pgcrypto文档。
这个小节展示如何使用用户产生的PGP密钥加密插入到一列中的数据。
转储public.key文件的内容,然后把它拷贝的剪贴板:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.14 (GNU/Linux)
mQENBFS1Zf0BCADNw8Qvk1V1C36Kfcwd3Kpm/dijPfRyyEwB6PqKyA05jtWiXZTh
2His1ojSP6LI0cSkIqMU9LAlncecZhRIhBhuVgKlGSgd9texg2nnSL9Admqik/yX
R5syVKG+qcdWuvyZg9oOOmeyjhc3n+kkbRTEMuM3flbMs8shOwzMvstCUVmuHU/V
vG5rJAe8PuYDSJCJ74I6w7SOH3RiRIc7IfL6xYddV42l3ctd44bl8/i71hq2UyN2
/Hbsjii2ymg7ttw3jsWAx2gP9nssDgoy8QDy/o9nNqC8EGlig96ZFnFnE6Pwbhn+
ic8MD0lK5/GAlR6Hc0ZIHf8KEcavruQlikjnABEBAAG0HHRlc3Qga2V5IDx0ZXN0
a2V5QGVtYWlsLmNvbT6JAT4EEwECACgFAlS1Zf0CGwMFCQHhM4AGCwkIBwMCBhUI
AgkKCwQWAgMBAh4BAheAAAoJEAd9cl4gJ8wwbfwH/3VyVsPkQl1owRJNxvXGt1bY
7BfrvU52yk+PPZYoes9UpdL3CMRk8gAM9bx5Sk08q2UXSZLC6fFOpEW4uWgmGYf8
JRoC3ooezTkmCBW8I1bU0qGetzVxopdXLuPGCE7hVWQe9HcSntiTLxGov1mJAwO7
TAoccXLbyuZh9Rf5vLoQdKzcCyOHh5IqXaQOT100TeFeEpb9TIiwcntg3WCSU5P0
DGoUAOanjDZ3KE8Qp7V74fhG1EZVzHb8FajR62CXSHFKqpBgiNxnTOk45NbXADn4
eTUXPSnwPi46qoAp9UQogsfGyB1XDOTB2UOqhutAMECaM7VtpePv79i0Z/NfnBe5
AQ0EVLVl/QEIANabFdQ+8QMCADOipM1bF/JrQt3zUoc4BTqICaxdyzAfz0tUSf/7
Zro2us99GlARqLWd8EqJcl/xmfcJiZyUam6ZAzzFXCgnH5Y1sdtMTJZdLp5WeOjw
gCWG/ZLu4wzxOFFzDkiPv9RDw6e5MNLtJrSp4hS5o2apKdbO4Ex83O4mJYnav/rE
iDDCWU4T0lhv3hSKCpke6LcwsX+7liozp+aNmP0Ypwfi4hR3UUMP70+V1beFqW2J
bVLz3lLLouHRgpCzla+PzzbEKs16jq77vG9kqZTCIzXoWaLljuitRlfJkO3vQ9hO
v/8yAnkcAmowZrIBlyFg2KBzhunYmN2YvkUAEQEAAYkBJQQYAQIADwUCVLVl/QIb
DAUJAeEzgAAKCRAHfXJeICfMMOHYCACFhInZA9uAM3TC44l+MrgMUJ3rW9izrO48
WrdTsxR8WkSNbIxJoWnYxYuLyPb/shc9k65huw2SSDkj//0fRrI61FPHQNPSvz62
WH+N2lasoUaoJjb2kQGhLOnFbJuevkyBylRz+hI/+8rJKcZOjQkmmK8Hkk8qb5x/
HMUc55H0g2qQAY0BpnJHgOOQ45Q6pk3G2/7Dbek5WJ6K1wUrFy51sNlGWE8pvgEx
/UUZB+dYqCwtvX0nnBu1KNCmk2AkEcFK3YoliCxomdOxhFOv9AKjjojDyC65KJci
Pv2MikPS2fKOAg1R3LpMa8zDEtl4w3vckPQNrQNnYuUtfj6ZoCxv
=XZ8J
-----END PGP PUBLIC KEY BLOCK-----
创建一个名为userssn的表并且插入一些敏感数据,这个例子中是Bob和Alice的社会保险号码。在”dearmor(“之后粘贴public.key的内容。
CREATE TABLE userssn( ssn_id SERIAL PRIMARY KEY,
username varchar(100), ssn bytea);
INSERT INTO userssn(username, ssn)
SELECT robotccs.username, pgp_pub_encrypt(robotccs.ssn, keys.pubkey) AS ssn
FROM (
VALUES ('Alice', '123-45-6788'), ('Bob', '123-45-6799'))
AS robotccs(username, ssn)
CROSS JOIN (SELECT dearmor('-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.14 (GNU/Linux)
mQENBFS1Zf0BCADNw8Qvk1V1C36Kfcwd3Kpm/dijPfRyyEwB6PqKyA05jtWiXZTh
2His1ojSP6LI0cSkIqMU9LAlncecZhRIhBhuVgKlGSgd9texg2nnSL9Admqik/yX
R5syVKG+qcdWuvyZg9oOOmeyjhc3n+kkbRTEMuM3flbMs8shOwzMvstCUVmuHU/V
vG5rJAe8PuYDSJCJ74I6w7SOH3RiRIc7IfL6xYddV42l3ctd44bl8/i71hq2UyN2
/Hbsjii2ymg7ttw3jsWAx2gP9nssDgoy8QDy/o9nNqC8EGlig96ZFnFnE6Pwbhn+
ic8MD0lK5/GAlR6Hc0ZIHf8KEcavruQlikjnABEBAAG0HHRlc3Qga2V5IDx0ZXN0
a2V5QGVtYWlsLmNvbT6JAT4EEwECACgFAlS1Zf0CGwMFCQHhM4AGCwkIBwMCBhUI
AgkKCwQWAgMBAh4BAheAAAoJEAd9cl4gJ8wwbfwH/3VyVsPkQl1owRJNxvXGt1bY
7BfrvU52yk+PPZYoes9UpdL3CMRk8gAM9bx5Sk08q2UXSZLC6fFOpEW4uWgmGYf8
JRoC3ooezTkmCBW8I1bU0qGetzVxopdXLuPGCE7hVWQe9HcSntiTLxGov1mJAwO7
TAoccXLbyuZh9Rf5vLoQdKzcCyOHh5IqXaQOT100TeFeEpb9TIiwcntg3WCSU5P0
DGoUAOanjDZ3KE8Qp7V74fhG1EZVzHb8FajR62CXSHFKqpBgiNxnTOk45NbXADn4
eTUXPSnwPi46qoAp9UQogsfGyB1XDOTB2UOqhutAMECaM7VtpePv79i0Z/NfnBe5
gCWG/ZLu4wzxOFFzDkiPv9RDw6e5MNLtJrSp4hS5o2apKdbO4Ex83O4mJYnav/rE
iDDCWU4T0lhv3hSKCpke6LcwsX+7liozp+aNmP0Ypwfi4hR3UUMP70+V1beFqW2J
bVLz3lLLouHRgpCzla+PzzbEKs16jq77vG9kqZTCIzXoWaLljuitRlfJkO3vQ9hO
v/8yAnkcAmowZrIBlyFg2KBzhunYmN2YvkUAEQEAAYkBJQQYAQIADwUCVLVl/QIb
DAUJAeEzgAAKCRAHfXJeICfMMOHYCACFhInZA9uAM3TC44l+MrgMUJ3rW9izrO48
WrdTsxR8WkSNbIxJoWnYxYuLyPb/shc9k65huw2SSDkj//0fRrI61FPHQNPSvz62
WH+N2lasoUaoJjb2kQGhLOnFbJuevkyBylRz+hI/+8rJKcZOjQkmmK8Hkk8qb5x/
HMUc55H0g2qQAY0BpnJHgOOQ45Q6pk3G2/7Dbek5WJ6K1wUrFy51sNlGWE8pvgEx
/UUZB+dYqCwtvX0nnBu1KNCmk2AkEcFK3YoliCxomdOxhFOv9AKjjojDyC65KJci
Pv2MikPS2fKOAg1R3LpMa8zDEtl4w3vckPQNrQNnYuUtfj6ZoCxv
=XZ8J
-----END PGP PUBLIC KEY BLOCK-----' AS pubkey) AS keys;
验证ssn列被加密。
从数据库提取public.key ID:
SELECT pgp_key_id(dearmor('-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.14 (GNU/Linux)
mQENBFS1Zf0BCADNw8Qvk1V1C36Kfcwd3Kpm/dijPfRyyEwB6PqKyA05jtWiXZTh
2His1ojSP6LI0cSkIqMU9LAlncecZhRIhBhuVgKlGSgd9texg2nnSL9Admqik/yX
R5syVKG+qcdWuvyZg9oOOmeyjhc3n+kkbRTEMuM3flbMs8shOwzMvstCUVmuHU/V
vG5rJAe8PuYDSJCJ74I6w7SOH3RiRIc7IfL6xYddV42l3ctd44bl8/i71hq2UyN2
/Hbsjii2ymg7ttw3jsWAx2gP9nssDgoy8QDy/o9nNqC8EGlig96ZFnFnE6Pwbhn+
ic8MD0lK5/GAlR6Hc0ZIHf8KEcavruQlikjnABEBAAG0HHRlc3Qga2V5IDx0ZXN0
a2V5QGVtYWlsLmNvbT6JAT4EEwECACgFAlS1Zf0CGwMFCQHhM4AGCwkIBwMCBhUI
AgkKCwQWAgMBAh4BAheAAAoJEAd9cl4gJ8wwbfwH/3VyVsPkQl1owRJNxvXGt1bY
7BfrvU52yk+PPZYoes9UpdL3CMRk8gAM9bx5Sk08q2UXSZLC6fFOpEW4uWgmGYf8
JRoC3ooezTkmCBW8I1bU0qGetzVxopdXLuPGCE7hVWQe9HcSntiTLxGov1mJAwO7
TAoccXLbyuZh9Rf5vLoQdKzcCyOHh5IqXaQOT100TeFeEpb9TIiwcntg3WCSU5P0
DGoUAOanjDZ3KE8Qp7V74fhG1EZVzHb8FajR62CXSHFKqpBgiNxnTOk45NbXADn4
eTUXPSnwPi46qoAp9UQogsfGyB1XDOTB2UOqhutAMECaM7VtpePv79i0Z/NfnBe5
AQ0EVLVl/QEIANabFdQ+8QMCADOipM1bF/JrQt3zUoc4BTqICaxdyzAfz0tUSf/7
Zro2us99GlARqLWd8EqJcl/xmfcJiZyUam6ZAzzFXCgnH5Y1sdtMTJZdLp5WeOjw
gCWG/ZLu4wzxOFFzDkiPv9RDw6e5MNLtJrSp4hS5o2apKdbO4Ex83O4mJYnav/rE
iDDCWU4T0lhv3hSKCpke6LcwsX+7liozp+aNmP0Ypwfi4hR3UUMP70+V1beFqW2J
bVLz3lLLouHRgpCzla+PzzbEKs16jq77vG9kqZTCIzXoWaLljuitRlfJkO3vQ9hO
v/8yAnkcAmowZrIBlyFg2KBzhunYmN2YvkUAEQEAAYkBJQQYAQIADwUCVLVl/QIb
DAUJAeEzgAAKCRAHfXJeICfMMOHYCACFhInZA9uAM3TC44l+MrgMUJ3rW9izrO48
WrdTsxR8WkSNbIxJoWnYxYuLyPb/shc9k65huw2SSDkj//0fRrI61FPHQNPSvz62
WH+N2lasoUaoJjb2kQGhLOnFbJuevkyBylRz+hI/+8rJKcZOjQkmmK8Hkk8qb5x/
HMUc55H0g2qQAY0BpnJHgOOQ45Q6pk3G2/7Dbek5WJ6K1wUrFy51sNlGWE8pvgEx
/UUZB+dYqCwtvX0nnBu1KNCmk2AkEcFK3YoliCxomdOxhFOv9AKjjojDyC65KJci
Pv2MikPS2fKOAg1R3LpMa8zDEtl4w3vckPQNrQNnYuUtfj6ZoCxv
=XZ8J
-----END PGP PUBLIC KEY BLOCK-----'));
pgp_key_id | 9D4D255F4FD2EFBB
这会显示用来加密ssn列使用的PGP键ID是9D4D255F4FD2EFBB。只要有新密钥被创建,都推荐执行这一步,然后将该ID保存下来用于跟踪。
用户可以使用这个键来查看哪一个密钥对被用来加密数据:
SELECT username, pgp_key_id(ssn) As key_used FROM userssn; username | Bob
key_used | 9D4D255F4FD2EFBB
---------+-----------------
username | Alice
key_used | 9D4D255F4FD2EFBB
注意: 不同的密钥可能具有相同的ID。这很少见,但是一种普通的事件。客户端应用应该尝试用每一个来解密看看哪一个合适——就像处理ANYKEY一样。请见pgcrypto文档中的。
-
如果用户使用口令创建一个密钥,用户可能必须在这里输入口令。不过对于这个例子的目的,口令为空。
加密gpfdist连接
gpfdists协议是gpfdist协议的一个安全版本,它能安全地标识文件服务器和Greenplum数据库并且加密其间的通信。使用gpfdists可以防止窃听和中间人攻击。
gpfdists协议利用下列值得注意的特性实现客户端/服务器的SSL安全性:
- 要求客户端证书。
- 不支持多语言证书。
- 不支持证书撤销列表(CRL)。
- TLSv1协议被用于TLS_RSA_WITH_AES_128_CBC_SHA加密算法。这些SSL参数不能被更改。
- 不支持SSL再协商。
- SSL忽略主机失配参数被设置为false。
- gpfdist服务器(server.key)或Greenplum数据库(client.key)不支持含有口令的私钥。
- 为使用的操作系统颁发合适的证书是用户的责任。通常,支持将证书转换成所要求的格式,例如可使用的SSL转换器。
用--ssl选项启动的gpfdist服务器只能用gpfdists协议通信。没有用--ssl选项启动的gpfdist服务器只能用gpfdist协议通信。更多有关gpfdist的细节请参考Greenplum数据库管理员指南。
有两种方式启用gpfdists协议:
- 用--ssl选项运行gpfdist,然后在CREATE EXTERNAL TABLE语句的LOCATION子句中使用gpfdists协议。
- 在YAML控制文件中将SSL选项设置为真,然后用它来运行gpload。运行的gpload会用--ssl选项启动gpfdist服务器,然后使用gpfdists协议。
在使用gpfdists时,下列客户端证书必须位于每个Segment的$PGDATA/gpfdists目录中:
- 客户端证书文件,client.crt
- 客户端私钥文件,client.key
- 受信证书发布机构,root.crt
重要: 不要用口令保护私钥。服务器不会为私钥提示要求口令,并且数据装载会在要求口令时失败报错。
在使用带SSL的gpload时,用户要在YAML控制文件中指定服务器证书的位置。在使用带SSL的gpfdist时,用户用—ssl选项指定服务器证书的位置。
下面的例子展示了如何安全地装载数据到外部表中。这个例子从所有带txt扩展名的文件使用gpfdists协议创建一个可读外部表ext_expenses。这些文件被格式化为用一个竖线(|)作为列定界符,并且用空格表示空。
- 在Segment主机上用--ssl选项运行gpfdist。
登入数据库并执行下列命令:
=# CREATE EXTERNAL TABLE ext_expenses
( name text, date date, amount float4, category text, desc1 text )
LOCATION ('gpfdists://etlhost-1:8081/*.txt', 'gpfdists://etlhost-2:8082/*.txt')
FORMAT 'TEXT' ( DELIMITER '|' NULL ' ') ;
上级主题: 最佳实践
SHA2算法在版本0.9.8时被加入OpenSSL。对于较老的版本,pgcrypto将使用内建代码。
2 OpenSSL支持的任何摘要算法都会被自动地取用。而加密算法则不能这样,它们需要被明确地支持。
AES从0.9.7开始被包括在OpenSSL中。对于较老的版本,pgcrypto将使用内建代码。