Cloud KMS Keyring & Keys
Keyrings and rotation-enabled crypto keys with per-key IAM for CMEK across GCS, BigQuery, Cloud SQL and disks.
Verification
Plan-validatedPassed: module logic verified on a mocked plan — inputs, validation rules, conditional creation and outputs resolve (no real provider, no cloud).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan: findings disclosed (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-06-28 · how we verify
Documentation
gcp-kms
A Cloud KMS key ring and its crypto keys, with automatic rotation on
by default for symmetric keys and least-privilege per-key IAM for CMEK
across GCS, BigQuery, Cloud SQL, Compute disks, and any other service that
accepts a customer-managed encryption key. Works with Terraform and
OpenTofu (>= 1.6), Google provider >= 7.0, < 8.0.
Status: static-validated, live-test pending. Ships under live-test quarantine — validated with
tofu fmt,tofu validate, andtflint. Real apply → verify → destroy against a GCP project is pending a cloud sandbox. KMS live-testing is special: key rings and keys are not deletable, so a live lane must randomize names and treat "destroy" as versions scheduled for destruction — see the lifecycle note below.
Secure defaults
- Rotation on by default — symmetric
ENCRYPT_DECRYPTkeys rotate every 90 days (7776000s) unless you overriderotation_period. Rotation only applies to symmetric keys; the module auto-nullsrotation_periodfor asymmetric/MAC keys, so their minimal config applies without having to setrotation_period = nullyourself. - Least-privilege per-key IAM — grants are additive
google_kms_crypto_key_iam_memberbindings scoped to a single key, so a CMEK consumer gets exactlycryptoKeyEncrypterDecrypteron the one key it needs, never broad ring-wide access. prevent_destroy = trueon every key — a code-review / plan guard so a key cannot be removed accidentally; operators must consciously lift it.destroy_scheduled_duration(default 30 days) — destroyed key versions sit in a recoverable window before material is irreversibly gone.- Regional location encouraged — keep key material within a jurisdiction;
HSM protection (
protection_level = "HSM", FIPS 140-2 L3) available per key.
Lifecycle caveat (important)
Cloud KMS key rings and crypto keys cannot be deleted. terraform destroy
removes them from state and schedules key versions for destruction; the
ring/key resources persist in GCP permanently. Pick stable names, and in a
live-test context randomize names per run since a name is never reclaimable.
Usage
module "kms" {
source = "./gcp-kms"
project_id = "my-project-123456"
location = "us-central1"
key_ring_name = "app-keyring"
keys = {
"gcs-cmek" = {
purpose = "ENCRYPT_DECRYPT"
rotation_period = "7776000s" # 90 days
iam = {
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
"serviceAccount:[email protected]",
]
}
}
}
}
# Use the key id as CMEK on another resource:
# kms_key_name = module.kms.crypto_key_ids["gcs-cmek"]
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
project_id | string | — | Host project (required) |
location | string | — | KMS location, e.g. us-central1, europe, global (required) |
key_ring_name | string | — | Key ring name — not reclaimable, pick a stable one (required) |
keys | map(object) | — | Keyed crypto keys: { purpose, rotation_period, algorithm, protection_level, destroy_scheduled_duration, labels, iam } (required) |
labels | map(string) | {} | Default labels merged onto every key |
Per-key fields: purpose (ENCRYPT_DECRYPT default), rotation_period
(7776000s; set null for non-symmetric), algorithm
(GOOGLE_SYMMETRIC_ENCRYPTION default), protection_level (SOFTWARE default,
or HSM), destroy_scheduled_duration (2592000s), labels, and iam
({ role => [members] }).
Outputs
key_ring_id, key_ring_name, crypto_key_ids, crypto_key_names,
crypto_keys.
Requirements
- Terraform or OpenTofu
>= 1.6 hashicorp/google>= 7.0, < 8.0
License
Commercial — LicenseRef-IaCBazaar-Commercial.