加密数据与数据库连接
本文介绍如何对数据库中的静态数据或网络中传输的数据进行加密,以防止被窃听或遭受中间人攻击。
-
客户端与 Coordinator 数据库之间的连接可以通过 SSL 加密。该功能由服务器配置参数
ssl
控制,默认值为off
。将ssl
设置为on
后,客户端与 Coordinator 之间的通信将启用加密。需要提前为 Coordinator 配置 SSL,具体参考 OpenSSL 配置。 -
Apache Cloudberry 支持在
gpfdist
(Cloudberry 并行文件分发服务)与各 Segment 节点之间的网络传输中使用 SSL 加密。参见加密 gpfdist 连接。 -
可以使用
pgcrypto
模块对数据库中静态数据进行加密或解密。列级加密可以保护如社会保障号、信用卡号等敏感信息。参见使用 pgcrypto 加密静态数据。
加密 gpfdist 连接
gpfdists
是 gpfdist
协议的安全版本,可实现文件服务器与 Apache Cloudberry 之间的身份验证,并对双方通信进行加密。使用 gpfdists
可以防止数据被窃听或遭遇中间人攻击。
gpfdists
协议使用客户端/服务端 SSL 安全机制,具备以下关键特性:
- 要求客户端证书;
- 不支持多语言证书;
- 不支持证书吊销列表(CRL);
- 要求最低 TLS 版本为 1.2;
- 支持 SSL 会话重协商;
- 不允许主机名校验忽略(即必须匹配);
- 不支持使用带口令的私钥,适用于
gpfdist
服务器(server.key)及 Apache Cloudberry 客户端(client.key); - 用户需自行根据操作系统环境签发适配的证书。通常可使用 SSL 转换工具(如 https://www.sslshopper.com/ssl-converter.html)进行格式转换。
如果以 --ssl
参数启动 gpfdist
服务器,则只能使用 gpfdists
协议进行通信;若不加 --ssl
参数,则只能使用普通的 gpfdist
协议。有关 gpfdist
的更多信息,参见 gpfdist
。
启用 gpfdists
协议有两种方式:
- 使用
--ssl
参数启动gpfdist
,并在CREATE EXTERNAL TABLE
语句中的LOCATION
子句中指定使用gpfdists
协议; - 使用带有
ssl: true
设置的 YAML 控制文件运行gpload
,此时gpload
会自动以--ssl
参数启动gpfdist
,并使用gpfdists
协议加载数据。
使用 gpfdists
时,每个 Segment 节点的 $PGDATA/gpfdists
目录中必须包含以下客户端证书文件:
- 客户端证书文件:
client.crt
- 客户端私钥文件:
client.key
- 受信任的根证书列表:
root.crt
不要为私钥文件设置口令。服务器不会提示输入口令,如果私钥被加密,数据加载过程会失败并报错。
当使用 gpload
并启用 SSL 时,你需要在 YAML 控制文件中指定服务器证书的位置。若使用 gpfdist
启用 SSL,则通过 --ssl
参数指定服务器证书路径。
下面是一个通过 gpfdists
协议安全加载外部数据表的示例。该示例创建了一个名为 ext_expenses
的可读外部表,读取所有扩展名为 .txt
的文件。使用 gpfdists
协议传输数据,文件以竖线(|
)作为列分隔符,空格代表空值。
-
在所有 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 ' ') ;
使用 pgcrypto 加密静态数据
Apache Cloudberry 提供的 pgcrypto
模块支持在数据库中对静态数据进行加密。管理员可以对含有敏感信息的列(如身份证号、信用卡号等)进行加密,增加数据安全性。加密后的数据只有拥有密钥的用户才能解密读取,即使访问磁盘也无法直接获取原始信息。
pgcrypto
在安装 Apache Cloudberry 时默认包含,但你必须在每个要使用它的数据库中显式启用该模块。
pgcrypto
支持使用 PGP 模式进行对称加密和非对称加密。对称加密使用同一个密钥进行加解密,速度较快,适合密钥交换无障碍的场景。非对称加密使用公钥加密、私钥解密,虽然更安全,但速度较慢,且对密钥强度要求更高。
使用 pgcrypto
需要考虑性能和可维护性开销。建议仅对确需加密的字段启用加密功能。注意,加密后的字段无法通过 索引进行搜索查询。
在实施数据库加密前,应了解以下 PGP 限制:
- 不支持签名功能,意味着不会验证加密子密钥是否归属于 Coordinator 密钥;
- 不支持将加密密钥作为 Coordinator 密钥,但这种做法本就不推荐,因此不构成实际限制;
- 不支持多个子密钥,虽然在常规 PGP 使用中很常见,但不应在
pgcrypto
中使用日常的 GPG/PGP 密钥,建议为此专门生成新的密钥对。
Apache Cloudberry 默认编译时启用了 zlib,因此 PGP 加密函数在加密前可对数据进行压缩。如果使用 OpenSSL 编译,还将支持更多加密算法。
由于 pgcrypto
函数在数据库服务器内部运行,数据与密码会以明文形式在 pgcrypto
与客户端应用之间传输。为了确保安全,建议使用本地连接或启用 SSL,并确保系统管理员与数据库管理员的可信度。
pgcrypto
会根据 PostgreSQL 主配置脚本自动配置自身行为。
启用了 zlib
编译选项后,pgcrypto
可以在加密前压缩数据。
pgcrypto
提供多种从基础到高级的加密功能。下表列出了支持的加密算法:
功能类型 | 内建支持 | OpenSSL 支持 |
---|---|---|
MD5 | 是 | 是 |
SHA1 | 是 | 是 |
SHA224/256/384/512 | 是 | 是 |
其他摘要算法 | 否 | 是 |
Blowfish | 是 | 是 |
AES | 是 | 是 |
DES/3DES/CAST5 | 否 | 是 |
原始加密(Raw Encryption) | 是 | 是 |
PGP 对称密钥加密 | 是 | 是 |
PGP 公钥加密 | 是 | 是 |
创建 PGP 密钥
在 Apache Cloudberry 中使用 PGP 非对称加密前,必须先生成公钥和私钥并完成安装。
本节假设你在 Linux 系统上安装 Apache Cloudberry,并使用 Gnu Privacy Guard(gpg
)命令行工具。请使用最新版的 GPG 来创建密钥。你可以通过以下网址为操作系统下载安装 GPG 工具:https://www.gnupg.org/download/。该网站提供适用于主流 Linux 发行版的安装包,也有适用于 Windows 和 macOS 的安装链接。
-
以 root 身份运行以下命令,并在交互菜单中选择选项 1:
# gpg --gen-key
gpg (GnuPG) 2.0.14; Copyright (C) 2009 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: directory '/root/.gnupg' created
gpg: new configuration file '/root/.gnupg/gpg.conf' created
gpg: WARNING: options in '/root/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring '/root/.gnupg/secring.gpg' created
gpg: keyring '/root/.gnupg/pubring.gpg' created
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? **1** -
根据提示填写信息,按照指引操作,例如:
RSA keys may be between 1024 and 4096 bits long.
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: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
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