AwsEncryptionSdk.Keyring.AwsKmsMrkDiscovery (AWS Encryption SDK v0.7.0)

View Source

AWS KMS MRK Discovery Keyring implementation.

Combines discovery keyring behavior with Multi-Region Key (MRK) awareness. Enables cross-region decryption of data encrypted with MRK keys without knowing the specific key ARN in advance.

Use Cases

  • Cross-region disaster recovery: Decrypt in any region with MRK replicas
  • Global applications: Access encrypted data from any region
  • Region failover: Transparent failover to replica regions

MRK vs Non-MRK Behavior

Key TypeBehavior
MRK (mrk-*)Reconstructs ARN with keyring's region, enables cross-region
Non-MRKOnly decrypts if key is in same region as keyring

Example: MRK Cross-Region

Data encrypted with arn:aws:kms:us-east-1:123:key/mrk-abc can be decrypted by a keyring configured for us-west-2 because:

  1. Keyring detects MRK key ID (mrk-abc)
  2. Reconstructs ARN: arn:aws:kms:us-west-2:123:key/mrk-abc
  3. Calls KMS Decrypt in us-west-2 using the regional replica

Operations

Encryption

MRK Discovery keyrings cannot encrypt. wrap_key/2 always returns {:error, :discovery_keyring_cannot_encrypt}.

Decryption (unwrap_key)

  1. Filters EDKs by provider ID "aws-kms"
  2. Validates ARN format and applies discovery filter
  3. For MRK keys: reconstructs ARN with configured region
  4. For non-MRK keys: only proceeds if regions match
  5. Calls KMS Decrypt with the (possibly reconstructed) ARN

Required Parameters

Unlike standard discovery keyring, MRK discovery requires a region:

ParameterDescription
kms_clientKMS client for API calls
regionAWS region for MRK ARN reconstruction

IAM Permissions Required

The principal needs kms:Decrypt on both the original key AND any MRK replicas that might be used:

{
  "Effect": "Allow",
  "Action": "kms:Decrypt",
  "Resource": [
    "arn:aws:kms:us-east-1:123456789012:key/mrk-*",
    "arn:aws:kms:us-west-2:123456789012:key/mrk-*"
  ]
}

Examples

Basic MRK Discovery

alias AwsEncryptionSdk.Keyring.AwsKmsMrkDiscovery
alias AwsEncryptionSdk.Keyring.KmsClient.ExAws
alias AwsEncryptionSdk.Cmm.Default
alias AwsEncryptionSdk.Client

# Create MRK discovery keyring for us-west-2
{:ok, kms_client} = ExAws.new(region: "us-west-2")
{:ok, keyring} = AwsKmsMrkDiscovery.new(kms_client, "us-west-2")

# Create client
cmm = Default.new(keyring)
client = Client.new(cmm)

# Decrypt data encrypted in ANY region with an MRK
{:ok, {plaintext, context}} = Client.decrypt(client, ciphertext)

With Discovery Filter

{:ok, keyring} = AwsKmsMrkDiscovery.new(kms_client, "us-west-2",
  discovery_filter: %{
    partition: "aws",
    accounts: ["123456789012"]
  }
)

Cross-Region Decryption Setup

# Data was encrypted in us-east-1 with:
# arn:aws:kms:us-east-1:123:key/mrk-abc

# Decrypt in us-west-2 (DR region)
{:ok, west_client} = ExAws.new(region: "us-west-2")
{:ok, keyring} = AwsKmsMrkDiscovery.new(west_client, "us-west-2",
  discovery_filter: %{partition: "aws", accounts: ["123456789012"]}
)

# This works because mrk-abc has a replica in us-west-2
{:ok, {plaintext, _}} = Client.decrypt(Client.new(Default.new(keyring)), ciphertext)

Spec Reference

https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/framework/aws-kms/aws-kms-mrk-discovery-keyring.md

Summary

Functions

Creates a new AWS KMS MRK Discovery Keyring.

Unwraps a data key using AWS KMS MRK Discovery.

MRK Discovery keyrings cannot encrypt - this always fails.

Types

discovery_filter()

@type discovery_filter() :: %{partition: String.t(), accounts: [String.t(), ...]}

t()

@type t() :: %AwsEncryptionSdk.Keyring.AwsKmsMrkDiscovery{
  discovery_filter: discovery_filter() | nil,
  grant_tokens: [String.t()],
  kms_client: struct(),
  region: String.t()
}

Functions

new(kms_client, region, opts \\ [])

@spec new(struct(), String.t(), keyword()) :: {:ok, t()} | {:error, term()}

Creates a new AWS KMS MRK Discovery Keyring.

Parameters

  • kms_client - KMS client struct implementing KmsClient behaviour
  • region - AWS region string for this keyring (e.g., "us-west-2")
  • opts - Optional keyword list:
    • :discovery_filter - Map with :partition (string) and :accounts (list of strings)
    • :grant_tokens - List of grant tokens for KMS API calls

Returns

  • {:ok, keyring} on success
  • {:error, reason} on validation failure

Examples

{:ok, client} = KmsClient.Mock.new(%{})
{:ok, keyring} = AwsKmsMrkDiscovery.new(client, "us-west-2")

# With discovery filter
{:ok, keyring} = AwsKmsMrkDiscovery.new(client, "us-west-2",
  discovery_filter: %{partition: "aws", accounts: ["123456789012"]}
)

unwrap_key(keyring, materials, edks)

Unwraps a data key using AWS KMS MRK Discovery.

For MRK EDKs, reconstructs the ARN with the keyring's configured region before calling KMS Decrypt, enabling cross-region decryption.

For non-MRK EDKs, filters out any where the region doesn't match.

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} = AwsKmsMrkDiscovery.unwrap_key(keyring, materials, edks)

wrap_key(aws_kms_mrk_discovery, encryption_materials)

@spec wrap_key(t(), AwsEncryptionSdk.Materials.EncryptionMaterials.t()) ::
  {:error, :discovery_keyring_cannot_encrypt}

MRK Discovery keyrings cannot encrypt - this always fails.

Returns

Always returns {:error, :discovery_keyring_cannot_encrypt}