概要 #
Cloud KMSは暗号鍵を生成・管理するサービスです。今回はTerraformでKeyRingとENCRYPT_DECRYPT用CryptoKeyを作成します。
重要なのは、KeyRingなどが通常のResourceと同じようには完全削除できない点です。専用の検証Projectで試します。
Terraformの基本操作は前提としています。暗号鍵の管理が初めての方向けです。
Key自体を使った実際の暗号化・復号処理、外部KeyのImportは扱いません。
検証すること #
- Cloud KMSのKeyRingとCryptoKeyを作成できること
- Rotation PeriodとPurposeをTerraformで設定できること
- Google Cloud CLIでKeyとVersionを確認できること
前提環境 #
- Google Cloud CLIとApplication Default Credentials(ADC)
- Terraform 1.5以降
- Cloud KMSを操作できる検証用Google Cloud Project
- 検証時のバージョン:Terraform 1.14.3、google 7.43.0
今回の構成 #
Cloud KMSはVPCに属しません。Projectの下にLocationごとのKeyRingがあり、その中にCryptoKeyが入る階層構造です。利用側はAPIエンドポイント経由でアクセスします。
flowchart TB
Caller["利用側
gcloud / アプリケーション"]
subgraph GCP["Google Cloud"]
subgraph Project["Project"]
subgraph KMS["Cloud KMS"]
subgraph Ring["KeyRing"]
Key["CryptoKey: tf-example-key
ENCRYPT_DECRYPT
GOOGLE_SYMMETRIC_ENCRYPTION"]
Ver["Key Version 1(ENABLED)"]
Key --- Ver
end
end
end
end
Caller -->|"encrypt / decrypt API"| Key
KeyRingはLocationに紐づき、あとから移動できません。またKeyRingとCryptoKeyは削除できないため、Location選びは最初に決める必要があります。
暗号化と復号では、鍵そのものは外に出ません。データをCloud KMSへ送り、処理結果を受け取ります。
sequenceDiagram
actor User as 手元の端末
participant KMS as Cloud KMS
participant Key as CryptoKey (鍵は外に出ない)
User->>KMS: encrypt (平文 16 bytes)
KMS->>Key: 鍵バージョン1で暗号化
KMS-->>User: 暗号文 97 bytes
User->>KMS: decrypt (暗号文)
Note over KMS,Key: 暗号文から鍵バージョンを判別
KMS-->>User: 平文
使用するTerraformコード #
KeyRing #
locals {
key_ring_name = "${var.key_ring_name_prefix}-${var.project_id}"
}
resource "google_kms_key_ring" "example" {
project = var.project_id
name = local.key_ring_name
location = var.location
}
KeyRingはKeyをまとめるContainerです。名前の衝突を避けるためProject IDを付加し、デフォルトLocationはglobalです。
CryptoKey #
resource "google_kms_crypto_key" "example" {
name = var.crypto_key_name
key_ring = google_kms_key_ring.example.id
purpose = "ENCRYPT_DECRYPT"
}
ENCRYPT_DECRYPTは対称暗号化・復号用です。実運用ではRotation Period、次回Rotation日時、IAM、Protection Levelなども設計します。
設定と実行 #
cd Basic-Examples/14-cloud-kms
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform fmt -check
terraform validate
terraform plan
terraform apply
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
crypto_key_name = "tf-example-key"
key_ring_name = "tf-example-keyring-YOUR_PROJECT_ID"
location = "asia-northeast1"
同じProjectで2回目を実行すると、KeyRingが残っているため失敗します。
Error: Error creating KeyRing: googleapi: Error 409: KeyRing already exists.
"reason": "RESOURCE_ALREADY_EXISTS"
後述のとおりKeyRingは削除できません。terraform.tfvarsでkey_ring_name_prefixを変えて再実行します。
GCP側で確認する #
gcloud kms keyrings describe \
"$(terraform output -raw key_ring_name)" \
--location="$(terraform output -raw location)" \
--project="$(terraform output -raw project_id)"
gcloud kms keys describe \
"$(terraform output -raw crypto_key_name)" \
--keyring="$(terraform output -raw key_ring_name)" \
--location="$(terraform output -raw location)" \
--project="$(terraform output -raw project_id)"
name: projects/YOUR_PROJECT_ID/locations/asia-northeast1/keyRings/tf-example-keyring-YOUR_PROJECT_ID/cryptoKeys/tf-example-key
purpose: ENCRYPT_DECRYPT
versionTemplate:
algorithm: GOOGLE_SYMMETRIC_ENCRYPTION
protectionLevel: SOFTWARE
実際に暗号化と復号を試すと、鍵が使える状態かを確認できます。
echo "hello terraform" > sample.txt
gcloud kms encrypt \
--key="$(terraform output -raw crypto_key_name)" \
--keyring="$(terraform output -raw key_ring_name)" \
--location="$(terraform output -raw location)" \
--project="$(terraform output -raw project_id)" \
--plaintext-file=sample.txt \
--ciphertext-file=sample.enc
gcloud kms decrypt \
--key="$(terraform output -raw crypto_key_name)" \
--keyring="$(terraform output -raw key_ring_name)" \
--location="$(terraform output -raw location)" \
--project="$(terraform output -raw project_id)" \
--ciphertext-file=sample.enc \
--plaintext-file=-
hello terraform
元のテキストが戻れば成功です。16バイトの平文が97バイトの暗号文になりました。Cloud KMSの暗号文には鍵のバージョン情報などが含まれるため、平文より大きくなります。
destroy時の重要な注意 #
terraform destroy
Cloud KMSのKeyRingはGoogle Cloudから削除できません。Terraform destroyでStateから外れても、Project側には名前が残ります。CryptoKeyも鍵Materialの即時完全消去とは異なるLifecycleを持ちます。
そのため、このサンプルはdestroyで完全に元の状態へ戻りません。同じProjectで再実行すると名前が衝突する場合は、key_ring_name_prefixを変更します。
検証用Projectを分け、残存Resourceと料金を理解してから実行します。Key Versionの保持や暗号処理には料金が発生します。
まとめ #
- KeyRingとCryptoKeyの階層をTerraformで定義できる
- 対称暗号用に
ENCRYPT_DECRYPTを指定できる - KMSはdestroyしても完全削除されないResourceがある
- Rotation、IAM、削除防止を本番要件として追加検討する
参考資料 #
次回 #
次はCloud MonitoringのAlert PolicyとEmail Notification Channelを作成します。