Skip to main content

KMS

dpl.KMS(
alias: str = None, # e.g. "alias/my-app" or "my-app"
description: str = None,
key_usage: str = "ENCRYPT_DECRYPT", # "ENCRYPT_DECRYPT" | "SIGN_VERIFY" | "GENERATE_VERIFY_MAC"
key_spec: str = "SYMMETRIC_DEFAULT", # "SYMMETRIC_DEFAULT" | "RSA_2048/3072/4096"
# | "ECC_NIST_P256/P384/P521" | "ECC_SECG_P256K1"
# | "HMAC_224/256/384/512"
enable_rotation: bool = None, # None → auto: True for SYMMETRIC_DEFAULT, False otherwise
deletion_policy: str = "Retain", # KMS uses Retain by default (security)
existing_key_id: str = None, # ID or ARN of an existing key (does not create resource)
env_var: str = None, # Forces the name of the generated env var
)

Auto-generated environment variable​

ConfigurationVariable
env_var="MY_KEY"MY_KEY (takes priority)
alias="myapp/encryption"MYAPP_ENCRYPTION_KEY_ID
No alias or env_varKMS_KEY_ID

Generated CloudFormation resources​

  • AWS::KMS::Key — with Enabled: True, KeyUsage, KeySpec, and a basic key policy
  • AWS::KMS::Alias — optional alias to identify the key by name
  • EnableKeyRotation is only added when key_spec="SYMMETRIC_DEFAULT" (asymmetric keys do not support automatic rotation)

Compile-time validations (E00)​

  • alias can only contain alphanumeric characters, -, _, /
  • key_usage must be one of the valid values
  • key_spec must be one of the valid values
  • enable_rotation=True is not valid for asymmetric keys (RSA, ECC, HMAC)
  • ECC key_spec is not compatible with key_usage="ENCRYPT_DECRYPT"
  • key_spec="SYMMETRIC_DEFAULT" is not compatible with key_usage="SIGN_VERIFY"

Examples​

Basic (auto-detected)​

app/features/tenant/routes.py
import deployless as dpl

kms_key = dpl.KMS(
alias="my-app/data",
description="Encryption key for sensitive data",
enable_rotation=True,
deletion_policy="Retain",
)

# No need to declare resources= or policies= — kms_key is auto-detected
# with "crud" permissions (Encrypt, Decrypt, GenerateDataKey, DescribeKey)
dpl.configure(description="Tenant Service")

Restricting permissions​

# This feature only needs to decrypt
dpl.configure(
resources={"data_key": (kms_key, "decrypt")},
)

Using the key in app code​

The environment variable is automatically injected:

app/features/tenant/services/kms_service.py
import boto3
import base64
import os

kms_client = boto3.client('kms')

def encrypt_with_kms(plaintext: str) -> str:
response = kms_client.encrypt(
KeyId=os.getenv('KMS_KEY_ID'),
Plaintext=plaintext.encode('utf-8'),
)
return base64.b64encode(response['CiphertextBlob']).decode('utf-8')

def decrypt_with_kms(ciphertext_b64: str) -> str:
ciphertext_blob = base64.b64decode(ciphertext_b64)
response = kms_client.decrypt(CiphertextBlob=ciphertext_blob)
return response['Plaintext'].decode('utf-8')
note

kms:Decrypt does not need to specify KeyId because the ciphertext already embeds the ID of the key that encrypted it.

Cross-feature key sharing​

A real pattern: the tenant feature encrypts the RSA private key, and the auth feature decrypts it on each login.

app/features/tenant/routes.py
import deployless as dpl

tenant_key = dpl.KMS(
alias="ums/tenant-keys",
description="Encryption of RSA private keys per tenant",
enable_rotation=True,
deletion_policy="Retain",
)

tenants_table = dpl.DynamoDB("ums-tenants", pk="tenant_id", deletion_policy="Retain")

# Restrict tenant_key to "encrypt" only (this feature doesn't need decrypt)
dpl.configure(
resources={"tenant_key": (tenant_key, "encrypt")},
)
app/features/auth/routes.py
import deployless as dpl
from app.shared.services.kms_service import tenant_key

# Restrict to "decrypt" only
dpl.configure(
resources={"tenant_key": (tenant_key, "decrypt")},
)

Asymmetric key for digital signing​

signing_key = dpl.KMS(
alias="my-app/signing",
description="RSA key for signing JWTs or documents",
key_usage="SIGN_VERIFY",
key_spec="RSA_2048",
)

# For SIGN_VERIFY keys, add additional actions via policies=
dpl.configure(
policies=[
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["kms:Sign", "kms:Verify", "kms:GetPublicKey"],
"Resource": dpl.Ref(signing_key),
}
],
}
],
)

Existing key​

dpl.KMS(existing_key_id="arn:aws:kms:us-east-1:123456789:key/abc-123")
# Does not generate a CloudFormation resource
# KMS_KEY_ID = "arn:aws:kms:us-east-1:123456789:key/abc-123"

Permission levels​

LevelIAM actions granted
"crud" (default)kms:Encrypt, kms:Decrypt, kms:GenerateDataKey, kms:DescribeKey
"encrypt"kms:Encrypt
"decrypt"kms:Decrypt