AwsEncryptionSdk.Keyring.AwsKms (AWS Encryption SDK v0.7.0)
View SourceAWS KMS Keyring implementation.
Encrypts and decrypts data keys using AWS Key Management Service (KMS). This is the primary keyring for AWS-based encryption workflows.
Use Cases
- Server-side encryption: Encrypt data at rest with KMS-managed keys
- Multi-party encryption: Use with Multi-keyring for redundant key access
- Compliance: Leverage KMS audit trails and key policies
Key Identifier Formats
The keyring accepts various KMS key identifier formats:
| Format | Example | Recommended |
|---|---|---|
| Key ARN | arn:aws:kms:us-west-2:123:key/abc | Yes |
| Alias ARN | arn:aws:kms:us-west-2:123:alias/my-key | Yes |
| Key ID | 12345678-1234-1234-1234-123456789012 | No* |
| Alias Name | alias/my-key | No* |
*Non-ARN formats work but limit portability and explicit region control.
Operations
Encryption (wrap_key)
When no plaintext data key exists:
- Calls KMS
GenerateDataKeyto create a new data key - Returns both plaintext and encrypted data key
When plaintext data key already exists (multi-keyring scenario):
- Calls KMS
Encryptto wrap the existing key - Returns additional encrypted data key (EDK)
Decryption (unwrap_key)
- Filters EDKs to find those with provider ID "aws-kms"
- Validates EDK key ARN matches configured key (supports MRK matching)
- Calls KMS
Decryptwith the first matching EDK - Returns decrypted plaintext data key
IAM Permissions Required
The IAM principal must have these KMS permissions:
For Encryption
{
"Effect": "Allow",
"Action": [
"kms:GenerateDataKey",
"kms:Encrypt"
],
"Resource": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
}For Decryption
{
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
}For Both (Recommended)
{
"Effect": "Allow",
"Action": [
"kms:GenerateDataKey",
"kms:Encrypt",
"kms:Decrypt"
],
"Resource": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
}Security Considerations
- Key Access: Anyone with KMS Decrypt permission for the key can decrypt data
- Encryption Context: Use encryption context to bind ciphertext to specific contexts
- Audit Trail: All KMS operations are logged to CloudTrail
- Key Rotation: Enable automatic key rotation in KMS for long-lived keys
- Grant Tokens: Use for temporary, fine-grained access control
Examples
Basic Usage
alias AwsEncryptionSdk.Keyring.AwsKms
alias AwsEncryptionSdk.Keyring.KmsClient.ExAws
alias AwsEncryptionSdk.Cmm.Default
alias AwsEncryptionSdk.Client
# Create KMS client for your region
{:ok, kms_client} = ExAws.new(region: "us-west-2")
# Create keyring with KMS key ARN
{:ok, keyring} = AwsKms.new(
"arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012",
kms_client
)
# Create CMM and client
cmm = Default.new(keyring)
client = Client.new(cmm)
# Encrypt
{:ok, ciphertext} = Client.encrypt(client, "sensitive data",
encryption_context: %{"tenant" => "acme", "purpose" => "storage"}
)
# Decrypt
{:ok, {plaintext, context}} = Client.decrypt(client, ciphertext)With Grant Tokens
{:ok, keyring} = AwsKms.new(
"arn:aws:kms:us-west-2:123:key/abc",
kms_client,
grant_tokens: ["grant-token-from-create-grant-api"]
)With Multi-Keyring for Redundancy
alias AwsEncryptionSdk.Keyring.Multi
# Primary KMS key (generator)
{:ok, primary} = AwsKms.new("arn:aws:kms:us-west-2:123:key/primary", west_client)
# Backup KMS key (child)
{:ok, backup} = AwsKms.new("arn:aws:kms:us-east-1:123:key/backup", east_client)
# Multi-keyring: encrypts with both, can decrypt with either
{:ok, multi} = Multi.new(generator: primary, children: [backup])Spec Reference
Summary
Functions
Creates a new AWS KMS Keyring.
Unwraps a data key using AWS KMS.
Wraps a data key using AWS KMS.
Types
Functions
Creates a new AWS KMS Keyring.
Parameters
kms_key_id- AWS KMS key identifier (ARN, alias ARN, alias name, or key ID)kms_client- KMS client struct implementing KmsClient behaviouropts- Optional keyword list::grant_tokens- List of grant tokens for KMS API calls
Returns
{:ok, keyring}on success{:error, reason}on validation failure
Errors
{:error, :key_id_required}- kms_key_id is nil{:error, :key_id_empty}- kms_key_id is empty string{:error, :invalid_key_id_type}- kms_key_id is not a string{:error, :client_required}- kms_client is nil{:error, :invalid_client_type}- kms_client is not a struct
Examples
{:ok, client} = KmsClient.Mock.new(%{})
{:ok, keyring} = AwsKms.new("arn:aws:kms:us-west-2:123:key/abc", client)
# With grant tokens
{:ok, keyring} = AwsKms.new("arn:aws:kms:us-west-2:123:key/abc", client,
grant_tokens: ["token1", "token2"]
)
@spec unwrap_key(t(), AwsEncryptionSdk.Materials.DecryptionMaterials.t(), [ AwsEncryptionSdk.Materials.EncryptedDataKey.t() ]) :: {:ok, AwsEncryptionSdk.Materials.DecryptionMaterials.t()} | {:error, term()}
Unwraps a data key using AWS KMS.
Filters EDKs to find those encrypted with KMS, then attempts decryption with the configured KMS key. Returns on first successful decryption.
Returns
{:ok, materials}- Data key successfully decrypted{:error, :plaintext_data_key_already_set}- Materials already have key{:error, {:unable_to_decrypt_any_data_key, errors}}- All decryption attempts failed
Examples
{:ok, result} = AwsKms.unwrap_key(keyring, materials, edks)
@spec wrap_key(t(), AwsEncryptionSdk.Materials.EncryptionMaterials.t()) :: {:ok, AwsEncryptionSdk.Materials.EncryptionMaterials.t()} | {:error, term()}
Wraps a data key using AWS KMS.
If materials don't have a plaintext data key, generates one using KMS GenerateDataKey. If materials already have a plaintext data key, encrypts it using KMS Encrypt.
Returns
{:ok, materials}- Data key generated/encrypted and EDK added{:error, reason}- KMS operation failed or validation error
Examples
{:ok, result} = AwsKms.wrap_key(keyring, materials)