GCP for DevOps — KMS & Encryption

3 minute read

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

Updated: