GCP for DevOps — KMS & Encryption
KMS & Encryption
Cloud KMS (Key Management Service) lets you create, manage, and use cryptographic keys for encryption and signing. It supports customer-managed encryption keys (CMEK), envelope encryption, and HSM-backed keys.
Encryption Hierarchy
GCP Encryption Hierarchy:
┌──────────────────────────────────────────┐
│ Google Default Encryption (DEK + KEK) │
│ • Automatic, no setup │
│ • Google manages all keys │
│ │
│ ┌──────────────────────────────────────┐│
│ │ CMEK (Customer-Managed Keys) ││
│ │ • You create keys in Cloud KMS ││
│ │ • You control rotation, access ││
│ │ • Google uses YOUR key to encrypt ││
│ │ ││
│ │ ┌──────────────────────────────────┐ ││
│ │ │ CSEK (Customer-Supplied Keys) │ ││
│ │ │ • You provide the key material │ ││
│ │ │ • Google never stores the key │ ││
│ │ │ • You are fully responsible │ ││
│ │ └──────────────────────────────────┘ ││
│ └──────────────────────────────────────┘│
└──────────────────────────────────────────┘
Create Keys
# Create a key ring
$ gcloud kms keyrings create my-keyring \
--location=us-central1
# Create an encryption key
$ gcloud kms keys create my-key \
--keyring=my-keyring \
--location=us-central1 \
--purpose=encryption \
--rotation-period=90d \
--next-rotation-time=$(date -u -v+90d +%Y-%m-%dT%H:%M:%SZ)
# Create an HSM-backed key
$ gcloud kms keys create my-hsm-key \
--keyring=my-keyring \
--location=us-central1 \
--purpose=encryption \
--protection-level=hsm
# List keys
$ gcloud kms keys list --keyring=my-keyring --location=us-central1
# Output:
# NAME PURPOSE PROTECTION_LEVEL
# projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key ENCRYPT_DECRYPT SOFTWARE
# projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-hsm-key ENCRYPT_DECRYPT HSM
Encrypt and Decrypt
# Encrypt a file
$ gcloud kms encrypt \
--key=my-key \
--keyring=my-keyring \
--location=us-central1 \
--plaintext-file=secret.txt \
--ciphertext-file=secret.enc
# Decrypt a file
$ gcloud kms decrypt \
--key=my-key \
--keyring=my-keyring \
--location=us-central1 \
--ciphertext-file=secret.enc \
--plaintext-file=secret-decrypted.txt
CMEK with GCP Services
Cloud Storage with CMEK
# Create a bucket with CMEK
$ gsutil mb -l us-central1 \
-k projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key \
gs://my-encrypted-bucket
# Set CMEK on existing bucket
$ gsutil kms encryption \
-k projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key \
gs://my-existing-bucket
BigQuery with CMEK
# Create dataset with CMEK
$ bq mk --dataset \
--default_kms_key=projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key \
my-project:encrypted_dataset
GKE with CMEK
# Create GKE cluster with CMEK for etcd encryption
$ gcloud container clusters create secure-cluster \
--region=us-central1 \
--database-encryption-key=projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key
Key Rotation
# Manually rotate a key
$ gcloud kms keys versions create \
--key=my-key \
--keyring=my-keyring \
--location=us-central1
# Update rotation schedule
$ gcloud kms keys update my-key \
--keyring=my-keyring \
--location=us-central1 \
--rotation-period=90d
# Disable an old key version
$ gcloud kms keys versions disable 1 \
--key=my-key \
--keyring=my-keyring \
--location=us-central1
# Destroy a key version (schedule)
$ gcloud kms keys versions destroy 1 \
--key=my-key \
--keyring=my-keyring \
--location=us-central1
IAM for KMS
# Grant encrypt/decrypt to a service account
$ gcloud kms keys add-iam-policy-binding my-key \
--keyring=my-keyring \
--location=us-central1 \
--member="serviceAccount:my-sa@my-project.iam.gserviceaccount.com" \
--role="roles/cloudkms.cryptoKeyEncrypterDecrypter"
# Grant encrypt-only (for writing)
$ gcloud kms keys add-iam-policy-binding my-key \
--keyring=my-keyring \
--location=us-central1 \
--member="serviceAccount:writer-sa@my-project.iam.gserviceaccount.com" \
--role="roles/cloudkms.cryptoKeyEncrypter"
Envelope Encryption
from google.cloud import kms
import base64
import os
client = kms.KeyManagementServiceClient()
key_name = "projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key"
# Generate a local data encryption key (DEK)
dek = os.urandom(32)
# Encrypt the DEK with KMS (wrap the key)
wrapped_dek = client.encrypt(
request={"name": key_name, "plaintext": dek}
).ciphertext
# Use DEK to encrypt data locally (fast, no API call)
from cryptography.fernet import Fernet
fernet_key = base64.urlsafe_b64encode(dek)
f = Fernet(fernet_key)
encrypted_data = f.encrypt(b"sensitive data")
# Store: wrapped_dek + encrypted_data
# To decrypt: unwrap DEK via KMS, then decrypt data locally
Common Mistakes
| Mistake | Why It’s Wrong | Fix |
|---|---|---|
| No key rotation | Compromised key = long exposure | Set automatic rotation |
| Too broad KMS permissions | Anyone can decrypt | Use least-privilege roles |
| Destroying keys immediately | Can’t decrypt existing data | Use scheduled destruction (24h+) |
| No CMEK for sensitive data | Google manages keys | Use CMEK for compliance |
| Same key for everything | One compromise = all data | Use separate keys per service |
Quick Reference
| Command | Description |
|---|---|
gcloud kms keyrings create |
Create key ring |
gcloud kms keys create |
Create key |
gcloud kms encrypt |
Encrypt data |
gcloud kms decrypt |
Decrypt data |
gcloud kms keys versions create |
Rotate key |
gcloud kms keys add-iam-policy-binding |
Grant access |
Next → Security Automation