BigQueryの列暗号化で使われる鍵セットのローテーションを試してみる

BigQueryの列暗号化で使われる鍵セットのローテーションを試してみる

Clock Icon2024.09.10

はじめに

データアナリティクス事業本部のkobayashiです。

BigQueryのCloud KMSによる列レベルの暗号化で使う鍵セットのローテーションを試してみたのでまとめます。

https://cloud.google.com/bigquery/docs/column-key-encrypt?hl=ja#rewrap-keyset

Cloud KMSでラップされた鍵セットのローテーション

鍵セットは列レベルの暗号化を行う際に使われるものでCloud KMSキーリング(関連するキーをグループ化するコンテナ)、暗号鍵(実際のデータ暗号化に使用)、および鍵バージョン(同じ暗号鍵の異なるバージョン)で構成されます。
鍵セットは主に以下のような確定的・非確定的暗号化関数で使用します。

https://dev.classmethod.jp/articles/bigquery-encrypt-determin-func/

鍵セットを定期的にローテーションすることでデータセキュリティを強化するたことができ、同じ鍵が長期間使用されることによるリスクを軽減し潜在的な脆弱性や攻撃の可能性を減らしたり、鍵が漏洩した場合でもその影響を特定の期間のデータに限定することができ全体的なデータセキュリティを維持できます。

今回はこの鍵セットのローテーションを以下のSQLで試してみます。
前提条件として暗号化は確定的暗号化関数を使います。

DECLARE SAMPLE_STR STRING DEFAULT '暗号化前の文字列';
DECLARE KMS_KEY STRING DEFAULT 'gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key';
DECLARE KEY_SET BYTES DEFAULT (SELECT KEYS.NEW_WRAPPED_KEYSET(KMS_KEY, 'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, KEY_SET,
                                                                     'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, NEW_KEY_SET,
                                                                         'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));

DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), SAMPLE_STR,
                                                                   ''));
SELECT 'KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_NEW_KEY_SET), ENC_SAMPLE_STR, '');

このSQLを細かく見ていきます。

DECLARE SAMPLE_STR STRING DEFAULT '暗号化前の文字列';
DECLARE KMS_KEY STRING DEFAULT 'gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key';

はじめに暗号化対象の文字列をSAMPLE_STRとして定義しています。また合わせてKMS_KEYも定義しています。

DECLARE KEY_SET BYTES DEFAULT (SELECT KEYS.NEW_WRAPPED_KEYSET(KMS_KEY, 'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, KEY_SET,
                                                                     'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, NEW_KEY_SET,
                                                                         'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));

次に鍵セットを定義しています。確定的暗号化を行っているので鍵セットの型はDETERMINISTIC_AEAD_AES_SIV_CMAC_256を指定しています。KEY_SETで最初のCloud KMS でラップされた鍵セットを作成し、NEW_KEY_SETKEY_SETをローテーションし、更にNEW_NEW_KEY_SETNEW_KEY_SETをローテーションしています。

  • KEY_SET: 最初のCloud KMS でラップされた鍵セット
  • NEW_KEY_SET: KEY_SETをローテーション
  • NEW_NEW_KEY_SET: NEW_KEY_SETをローテーション
DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), SAMPLE_STR,

次に最初に作成した鍵セットKEY_SETを使ってSAMPLE_STRを暗号化してENC_SAMPLE_STRに設定しています。

SELECT 'KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_NEW_KEY_SET), ENC_SAMPLE_STR, '');

最後に暗号化されているENC_SAMPLE_STRKEY_SETNEW_KEY_SETNEW_NEW_KEY_SETで復号化しています。全体を実行すると以下が返ってきてローテーションされた鍵セットでも問題なく復号化できることがわかります。

f0_ f1_
KEY_SET 暗号化前の文字列
NEW_KEY_SET 暗号化前の文字列
NEW_NEW_KEY_SET 暗号化前の文字列

ローテーションする前の鍵セットでの復号化

ではこのSQLのうち暗号化する箇所で一度ローテーションされた鍵セットを使うように変更して実行してみます。

DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), SAMPLE_STR,DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), SAMPLE_STR,
Query error: DETERMINISTIC_DECRYPT_STRING failed: decryption failed; Error in DETERMINISTIC_DECRYPT_STRING (KEYS.KEYSET_CHAIN(\"gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key\", FIRST_LEVEL_KEYSET), b'\\001\\337\\264\\377\\307\\012\\144\\204\\077\\012\\053\\331\\070\\246\\116\\317\\274\\057\\363\\011\\331\\005\\064\\223\\051\\114\\154\\211\\351\\371\\106\\130\\362\\073\\166\\237\\210\\250\\224\\303\\220\\150\\307\\124\\105, ); error in DETERMINISTIC_DECRYPT_STRING expression at [12:5]

当然、ローテーションした鍵セットで暗号化を行っているのでローテーション前の鍵セットでは復号化ができないためエラーとなりました。

ただ当然ローテーションした鍵セットを更にローテーションしても復号化は問題なくできますので以下の様にコメントアウトして実行すれば問題なくクエリの実行は成功します。

BEGIN
    DECLARE SAMPLE_STR STRING DEFAULT '暗号化前の文字列';
    DECLARE KMS_KEY STRING DEFAULT 'gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key';
    DECLARE KEY_SET BYTES DEFAULT (SELECT KEYS.NEW_WRAPPED_KEYSET(KMS_KEY, 'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
    DECLARE NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, KEY_SET,
                                                                         'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
    DECLARE NEW_NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, NEW_KEY_SET,
                                                                             'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));

    DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), SAMPLE_STR,
                                                                       ''));
--     SELECT 'KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), ENC_SAMPLE_STR, '')
--     UNION ALL
    SELECT 'NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), ENC_SAMPLE_STR, '')
    UNION ALL
    SELECT 'NEW_NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_NEW_KEY_SET), ENC_SAMPLE_STR, '');
END;
f0_ f1_
NEW_KEY_SET 暗号化前の文字列
NEW_NEW_KEY_SET 暗号化前の文字列

まとめ

BigQueryのCloud KMSによる列レベルの暗号化で使う鍵セットのローテーションを試してみました。鍵セットの定期的なローテーションはデータセキュリティを強化するための重要な手段になるので、列レベルの暗号化を行った際は適切なローテーション戦略を立てることが重要です。

最後まで読んで頂いてありがとうございました。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.