Cryptographic Keys Should Be Rotated
More Info:
Rotate cryptographic keys on a regular schedule. Thus, key rotation should be enabled on all cryptographic keys. Google will handle the rotation of the encryption key itself, so previous data does not need to be re-encrypted before the rotation occurs.
Risk Level
Medium
Address
Operational Maturity, Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- GDPR
- ISO 27001
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Using Console
Below are step‑by‑step console instructions to properly configure and remediate cryptographic key issues for GCP Compute Engine using Cloud KMS (CMEK). This covers the most common misconfigurations: using default Google‑managed keys only, not rotating keys, and incorrect IAM on keys.
1. Create or Verify a Cloud KMS Key (CMEK)
- In the Google Cloud Console, go to:
Security → Key Management (or search “Key Management”). - Ensure you’re in the correct project (top nav).
- Click Create key ring:
- Name: e.g.
compute-keyring - Location type: usually Regional
- Location: choose the same region as your Compute Engine resources.
- Click Create.
- Name: e.g.
- On the new key ring, click Create key:
- Name: e.g.
compute-disk-key - Protection level: Software (or HSM if required by policy).
- Purpose: Symmetric encryption/decryption.
- Rotation period: set per your policy (e.g.
90 days) and enable automated rotation. - Click Create.
- Name: e.g.
2. Grant Compute Engine Permission to Use the Key
You must allow the Compute Engine service account to use the key.
- Identify the service account:
- For project‑wide default, it’s usually:
PROJECT_NUMBER-compute@developer.gserviceaccount.com - To confirm, go to IAM & Admin → Service Accounts and find:
- “Compute Engine default service account” or
- The custom service account attached to your VM(s).
- For project‑wide default, it’s usually:
- In the console, go to Security → Key Management → Key rings.
- Click the key ring, then click your key (e.g.
compute-disk-key). - Go to the Permissions tab.
- Click Grant access:
- New principals: add the Compute service account from step 1.
- Role:
- Prefer fine‑grained: Cloud KMS CryptoKey Encrypter/Decrypter
(or at minimum what your policy requires).
- Prefer fine‑grained: Cloud KMS CryptoKey Encrypter/Decrypter
- Click Save.
3. Use CMEK for New Disks / New VMs
You cannot change the encryption key of an existing disk in place; you must create a new disk or snapshot+disk using the CMEK.
3.1 New VM with CMEK‑encrypted boot disk
- Go to Compute Engine → VM instances.
- Click Create instance.
- Under Boot disk, click Change.
- Select your image as usual.
- Expand the Advanced options or Encryption section.
- Select Customer‑managed key (CMEK).
- Click Browse and select your key:
- Choose the correct Key ring and Key created earlier.
- Click Select (for the disk), then Create (for the VM).
3.2 New additional data disk with CMEK
- While creating or editing a VM, under Additional disks, click Add new disk.
- Configure disk type/size.
- Expand Encryption options.
- Choose Customer‑managed key (CMEK) and select your KMS key.
- Save and create/update the VM.
4. Migrate Existing Disks to CMEK
To remediate existing disks not using CMEK:
4.1 Using snapshots
- Go to Compute Engine → Disks.
- Select the disk you want to remediate.
- Click Create snapshot:
- Name the snapshot (e.g.
disk1-snap-cmek-migrate). - Encryption:
- Choose Customer‑managed key (CMEK).
- Select your KMS key.
- Click Create.
- Name the snapshot (e.g.
- After snapshot is ready, go to Compute Engine → Disks → Create disk:
- Source type: Snapshot.
- Source snapshot: select the snapshot you just created.
- Under Encryption, choose Customer‑managed key (CMEK) and select the same key.
- Click Create.
- Stop the VM that used the original disk.
- Detach the old disk and attach the new CMEK‑encrypted disk:
- VM details → Edit → detach old disk, add existing disk (the new CMEK disk).
- Start the VM and verify it functions correctly.
- Once confirmed, delete the old, non‑CMEK disk if no longer needed.
5. Fix Key Rotation and Lifecycle
If the misconfiguration is about non‑rotating or long‑lived keys:
- Go to Security → Key Management.
- Click your key.
- Under Rotation schedule:
- Ensure Automatic rotation is enabled.
- Set a rotation period that complies with policy (e.g. 30–90 days).
- If you need a new primary key version immediately:
- On the Versions tab, click Add new version.
- (Optional) After validation, Disable or Destroy older key versions according to your retention policy.
Note: Disks already encrypted with a CMEK will automatically use the primary key version; using rotation does not require re‑creating disks.
6. Tighten IAM on Keys
To remediate over‑permissive KMS IAM:
- Go to Security → Key Management → Key rings → [your key] → Permissions.
- Remove broad roles from wide groups/principals:
- Avoid
roles/owner,roles/editor, orroles/cloudkms.adminfor large groups.
- Avoid
- Only keep:
- Service accounts that need
Encrypter/Decrypterto read/write disks. - Limited admins for
Cloud KMS Adminif required.
- Service accounts that need
- Click Save.
7. Validate the Remediation
- For each VM:
- Go to Compute Engine → VM instances → [VM].
- Under Boot disk / Additional disks, check Encryption shows your CMEK key.
- For the KMS key:
- Confirm Rotation is enabled.
- Confirm IAM is appropriately restricted.
- Optionally, run Security Command Center or Policy Scanner (if in use) to confirm findings about “cryptographic keys” are cleared.
If you tell me your specific “cryptographic keys” finding text (from SCC, Forseti, or another tool), I can tailor these steps exactly to that control.
Using CLI
Below is a practical, step‑by‑step way to remediate common “Cryptographic Keys” misconfigurations for GCP Compute Engine using the gcloud CLI, focused on moving from default Google‑managed encryption to Cloud KMS CMEK and tightening key controls.
If your specific finding text is different (e.g., about service account keys or SSH keys), tell me the exact finding and I’ll adapt.
1. Prerequisites
# Set your project
gcloud config set project PROJECT_ID
# Enable required APIs
gcloud services enable \
compute.googleapis.com \
cloudkms.googleapis.com
You’ll need an IAM identity with (at least):
roles/ownerorroles/compute.admin+roles/cloudkms.admin+roles/cloudkms.cryptoKeyEncrypterDecrypter
2. Create a KMS Key Ring and Crypto Key
# Variables
LOCATION="us-central1" # or your region
KEYRING="compute-cekm-keyring"
KEY_NAME="compute-default-key"
# Create key ring
gcloud kms keyrings create "$KEYRING" \
--location="$LOCATION"
# Create symmetric crypto key
gcloud kms keys create "$KEY_NAME" \
--location="$LOCATION" \
--keyring="$KEYRING" \
--purpose="encryption" \
--protection-level="software" # or hsm if needed
3. Grant Compute Engine Access to the Key
Identify the Compute Engine service agents (at project level):
PROJECT_NUMBER=$(gcloud projects describe "$(gcloud config get-value project)" --format="value(projectNumber)")
COMPUTE_SA="service-$PROJECT_NUMBER@compute-system.iam.gserviceaccount.com"
Grant it cryptoKeyEncrypterDecrypter:
gcloud kms keys add-iam-policy-binding "$KEY_NAME" \
--keyring="$KEYRING" \
--location="$LOCATION" \
--member="serviceAccount:$COMPUTE_SA" \
--role="roles/cloudkms.cryptoKeyEncrypterDecrypter"
If you use a custom service account for VMs, also grant that account:
CUSTOM_SA="my-vm-sa@PROJECT_ID.iam.gserviceaccount.com"
gcloud kms keys add-iam-policy-binding "$KEY_NAME" \
--keyring="$KEYRING" \
--location="$LOCATION" \
--member="serviceAccount:$CUSTOM_SA" \
--role="roles/cloudkms.cryptoKeyEncrypterDecrypter"
4. Create New Disks/VMs Encrypted with CMEK
4.1 New Disk with CMEK
DISK_NAME="my-disk-cmek"
ZONE="us-central1-a"
gcloud compute disks create "$DISK_NAME" \
--zone="$ZONE" \
--size=100GB \
--type=pd-balanced \
--csek-key-file="" \
--kms-key=projects/$(gcloud config get-value project)/locations/$LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME
4.2 New VM with CMEK Root Disk
VM_NAME="vm-cmek"
gcloud compute instances create "$VM_NAME" \
--zone="$ZONE" \
--machine-type=e2-medium \
--boot-disk-size=50GB \
--boot-disk-type=pd-balanced \
--boot-disk-kms-key=projects/$(gcloud config get-value project)/locations/$LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME
5. Migrate Existing Disks to CMEK
You can’t flip an existing disk’s key in place; you must recreate it from a snapshot or image using CMEK.
5.1 Snapshot the Existing Disk
EXISTING_DISK="old-disk"
ZONE="us-central1-a"
SNAPSHOT_NAME="${EXISTING_DISK}-snapshot"
gcloud compute disks snapshot "$EXISTING_DISK" \
--zone="$ZONE" \
--snapshot-names="$SNAPSHOT_NAME"
5.2 Create a New Disk from Snapshot Using CMEK
NEW_DISK="${EXISTING_DISK}-cmek"
gcloud compute disks create "$NEW_DISK" \
--zone="$ZONE" \
--source-snapshot="$SNAPSHOT_NAME" \
--kms-key=projects/$(gcloud config get-value project)/locations/$LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME
5.3 Attach New Disk / Replace Boot Disk
For data disks, detach the old one and attach the new:
VM_NAME="my-vm"
# Detach old disk
gcloud compute instances detach-disk "$VM_NAME" \
--zone="$ZONE" \
--disk="$EXISTING_DISK"
# Attach new disk
gcloud compute instances attach-disk "$VM_NAME" \
--zone="$ZONE" \
--disk="$NEW_DISK"
For boot disks, safest route is:
- Stop VM.
- Create an image from the existing boot disk.
- Create a new VM from that image with
--boot-disk-kms-key=.... - Re‑apply network/metadata settings and delete the old VM.
Example:
BOOT_DISK="vm-boot-disk"
IMAGE_NAME="vm-boot-image"
# Create image from existing boot disk
gcloud compute images create "$IMAGE_NAME" \
--source-disk="$BOOT_DISK" \
--source-disk-zone="$ZONE"
# Create new VM with CMEK boot disk
NEW_VM="vm-cmek-boot"
gcloud compute instances create "$NEW_VM" \
--zone="$ZONE" \
--source-machine-image="" \
--image="$IMAGE_NAME" \
--boot-disk-kms-key=projects/$(gcloud config get-value project)/locations/$LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME
Then migrate traffic and delete the old instance.
6. Enforce Key Rotation
Set rotation period and next rotation time:
gcloud kms keys update "$KEY_NAME" \
--location="$LOCATION" \
--keyring="$KEYRING" \
--rotation-period="90d" \
--next-rotation-time="$(date -u -d '90 days' +%Y-%m-%dT%H:%M:%SZ)"
KMS handles key versions; CMEK resources continue to work with new versions automatically.
7. Harden KMS IAM
Review and remove overly broad access:
gcloud kms keys get-iam-policy "$KEY_NAME" \
--location="$LOCATION" \
--keyring="$KEYRING"
Remove any allUsers, allAuthenticatedUsers, or unnecessary roles, and keep to:
roles/cloudkms.cryptoKeyEncrypterDecrypterfor only required service accounts.roles/cloudkms.adminfor a small admin group.
Update via:
gcloud kms keys set-iam-policy "$KEY_NAME" \
--location="$LOCATION" \
--keyring="$KEYRING" \
policy.json
(where policy.json is your edited IAM policy).
If you can paste the exact “Cryptographic Keys” finding text (e.g., from Security Command Center or CIS benchmark), I’ll tailor these commands exactly to that control (disks, snapshots, images, etc.).
Using Python
Below is a concise, step‑by‑step approach to remediate cryptographic key misconfigurations for Google Compute Engine (GCE) using Python, focusing on:
- Moving from Google‑managed to customer‑managed encryption keys (CMEK)
- Correct IAM permissions on keys
- Enforcing proper key rotation and usage
1. Identify Where CMEK Should Be Used
Common targets:
- Boot disks and data disks on VM instances
- Images and snapshots
Check which disks are unencrypted with CMEK (i.e., currently using Google‑managed keys):
gcloud compute disks list --format="table(name,zone,kind,sourceImage,sourceSnapshot,location,users,encryptionKey)"
Any disk equal to Google managed in encryptionKey is a remediation target.
2. Set Up KMS for CMEK
2.1. Enable APIs (one time)
gcloud services enable \
cloudkms.googleapis.com \
compute.googleapis.com
2.2. Create a Key Ring and Crypto Key
Using Python (Cloud KMS client):
from google.cloud import kms_v1
project_id = "YOUR_PROJECT_ID"
location_id = "us-central1" # match/near your compute region
key_ring_id = "compute-keyring"
crypto_key_id = "compute-disk-key"
client = kms_v1.KeyManagementServiceClient()
parent = f"projects/{project_id}/locations/{location_id}"
# Create key ring
key_ring_name = client.key_ring_path(project_id, location_id, key_ring_id)
try:
client.get_key_ring(request={"name": key_ring_name})
except Exception:
client.create_key_ring(
request={"parent": parent, "key_ring_id": key_ring_id, "key_ring": {}}
)
# Create crypto key with rotation
crypto_key_name = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id)
from google.protobuf import duration_pb2, timestamp_pb2
import datetime
rotation_period = duration_pb2.Duration(seconds=60 * 60 * 24 * 30) # 30 days
next_rotation = timestamp_pb2.Timestamp()
next_rotation.FromDatetime(datetime.datetime.utcnow() + datetime.timedelta(days=1))
crypto_key = {
"purpose": kms_v1.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT,
"rotation_schedule": {
"rotation_period": rotation_period,
"next_rotation_time": next_rotation,
},
}
try:
client.get_crypto_key(request={"name": crypto_key_name})
except Exception:
client.create_crypto_key(
request={
"parent": key_ring_name,
"crypto_key_id": crypto_key_id,
"crypto_key": crypto_key,
}
)
3. Grant the Compute Service Account Access to the Key
Each instance uses a service account. That SA needs roles/cloudkms.cryptoKeyEncrypterDecrypter on the crypto key.
Typical default GCE service account:
PROJECT_NUMBER-compute@developer.gserviceaccount.com
from google.cloud import kms_v1
from google.iam.v1 import policy_pb2
project_id = "YOUR_PROJECT_ID"
location_id = "us-central1"
key_ring_id = "compute-keyring"
crypto_key_id = "compute-disk-key"
compute_sa = "PROJECT_NUMBER-compute@developer.gserviceaccount.com"
client = kms_v1.KeyManagementServiceClient()
crypto_key_name = client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id)
policy = client.get_iam_policy(request={"resource": crypto_key_name})
binding = next((b for b in policy.bindings if b.role == "roles/cloudkms.cryptoKeyEncrypterDecrypter"), None)
if not binding:
binding = policy_pb2.Binding(role="roles/cloudkms.cryptoKeyEncrypterDecrypter", members=[])
policy.bindings.append(binding)
member = f"serviceAccount:{compute_sa}"
if member not in binding.members:
binding.members.append(member)
client.set_iam_policy(request={"resource": crypto_key_name, "policy": policy})
4. Create New Disks/VMs with CMEK (Python)
CMEK cannot be applied in-place to an existing disk. You must create new disks with CMEK and migrate.
4.1. Create a CMEK‑Encrypted Disk
from googleapiclient import discovery
from google.oauth2 import service_account
project = "YOUR_PROJECT_ID"
zone = "us-central1-a"
disk_name = "cmek-data-disk"
kms_key = "projects/YOUR_PROJECT_ID/locations/us-central1/keyRings/compute-keyring/cryptoKeys/compute-disk-key"
credentials = service_account.Credentials.from_service_account_file("path/to/sa.json")
compute = discovery.build("compute", "v1", credentials=credentials)
disk_body = {
"name": disk_name,
"sizeGb": "100",
"type": f"projects/{project}/zones/{zone}/diskTypes/pd-balanced",
"diskEncryptionKey": {
"kmsKeyName": kms_key
},
}
operation = compute.disks().insert(project=project, zone=zone, body=disk_body).execute()
4.2. Create a VM Using CMEK for Boot Disk
instance_name = "cmek-instance"
machine_type = f"zones/{zone}/machineTypes/e2-medium"
source_image = "projects/debian-cloud/global/images/family/debian-12"
instance_body = {
"name": instance_name,
"machineType": f"projects/{project}/{machine_type}",
"disks": [
{
"boot": True,
"autoDelete": True,
"initializeParams": {
"sourceImage": source_image,
"diskSizeGb": "20",
"diskType": f"projects/{project}/zones/{zone}/diskTypes/pd-balanced",
"diskEncryptionKey": {"kmsKeyName": kms_key},
},
}
],
"networkInterfaces": [{"network": "global/networks/default", "accessConfigs": [{"type": "ONE_TO_ONE_NAT"}]}],
"serviceAccounts": [
{
"email": "PROJECT_NUMBER-compute@developer.gserviceaccount.com",
"scopes": ["https://www.googleapis.com/auth/cloud-platform"],
}
],
}
operation = compute.instances().insert(project=project, zone=zone, body=instance_body).execute()
5. Migrate Existing Disks to CMEK
For each non‑CMEK disk:
- Create a snapshot of the disk.
- Create a new disk from that snapshot with CMEK.
- Detach the old disk from the instance.
- Attach the new CMEK disk.
- Delete the old disk when verified.
5.1. Snapshot the Existing Disk
disk = "old-disk"
snapshot_name = "old-disk-snap"
snapshot_body = {"name": snapshot_name}
operation = compute.disks().createSnapshot(
project=project, zone=zone, disk=disk, body=snapshot_body
).execute()
5.2. Create New Disk from Snapshot with CMEK
new_disk = "old-disk-cmek"
disk_body = {
"name": new_disk,
"sourceSnapshot": f"projects/{project}/global/snapshots/{snapshot_name}",
"diskEncryptionKey": {"kmsKeyName": kms_key},
}
operation = compute.disks().insert(project=project, zone=zone, body=disk_body).execute()
5.3. Detach Old Disk and Attach New Disk
instance = "INSTANCE_NAME"
device_name = "old-disk"
# Detach old disk
compute.instances().detachDisk(
project=project, zone=zone, instance=instance, deviceName=device_name
).execute()
# Attach new CMEK disk
attach_body = {
"source": f"projects/{project}/zones/{zone}/disks/{new_disk}",
"autoDelete": True,
"boot": False,
"deviceName": device_name,
}
compute.instances().attachDisk(
project=project, zone=zone, instance=instance, body=attach_body
).execute()
6. Harden Key Management
- Restrict IAM on KMS keys:
- Only necessary service accounts:
roles/cloudkms.cryptoKeyEncrypterDecrypter - Admins:
roles/cloudkms.adminwith least privilege.
- Only necessary service accounts:
- Enable key rotation (already set in Step 2.2).
- Disable or destroy old keys only after:
- All disks/images/snapshots no longer depend on them.
- Audit:
-
Enable Cloud Logging & Cloud Audit Logs for KMS.
-
Periodically verify disks use CMEK:
gcloud compute disks list --format="table(name,zone,encryptionKey.kmsKeyName)"
-
If you paste a specific current configuration (disk/instance JSON or output of gcloud compute instances describe), I can give tailored Python snippets to fix exactly that setup.
Using Terraform
resource "google_kms_key_ring" "KEY_RING" {
name = "KEY_RING_NAME" # replace with your key ring name
location = "KEY_RING_LOCATION" # e.g. "us-central1"
}
resource "google_kms_crypto_key" "CRYPTO_KEY" {
name = "CRYPTO_KEY_NAME" # replace with your crypto key name
key_ring = google_kms_key_ring.KEY_RING.id
purpose = "ENCRYPT_DECRYPT"
# Enable automatic rotation with a maximum period of 90 days
rotation_period = "7776000s" # 90 days in seconds
# Optional but recommended: set an explicit next rotation time (RFC3339)
# next_rotation_time = "2024-10-01T00:00:00Z"
}
Changing rotation_period on an existing google_kms_crypto_key is an in‑place update and does not force key replacement.
Verification: terraform plan should show an in-place update to google_kms_crypto_key.CRYPTO_KEY with rotation_period changing from null (or a value > 7776000s) to "7776000s" (and next_rotation_time set/updated if you specified it).