Cloud KMS による列レベルの暗号化

Cloud Key Management Service(Cloud KMS)を使用して鍵を暗号化すると、BigQuery テーブル内の値が暗号化されるようになります。Cloud KMS 鍵セットまたはラップされた鍵セットとともに AEAD 暗号化関数を使用することで、列レベルの第 2 の保護レイヤを追加できます。

はじめに

保護レイヤを追加する目的で、Cloud KMS はデータ暗号鍵(DEK)を 2 番目の鍵暗号鍵(KEK)で暗号化します。BigQuery では、平文の鍵セットではなく暗号化された鍵セットを参照することで、鍵の露呈リスクを軽減できます。KEK は対称暗号化された鍵セットであり、Cloud KMS に安全に保存され、Identity and Access Management(IAM)のロールと権限を使って管理されます。

BigQuery では確定的および非確定的な暗号化関数がサポートされています。確定的暗号化では、保存されているデータと追加の認証データ(省略可)の両方が同一である場合、暗号テキストが同一になります。これにより、暗号化された列に基づく集約と結合が可能になります。非確定的暗号化では、暗号化されたデータに関係なく、保存された暗号テキストが一意になるので、クラスタリング、集約、結合はできません。

クエリの実行時に、KEK の Cloud KMS リソースパスおよびラップされた DEK の暗号テキストを指定します。BigQuery は Cloud KMS を呼び出して DEK をラップ解除し、その鍵を使用してクエリのデータを復号します。ラップ解除された DEK のバージョンは、クエリの期間中にのみメモリに保存され、その後破棄されます。

Cloud External Key Manager がサポートされているリージョンで Cloud KMS をご使用の場合は、Cloud KMS で Cloud EKM ベースの鍵を使用できます。

ユースケース

Cloud KMS 鍵を使用した暗号化のユースケースには、次のようなものがあります。

  • 外部で暗号化されたデータを BigQuery に保存する必要があり、キーセットを平文で保存しないようにする場合。この場合、データをテーブルからエクスポートしたり、SQL クエリで復号したりできます。
  • BigQuery で暗号化データに対する「二重アクセス制御」を行う。ユーザーがクリアテキストでデータを読み取るには、テーブルと暗号鍵の両方に対する権限を付与されている必要があります。
ユーザー権限マトリックス
テーブルに対する権限あり テーブルに対する権限なし
鍵に対する権限あり 暗号化されたデータの読み取りと復号を行う。 アクセス不可。
鍵に対する権限なし 暗号化されたデータの読み取り。 アクセス不可。

ユーザーが KMS 鍵にアクセスする権限を持ち、ラップされたキーセットへのアクセス権がある場合、SQL 関数はキーセットのラップを解除して暗号テキストを復号できます。また、ユーザーは Cloud KMS の REST API または CLI を使用して鍵セットのラップを解除することもできます。
次のクエリの例では、KMS SQL 関数を使用して非確定的暗号テキストを復号します。

SELECT
  AEAD.DECRYPT_STRING(
    KEYS.KEYSET_CHAIN(@kms_resource_name, @first_level_keyset),
    ciphertext,
    additional_authenticated_data)
FROM
  ciphertext_table
WHERE
  ...

ユースケースの例

郵便番号を機密情報と見なす実装を想定します。AEAD 暗号化関数を使用して郵便番号データを BigQuery テーブルに挿入します。こうすることで、Zipcode 列を暗号化できます。この例では、ラップされた鍵セット管理機能がある AEAD.ENCRYPT 関数を使用します。KEYS.KEYSET_CHAIN 関数は KEK を使ってデジタル暗号鍵を暗号化し、AEAD.ENCRYPT 関数は KMS に情報を渡します。

暗号化と復号のための鍵セットチェーンにより、データ暗号鍵(DEK)が KEK で暗号化またはラップされて、その KEK とともに渡されるようになります。ラップされた DEK は、SQL 関数内で復号またはラップ解除され、データの暗号化または復号に使用されます。

AEAD 非確定的関数は、テーブルで実行されるクエリ内の関数を使ってアクセスされるときに、データを復号できます。

画像

AEAD 確定的関数は、テーブルで実行されるクエリ内の関数を使ってアクセスされるときに、データを復号できます。また、暗号化データを使用した集約と結合をサポートしています。

画像

非確定的関数の構文

非確定的関数の使用でサポートされる構文は次のとおりです。

