GCPのSecret Manager・Cloud KMS・CMEKの違い

GCPのセキュリティを学ぶとき、Secret ManagerCloud KMSCMEK が混ざりやすくなります。

どれも「秘密っぽいもの」や「鍵」に関係しますが、役割は違います。Secret Managerはアプリが読む秘密値を保管するサービスCloud KMSは暗号鍵を管理して暗号処理に使うサービスCMEKはGCPサービスの保存時暗号化にCloud KMSの鍵を使う方式です。

本記事では、APIキー、暗号鍵、CMEK設定、鍵リソース、鍵材料を分けて整理します。

まず結論

最初は以下で押さえると分かりやすいです。

用語何か典型例
Secret Managerアプリが読む秘密値の保管庫APIキー、DBパスワード、Webhook secret
Cloud KMS暗号鍵を管理し、鍵を使った暗号処理を提供するサービス暗号化、復号、署名、鍵ローテーション
CMEKGCPサービスの保存時暗号化に、Cloud KMS上の顧客管理鍵を使う方式Cloud SQL、GCS、BigQueryにKMS鍵を指定
判断軸
  • .env に入れそうな値を安全に置きたい → Secret Manager
  • 暗号化に使う鍵を管理したい → Cloud KMS
  • Cloud SQL / GCS / BigQuery などの保存時暗号化に自分のKMS鍵を使いたい → CMEK

Secret Managerは秘密値を保管する

Secret Managerは、アプリケーションが実行時に読む秘密値を保管するサービスです。

たとえば以下のような値です。

DATABASE_PASSWORD=xxxxx
STRIPE_SECRET_KEY=sk_live_xxxxx
OPENAI_API_KEY=xxxxx
WEBHOOK_SECRET=xxxxx

これらはアプリが値そのものを取り出して使います。たとえば、アプリがSecret ManagerからAPIキーを読み、その値を外部API呼び出しに使います。

つまりSecret Managerで保管するのは、アプリが知る必要のある秘密の文字列です。

Cloud KMSは暗号鍵を管理する

Cloud KMSは、暗号鍵を作成・保管・ローテーションし、その鍵を使った暗号処理を提供するサービスです。

ここで重要なのは、Cloud KMSの鍵は基本的に外へ取り出して使うものではないことです。アプリは鍵の中身を受け取るのではなく、Cloud KMSに処理を依頼します。

暗号化では、アプリがCloud KMSに「このデータを暗号化して」と依頼し、Cloud KMSが内部の鍵で暗号化して、暗号文を返します。

復号では、アプリがCloud KMSに「この暗号文を復号して」と依頼し、Cloud KMSが内部の鍵で復号して、平文を返します。

Cloud KMSは「鍵管理サービス」ですが、単に鍵を保管するだけではありません。鍵を外に出さずに、暗号化・復号・署名・検証などの処理も提供します。

鍵リソースと鍵材料は違う

Cloud KMSで混乱しやすいのは、「鍵」という言葉に2つのレベルがあることです。

種類ユーザーが見えるか
鍵リソース見えるprojects/prod/locations/asia-northeast1/keyRings/db/cryptoKeys/prod-db-key
鍵材料基本的に見えない実際の暗号鍵のビット列

ユーザーは、Cloud KMS上にどの鍵リソースがあるかを知っています。CMEK設定でも、この鍵リソースを指定します。

一方で、その鍵リソースの中身である鍵材料は通常見ません。アプリやユーザーが鍵材料を手元にコピーして使うのではなく、Cloud KMSが内部で使います。

Cloud KMSの階層は、おおまかに以下です。

Project
  └─ Location
      └─ KeyRing
          └─ CryptoKey
              ├─ Version 1
              ├─ Version 2
              └─ Version 3

CryptoKey がCMEK設定で指定する鍵リソースです。ローテーションすると、その中に新しい CryptoKeyVersion が作られます。

CMEKはCloud KMS鍵を保存時暗号化に使う方式

CMEKは、Customer-Managed Encryption Key の略です。

これはCloud KMSそのものではなく、GCPサービスの保存時暗号化に、Google管理鍵ではなく顧客管理のCloud KMS鍵を使う方式です。

方式鍵の扱い
通常Cloud SQL / Cloud Storage / BigQuery などがGoogle管理の鍵で保存時暗号化する
CMEKCloud SQL / Cloud Storage / BigQuery などがCloud KMS上の自分管理の鍵で保存時暗号化する

Cloud SQLを例にすると、作成時や設定時に暗号化キーを指定します。

Encryption
  ○ Google-managed encryption
  ● Customer-managed encryption key
      KMS key: projects/.../cryptoKeys/prod-db-key

この「Cloud SQLにこのCloud KMS鍵を使わせる設定」がCMEKです。

CMEKで実際に起きていること

CMEKを使うと、Cloud SQLやBigQueryが巨大なデータ本体を毎回Cloud KMSへ送って暗号化する、というより、内部的には鍵を階層化して守ります。

この節では同じ仕組みを2段階の図で説明します。まず全体像をつかむための簡易図、次にその内部を鍵の階層まで分解した詳細図です。

簡易図で見ると、CMEKは「このGCPリソースの保存時暗号化に、このCloud KMS鍵を使う」という設定です。

flowchart LR
  subgraph service["GCPサービス側(Cloud SQL / GCS / BigQuery)"]
    resource["保存対象のリソース"]
    cmek["CMEK設定<br/>このKMS鍵を使う"]
    encrypted["暗号化済みデータ<br/>暗号文として保存"]
  end

  subgraph kms["Cloud KMS"]
    key["鍵リソース"]
  end

  resource -->|"保存時暗号化"| encrypted
  resource -->|"参照する設定"| cmek
  cmek -->|"指定された鍵"| key
  key -->|"鍵を外に出さずに暗号処理へ使う"| encrypted

