
# 透明数据加密
透明加密提供表级数据加密存储功能。当用户使用本特性提供的语法创建加密表后，数据库向磁盘写入加密表数据前，会自动将其加密；同时，数据库从磁盘读取加密表数据后，会自动将其解密。向加密表中进行数据插入、更新、查询和删除等操作的语法与非加密表一致。
![](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
- 使用透明加密前需先开启透明加密功能。开启操作请参见《用户指南》中"账号和网络安全 \> GaussDB开启透明加密"章节。
 
#### 查看透明加密基本配置
1. 查看透明加密功能是否已开启 
   enable_tde取值为on时表示开启，取值为off时表示关闭。
   ```
   gaussdb=# SHOW enable_tde;
    enable_tde
   ------------
    on
   (1 row)
   ```
   
   
2. 查看是否已设置访问密钥管理服务的参数 
   tde_key_info参数为空时表示未设置，tde_key_info不为空时表示已设置。
   ```
   gaussdb=# show tde_key_info;
         tde_key_info
   -------------------------
    keyType=...
   ```
   
   
 
#### 操作加密表
1. 创建加密表。 
   创建表时，通过在WITH子句中设置enable_tde=on参数，即可设置该表为加密表。
   数据库默认使用'AES_128_CTR'算法对加密表进行加密，如需使用其他算法，可通过encrypt_algo参数设置。
   ```
   gaussdb=# CREATE TABLE t1 (c1 INT, c2 TEXT) WITH (enable_tde = on);
   CREATE TABLE
   gaussdb=# CREATE TABLE t2 (c1 INT, c2 TEXT) WITH (enable_tde = on, encrypt_algo = 'SM4_CTR');
   CREATE TABLE
   ```
   
   
2. 查看加密表基本信息。 
   加密表基本信息存储在pg_class系统表中的reloptions字段中。其中，dek_cipher为数据密钥密文，由数据库自动生成，并由密钥管理服务加密。每个加密表都有1个独立的数据密钥。
   ```
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 't1';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    t1      | {orientation=row,enable_tde=on,encrypt_algo=AES_128_CTR,compression=no,storage_type=USTORE,key_type=...,dek_cipher=...
   ```
   执行如下语句查询数据库下全部加密表。
   ```
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE reloptions::text LIKE '%enable_tde=on%';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    t1      | {orientation=row,enable_tde=on,encrypt_algo=AES_128_CTR,compression=no,storage_type=USTORE,key_type=...,dek_cipher=...
   ```
   
   
3. 向加密表写入数据。 
   操作加密表与非加密表的语法一致。数据库将表中数据写入磁盘前，才会自动对加密表的数据进行加密。
   ```
   gaussdb=# INSERT INTO t1 VALUES (1, 'tde plain 123');
   INSERT 0 1
   ```
   
   
4. 从加密表查询数据。 
   对于合法用户而言，查询加密表与非加密表的语法一致，加解密操作由数据库自动实现。如果攻击者绕过数据库，直接读取磁盘上加密表对应的数据文件，会发现文件中的数据均已被加密。
   ```
   gaussdb=# SELECT * FROM t1;
    c1 |      c2
   ----+---------------
     1 | tde plain 123
   (1 row)
   ```
   
   
5. 轮转加密表的密钥。 
   为提高安全性，建议定期使用以下语法轮转加密表的数据密钥，即使用新的密钥对数据进行加密。
   ```
   gaussdb=# ALTER TABLE t1 ENCRYPTION KEY ROTATION;
   ALTER TABLE
   ```
   轮转密钥后，数据库仍可以正常解密由旧密钥加密的数据。
   
   
6. 加密表与非加密表转换。 
   透明加密支持将加密表转换为非加密表，以及将非加密表转换为加密表。建议在每次转换后，手动执行VACUUM FULL tablename命令，以同步转换表中所有数据。
   ```
   gaussdb=# CREATE TABLE t3 (c1 INT, c2 TEXT);
   CREATE TABLE
   gaussdb=# ALTER TABLE t3 SET (enable_tde = on);
   ALTER TABLE
   gaussdb=# VACUUM FULL t3;
   VACUUM
   gaussdb=# ALTER TABLE t3 SET (enable_tde = off);
   ALTER TABLE
   gaussdb=# VACUUM FULL t3;
   VACUUM
   ```
   
   
7. 删除加密表。 
   ```
   gaussdb=# DROP TABLE IF EXISTS t1, t2, t3;
   DROP TABLE
   ```
   
   
 
#### 操作加密索引
1. 创建加密表。 
   创建索引的基表，需确保基表也是加密表。
   ```
   gaussdb=# CREATE TABLE t1 (c1 INT, c2 TEXT) WITH (enable_tde = on);
   CREATE TABLE
   ```
   
   
2. 创建加密索引。 
   与创建加密表的方式相同，通过在WITH子句中设置enable_tde=on参数，即将索引设置为加密索引。
   索引与基表使用相同的加密算法和密钥，对基表进行密钥轮转时，索引也会使用新密钥。
   ```
   gaussdb=# CREATE INDEX i1 ON t1(c2) WITH (enable_tde = on);
   CREATE INDEX
   ```
   
   
3. 查看加密索引基本信息。 
   与加密表一样，索引基本信息也存储在pg_class系统表中的reloptions字段中，索引的dek_cipher、encrypt_algo等参数与基表保持一致。
   ```
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 'i1';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    i1      | {orientation=row,enable_tde=on,encrypt_algo=AES_128_CTR,compression=no,storage_type=USTORE,key_type=...,dek_cipher=...
   ```
   
   
4. 加密索引与非加密索引转换。 
   透明加密支持将非加密索引转换为加密索引，将加密索引转换为非加密索引。
   ```
   gaussdb=# CREATE TABLE t2 (c1 INT, c2 TEXT) WITH (enable_tde = on);
   ALTER TABLE
   gaussdb=# CREATE INDEX i2 ON t2(c2);
   CREATE INDEX
   gaussdb=# ALTER INDEX i2 SET (enable_tde = on);
   ALTER INDEX
   gaussdb=# ALTER INDEX i2 SET (enable_tde = off);
   ALTER INDEX
   ```
   
   
5. 自动对索引进行加密。 
   默认情况下，主动设置enable_tde参数才可创建加密索引。当设置GUC参数tde_index_default_encrypt=on，且以加密表为基表创建索引时，数据库会自动将索引转换为加密索引。示例如下：
   ```
   gaussdb=# CREATE TABLE t3 (c1 INT, c2 TEXT) WITH (enable_tde = on);
   ALTER TABLE
   gaussdb=# CREATE INDEX i3 ON t3(c2);
   CREATE INDEX
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 'i3';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    i3      | {orientation=row,enable_tde=on,encrypt_algo=AES_128_CTR,compression=no,storage_type=USTORE,key_type=...,dek_cipher=...
   -- 解释：虽然未指定i3为加密索引，但是开启了tde_index_default_encrypt=on，且基表t3是加密表，数据库自动将i3转换为加密索引
   ```
   
   
6. 删除加密表和索引。 
   ```
   gaussdb=# DROP TABLE IF EXISTS t1, t2, t3;
   DROP TABLE
   ```
   
   
 
#### 支持加密Xlog和undo-log
1. 创建TDE属性的表。 
   ```
   gaussdb=# CREATE TABLE t1 (c1 INT, c2 TEXT) WITH (enable_tde = on);
   CREATE TABLE
   ```
   
   
2. 记录Xlog的写入位置。
   
   ```
   gaussdb=# SELECT pg_xlogfile_name_offset((SELECT pg_current_xlog_location()));
         pg_xlogfile_name_offset
   ------------------------------------
    (00000001000000000000000D,3121400)
   (1 row)
   ```
   
   
3. 操作含TDE属性的表，生成携带数据的Xlog。 
   ```
   gaussdb=# INSERT INTO t1 VALUES (1, 'sssssssssssssssss');
   INSERT 0 1
   ```
   
   
4. 基于[步骤2]获取的Xlog写入位置，执行hexdump命令验证数据在Xlog中已被加密；$DATADIR为实际的数据目录。
   
   ```
   gaussdb=#  \! hexdump -C $DATADIR/pg_xlog/00000001000000000000000D -s 3121400 -n 2048
   002fa0f8  5e 00 00 80 01 00 00 00  00 00 00 00 00 00 00 00  |^...............|
   002fa108  d8 9c 2f 0d 00 00 00 00  e0 16 00 00 00 00 00 00  |../.............|
   002fa118  26 74 d4 9e ff 38 b8 17  00 00 00 00 00 00 d8 0e  |&t...8..........|
   002fa128  00 00 00 00 00 00 52 31  01 00 00 00 00 00 6b 26  |......R1......k&|
   002fa138  06 00 00 00 00 00 7a 33  01 00 00 00 00 00 7b 33  |......z3......{3|
   002fa148  01 00 00 00 00 00 f0 3d  2f 0d 00 00 00 00 00 00  |.......=/.......|
   002fa158  3e 00 00 80 01 00 00 00  ab 33 01 00 00 00 00 00  |>........3......|
   002fa168  f8 a0 2f 0d 00 00 00 00  80 16 00 00 00 00 00 00  |../.............|
   002fa178  14 79 79 89 ff 18 00 00  00 00 00 10 00 00 00 00  |.yy.............|
   002fa188  10 00 00 10 00 00 00 00  00 00 00 00 00 00 00 00  |................|
   002fa198  3e 00 00 80 01 00 00 00  ab 33 01 00 00 00 00 00  |>........3......|
   002fa1a8  58 a1 2f 0d 00 00 00 00  b0 16 00 00 00 00 00 00  |X./.............|
   002fa1b8  6d 09 43 cc ff 18 00 00  00 00 00 10 00 00 00 80  |m.C.............|
   002fa1c8  00 00 00 10 00 00 00 00  00 00 00 00 00 00 00 00  |................|
   002fa1d8  13 02 00 80 01 00 00 00  ab 33 01 00 00 00 00 00  |.........3......|
   002fa1e8  98 a1 2f 0d 00 00 00 00  80 14 00 00 00 00 00 80  |../.............|
   002fa1f8  12 61 3e 44 40 60 1d 00  7f 06 00 00 13 32 00 00  |.a>D@`.......2..|
   002fa208  57 41 00 00 25 94 24 f9  f6 8d 46 50 8a f7 3f 92  |WA..%.$...FP..?.|
   002fa218  98 08 2c 57 a2 fc 16 3d  18 dc 6f 67 9e 8a c8 ba  |..,W...=..og....|
   002fa228  a3 7b 58 3f ba 50 d9 6c  52 d2 91 01 75 a7 a4 d9  |.{X?.P.lR...u...|
   002fa238  05 86 2d b1 10 aa 1c 46  14 7f 00 00 d3 3a 4a 22  |..-....F.....:J"|
   002fa248  e0 55 00 00 7f 06 00 00  09 00 00 01 00 35 a8 44  |.U...........5.D|
   002fa258  00 7f 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
   ```
   
   
5. 删除t1表数据，生成undo-log，判断undo文件已被加密；$DATADIR为实际的数据目录。 
   预期：无法搜索到数据明文
   ```
   gaussdb=# DELETE FROM t1;
   DELETE 1
   gaussdb=# \q
   grep -c 'sssssssssssssssss' $DATADIR/undo/permanent/*
   ```
   
   
6. 删除加密表。 
   ```
   gaussdb=# DROP TABLE IF EXISTS t1;
   DROP TABLE
   ```
   
   
 
#### 开启透明数据异步加密
1. 查看透明数据异步加密功能是否已开启。 
   enable_tde_async_encryption取值为on时表示开启，取值为off时表示关闭。
   ```
   gaussdb=# SHOW enable_tde_async_encryption;
    enable_tde_async_encryption
   -----------------------------
    on
   (1 row)
   ```
   
   
2. 创建多张透明加密表。 
   ```
   gaussdb=# CREATE TABLE t1 (C1 INT, C2 TEXT) WITH (ENABLE_TDE = ON);
   CREATE TABLE
   gaussdb=# CREATE TABLE t2 (C1 INT, C2 TEXT) WITH (ENABLE_TDE = ON, ENCRYPT_ALGO = 'SM4_CTR');
   CREATE TABLE
   ```
   
   
3. 查看加密表基本信息。 
   上一步骤创建的多张加密表使用同一数据密钥，也即异步加密密钥，此处将其标识为\<async_dek1\>。
   ```
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 't1';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    t1      | {enable_tde=on,encrypt_algo=AES_128_CTR,...,dek_cipher=<async_dek1>
   (1 row)
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 't2';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    t2      | {enable_tde=on,encrypt_algo=SM4_CTR,...,dek_cipher=<async_dek1>
   (1 row)
   ```
   
   
4. 轮转表级加密密钥。 
   明确提示enable_tde_async_encryption参数打开时，无法轮转表级数据密钥。
   ```
   gaussdb=# ALTER TABLE t1 ENCRYPTION KEY ROTATION;
   NOTICE:  Unable to rotate key for encrypted table when parameter enable_tde_async_encryption is on.
   ALTER TABLE
   ```
   
   
5. 轮转异步加密密钥。 
   ```
   gaussdb=# ALTER ASYNC ENCRYPTION KEY ROTATION;
   ALTER TDE ROTATE ENCRYPTION KEY
   ```
   
   
6. 创建多张新的加密表，并查看加密表基本信息。 
   新创建的多张加密表使用同一数据密钥，也即轮转后的新异步加密密钥，此处将其标识为\<async_dek2\>；其与步骤2创建加密表密钥不同。
   ```
   gaussdb=# CREATE TABLE t3 (C1 INT, C2 TEXT) WITH (ENABLE_TDE = ON);
   CREATE TABLE
   gaussdb=# CREATE TABLE t4 (C1 INT, C2 TEXT) WITH (ENABLE_TDE = ON, ENCRYPT_ALGO = 'SM4_CTR');
   CREATE TABLE
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 't3';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    t3      | {enable_tde=on,encrypt_algo=AES_128_CTR,...,dek_cipher=<async_dk2>
   (1 row)
   gaussdb=# SELECT relname,reloptions FROM pg_class WHERE relname = 't4';
    relname | reloptions
   ---------+-----------------------------------------------------------------------------------------------------------------------
    t4      | {enable_tde=on,encrypt_algo=SM4_CTR,...,dek_cipher=<async_dk2>
   (1 row)
   ```
   
   
7. 删除全部加密表。 
   ```
   gaussdb=# DROP TABLE t1,t2,t3;
   DROP TABLE
   ```
   
   
 
#### 透明加密加载KAE加速引擎
1. 确保数据库集群各节点已正确安装KAE2版本加速引擎，确保数据库OS用户具备hisec2设备与KAE日志权限。 
   ![](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
   KAE加速引擎的安装与权限配置，可参考[鲲鹏社区](https://www.hikunpeng.com/document/detail/zh/kunpengaccel/encryp-decryp/devg-kae/kunpengaccel_16_0007.html)。
   
   
2. 集群安装前在各节点配置环境变量用于指向OpenSSL KAE引擎动态库安装路径；或在集群完成安装后配置，但必须重启om_monitor进程才可生效。 
   ```
   export OPENSSL_ENGINES=/usr/local/lib/engines-3.0
   ```
   
   
3. 启动数据库 
   查看gs_log日志，有如下日志即表明高斯数据库加载KAE加速引擎成功。
   ```
   Tde has successfully initialized the KAE engine and fetched the SM4 cipher.
   ```
   
   
 
#### 关闭透明加密
将enable_tde参数配置为off，具体设置方式请参考《参考》中"数据库运行参数说明 \> GUC参数说明 \> 安全配置"章节。
![](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
开启透明加密功能后，不建议关闭，关闭可能导致以下问题：
- 无法创建新加密表，旧加密表数据无法解密读取。
- 若已开启日志加密功能，关闭透明加密会造成已加密的redo/undo log回放失败，可能导致集群启动失败或节点状态异常。
- 若备份加密表或加密日志数据，将导致恢复失败。
 
#### 常见问题
- 问题一：客户端回显或日志中提示curl失败，返回错误信息包含"Couldn't resolve host"。 原因：对于tde_key_info中配置的域名，操作系统无法映射到其IP。
  解决：获取所配置IAM或KMS服务的IP地址，随后使用root用户，向/etc/hosts（沙箱环境为/var/chroot/etc/hosts）文件添加域名解析规则即可。
  ```
  echo 'xxx.xxx.xxx.xxx hostname' >> /etc/hosts
  ```
  
- 问题二：客户端回显或日志中错误信息为"failed to find file '$GAUSSHOME/gs_security/tde.key.cipher'"。 原因：KMS场景下，主机或备机节点上未完成对认证敏感信息加密的动作。
  解决：确保全部数据库节点已执行认证敏感信息加密，随后重启数据库。
  
- 问题三：第三方GM0018标准加密库场景，多次尝试执行透明加密相关DDL/DML语句失败，报错为加密机接口调用错误。 原因：加密机客户端so库配置错误；加密机服务端功能异常；节点环境信号量异常。
  解决：联系运维人员进行加密机客户端so库配置与服务端故障排查，节点环境执行ipcs命令确认数据库用户加密机信号量是否被异常清理；排除完成后可尝试重启恢复。
  
 