AEAD.ENCRYPT(
  KEYS.KEYSET_CHAIN(kms_resource_name, first_level_keyset),
  plaintext,
  additional_authenticated_data)
AEAD.DECRYPT_STRING(
  KEYS.KEYSET_CHAIN(kms_resource_name, first_level_keyset),
  ciphertext,
  additional_authenticated_data)
AEAD.DECRYPT_BYTES(
  KEYS.KEYSET_CHAIN(kms_resource_name, first_level_keyset),
  ciphertext,
  additional_authenticated_data)

AEAD.DECRYPT_BYTESAEAD.ENCRYPTAEAD.DECRYPT_STRINGKEYS.KEYSET_CHAIN 関数の構文をご覧ください。

確定的な関数の構文

確定的関数の使用でサポートされる構文は次のとおりです。

DETERMINISTIC_ENCRYPT(
  KEYS.KEYSET_CHAIN(kms_resource_name, first_level_keyset),
  plaintext,
  additional_data)
DETERMINISTIC_DECRYPT_STRING(
  KEYS.KEYSET_CHAIN(kms_resource_name, first_level_keyset),
  ciphertext,
  additional_data)
DETERMINISTIC_DECRYPT_BYTES(
  KEYS.KEYSET_CHAIN(kms_resource_name, first_level_keyset),
  ciphertext,
  additional_data)

DETERMINISTIC_DECRYPT_BYTESDETERMINISTIC_ENCRYPTDETERMINISTIC_DECRYPT_STRINGKEYS.KEYSET_CHAIN 関数の構文をご覧ください。

ロールと権限

Cloud KMS のロールのリストについては、Cloud KMS の権限とロールをご覧ください。

制限事項

Cloud KMS による暗号化には次の制限と制約があります。

  • Cloud KMS 鍵は、クエリと同じリージョンまたはマルチリージョンに限定されます。信頼性の理由から、グローバル Cloud KMS 鍵は使用できません。

  • KEYS.ROTATE_KEYSET 関数を使用して、ラップされた鍵セットをローテーションすることはできません。

  • 現在、BigQuery クエリの定数パラメータは診断クエリプランのユーザーに公開されています。これは、KEYSET_CHAIN 関数の kms_resource_name パラメータと first_level_keyset パラメータに影響する可能性があります。鍵は平文では決して公開されません。また、ラップされた鍵セットを復号するには Cloud KMS 鍵に対する権限が必要です。これにより、ユーザーが鍵セットを復号する権限を持っていない限り、診断クエリプランを介してキーが露呈しなくなります。

  • 列ベースの暗号化をタイプベースのセキュリティ分類で使用する場合、次の制限があります。

    • 列レベルのセキュリティ: ユーザーは、アクセスを許可されている列のデータのみを復号または暗号化できます。

    • 行レベルのセキュリティ: ユーザーは、アクセスを許可されている行のデータのみを復号できます。

  • 鍵データを平文テキストで送信する未加工の暗号化関数と比べて、列レベルの SQL 関数はパフォーマンスに大きな影響を与えません。

始める前に

Cloud KMS 鍵、鍵セット、暗号化されたテーブル、確定的関数、非確定的関数を操作するには、あらかじめ次のことを行う必要があります。

  1. Google Cloud プロジェクトを作成します。

  2. BigQuery データセットを作成します。

  3. Cloud KMS キーリングを作成します。

  4. ソフトウェアまたはハードウェア セキュリティ モジュール(HSM)の保護レベルを使用して、暗号化された列のための Cloud KMS 鍵を作成します。

  5. Cloud KMS 鍵、暗号化、復号を処理するユーザー権限を付与します。

