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.
kms:CreateKey and kms:PutKeyPolicy).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-usCreate the KMS key with a cross-account key policy
The key policy grants Anthropic's IAM role cross-account access. Three statements are required:
kms:Encrypt and kms:Decrypt actions, which Anthropic uses to encrypt and decrypt the data keys that protect your workspace data (envelope encryption).DescribeKey has no EncryptionContext parameter, so an EncryptionContext condition 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.Arn from the output. You need it when you register the key in the next step.
The EncryptionContext condition 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 the Condition block from the AllowAnthropicCMEKCrypto statement and add it later with kms: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 915198916910 under key usage permissions there, the generated policy grants the whole Anthropic account broader actions (such as kms:ReEncrypt* and kms:GenerateDataKey*) with no EncryptionContext condition, 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 the anthropic-cmek-client-us role, with the EncryptionContext condition).




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:
AccessDeniedException when a kms:EncryptionContext:anthropic:compartment_uuid condition 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 the Condition block from the AllowAnthropicCMEKCrypto statement and re-validate.aws:PrincipalOrgID does 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.aws kms get-key-policy --key-id <id> --policy-name default.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}")On Claude Platform on AWS, CMEK uses AWS KMS keys only, and setup differs from the preceding sections in these ways:
aws-external-anthropic.amazonaws.com. Anthropic's IAM role and account ID are not used, so the ARN for Anthropic does not apply.mrk-) and alias ARNs are rejected; use the key ARN.EncryptionContext condition therefore needs no all-zeros entry.ekey_ ID.kms:CreateKey and kms:PutKeyPolicy).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 is RegisterKey (with ListKeys and GetKey to view registrations), and attaching one is UpdateWorkspace or CreateWorkspace. The external key actions (and CreateWorkspace) are account-scoped, so grant them on Resource: "*"; a policy limited to workspace ARNs does not include them.kms:DescribeKey, kms:Encrypt, and kms:Decrypt on the key. Your principal's access to the key is checked when you attach it, in addition to the service principal's.kms:ListKeys and kms:DescribeKey for the principal you sign in with. Without them, paste the key ARN instead.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 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 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:ListKeys and kms: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 EncryptionContext condition, and the account-wide aws:SourceArn pattern 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:
aws-external-anthropic.amazonaws.com service principal and grants kms:Encrypt, kms:Decrypt, and kms:GenerateDataKey, plus kms:DescribeKey in a separate statement that has no EncryptionContext condition.aws:SourceArn condition matches this workspace's ARN (your account ID, and the workspace if you listed specific ARNs), and any EncryptionContext condition includes this workspace's compartment ID.kms:DescribeKey, kms:Encrypt, and kms:Decrypt on the key.kms: event in CloudTrail in the key's account (it shows the calling principal and, for cryptographic calls, the encryption context), then retry with the aws:SourceArn condition temporarily removed to tell a source-ARN mismatch apart from an encryption-context mismatch.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?