TDE (透過的データ暗号化) は、データベースレイヤーでデータを透過的に暗号化します。これにより、権限のないユーザーがデータベースをバイパスして、ストレージレイヤーから機密情報を直接読み取ることを防ぎます。
適用範囲
この機能は、Oracle 構文互換性 2.0 を使用し、マイナーエンジンバージョンが 2.0.14.5.1.1 以降である PolarDB for PostgreSQL (Oracle 互換) クラスターでサポートされています。
マイナーエンジンバージョンは、コンソールで表示するか、SHOW polardb_version; 文を実行して確認できます。マイナーエンジンバージョンが要件を満たしていない場合は、マイナーエンジンバージョンをアップグレードする必要があります。
背景情報
中国では、インターネット上の情報セキュリティを確保するため、サービス開発者は次のようなデータセキュリティ基準に準拠する必要があります:
中華人民共和国暗号法 (2020年1月1日施行)
サイバーセキュリティ等級保護制度 (GB/T 22239-2019)
国際的には、一部の業界にも次のようなデータセキュリティ基準があります:
Payment Card Industry Data Security Standard (PCI DSS)
医療保険の相互運用性と説明責任に関する法律 (HIPAA)
一般データ保護規則 (GDPR)
カリフォルニア州消費者プライバシー法 (CCPA)
サーベンス・オクスリー法 (SOX)
これらのデータセキュリティ要件を満たすために、PolarDB は TDE 機能を提供します。認証されたユーザーは、アプリケーションのコードや構成を変更することなく、データに透過的にアクセスできます。TDE は、OS ユーザーが表領域ファイル内の機密データを読み取ることを防ぎ、悪意のあるユーザーがディスクやバックアップからプレーンテキストデータを読み取ることを防ぎます。
用語集
用語 | 説明 |
キー暗号化キー (KEK) | 別のキーを暗号化するキー。 |
メモリデータ暗号化キー (MDEK) | メモリに保存されるデータ暗号化キー。 |
テーブルデータ暗号化キー (TDEK) | テーブルデータ暗号化キー。HKDF アルゴリズムを使用して MDEK から生成され、メモリに保存され、データの暗号化に使用されます。 |
WAL データ暗号化キー (WDEK) | WAL データ暗号化キー。HKDF アルゴリズムを使用して MDEK から生成され、メモリに保存され、データの暗号化に使用されます。 |
キーのハッシュベースメッセージ認証コード (HMACK) | ハッシュベースのメッセージ認証コードアルゴリズムを使用して生成されたキー。パスフレーズが SHA-512 アルゴリズムで処理された後、KEK と HMACK が生成されます。 |
キー暗号化キーのハッシュベースメッセージ認証コード (KEK_HMAC) | ハッシュベースのメッセージ認証コードアルゴリズムを使用して生成されたキー暗号化キーのダイジェスト。KEK_HMAC は、HMAC アルゴリズムを使用して ENCMDEK と HMACK から生成されます。キーが復元される際の検証情報として使用されます。 |
暗号化されたメモリデータ暗号化キー (ENCMDEK) | メモリに保存される暗号化されたデータ暗号化キー。ENCMDEK は、MDEK を KEK で暗号化することによって生成されます。 |
仕組み
キー管理モジュール
キー構造
TDE は、キー暗号化キー (KEK) とデータ暗号化キーで構成される 2 層のキー構造を使用します。データ暗号化キーはデータベースデータを暗号化し、KEK はデータ暗号化キーを暗号化します。2 つのキーは次のように記述されます:
キー暗号化キー (KEK) とその検証値 (HMACK):システムは
polar_cluster_passphrase_commandパラメーターで指定されたコマンドを実行し、出力の SHA-512 ハッシュを計算して 64 バイトのデータを取得します。最初の 32 バイトが KEK で、最後の 32 バイトが HMACK です。テーブルデータ暗号化キー (TDEK) と WAL データ暗号化キー (WDEK):これらのキーは、暗号技術における安全な乱数ジェネレータによって生成され、データと WAL ログの暗号化に使用される実際のキーです。検証値は HMAC アルゴリズムを使用して生成され、KEK の検証に使用され、共有ストレージに保存されます。
KEK と HMACK は毎回外部ソースから取得されます。たとえば、KMS から取得できます。テスト目的では、
echo passphraseを実行して取得できます。ENCMDEK と KEK_HMAC は共有ストレージに保存する必要があります。これにより、プライマリノードと読み取り専用ノードがファイルを読み取り、次回の起動時に実際のデータ暗号化キーを取得できるようになります。データ構造は次のとおりです:typedef struct KmgrFileData { /* kmgr ファイルのバージョン */ uint32 kmgr_version_no; /* データページは暗号化されているか?暗号化が無効な場合はゼロ */ uint32 data_encryption_cipher; /* * データ暗号化のためのラップされたキー情報。 */ WrappedEncKeyWithHmac tde_rdek; WrappedEncKeyWithHmac tde_wdek; /* 上記すべての CRC... 必ず最後に配置すること! */ pg_crc32c crc; } KmgrFileData;このファイルはデータベース初期化 (initdb) 中に生成されます。これにより、スタンバイノードは
pg_basebackupを使用してファイルを取得できます。クラスターが実行中の場合、TDE 関連の制御情報はプロセスのメモリに保存されます。構造は次のとおりです:
static keydata_t keyEncKey[TDE_KEK_SIZE]; static keydata_t relEncKey[TDE_MAX_DEK_SIZE]; static keydata_t walEncKey[TDE_MAX_DEK_SIZE]; char *polar_cluster_passphrase_command = NULL; extern int data_encryption_cipher;キーの暗号化
キーはデータベースの初期化中に生成されます。プロセスを次の図に示します:

システムは
polar_cluster_passphrase_commandで指定されたコマンドを実行して、32 バイトの KEK と 32 バイトの HMACK を取得します。システムは OpenSSL の乱数生成アルゴリズムを呼び出して MDEK を生成します。
システムは MDEK を使用して OpenSSL の HKDF アルゴリズムを呼び出し、TDEK を生成します。
システムは MDEK を使用して OpenSSL の HKDF アルゴリズムを呼び出し、WDEK を生成します。
システムは KEK を使用して MDEK を暗号化し、ENCMDEK を生成します。
システムは HMAC アルゴリズムを使用して ENCMDEK と HMACK から KEK_HMAC を生成します。KEK_HMAC は、キーが復元される際の検証情報として使用されます。
システムは、ENCMDEK、KEK_HMAC、および
KmgrFileData構造体のその他の情報を global/kmgr ファイルに書き込みます。
キーの復号
データベースがクラッシュまたは再起動した場合、データ暗号化キーは保存されている暗号文から回復する必要があります。プロセスは次のとおりです:

システムは global/kmgr ファイルを読み取り、ENCMDEK と KEK_HMAC を取得します。
システムは
polar_cluster_passphrase_commandで指定されたコマンドを実行して、KEK と HMACK を取得します。システムは HMAC アルゴリズムを使用して ENCMDEK と HMACK から新しい KEK_HMAC (KEK_HMAC') を生成します。次に、KEK_HMAC' を保存されている KEK_HMAC と比較します。それらが同じであれば、プロセスは続行されます。異なる場合は、エラーが返されます。
システムは KEK を使用して ENCMDEK を復号し、MDEK を生成します。
システムは MDEK を使用して OpenSSL の HKDF アルゴリズムを呼び出し、TDEK を生成します。入力情報が特定のものであるため、同じ TDEK が生成されます。
システムは MDEK を使用して OpenSSL の HKDF アルゴリズムを呼び出し、WDEK を生成します。入力情報が特定のものであるため、同じ WDEK が生成されます。
キーローテーション
キーローテーションは、新しい KEK で MDEK を再暗号化し、新しい kmgr ファイルを生成するプロセスです。これには、古い KEK で MDEK を復号し、新しい KEK で再暗号化することが含まれます。プロセスを次の図に示します:

システムは global/kmgr ファイルを読み取り、ENCMDEK と KEK_HMAC を取得します。
polar_cluster_passphrase_commandを実行すると、64 バイトの KEK + HMACK が返されます。システムは HMAC アルゴリズムを使用して ENCMDEK と HMACK から新しい KEK_HMAC (KEK_HMAC') を生成します。次に、KEK_HMAC' を保存されている KEK_HMAC と比較します。それらが同じであれば、プロセスは続行されます。異なる場合は、エラーが返されます。
システムは KEK を使用して ENCMDEK を復号し、MDEK を生成します。
システムは
polar_cluster_passphrase_commandで指定されたコマンドを再度実行して、新しい KEK (new_KEK) と新しい HMACK (new_HMACK) を取得します。システムは new_KEK を使用して MDEK を暗号化し、新しい ENCMDEK (new_ENCMDEK) を生成します。
システムは HMAC アルゴリズムを使用して new_ENCMDEK と new_HMACK から新しい KEK_HMAC (new_KEK_HMAC) を生成します。new_KEK_HMAC は、将来のキー復元の検証情報として使用されます。
システムは、new_ENCMDEK、new_KEK_HMAC、および
KmgrFileData構造体のその他の情報を global/kmgr ファイルに書き込みます。
暗号化モジュール
すべてのユーザーデータは、AES-128 または AES-256 暗号化アルゴリズムを使用してページレベルで暗号化されます。デフォルトでは、AES-256 が使用されます。
(ページ LSN, ページ番号)のペアは、各データページの暗号化の初期化ベクトル (IV) として使用されます。IV は、同じプレーンテキストを複数回暗号化しても異なる暗号文が生成されることを保証します。各ページのヘッダーデータ構造は次のとおりです:
typedef struct PageHeaderData { /* XXX LSN はページ編成されたブロックだけでなく、*あらゆる*ブロックのメンバーです */ PageXLogRecPtr pd_lsn; /* LSN: このページへの最後の変更に対する xlog * レコードの最後のバイトの次のバイト */ uint16 pd_checksum; /* チェックサム */ uint16 pd_flags; /* フラグビット、以下を参照 */ LocationIndex pd_lower; /* 空き領域の開始オフセット */ LocationIndex pd_upper; /* 空き領域の終了オフセット */ LocationIndex pd_special; /* 特殊領域の開始オフセット */ uint16 pd_pagesize_version; TransactionId pd_prune_xid; /* 最も古いプルーニング可能な XID、またはない場合はゼロ */ ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* ラインポインター配列 */ } PageHeaderData;説明ここで:
pd_lsnは、復号に初期化ベクトル (IV) が必要なため、暗号化できません。pd_flagsフィールドには、ページが暗号化されているかどうかを示す0x8000フラグが含まれています。このフラグは暗号化されません。これにより、プレーンテキストページを読み取るための下位互換性が提供され、既存のクラスターで TDE を有効にできます。pd_checksumは暗号化されません。これにより、ページのチェックサムを暗号文に対して検証できます。
暗号化されたファイル
ユーザーデータを含むファイルは暗号化されます。たとえば、データディレクトリの次のサブディレクトリにあるファイルは暗号化されます:
base/global/pg_tblspc/pg_replslot/pg_stat/pg_stat_tmp/
暗号化のタイミング
データはページに編成され、ページレベルで暗号化されます。ページがディスクに書き込まれる前に、そのチェックサムが計算されます。チェックサムが無効になっている場合でも、
PageSetChecksumCopyやPageSetChecksumInplaceなどのチェックサム関連の関数は引き続き呼び出されます。したがって、暗号化プロセスは、記憶媒体上のすべてのユーザーデータが暗号化されることを保証するために、チェックサムが計算される直前に行われます。
復号モジュール
ページがストレージからメモリに読み込まれると、そのチェックサムが検証されます。チェックサムが無効になっている場合でも、
PageIsVerified関数は検証のために引き続き呼び出されます。したがって、復号プロセスは、メモリ内のデータがプレーンテキストであることを保証するために、チェックサムが検証された直後に行われます。