これ以降のセクションで参照される、以下の概念にご注意ください。

  • PROJECT_ID: Google Cloud プロジェクトの名前。

  • DATASET_NAME: BigQuery データセットの名前。

  • LOCATION_ID: BigQuery データセットのロケーション。

  • TABLE_NAME: BigQuery テーブルの名前。

  • KEY_RING_ID: Cloud KMS キーリングの名前。

  • KEY_ID: Cloud KMS 鍵の名前。

  • KMS_KEY: 次の形式の Cloud KMS 鍵(KEK):

    'gcp-kms://projects/PROJECT_ID/locations/LOCATION_ID/keyRings/KEY_RING_ID/cryptoKeys/KEY_ID'

    Cloud KMS 鍵の例を次に示します。

    'gcp-kms://projects/myProject/locations/us/keyRings/myKeyRing/cryptoKeys/myKeyName'
    
  • KMS_KEY_SHORT: KMS_KEY に似ていますが、次の形式です。

    projects/PROJECT_ID/locations/LOCATION_ID/keyRings/KEY_RING_ID/cryptoKeys/KEY_ID
  • KEYSET_DECODED: BYTES シーケンスとしてデコードされた鍵セット。出力は、デコードされたラップ済み鍵セットの場合と似ています。

    鍵セット関数は鍵セットをバイトとして返しますが、ユーザー出力はエンコードされた文字列として表示されます。エンコードされた鍵セットをデコードされた鍵セットに変換するには、Cloud KMS 鍵セットのデコードをご覧ください。

  • KEYSET_ENCODED: STRING としてエンコードされた鍵セット。出力は、エンコードされたラップ済み鍵セットの場合と似ています。

    エンコードされた鍵セットをデコードされた鍵セットに変換するには、Cloud KMS 鍵セットのデコードをご覧ください。

  • WRAPPED_KEYSET_DECODED: BYTES シーケンスとしてデコードされたラップ済み鍵セット。出力の例を以下に示します。

    b'\x0a$\x00\xa6\xee\x12Y\x8d|l"\xf7\xfa\xc6\xeafM\xdeefy\xe9\x7f\xf2z\xb3M\
    xf6"\xd0\xe0Le\xa8\x8e\x0fR\xed\x12\xb7\x01\x00\xf0\xa80\xbd\xc1\x07Z\\
    \xd0L<\x80A0\x9ae\xfd(9\x1e\xfa\xc8\x93\xc7\xe8\...'
    

    ラップされた鍵セット関数はラップされた鍵セットをバイトとして返しますが、ユーザー出力はエンコードされた文字列として表示されます。エンコードされたラップ済み鍵セットをデコードされたラップ済み鍵セットに変換するには、Cloud KMS 鍵セットのデコードをご覧ください。

  • WRAPPED_KEYSET_ENCODED: STRING としてエンコードされたラップ済み鍵セット。出力の例を以下に示します。

    'CiQApu4SWTozQ7lNwITxpEvGlo5sT2rv1tyuSv3UAMtoTq/lhDwStwEA8KgwvX7CpVVzhWWMkRw
    WZNr3pf8uBIlzHeunCy8ZsQ6CofQYFpiBRBB6k/QqATbiFV+3opnDk/6dBL/S8OO1WoDC+DdD9
    uzEFwqt5D20lTXCkGWFv1...'
    

    エンコードされたラップ済み鍵セットをデコードされたラップ済み鍵セットに変換するには、Cloud KMS 鍵セットのデコードをご覧ください。

鍵管理

以降のセクションでは、Cloud KMS 鍵で実行できる一般的なタスクについて説明します。

鍵セットを作成する

ラップされた鍵セットまたは未加工の鍵セットを作成できます。それには、次のセクションの手順を行います。

未加工の鍵セットを作成する

次のクエリを実行して、DETERMINISTIC_AEAD_AES_SIV_CMAC_256 型の鍵を持つ鍵セットを作成します。

SELECT KEYS.NEW_KEYSET('DETERMINISTIC_AEAD_AES_SIV_CMAC_256') AS raw_keyset

ラップされた鍵セットを作成する

次のクエリを実行して、DETERMINISTIC_AEAD_AES_SIV_CMAC_256 型の鍵を持つ Cloud KMS でラップされた鍵セットを作成します。

SELECT KEYS.NEW_WRAPPED_KEYSET(
  KMS_KEY,
  'DETERMINISTIC_AEAD_AES_SIV_CMAC_256')

鍵セットをデコードする

鍵セットを返す SQL 関数は BYTES 形式で鍵セットを生成しますが、ユーザーに表示される結果は STRING 形式でエンコードされて表示されます。このエンコードされた文字列をデコードされたバイト シーケンスに変換してリテラル鍵暗号化関数として使用したい場合には、次のクエリを使用します。

ラップされた鍵セットをデコードする

次のクエリを実行して、Cloud KMS でラップされた鍵セットをデコードします。

SELECT FORMAT('%T', FROM_BASE64(WRAPPED_KEYSET_ENCODED'))

未加工の鍵セットをデコードする

次のクエリを実行して未加工の鍵セットをデコードします。

SELECT FORMAT('%T', FROM_BASE64(KEYSET_ENCODED'))

ラップされた鍵セットを再ラップする

次のクエリを実行して、Cloud KMS でラップされた鍵セットを新しい Cloud KMS 鍵で再ラップします。KMS_KEY_CURRENT は、鍵セットの暗号化に使用される新しい KMS_KEY を表します。KMS_KEY_NEW は、鍵セットの暗号化に使用される新しい KMS_KEY を表します。

SELECT KEYS.REWRAP_KEYSET(
  KMS_KEY_CURRENT,
  KMS_KEY_NEW,
  WRAPPED_KEYSET_DECODED)

ラップされた鍵セットをローテーションする

次のクエリを実行して、DETERMINISTIC_AEAD_AES_SIV_CMAC_256 型の鍵を持つ Cloud KMS でラップされた鍵セットをローテーションします。

SELECT KEYS.ROTATE_WRAPPED_KEYSET(
  KMS_KEY,
  WRAPPED_KEYSET_DECODED,
  'DETERMINISTIC_AEAD_AES_SIV_CMAC_256')

ラップされた鍵セットから未加工の鍵セットを生成する

一部の暗号化関数では未加工の鍵セットが必要です。Cloud KMS でラップされた鍵セットを復号して未加工の鍵セットを生成するには、次の手順を完了します。

  1. ラップされた鍵セットを作成します

  2. bq コマンドライン ツールで次のコマンドを入力して、ラップされた鍵セットを keyset_to_unwrap というファイルに保存し、ラップされた鍵セットを復号して、KEYSET_DECODED 形式で出力を生成します。

    echo WRAPPED_KEYSET_ENCODED | base64 -d > /tmp/decoded_wrapped_key
    gcloud kms decrypt \
    --ciphertext-file=/tmp/decoded_wrapped_key \
    --key=KMS_KEY_SHORT \
    --plaintext-file=/tmp/keyset_to_unwrap.dec \
    --project=PROJECT_ID
    od -An --format=o1 /tmp/keyset_to_unwrap.dec | tr ' ' '\'

未加工の鍵セットからラップされた鍵セットを生成する

一部の暗号化関数では、Cloud KMS でラップされた鍵セットが必要です。未加工の鍵セットを暗号化して、ラップされた鍵セットを生成するには、次の手順を完了します。

  1. 未加工の鍵セットを作成します。

  2. bq コマンドライン ツールで次のコマンドを入力して、未加工の鍵セットを keyset_to_wrap というファイルに保存し、未加工の鍵セットを暗号化して、WRAPPED_KEYSET_DECODED 形式で出力を生成します。

    echo KEYSET_ENCODED | base64 -d > /tmp/decoded_key
    gcloud kms encrypt \
    --plaintext-file=/tmp/decoded_key \
    --key=KMS_KEY_SHORT \
    --ciphertext-file=/tmp/keyset_to_wrap.dec \
    --project=PROJECT_ID
    od -An --format=o1 /tmp/keyset_to_wrap.dec | tr ' ' '\'

DLP 関数向けにラップされた鍵を生成する

DLP 関数では、暗号鍵が必要であり、その鍵を使用してラップされた鍵を取得します。

  1. 新しい暗号鍵を生成するには、コマンドラインで次のコマンドを実行します。鍵のサイズは 16、24、32 バイトにできます。次の例では、16 バイトの鍵を使用しています。

    openssl rand 16 > rand.key.16.bin
    
  2. 生成された 16 バイトの鍵を KMS 鍵でラップします。次の例をご覧ください。

    KEYRING=projects/myproject/locations/us/keyRings/kms-test
    KEY=projects/myproject/locations/us/keyRings/kms-test/cryptoKeys/test-Kek
    PROJECT="myproject"
    
    gcloud kms encrypt --project $PROJECT --location us --keyring $KEYRING --key $KEY --plaintext-file ./rand.key.16.bin --ciphertext-file ./rand.key.16.wrapped
    
  3. これで、ラップされた鍵の BYTES リテラル、またはラップされた鍵の base64 形式を取得できます。

    • バイトリテラル

      username:~/tmp$ od -b ./rand.key.16.wrapped | cut -d ' ' -f 2- | head -n -1 | sed  -e 's/^/ /' | tr ' ' '\'
      

      出力は次のようになります。

      \012\044\000\325\155\264\153\246\071\172\130\372\305\103\047\342\356\061\077\014\030\126\147\041\126\150\012\036\020\202\215\044\267\310\331\014\116\233\022\071\000\363\344\230\067\274\007\340\273\016\212\151\226\064\200\377\303\207\103\147\052\267\035\350\004\147\365\251\271\133\062\251\246\152\177\017\005\270\044\141\211\116\337\043\035\263\122\340\110\333\266\220\377\247\204\215\233
      
    • Base64 形式

      username:~/tmp$ base64 ./rand.key.16.wrapped
      

      出力は次のようになります。

      CiQA1W20a6Y5elj6xUMn4u4xPwwYVmchVmgKHhCCjSS3yNkMTpsSOQDz5Jg3vAfguw6KaZY0gP/Dh0NnKrcd6ARn9am5WzKppmp/DwW4JGGJTt8jHbNS4EjbtpD/p4SNmw==
      

鍵セット内の鍵の数を取得する

次のクエリを実行して、未加工の鍵セット内の鍵の数を取得します。

  1. ラップされた鍵セットを操作している場合は、まず未加工の鍵セットを生成してください。

  2. 未加工の鍵セットを使用して次のクエリを実行します。

    SELECT KEYS.KEYSET_LENGTH(KEYSET_DECODED) as key_count;

鍵セットの JSON 表現を取得する

次のクエリを実行して、未加工の鍵セットの JSON 表現を表示します。

  1. ラップされた鍵セットを操作している場合は、まず未加工の鍵セットを生成してください。

  2. 未加工の鍵セットを使用して次のクエリを実行します。

    SELECT KEYS.KEYSET_TO_JSON(KEYSET_DECODED);

暗号化および復号化

未加工の鍵セットまたはラップされた鍵セットを使用して、テーブルの列を暗号化できます。また、列で確定的暗号化または非確定的暗号化を使用するよう選択することもできます。このセクションの例ではラップされた鍵セットを使用しますが、ラップされた鍵セットを未加工の鍵セットに置き換えることができます。

ラップされた鍵セットを使用して列を確定的に暗号化する

次のクエリを実行してテーブルを作成し、確定的暗号化によって Cloud KMS でラップされた鍵セットを encrypted_content という列に保存します。

  1. ラップされた鍵セットを作成します。

  2. ラップされた鍵セットを使用して列を暗号化します。

    CREATE OR REPLACE TABLE DATASET_NAME.TABLE_NAME AS
      SELECT DETERMINISTIC_ENCRYPT(
        KEYS.KEYSET_CHAIN(KMS_KEY, WRAPPED_KEYSET_DECODED),
        'plaintext',
        '') AS encrypted_content

ラップされた鍵セットを使用して列を確定的に復号する

次のクエリを実行し、Cloud KMS でラップされた鍵セットを使用して、暗号化されたコンテンツを含む列を確定的に復号します。このクエリでは、encrypted_content という列のあるテーブルを参照することを前提としています。

SELECT DETERMINISTIC_DECRYPT_STRING(
  KEYS.KEYSET_CHAIN(KMS_KEY, WRAPPED_KEYSET_DECODED),
  encrypted_content,
  '')
FROM DATASET_NAME.TABLE_NAME

ラップされた鍵セットを使用して列を非確定的に暗号化する

ラップされた鍵セットを使用して列を確定的に暗号化するをご覧ください。ただし、DETERMINISTIC_ENCRYPTAEAD.ENCRYPT に置き換えます。鍵セットのタイプが AEAD_AES_GCM_256 であることを確認してください。

ラップされた鍵セットを使用して列を非確定的に復号する

ラップされた鍵セットを使用して列を確定的に復号するをご覧ください。ただし、DETERMINISTIC_DECRYPT_STRINGAEAD.DECRYPT_STRING に置き換えます。鍵セットのタイプが AEAD_AES_GCM_256 であることを確認してください。

次のステップ

  • Cloud KMS の詳細を確認する。このトピックには、Google Cloud の列レベルの暗号化に関する概念情報が含まれています。
  • BigQuery の AEAD 暗号化の詳細を確認する。このトピックでは、特に BigQuery を対象とした列レベルの暗号化の概念を説明します。
  • BigQuery の AEAD 暗号化関数について詳細を確認する。このトピックには、BigQuery で列レベルの暗号化に使用できるすべての SQL 関数が含まれています。