Configure AWS KMS for CMEK
Use AWS KMS to provide an encryption key for your organization.
claude "/claude-api help me configure a customer-managed encryption key with AWS KMS"This guide walks through configuring an AWS KMS key as a customer-managed encryption key (CMEK) for your Anthropic organization.
Prerequisites
- An AWS account with permissions to create KMS keys and set key policies (
kms:CreateKeyandkms:PutKeyPolicy). - An Anthropic Admin API key for your organization.
- The AWS CLI installed and authenticated.
Amazon Resource Name (ARN) for Anthropic
To have Anthropic use your encryption key, you must give Anthropic's IAM role a KMS key it can use for encrypting data. The ARN for Anthropic CMEK is:
arn:aws:iam::915198916910:role/anthropic-cmek-client-usEncryption key setup
Create the KMS key with a cross-account key policy
The key policy grants Anthropic's IAM role cross-account access. Three statements are required:
- Account root admin: the standard KMS pattern. Your account retains full admin control.
- Anthropic encrypt and decrypt: the
kms:Encryptandkms:Decryptactions, which Anthropic uses to encrypt and decrypt the data keys that protect your workspace data (envelope encryption). - Anthropic describe: the metadata read Anthropic performs at startup. It is granted separately because
DescribeKeyhas noEncryptionContextparameter, so anEncryptionContextcondition on this action would always deny.
export YOUR_ACCOUNT=$(aws sts get-caller-identity --query Account --output text) aws kms create-key \ --region <region> \ --description "Anthropic CMEK" \ --key-usage ENCRYPT_DECRYPT \ --policy "{ \"Version\": \"2012-10-17\", \"Statement\": [ { \"Sid\": \"AccountRootAdmin\", \"Effect\": \"Allow\", \"Principal\": {\"AWS\": \"arn:aws:iam::${YOUR_ACCOUNT}:root\"}, \"Action\": \"kms:*\", \"Resource\": \"*\" }, { \"Sid\": \"AllowAnthropicCMEKCrypto\", \"Effect\": \"Allow\", \"Principal\": {\"AWS\": \"arn:aws:iam::915198916910:role/anthropic-cmek-client-us\"}, \"Action\": [\"kms:Encrypt\", \"kms:Decrypt\"], \"Resource\": \"*\", \"Condition\": { \"StringEquals\": { \"kms:EncryptionContext:anthropic:compartment_uuid\": [ \"00000000-0000-0000-0000-000000000000\", \"<compartment-uuid>\" ] } } }, { \"Sid\": \"AllowAnthropicCMEKDescribe\", \"Effect\": \"Allow\", \"Principal\": {\"AWS\": \"arn:aws:iam::915198916910:role/anthropic-cmek-client-us\"}, \"Action\": \"kms:DescribeKey\", \"Resource\": \"*\" } ] }"Capture
KeyMetadata.Arnfrom the output. You need it when you register the key in the next step.The
EncryptionContextcondition is recommended but optional. Anthropic always includes your workspace's compartment ID in the encryption context, so ciphertext is cryptographically bound to that compartment regardless. Adding the condition provides defense-in-depth at the IAM layer. To start without it, omit theConditionblock from theAllowAnthropicCMEKCryptostatement and add it later withkms:PutKeyPolicy.You can also create the key from the AWS Console. Choose a symmetric key with the encrypt and decrypt key usage, a single-region key, and KMS key material origin. The Create-key wizard commits a key policy at its Review step: If you add Anthropic's account ID
915198916910under key usage permissions there, the generated policy grants the whole Anthropic account broader actions (such askms:ReEncrypt*andkms:GenerateDataKey*) with noEncryptionContextcondition, and validation would still succeed against it. To avoid leaving an over-permissive key, finish the wizard with administrative permissions only, then open the key's Key policy tab and replace the JSON with the role-scoped policy shown earlier (the three statements scoped to theanthropic-cmek-client-usrole, with theEncryptionContextcondition).
Configure key: symmetric, encrypt and decrypt, single-region key. 
Add an alias and description for the key. 
Define key administrative permissions (optional). Your account retains full admin control. 
Do not add Anthropic's account ID here. This wizard step produces an over-permissive policy. Leave usage permissions empty and edit the Key policy JSON after creation (see the preceding key policy).
Register the key with Anthropic
How you register the key depends on which product you use.
Register the key with Anthropic
Create an external key configuration through the Admin API.
client = anthropic.Anthropic() external_key = client.beta.organization.external_keys.create( display_name="<friendly-name>", geo="us", provider_config={"type": "aws", "kms_arn": "<key-arn-from-create-key-step>"}, ) print(f"id: {external_key.id}") print(f"display_name: {external_key.display_name}")The response contains the external key ID:
{ "type": "external_key", "id": "ekey_<id>", "display_name": "<friendly-name>" }Validate the key
Trigger an encrypt and decrypt round-trip against your key.
client = anthropic.Anthropic() validation = client.beta.organization.external_keys.validate("ekey_<id>") print(f"status: {validation.status}") print(f"error: {validation.error}")A successful response looks like this:
{ "type": "external_key_validation", "status": "success", "error": null }If validation fails, common causes are:
- Encryption context mismatch: Validation fails while data traffic works (or the reverse) with an opaque
AccessDeniedExceptionwhen akms:EncryptionContext:anthropic:compartment_uuidcondition allows only one of the two values Anthropic sends. Validation sends the all-zeros UUID (00000000-0000-0000-0000-000000000000); live traffic sends the attached workspace's compartment ID. Confirm the condition lists both. To rule the condition out entirely, temporarily remove theConditionblock from theAllowAnthropicCMEKCryptostatement and re-validate. - Resource control policies (RCPs): If your AWS organization has an RCP that denies KMS operations when
aws:PrincipalOrgIDdoes not match your org, it blocks Anthropic's cross-account role. The RCP needs a carve-out for this key or for Anthropic's role ARN. Service control policies do not apply here, because they do not evaluate for external principals calling through resource-based policies. - Access granted through IAM instead of the key policy: Cross-account KMS access must be granted in the key policy itself, not through an IAM policy in your account. Check with
aws kms get-key-policy --key-id <id> --policy-name default. - Region mismatch: Confirm the key's region is one Anthropic operates in for the geo tier you configured.
- Encryption context mismatch: Validation fails while data traffic works (or the reverse) with an opaque
Attach the key to a workspace
Once the key is validated, attach it to a new workspace before you send any requests to that workspace. For a workspace that already receives requests, the key can take up to a day to take effect.
client = anthropic.Anthropic() workspace = client.beta.organization.workspaces.update( "<workspace-id>", external_key_id="ekey_<id>" ) print(f"id: {workspace.id}") print(f"external_key_id: {workspace.external_key_id}")
Set up CMEK on Claude Platform on AWS
On Claude Platform on AWS, CMEK uses AWS KMS keys only, and setup differs from the preceding sections in these ways:
- Principal: Your key policy grants access to the AWS service principal
aws-external-anthropic.amazonaws.com. Anthropic's IAM role and account ID are not used, so the ARN for Anthropic does not apply. - Key requirements: The key must be a symmetric KMS key with encrypt and decrypt usage, single-region, and in the same AWS account and region as the workspace you attach it to. Cross-account keys are not supported: the key must be in the AWS account that hosts your organization. Multi-region keys (key IDs that begin with
mrk-) and alias ARNs are rejected when you register the key; use the key ARN. - No separate validation step: Apart from those checks on the key ARN at registration, the key is validated when you attach it to a workspace. The attach call performs an encrypt/decrypt round against the key with that workspace's compartment ID as the encryption context, so a key policy problem surfaces at attach time rather than at registration. Unlike the Claude Platform policy earlier on this page, an
EncryptionContextcondition therefore needs no all-zeros entry. - Where you manage keys: Register and attach keys in the Claude Console, signed in through AWS with the Admin role. The external key endpoints are also available on Claude Platform on AWS, authorized through IAM actions; there, a key is identified by its KMS key ARN rather than an
ekey_ID.
Prerequisites
- The AWS account that hosts your Claude Platform on AWS organization, with permissions to create KMS keys and set key policies (
kms:CreateKeyandkms:PutKeyPolicy). - The Admin role in the Claude Console for Claude Platform on AWS. See Using the Claude Console.
- For the IAM principal you sign in to the Claude Console with: besides
aws-external-anthropic:AssumeConsole, the IAM actions for the operations you perform there, because the Encryption keys page and key attachment go through the AWS gateway. Registering a key isRegisterKey(withListKeysandGetKeyto view registrations), and attaching one isUpdateWorkspaceorCreateWorkspace. The external key actions (andCreateWorkspace) are account-scoped, so grant them onResource: "*"; a policy limited to workspace ARNs does not include them. - For the IAM principal that attaches the key to a workspace (the identity you signed in to the Claude Console with):
kms:DescribeKey,kms:Encrypt, andkms:Decrypton the key. Your principal's access to the key is checked when you attach it, in addition to the service principal's. - Optional, for the key picker in the Claude Console:
kms:ListKeysandkms:DescribeKeyfor the principal you sign in with. Without them, paste the key ARN instead.
Create the KMS key
The key policy has three statements: your account's root admin statement; a statement that lets the Claude Platform on AWS service principal encrypt, decrypt, and generate data keys; and a separate statement for kms:DescribeKey. Both service-principal statements carry a recommended aws:SourceArn condition: the service calls your key on behalf of a specific workspace and passes that workspace's ARN as the source ARN, so the pattern shown limits the grant to workspaces in your own AWS account. DescribeKey is granted separately because it has no EncryptionContext parameter, so an EncryptionContext condition on that action would always deny.
If you plan to use the optional EncryptionContext condition shown here, create the workspace first (without a key) and copy its compartment ID from the Claude Console under Workspace > Security, under Encryption key (the Compartment ID field), or from the compartment_id field returned by the Get Workspace endpoint. Substitute it for <compartment-uuid>. Otherwise, delete the StringEquals entry from that statement's Condition block and keep the ArnLike entry.
export YOUR_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
aws kms create-key \
--region <workspace-region> \
--description "Anthropic CMEK (Claude Platform on AWS)" \
--key-usage ENCRYPT_DECRYPT \
--policy "{
\"Version\": \"2012-10-17\",
\"Statement\": [
{
\"Sid\": \"AccountRootAdmin\",
\"Effect\": \"Allow\",
\"Principal\": {\"AWS\": \"arn:aws:iam::${YOUR_ACCOUNT}:root\"},
\"Action\": \"kms:*\",
\"Resource\": \"*\"
},
{
\"Sid\": \"AllowClaudePlatformOnAWSCrypto\",
\"Effect\": \"Allow\",
\"Principal\": {\"Service\": \"aws-external-anthropic.amazonaws.com\"},
\"Action\": [\"kms:Encrypt\", \"kms:Decrypt\", \"kms:GenerateDataKey\"],
\"Resource\": \"*\",
\"Condition\": {
\"ArnLike\": {
\"aws:SourceArn\": \"arn:aws:aws-external-anthropic:*:${YOUR_ACCOUNT}:workspace/*\"
},
\"StringEquals\": {
\"kms:EncryptionContext:anthropic:compartment_uuid\": [
\"<compartment-uuid>\"
]
}
}
},
{
\"Sid\": \"AllowClaudePlatformOnAWSDescribe\",
\"Effect\": \"Allow\",
\"Principal\": {\"Service\": \"aws-external-anthropic.amazonaws.com\"},
\"Action\": \"kms:DescribeKey\",
\"Resource\": \"*\",
\"Condition\": {
\"ArnLike\": {
\"aws:SourceArn\": \"arn:aws:aws-external-anthropic:*:${YOUR_ACCOUNT}:workspace/*\"
}
}
}
]
}"Capture KeyMetadata.Arn from the output. You need it when you register the key.
Both conditions are optional hardening, and they compose. The aws:SourceArn condition can be written before any workspace exists; to pin the key to particular workspaces instead of your whole account, list their full workspace ARNs in place of the wildcard pattern, and to start without it, delete the ArnLike entry from both service-principal statements (removing a Condition block that this leaves empty). The EncryptionContext condition is also optional. Every encrypt, decrypt, and data-key call made for a workspace, including the attach-time check, carries that workspace's compartment ID as anthropic:compartment_uuid, so the condition lists the compartment ID of each workspace you attach the key to and needs no all-zeros entry. Adding it binds the key to the workspaces you list at the IAM layer as well. Because a compartment ID exists only once its workspace exists, the order is: create the workspace, put its compartment ID in the condition (at key creation, or later with kms:PutKeyPolicy), then attach the key. Before attaching the key to each additional workspace, add that workspace's compartment ID the same way. To start without it, delete the StringEquals entry from the AllowClaudePlatformOnAWSCrypto statement's Condition block; if you add it later, include the compartment ID of every workspace the key is already attached to.
You can also create the key from the AWS Console: choose a symmetric key with the encrypt and decrypt key usage, a single-region key, and KMS key material origin, in the workspace's region. Leave key usage permissions empty in the Create-key wizard, then open the key's Key policy tab and replace the JSON with the policy shown here.
Register and attach the key
Register the key
In the Claude Console, open Settings > Encryption keys and click Add key. Enter a display name, then choose the key from the key picker or choose Enter ARN manually and paste the key ARN, and click Add. The key must be in the AWS account that hosts your organization; cross-account keys are not supported. The picker lists the enabled, customer-managed, symmetric, single-region keys in your account in one of your organization's regions; for a key the picker doesn't list, enter the ARN. It lists keys only if the principal you signed in with can call
kms:ListKeysandkms:DescribeKey.Attach the key to a workspace
Attach the key to a new workspace before you send any requests to that workspace. For a workspace that already receives requests, the key can take up to a day to take effect. In the Claude Console, open the workspace and, under Security, select the key in Encryption key, save, and confirm. You can also select a key when you create a workspace in the Claude Console, but only if your key policy does not yet name specific workspaces (no
EncryptionContextcondition, and the account-wideaws:SourceArnpattern rather than individual workspace ARNs), because the workspace's ID and compartment ID are assigned at creation. Once attached, a workspace's key can't be changed.This is when the key is validated: the attach call checks your principal's access to the key and performs an encrypt/decrypt round against it with the workspace's compartment ID as the encryption context, so a problem with either the key policy or your principal's permissions surfaces as an error on that call. If the attach fails with a KMS access error, check the following:
- The key policy names the
aws-external-anthropic.amazonaws.comservice principal and grantskms:Encrypt,kms:Decrypt, andkms:GenerateDataKey, pluskms:DescribeKeyin a separate statement that has noEncryptionContextcondition. - The
aws:SourceArncondition matches this workspace's ARN (your account ID, and the workspace if you listed specific ARNs), and anyEncryptionContextcondition includes this workspace's compartment ID. - The key is enabled, single-region, and in the same AWS account and region as the workspace.
- The principal you are signed in as has
kms:DescribeKey,kms:Encrypt, andkms:Decrypton the key. - No service control policy or resource control policy in your AWS organization prevents the service principal or your principal from using the key.
- If the policy looks right and the attach still fails, find the denied
kms:event in CloudTrail in the key's account (it shows the calling principal and, for cryptographic calls, the encryption context), then retry with theaws:SourceArncondition temporarily removed to tell a source-ARN mismatch apart from an encryption-context mismatch. Once the key is attached, whether on that retry or after you correct the encryption context, restore theArnLikeentry on both service-principal statements withkms:PutKeyPolicy, using the account-wideaws:SourceArnpattern or the ARN of every workspace the key is attached to.
- The key policy names the
Terraform
For infrastructure-as-code deployments, the same steps map to the aws provider with the aws_kms_key and aws_kms_alias resources.
Was this page helpful?