簡易図では、Cloud KMSの鍵の働きを「鍵を外に出さずに暗号処理へ使う」という1本の矢印にまとめました。しかし実際には、この矢印の内側で鍵が2層に分かれています。この階層を理解するために、次の2つの用語を押さえます。

用語役割
DEKData Encryption Key。実データを暗号化する鍵
KEKKey Encryption Key。DEKを暗号化する鍵

この2つの鍵は、次のように使われます。

  • 実データはDEKで暗号化され、暗号化済みデータとしてサービス側に保存される
  • DEKはKEK(Cloud KMSの鍵)で暗号化され、暗号化済みDEKとしてサービス側に保存される

この関係を表したのが以下の詳細図です。「GCPサービス側」「Cloud KMS」という枠は簡易図と同じで、簡易図で1本の矢印にまとめていた部分が、DEKとKEKの2層に分解されています。簡易図でCloud KMSの枠内にあった「鍵リソース」が、詳細図ではKEK(CMEKで指定した鍵)にあたります。

ここで場所の区別が重要です。Cloud KMSの中にあるのはKEKだけです。DEKはGCPサービス側でデータのそばで使われ、KEKで暗号化した状態(暗号化済みDEK)でサービス側に保存されます。Cloud KMSへ渡すのはDEKであってデータ本体ではないため、冒頭で述べたとおり「巨大なデータを毎回KMSへ送る」ことにはなりません。

flowchart TB
  subgraph service["GCPサービス側(Cloud SQL / GCS / BigQuery)"]
    data["データ"]
    dek["DEK<br/>データ暗号化鍵"]
    encryptedData["暗号化済みデータ"]
    wrappedDek["暗号化済みDEK"]
  end

  subgraph kms["Cloud KMS"]
    kek["KEK(Cloud KMS鍵)<br/>CMEKで指定した鍵リソース"]
  end

  dek -->|"データを暗号化"| encryptedData
  data --> encryptedData
  dek -->|"暗号化を依頼"| kek
  kek -->|"KEKで包んで返す<br/>鍵材料は外に出さない"| wrappedDek

つまり、CMEKでユーザーが管理するのはKEKにあたるCloud KMS側の鍵リソースです。個々のデータを暗号化するDEKは、GCPサービスが内部で扱うため、ユーザーが直接管理するわけではありません。

ローテーションは鍵バージョンを切り替えること

Cloud KMSのローテーションは、同じ CryptoKey の中に新しい CryptoKeyVersion を作り、今後の暗号化に使うprimary versionを切り替えることです。

ローテーション前:
prod-db-key
  version 1 ← primary

ローテーション後:
prod-db-key
  version 1
  version 2 ← primary

新しく暗号化するデータには新しいprimary versionが使われます。一方で、過去に暗号化したデータを復号するために、古いversionは必要に応じて残ります。

そのため、ローテーションは「古い鍵を即座に捨てる」ではなく、新しい暗号化に使う鍵バージョンを切り替えると見ると分かりやすいです。

Google-managed key・CMEK・CSEK・Cloud EKM

GCPの暗号鍵まわりでは、CMEK以外にも似た用語が出てきます。

用語ざっくり鍵の管理
Google-managed encryption keyデフォルトの保存時暗号化Googleが管理
CMEKCloud KMS上の顧客管理鍵をGCPサービスに使わせるユーザーがCloud KMSで管理
CSEKユーザーが鍵材料をリクエスト時に渡すユーザーが鍵材料を管理
Cloud EKMGoogle Cloud外部のKMS/HSMに鍵を置く外部鍵管理システムで管理
PCAでの判断
  • 標準の保存時暗号化でよい → Google-managed encryption key
  • 顧客管理鍵、ローテーション、無効化、監査、規制対応 → CMEK / Cloud KMS
  • 鍵をGoogle Cloud外に置きたい → Cloud EKM

CSEKは、自分で鍵材料を渡す方式です。運用負荷が高く、まずはCMEKを基本として考えるほうが分かりやすいです。

Secret ManagerとCloud KMSは代替関係ではない

Secret ManagerとCloud KMSは代替関係ではありません

サービス役割
Secret Managerアプリが読む秘密値を保管する
Cloud KMS暗号化に使う鍵を管理し、鍵を使った暗号処理を提供する

たとえば、アプリがDBパスワードを読むならSecret Managerです。Cloud RunがSecret ManagerからDBパスワードを読み、その値を使ってCloud SQLへ接続します。

一方で、Cloud SQLの保存データを顧客管理鍵で暗号化したいならCloud KMS / CMEKです。Cloud SQLのCMEK設定でCloud KMS鍵を指定し、保存時暗号化にその鍵を使います。

まとめ

  • Secret Managerは、APIキーやDBパスワードなどアプリが読む秘密値を保管する
  • Cloud KMSは、暗号鍵を管理し、暗号化・復号・署名などの処理を提供する
  • Cloud KMSの鍵は、鍵リソース名は見えるが、鍵材料は通常見えない
  • CMEKは、GCPサービスの保存時暗号化にCloud KMS上の顧客管理鍵を使う方式
  • ローテーションは、同じCryptoKey内で新しいkey versionをprimaryにすること
  • 標準でよいならGoogle-managed key、顧客管理鍵が必要ならCMEK、外部鍵管理が必要ならCloud EKMを検討する

参考

タグ: GCP, クラウド設計, セキュリティ