Guide · AWS KMS · Multi-Region Keys
AWS KMS Multi-Region Keys for MCP Servers — Cross-Region Decrypt, DR Failover
AWS KMS multi-region keys (MRKs) are a set of KMS keys in different AWS regions that share the same key material and key ID suffix — a ciphertext envelope encrypted with the primary key in us-east-1 can be decrypted by a replica key in eu-west-1 without sending the ciphertext across regions and without a cross-region KMS API call, because both keys are cryptographically identical. For MCP servers this matters in two specific scenarios: (1) global active-active deployments where a user in Europe cannot afford the 100–150ms round-trip to a KMS endpoint in us-east-1, and (2) disaster recovery where the primary region becomes unavailable and an encrypted database replica in the secondary region must be readable. For all other cases, single-region keys with cross-region replication of encrypted data are simpler and cheaper.
TL;DR
Create a multi-region primary key with --multi-region, replicate it to secondary regions with replicate-key, and point each region's MCP server deployment at its local replica. For DR failover use update-primary-region to promote a replica. Each region's key costs $1/month independently. See the KMS overview for single-region key basics, the envelope encryption guide for the ciphertext portability mechanics, the key policies guide for per-region policy management, and the CloudTrail monitoring guide for cross-region event aggregation.
Multi-region key concepts
A multi-region key family consists of one primary key and one or more replica keys. All keys in the family share the same key material, meaning a ciphertext produced by any key in the family can be decrypted by any other key in the family. The key ID suffix (mrk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX) is identical across all replicas; the ARN differs only in the region segment.
| Property | Single-region key | Multi-region key |
|---|---|---|
| Key ID format | abc12345-1234-1234-1234-abcdef123456 | mrk-abc123def456... (32 hex chars after "mrk-") |
| Key ARN | arn:aws:kms:us-east-1:123456789012:key/abc12345-... | arn:aws:kms:us-east-1:123456789012:key/mrk-abc123... |
| Cross-region decrypt | Not possible — ciphertext can only be decrypted in the region where the key exists | Possible — replica in eu-west-1 can decrypt ciphertext made by primary in us-east-1 |
| Key rotation | Automatic annual or on-demand | Manual only (create new MRK, migrate; automatic rotation not supported on MRKs) |
| Pricing | $1/month per key | $1/month per key per region ($1 primary + $1 per replica) |
| Key policy | Single policy per key | Independent policy per region — each replica has its own key policy |
The critical distinction: multi-region keys share key material, not key policies. You must configure access control independently in each region. If you add a new IAM role to the key policy in us-east-1, the eu-west-1 replica's policy is unchanged — you must run PutKeyPolicy separately in each region where that role needs access.
Create a primary MRK and replicate to secondary regions
# Create a multi-region primary key in us-east-1
aws kms create-key \
--description "MCP server multi-region secrets key" \
--key-usage ENCRYPT_DECRYPT \
--key-spec SYMMETRIC_DEFAULT \
--multi-region \
--region us-east-1 \
--tags TagKey=Service,TagValue=mcp-server TagKey=MultiRegion,TagValue=true \
--policy file://key-policy.json
# Output includes:
# KeyMetadata.KeyId: "mrk-1234abcd5678efgh9012ijkl3456mnop"
# KeyMetadata.MultiRegion: true
# KeyMetadata.MultiRegionConfiguration.MultiRegionKeyType: "PRIMARY"
# KeyMetadata.MultiRegionConfiguration.PrimaryKey.Arn: "arn:aws:kms:us-east-1:123456789012:key/mrk-..."
# KeyMetadata.MultiRegionConfiguration.ReplicaKeys: [] (none yet)
PRIMARY_KEY_ARN="arn:aws:kms:us-east-1:123456789012:key/mrk-1234abcd5678efgh9012ijkl3456mnop"
# Create aliases in primary region
aws kms create-alias \
--alias-name alias/mcp-server-mrk-prod \
--target-key-id $PRIMARY_KEY_ARN \
--region us-east-1
# Replicate the primary key to eu-west-1
# This copies key material; not possible to replicate existing single-region key
aws kms replicate-key \
--key-id $PRIMARY_KEY_ARN \
--replica-region eu-west-1 \
--description "MCP server MRK replica — eu-west-1" \
--tags TagKey=Service,TagValue=mcp-server TagKey=MultiRegion,TagValue=true \
--policy file://key-policy.json
# Replication takes ~30 seconds; check status:
aws kms describe-key \
--key-id $PRIMARY_KEY_ARN \
--region us-east-1 \
--query 'KeyMetadata.MultiRegionConfiguration.ReplicaKeys'
# Create alias in the replica region
REPLICA_KEY_ARN="arn:aws:kms:eu-west-1:123456789012:key/mrk-1234abcd5678efgh9012ijkl3456mnop"
aws kms create-alias \
--alias-name alias/mcp-server-mrk-prod \
--target-key-id $REPLICA_KEY_ARN \
--region eu-west-1
# Replicate to ap-southeast-1 as well (same command, different --replica-region)
aws kms replicate-key \
--key-id $PRIMARY_KEY_ARN \
--replica-region ap-southeast-1 \
--policy file://key-policy.json
Note that both the primary and all replicas share the same alias name (alias/mcp-server-mrk-prod) in their respective regions. This allows application code to always use alias/mcp-server-mrk-prod regardless of which region it is running in — the same alias name resolves to the local region's key. If you replicate to a new region later, create the alias in that region before deploying the application.
Cross-region ciphertext portability
The key feature of MRKs is that ciphertext produced in one region is decryptable in another without any re-encryption step. The KMS ciphertext format embeds the key ID (not the full ARN including region) in the ciphertext metadata — when a replica in eu-west-1 receives a ciphertext that references key ID mrk-1234abcd..., it recognizes this as a key it manages and decrypts it successfully.
// MCP server example: encrypt in us-east-1 (e.g., data written by US users)
// and decrypt in eu-west-1 (e.g., same data read by EU users, zero cross-region KMS latency)
// Write path — application running in us-east-1
const kmsUS = new KMSClient({ region: 'us-east-1' });
const { Plaintext, CiphertextBlob } = await kmsUS.send(new GenerateDataKeyCommand({
KeyId: 'alias/mcp-server-mrk-prod', // resolves to primary key in us-east-1
KeySpec: 'AES_256',
EncryptionContext: { tenantId: 'tenant-abc', env: 'production' },
}));
// ... encrypt payload locally, store encryptedPayload + CiphertextBlob in database
// Read path — same application running in eu-west-1 (database replica)
const kmsEU = new KMSClient({ region: 'eu-west-1' });
const { Plaintext: dataKey } = await kmsEU.send(new DecryptCommand({
CiphertextBlob: storedCiphertextBlob, // blob produced by us-east-1 primary key
EncryptionContext: { tenantId: 'tenant-abc', env: 'production' },
// No KeyId needed — KMS extracts key ID from ciphertext blob metadata
// KMS matches mrk-1234abcd... to the eu-west-1 replica automatically
}));
// ... decrypt payload locally with recovered data key
This portability is not available with single-region keys — a ciphertext encrypted with a us-east-1 single-region key cannot be decrypted in eu-west-1 even if an identical key policy exists there, because there is no shared key material. The only workaround with single-region keys is to call ReEncrypt via the source region, which requires a network round-trip and the source region to be available.
DR failover with update-primary-region
If the primary region (us-east-1) becomes unavailable due to an AWS regional outage, existing replicas can continue to serve Decrypt operations independently — they do not depend on the primary for day-to-day cryptographic work. The primary designation only affects which region can run management operations (CreateGrant, PutKeyPolicy on all replicas simultaneously). For cryptographic operations, a replica works the same as the primary.
# Promote eu-west-1 replica to primary during a DR scenario
# Run this command from the REPLICA region you want to promote
aws kms update-primary-region \
--key-id mrk-1234abcd5678efgh9012ijkl3456mnop \
--primary-region eu-west-1 \
--region eu-west-1
# The old primary (us-east-1) becomes a replica
# The eu-west-1 replica becomes the new primary
# This operation can be run from any active replica region
# After failover: verify new primary configuration
aws kms describe-key \
--key-id mrk-1234abcd5678efgh9012ijkl3456mnop \
--region eu-west-1 \
--query 'KeyMetadata.MultiRegionConfiguration'
# After the original primary region recovers, it will show as a replica:
aws kms describe-key \
--key-id mrk-1234abcd5678efgh9012ijkl3456mnop \
--region us-east-1 \
--query 'KeyMetadata.MultiRegionConfiguration.MultiRegionKeyType'
# Output: "REPLICA" (was PRIMARY before the failover)
Important: update-primary-region does not affect the key material or the ability of any region to process Decrypt calls — it only changes which key is the administrative "source of truth". During a full regional outage of us-east-1, your eu-west-1 MCP server deployment continues to decrypt data transparently. The update-primary-region call is needed if you want to run management operations (add a new replica, rotate key material) from a different region during the outage.
Rotation for multi-region keys
Automatic key rotation is not supported for multi-region keys. This is intentional — rotating key material on a primary would need to synchronize new material to all replicas atomically, which KMS cannot guarantee across regions. The correct rotation approach for MRKs is a manual process of creating a new MRK, migrating ciphertext with ReEncrypt, and eventually deleting the old MRK family.
# Manual MRK rotation process
# Step 1: Create a new MRK family (new key material)
aws kms create-key \
--description "MCP server MRK v2 (rotation from v1)" \
--key-usage ENCRYPT_DECRYPT \
--key-spec SYMMETRIC_DEFAULT \
--multi-region \
--region us-east-1
NEW_MRK_ID="mrk-newkey..."
# Step 2: Replicate new key to all regions where old key had replicas
aws kms replicate-key --key-id $NEW_MRK_ID --replica-region eu-west-1
aws kms replicate-key --key-id $NEW_MRK_ID --replica-region ap-southeast-1
# Step 3: Update alias to point to new key in each region
aws kms update-alias --alias-name alias/mcp-server-mrk-prod --target-key-id $NEW_MRK_ID --region us-east-1
aws kms update-alias --alias-name alias/mcp-server-mrk-prod --target-key-id mrk-newkey-eu --region eu-west-1
aws kms update-alias --alias-name alias/mcp-server-mrk-prod --target-key-id mrk-newkey-ap --region ap-southeast-1
# Step 4: Run ReEncrypt on existing data key blobs to wrap them under the new MRK
# (do this in batches; existing blobs still decryptable by old key during transition)
aws kms re-encrypt \
--ciphertext-blob fileb://old-data-key-blob.bin \
--destination-key-id alias/mcp-server-mrk-prod \
--destination-encryption-context '{"tenantId":"abc","env":"production"}'
# Step 5: After all blobs migrated, schedule deletion of old MRK primary
# (must delete all replicas first — cannot delete a primary while replicas exist)
aws kms schedule-key-deletion --key-id $OLD_MRK_ID --region eu-west-1 --pending-window-in-days 30
aws kms schedule-key-deletion --key-id $OLD_MRK_ID --region ap-southeast-1 --pending-window-in-days 30
aws kms schedule-key-deletion --key-id $OLD_MRK_ID --region us-east-1 --pending-window-in-days 30
Failure modes reference
| Failure | Symptom | Fix |
|---|---|---|
| Replica not yet available after replicate-key | Decrypt in eu-west-1 fails with NotFoundException seconds after replicate-key returns | Replication takes ~30 seconds; poll describe-key in the replica region until KeyState = Enabled; add retry logic in deployment scripts with exponential backoff |
| AccessDeniedException in replica region | Decrypt succeeds in us-east-1 primary but fails in eu-west-1 replica | Key policies are NOT replicated — each replica has an independent policy; run PutKeyPolicy in eu-west-1 with the same policy that works in us-east-1 |
| enable-key-rotation returns UnsupportedOperationException on MRK | Attempting automatic rotation on MRK fails | Automatic rotation not supported on MRKs; use manual rotation process (create new MRK, ReEncrypt existing blobs, update alias, delete old MRK) |
| Cannot delete primary while replicas exist | schedule-key-deletion on primary returns MRKInvalidStateException | Delete all replica keys first (in each replica region), wait for deletion to complete, then schedule primary deletion |
| update-primary-region fails during DR | Attempting to promote eu-west-1 during us-east-1 outage fails with error referencing primary region | update-primary-region requires the current primary region to be reachable; if it is unavailable, the replicas still process Decrypt independently — defer promotion until primary recovers, or escalate to AWS support |
| Ciphertext from single-region key rejected in other region | Decrypt fails in eu-west-1 with InvalidCiphertextException for blobs encrypted with a non-MRK | Single-region key ciphertext cannot cross regions; MRK ciphertext portability only works within the same MRK family; must re-encrypt using source region KMS, not replica |
| Alias not created in replica region | Application code using alias/mcp-server-mrk-prod fails in eu-west-1 with NotFoundException | Aliases are not replicated; create alias in each replica region explicitly after replication; automation: iterate all regions where replica exists and create alias in each |