Examples¶
Basic KMS Key¶
A minimal KMS key with full encrypt/decrypt access for a single IAM role.
module "encryption_key" {
source = "registry.infrahouse.com/infrahouse/key/aws"
version = "0.3.0"
environment = "production"
service_name = "my-app"
key_name = "my-app-data"
key_description = "Encryption key for my-app data at rest"
key_users = [
"arn:aws:iam::123456789012:role/my-app-role"
]
}
See examples/basic/ for a complete working example.
Split Encrypt/Decrypt Permissions¶
Grant encrypt-only access to a producer service and decrypt-only access to a consumer, following the principle of least privilege.
module "encryption_key" {
source = "registry.infrahouse.com/infrahouse/key/aws"
version = "0.3.0"
environment = "production"
service_name = "data-pipeline"
key_name = "pipeline-data"
key_description = "Encryption key for data pipeline"
key_encrypt_only_users = [
"arn:aws:iam::123456789012:role/data-producer"
]
key_decrypt_only_users = [
"arn:aws:iam::123456789012:role/data-consumer"
]
}
See examples/split-permissions/ for a complete working example.
S3 Bucket Encryption¶
Use the KMS key to encrypt an S3 bucket:
module "encryption_key" {
source = "registry.infrahouse.com/infrahouse/key/aws"
version = "0.3.0"
environment = "production"
service_name = "my-app"
key_name = "s3-data"
key_description = "Encryption key for S3 bucket data"
key_users = [
"arn:aws:iam::123456789012:role/my-app-role"
]
}
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = aws_s3_bucket.example.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = module.encryption_key.kms_key_arn
}
}
}
Multiple Roles with Mixed Permissions¶
Combine all three user lists for complex access patterns:
module "encryption_key" {
source = "registry.infrahouse.com/infrahouse/key/aws"
version = "0.3.0"
environment = "production"
service_name = "shared-data"
key_name = "shared-data"
key_description = "Shared encryption key with role-based access"
# Admin role gets full access
key_users = [
"arn:aws:iam::123456789012:role/admin"
]
# API services can only encrypt (write)
key_encrypt_only_users = [
"arn:aws:iam::123456789012:role/api-service-a",
"arn:aws:iam::123456789012:role/api-service-b"
]
# Backend processors can only decrypt (read)
key_decrypt_only_users = [
"arn:aws:iam::123456789012:role/processor"
]
}
Using the Key in Python¶
Simple Encrypt/Decrypt¶
The simplest way to use a KMS key — encrypt and decrypt small payloads (up to 4 KB) directly via the KMS API:
import boto3
kms = boto3.client("kms")
key_arn = "arn:aws:kms:us-west-2:123456789012:key/..."
# Encrypt
response = kms.encrypt(KeyId=key_arn, Plaintext=b"Hello world")
ciphertext = response["CiphertextBlob"]
# Decrypt
response = kms.decrypt(CiphertextBlob=ciphertext)
plaintext = response["Plaintext"] # b"Hello world"
Envelope Encryption with Fernet¶
For data larger than 4 KB, use envelope encryption: KMS generates a data key, you encrypt data locally with that key, then store the encrypted data key alongside the ciphertext. This way, KMS only encrypts/decrypts the small data key, not your entire payload.
This example uses Fernet from the cryptography library (AES-128-CBC with HMAC authentication):
import base64
import boto3
from cryptography.fernet import Fernet
kms = boto3.client("kms")
key_arn = "arn:aws:kms:us-west-2:123456789012:key/..."
# --- Encrypt ---
# Ask KMS for a data key (plaintext + encrypted copies)
response = kms.generate_data_key(KeyId=key_arn, KeySpec="AES_256")
plaintext_key = response["Plaintext"] # 32 bytes, use locally
encrypted_key = response["CiphertextBlob"] # store this, it's safe
# Encrypt your data locally with the plaintext key
# Fernet expects a 32-byte key, base64url-encoded
fernet = Fernet(base64.urlsafe_b64encode(plaintext_key))
ciphertext = fernet.encrypt(b"This can be megabytes of data")
# Discard the plaintext key from memory
del plaintext_key
# Store encrypted_key + ciphertext together (e.g., in S3 or a database)
# encrypted_key is ~200 bytes; ciphertext is your data + overhead
# --- Decrypt ---
# Recover the plaintext data key via KMS
response = kms.decrypt(CiphertextBlob=encrypted_key)
plaintext_key = response["Plaintext"]
# Decrypt the data locally
fernet = Fernet(base64.urlsafe_b64encode(plaintext_key))
data = fernet.decrypt(ciphertext) # b"This can be megabytes of data"
Tip
Install with pip install cryptography. Fernet provides authenticated encryption (AES-CBC + HMAC-SHA256), so it detects tampering automatically.