1. 1 特性背景
  2. 2 实现方案
    1. 2.1 系统表
      1. 1. pg_key_info 密钥信息
      2. 2. pg_key_data 密钥数据
      3. 3. pg_encryption 加密对象
    2. 2.2 定义表
    3. 2.3 定义表加密
    4. 2.4 操作表
    5. 2.5 管理表加密
    6. 2.6 管理主密钥
    7. 2.7 管理数据密钥
    8. 2.8 管理加密定义
    9. 2.8 未来计划
      1. 一、功能补充
      2. 二、语法复用
  3. 3 关键设计
    1. 3.1 格式设计
    2. 3.2 流程设计
      1. 整体流程
      2. 加密粒度
      3. 加密时机
      4. 加密判断
      5. 密钥存储
      6. 解密时机
      7. 解密判断
      8. 密钥来源
    3. 3.3 其他设计
    4. 3.2 主备密钥同步
  4. 4 特性源码
    1. 4.1 功能概览
      1. 基本功能篇
      2. 高级功能篇
      3. 加强篇
    2. 4.2 新增系统表 pg_key_info
    3. 4.2 新增系统表 pg_key_data
    4. 4.3 新增语法 CREATE KEY
    5. 4.4 新增语法 CREATE TABLE .. (protect=$data_key)
    6. 4.5 对加密对象的数据进行加密
  5. 参考

1 特性背景

2 实现方案

2.1 系统表

1. pg_key_info 密钥信息

keyoidkeynametypealrotithmstorageaccessprotectcreate_timeround
1mk_1master_keyanylocalkmspath=./keyfile$pass12024/02/01 13:01:01-
2dk_1date_keyaes_256_cbcdatabasem100.d100.b1.i2mk12024/02/01 13:01:010

2. pg_key_data 密钥数据

oidkeydataalgorithm
3abcd1234aes_256

3. pg_encryption 加密对象

typenameoidspecialprotectoldest_round
tablet1100-dk_11

2.2 定义表

  1. 定义表
    定义表的语法与非加密表一致,我们通过单独的语法定义ENCRYPTION。

    CREATE TABLE t1 (c1 INT, c2 TEXT);
    
  2. 定义索引

    CREATE INDEX i1 ON t1 (c1);
    

2.3 定义表加密

  1. 定义主密钥

    CREATE KEY mk_1 (type=master_key, storage=localkms, access='./keyfile', protect='$pass1');
    
  2. 定义数据密钥

    CREATE KEY dk_1 (type=data_key, protect=mk_1, algorithm=aes_256_cbc);
    
  3. 定义表加密
    表上的索引默认不加密

    CREATE ENCRYPTION (protect=dk_1) ON TABLE t1;
    

CREATE TABLE t1 (c1 INT, c2 TEXT);
CREATE KEY mk_1 (type=master_key, storage=localkms, access=’./keyfile’, protect=’$pass1’);
CREATE KEY dk_1 (type=data_key, protect=mk_1, algorithm=aes_256_cbc);
CREATE ENCRYPTION (protect=dk_1) ON TABLE t1;
SELECT * FROM pg_encryption;

  1. 定义表上索引加密

    CREATE ENCRYPTION (protect=dk_1) ON TABLE t1 WITH (index=on);
    
  2. 定义表上xlog加密

    CREATE ENCRYPTION (protect=dk_1) ON TABLE t1 WITH (index=on, xlog=on);
    
  3. 定义索引加密

    CREATE ENCRYPTION (protect=dk_1) ON INDEX i1;
    

2.4 操作表

  1. 写入数据

    INSERT INTO t1 VALUES (1, 'aaaaa');
    
  2. 查询数据

    SELECT * FROM t1;
    

2.5 管理表加密

  1. 查看表加密

    SELECT * FROM pg_encryption;
    
  2. 修改表加密的密钥

    ALTER ENCRYPTION (protect=dk_2) ON TABLE t1;
    
  3. 删除表加密

    DROP ENCRYPTION ON TABLE t1;
    

2.6 管理主密钥

  1. 查看主密钥信息

    SELECT * FROM pg_key_info WHERE type = 'master_key';
    
  2. 修改主密钥

    ALTER KEY mk_1 SET (access='./keyfile2');
    
  3. 删除主密钥

    DROP KEY mk_1;
    

2.7 管理数据密钥

  1. 查看数据密钥信息

    SELECT * FROM pg_key_info WHERE type = 'data_key';
    
  2. 查看数据密钥密文

    SELECT * FROM pg_key_data;
    
  3. 轮转数据密钥

    ROTATION KEY dk_1;
    
  4. 修改数据密钥

    ALTER KEY dk_1 SET (protect=mk_2);
    
  5. 收集旧版本数据密钥信息

    VACUUM FULL t1;
    
  6. 回收旧版本数据密钥

    VACUUM KEY dk_1;
    
  7. 删除数据密钥

    DROP KEY dk_1;
    

2.8 管理加密定义

  1. 删除加密定义

    DROP ENCRYPTION ON TABLE t1;
    

2.8 未来计划

一、功能补充

  1. 在ENCRYPTION与KEY,KEY与KEY之间,添加DEPENDENCY约束
  2. 为ENCRYPTION和KEY添加ACL,控制访问权限

二、语法复用

  1. 定义列加密
    该种定义可用于全密态数据库

    CREATE ENCRYPTION (protect=dk_1) ON COLUMN t1(c1);
    
  2. 定义表空间加密

    CREATE ENCRYPTION (protect=dk_1) ON TABLESPACE spc1;
    
  3. 定义数据库加密

    CREATE ENCRYPTION (protect=dk_1) ON DATABASE spc1;
    
  4. 定义xlog加密

    CREATE ENCRYPTION (protect=dk_1) ON XLOG;
    

3 关键设计

3.1 格式设计

  • Page格式

    +---------------+
    | PageHeader    | 在Header中,标记Page属于加密表,并标记加密状态
    |               |
    | tuple ..      |
    | tuple 2       |
    | tuple 1       |
    | PageSpecial   | 在Special中,记录密钥信息
    +---------------+
    
  • PageSpecial格式

    typedef struct {
        uint8 version;
        uint8 algo;
        Tid   datakeypos;
        uchar iv[16];
        uchar mac[32];
    } PageEncInfo;
    

3.2 流程设计

整体流程

@user
    create table t1 (.. dk_1)
@user:
    insert into t1 (..abc)
@kernel.postgres:
    heap_insert(t1, 'abc')
    page_init(t1.dk_1, page)
        memcpy(page, get_enc_info(t1.dk_1))
        page_set_flag(page, tde_flag)
    page_add_item(page, 'abc')
@kernel.checkpoint:
    smgrwrite(page)
        if (is_page_set_flag(page, tde_flag))
            page_encrypt_date(page)

加密粒度

加密时机

加密判断

密钥存储

解密时机

解密判断

密钥来源

3.3 其他设计

3.2 主备密钥同步

# 主机
page_init(page, encinfo)
    memcpy(page, encinfo)

4 特性源码

4.1 功能概览

基本功能篇

  1. 新增系统表:pg_key_info
  2. 新增系统表:pg_key_data
  3. 新增语法:CREATE KEY
  4. 新增语法:CREATE TABLE .. (encrypt=xx)
  5. 加密判断与密钥存储
  6. 解密判断与密钥来源

高级功能篇

  1. 索引的加密判断与密钥存储

  2. 加密Redo Log

加强篇

  1. 新增视图

4.2 新增系统表 pg_key_info

  1. 查找oid

    cd $PGCODE/src/include/catalog
    chmod +x ./unused_oids
    ./unused_oids
    

    4001

  2. 新增头文件 pg_key_info.h

    touch pg_key_info.h
    git add ./pg_key_info.h
    
    #ifndef
    
  3. 编译头文件

    cd $PGCODE/src/backend/catalog
    vi Makefile
    
    # add pg_key_info.h
    
  4. 添加缓存 skip now

    cd $PGCODE/src/include/catlog
    vi indexing.h
    
DECLARE_UNIQUE_INDEX(pg_key_info_keyoid, 4002, on pg_key_info using btree(keyoid oid_ops));
#define KeyInfoKeyoidIndexId		4002
  1. 编译、安装、启动

  2. 验证

    SELECT * FROM pg_key_info;
    \d pg_key_info
    

4.2 新增系统表 pg_key_data

流程和方法与新增pg_key_info一致,此处不再赘述

4.3 新增语法 CREATE KEY

  1. 定义主密钥

    CREATE KEY mk_1 (type=master_key, storage=localkms, access='./keyfile', protect='$pass1');
    
  2. 定义数据密钥

    CREATE KEY dk_1 (type=data_key, protect=mk_1, algorithm=aes_256_cbc);
    
  3. 负向用例

    -- 1. 不设置密钥类型
    CREATE KEY key1 (storage=localkms, access='./keyfile', protect='$pass1');
    
    -- 2. 主密钥 重名
    CREATE KEY mk_1 (type=master_key, storage=localkms, access='./keyfile', protect='$pass1');
    
    -- 3. 主密钥 未设置必要参数:storage等
    CREATE KEY mk_2 (type=master_key, access='./keyfile', protect='$pass1');
    
    -- 4. 主密钥 设置不支持的参数:keyoid, unkownpara
    CREATE KEY mk_2 (type=master_key, keyoid=1, torage=localkms, access='./keyfile', protect='$pass1');
    CREATE KEY mk_2 (type=master_key, unkownpara=1, torage=localkms, access='./keyfile', protect='$pass1');
    
    -- 5. 数据密钥 重名
    CREATE KEY dk_1 (type=data_key, protect=mk_1, algorithm=aes_256_cbc);
    
    --6. 数据密钥 对应的主密钥不存在
    CREATE KEY dk_2 (type=data_key, protect=mk_8, algorithm=aes_256_cbc);
    
    --7. 数据密钥 不支持的算法
    CREATE KEY dk_2 (type=data_key, protect=mk_1, algorithm=rsa_2048);
    

4.4 新增语法 CREATE TABLE .. (protect=$data_key)

  1. 创建加密表

    CREATE TABLE t1 (c1 INT, c2 TEXT) WITH (protect=dk_1);
    
  2. 创建加密索引

    CREATE INDEX i1 ON t1 USING btree(c2) WITH (protect=dk_1);
    
  3. 负向用例

    -- 不设置参数
    CREATE TABLE t2 (c1 INT, c2 TEXT) WITH (protect);
    
    -- 不存在的数据密钥
    CREATE TABLE t2 (c1 INT, c2 TEXT) WITH (protect=dk_8);
    
    -- 密钥类型为主密钥
    CREATE TABLE t2 (c1 INT, c2 TEXT) WITH (protect=mk_1);
    

4.5 对加密对象的数据进行加密

参考