
AWS KMS (Key Management Service)AuthorCloudBrum editorial teamLast reviewedReading time~12 minLevelBeginner to advanced
Amazon Web Services · Security · Encryption key management
AWS KMS keeps the keys, and your services ask it to encrypt and decrypt their data. You create a KMS key, decide who may administer it and who may use it, and from then on S3, EBS, RDS, Lambda and your own code call KMS instead of holding key material themselves. The key never leaves the service’s hardware security modules in plain form, and every use is written to CloudTrail. Two mistakes cause most of the trouble: a key policy that locks people out, and a busy workload that sends millions of requests a month to a key that costs one dollar to store.
On this page (17 sections)
Mind map: AWS KMS at a glance
Free to share. The downloaded image includes the CloudBrum link.
Key features (summary)
- Keys that stay in the hardwareA KMS key is created inside hardware security modules that AWS runs. You can use it to encrypt and decrypt, but you can’t read the key material of a symmetric key, and so neither can anyone who steals a credential.
- Envelope encryptionKMS encrypts small things directly (up to 4 KB). For anything larger it hands your code a data key, in plain and encrypted form. You encrypt the data locally with the plain key, throw it away, and store the encrypted key next to the data.
- Three ways to grant accessEvery key has a key policy. IAM policies can add permissions only if the key policy allows it, and grants hand out narrow, temporary rights to a service or a role. Conditions such as kms:ViaService limit a key to one service.
- RotationAutomatic rotation creates new key material on a schedule of 90 to 2,560 days (365 by default) and keeps the old material so existing data can still be read. You can also rotate on demand.
- Multi-Region keysA multi-Region key has the same key ID and key material in several Regions, so data encrypted in one Region can be decrypted in another without a round trip. Each replica keeps its own policy.
- Built into AWS servicesS3, EBS, RDS, DynamoDB, Lambda, Secrets Manager and many other services can encrypt with a KMS key you choose, and you don’t write any cryptography code for that.
- More than one kind of keyBesides symmetric keys there are RSA and elliptic curve key pairs for signing and encryption, HMAC keys, and ML-DSA keys for post-quantum signatures. You can import your own key material, or keep the key outside AWS in an external key store.
- Every use is loggedEach call to KMS is recorded in CloudTrail with the caller, the key and the encryption context, which is how you answer who decrypted what and when.
Basic concepts
- KMS key
- The main resource in the service. It used to be called a customer master key (CMK). A KMS key holds key material and metadata such as its state, usage and key policy.
- AWS owned, AWS managed and customer managed keys
- AWS owned keys sit in service accounts and you never see them. AWS managed keys (for example aws/s3) appear in your account, free of a monthly fee, and you can’t change their policy. Customer managed keys are the ones you create and control.
- Key policy
- A resource policy attached to one key. It is the first thing KMS checks, and an IAM policy has no effect unless the key policy allows IAM to take part.
- Grant
- A temporary, narrow permission on a key that you or an AWS service creates for a grantee, usually for a single task such as attaching an encrypted volume.
- Data key
- A key that KMS generates for you to encrypt data outside KMS. You get it in plain text and as a copy encrypted under a KMS key.
- Envelope encryption
- Encrypting data with a data key, and then encrypting that data key with a KMS key. It keeps large data out of KMS and keeps the number of calls low.
- Encryption context
- Extra key and value pairs that KMS binds to the ciphertext. They aren’t secret, they appear in CloudTrail, and the same pairs must be supplied to decrypt.
- Alias
- A friendly name such as alias/orders-prod that points to a key. You can move an alias to a new key without changing code.
- Multi-Region key
- A set of related keys in different Regions that share an ID and key material. One is the primary and the others are replicas.
- Key material
- The cryptographic secret inside a KMS key. KMS can generate it, you can import it, or it can live in an external key manager.
- Custom key store
- A key store backed by an AWS CloudHSM cluster that you own, for keys that must sit in a single-tenant HSM.
- External key store (XKS)
- A key store where the key material stays in an external key manager that you run outside AWS, and KMS sends the cryptographic operations to it.
- Key state
- Enabled, disabled, pending deletion, pending import and so on. A key that isn’t enabled can’t be used, and neither can the data that depends on it.
How to create & configure it
Create a customer managed key and use it with the AWS CLI
- Decide who administers and who usesWrite down two lists: the role that manages the key and the roles or services that may encrypt and decrypt with it. Keep them separate, because the administrator doesn’t need to read the data.
- Write the key policy firstStart from a policy that names the administrator role, the user roles and the account root (which turns on IAM policies). A key policy that leaves everyone out is the one mistake that needs AWS Support to fix.
- Create the key and an aliasRun create-key with the policy, then create-alias with a name such as alias/orders-prod. Use the alias in code and in other services' settings.
- Turn on rotationEnable automatic rotation and set the period. A year is the default and a shorter period is a policy decision, because every rotation adds a billable version of the key material.
- Point a service at the keyFor example, set default encryption on an S3 bucket to SSE-KMS with your key and switch on S3 Bucket Keys, so S3 doesn’t call KMS for every object.
- Use data keys in your own codeAsk for a data key with generate-data-key, encrypt locally with an AES-GCM library, keep the encrypted data key with the ciphertext and pass an encryption context that names the tenant or record.
- Allow a service through a grant or a conditionWhere a service needs access for a task, create a grant. Where a role should use the key only through one service, add kms:ViaService to the policy.
- Watch itSend CloudTrail to a log bucket and alert on ScheduleKeyDeletion, DisableKey, policy changes and a sudden rise in Decrypt calls.
- Plan the end of the keyNever delete a key you are unsure about. Disable it first, wait, and then schedule deletion with the longest waiting period. Data that was encrypted under a deleted key is gone for good.
Tip: do the first run in a test account with a throwaway bucket. The commands are short, and the key policy is the only part that is hard to undo. See the code references for the same setup as Terraform.
Common issues after configuration
| Symptom | Likely cause | What to check / fix |
|---|---|---|
| AccessDeniedException: ... is not authorized to perform: kms:Decrypt | The key policy doesn’t allow the caller, or it allows IAM but the role’s policy lacks the action, or a condition such as kms:ViaService doesn’t match | Check both sides: the key policy for the principal and the identity policy for the action. Read the denial in CloudTrail to see which key and context were used. |
| KMSInvalidStateException or DisabledException | The key is disabled, pending deletion or pending import | Look at describe-key. Enable the key, or cancel the deletion with cancel-key-deletion if the waiting period isn’t over. |
| ThrottlingException: Rate exceeded | The shared per-second quota for the Region and key type was reached, often by many small encrypt or decrypt calls | Use envelope encryption and cache data keys with the Encryption SDK, enable S3 Bucket Keys, retry with backoff, and ask for a quota increase if the load is legitimate. |
| InvalidCiphertextException on decrypt | The encryption context is different, the ciphertext was changed, or it was produced by another key or Region | Pass the same context that was used to encrypt, and check that you’re calling the Region where the key lives. |
| The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access | The call went to another Region or another account, or the key was deleted | Check the key ARN in the ciphertext metadata, use a multi-Region key for cross-Region reads, and confirm cross-account access in both policies. |
| ValidationException when encrypting a file | The payload is more than 4,096 bytes, which is the limit for a direct Encrypt call | Generate a data key and encrypt the file locally, then store the encrypted data key with it. |
| MalformedPolicyDocumentException or a key nobody can manage | A policy update removed the only principals who could change it, or names a principal that doesn’t exist | Test policy changes in a copy first. If a key is already locked, only AWS Support can help, so keep the account root in the policy. |
| A cross-account user can’t use the key | Only one side was set up: the key policy trusts the other account, but nobody there granted the role permission, or the opposite | Add the external account (or role) to the key policy and add kms:Decrypt, kms:GenerateDataKey and the other needed actions to the role in the other account. |
| An encrypted EBS volume or RDS instance won’t start after a key change | The key was disabled or its policy dropped the service’s grant | Re-enable the key and recreate the grant. Keep a runbook for the key and a monitor that warns before anyone disables it. |
| The monthly KMS bill is bigger than the number of keys suggests | Requests, not storage, dominate: S3 with SSE-KMS and no bucket key, or a Lambda that decrypts on every invocation | Turn on S3 Bucket Keys, cache decrypted values, and read the CloudTrail event counts by key before you change anything. |
| Decrypt works in one Region and not in the DR Region | The key is single-Region, so the DR Region has no copy of it | Use a multi-Region key for data that must be readable in both, and replicate it before you need it. |
Use cases: when and where to use it
Good fit
- Teams that must show auditors who can use a key, and who did
- Any workload that stores personal, financial or health data on AWS and needs encryption at rest under a key you control
- Applications that encrypt their own data with envelope encryption
- Signing tokens, documents or code with asymmetric keys that never leave the hardware
- Disaster-recovery designs that need the same data readable in two Regions
- Organisations that want one central place to disable a key and so cut off access to the data
Consider something else
- Passwords, API tokens and database credentials → AWS Secrets Manager, which uses KMS to protect them
- TLS certificates for your domain → AWS Certificate Manager
- A key that must live in a dedicated, single-tenant HSM that you manage → AWS CloudHSM, or a KMS custom key store
- Encryption you do on a device or in a browser → a client-side library and your own key handling
- The same job on other clouds → compare Azure Key Vault and Cloud KMS
Pros: why consider it?
Why teams choose it
- Keys never leave the hardware in plain form, and every use is logged
- Native integration with most AWS storage, database and compute services
- Fine-grained control through key policies, IAM and grants
- Automatic and on-demand rotation without changing the data or the code
- Multi-Region keys for cross-Region reads and disaster recovery
- A low fixed price per key, and a free tier of requests
Trade-offs to weigh
- A key policy mistake can lock everybody out, and the fix goes through AWS Support
- Request charges and quotas surprise busy workloads
- Deleted keys can’t be recovered, and neither can the data under them
- Keys are Regional unless you create a multi-Region key
- Not a place for passwords or API tokens, which belong in Secrets Manager
- Cross-account setups need matching policies on both sides
Common threats, vulnerabilities & risks
| Risk | Severity | Why it matters | Mitigation |
|---|---|---|---|
| Scheduling the deletion of a key that still protects data | High | Once the waiting period ends, the key material is destroyed and the encrypted data can’t be read again. | Disable the key first, watch for failures, use the 30-day waiting period and alert on ScheduleKeyDeletion. |
| A key policy that grants administrators the use of data | High | Anyone who can change the policy can give themselves decrypt rights, so the key doesn’t protect the data from them. | Split administrators from users, and use a service control policy to limit who can edit key policies. |
| Wildcard principals in a key policy | High | Principal: * without strict conditions makes the key usable by far more identities than intended. | Name roles, add kms:CallerAccount or aws:PrincipalOrgID conditions, and review policies with IAM Access Analyzer. |
| A policy change that locks everyone out | Medium | A key with no usable administrator can only be recovered through AWS Support. | Keep the account root statement, and test policy edits on a scratch key first. |
| No rotation or a forgotten rotation setting | Medium | Key material is used for years, which widens the damage of a leak and fails some compliance checks. | Turn on rotation by default in your module, and check it with an AWS Config rule. |
| Everything encrypted under one key | Medium | A single key is a large blast radius and a single point for throttling. | Use a key per application and environment, and a separate key for each data classification. |
| Data keys or plaintext logged or cached too long | Medium | A data key that leaks in a log defeats the whole design. | Keep plain data keys in memory only, clear them after use and keep them out of logs and traces. |
| Cross-Region data without a key plan | Low–Med | A backup or replica in another Region that was encrypted with a single-Region key can’t be read there. | Use multi-Region keys or re-encrypt on copy, and test a restore in the second Region. |
| No alert on key events | Low–Med | Disabling a key or changing its policy can go unseen for days. | Create CloudWatch alarms or EventBridge rules for DisableKey, ScheduleKeyDeletion and PutKeyPolicy. |
Performance optimisation
- Use envelope encryption and keep data keys in a short-lived cache, so a busy service doesn’t call KMS for every record.
- Enable S3 Bucket Keys on buckets that use SSE-KMS, which cuts the number of KMS requests sharply, according to AWS.
- Keep keys in the same Region as the workload, since every call crosses the network to the KMS endpoint.
- Use a VPC interface endpoint for KMS so calls from private subnets don’t go through a NAT gateway.
- Retry with exponential backoff and jitter on throttling errors, and let the SDK do it.
- Use the AWS Encryption SDK when you need caching of data keys and a standard message format.
- Spread very hot workloads across several keys, because quotas are per key type and Region, and check them in Service Quotas.
- Use asymmetric keys only where needed, since their operations are slower and cost more than symmetric ones.
Reduce monthly cost
FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for AWS KMS.
- Count the keys first: each customer managed key costs about one dollar a month, so a key per application and stage is cheap, and a key per customer record is not.
- Use AWS managed keys where the default policy is acceptable, since they have no monthly fee.
- Turn on S3 Bucket Keys, because object-level KMS requests are the usual source of a large bill.
- Cache data keys and decrypted values in your application for a short time.
- Remember that rotation adds charges for each older version of key material that stays in the key. A shorter period costs a bit more.
- Delete keys that nobody needs, after the disable-and-wait routine, so you stop paying for them.
- Watch asymmetric and HMAC requests, which are priced higher than symmetric ones.
- Check multi-Region replicas: each replica is billed as its own key.
- Look at requests by key in CloudTrail or Cost Explorer before you decide which workload to tune.
- Tag keys with an owner and a project, and add a budget alert on KMS spend.
Prices come from AWS's public pricing page and secondary sources as we read them in October 2026. They differ by Region and change over time, so check the live page and the calculator before you plan around them (see Pricing).
Security optimisation
- Write separate key administrators and key users, and avoid giving one role both.
- Keep the account root statement in the key policy so IAM policies work, and so the key can’t be orphaned.
- Use encryption context and the kms:EncryptionContext condition to tie a key’s use to a tenant, table or application.
- Limit a role to a service with kms:ViaService, and to your organisation with aws:PrincipalOrgID when sharing keys.
- Turn on automatic rotation for symmetric keys, and decide a rotation period that matches your policy.
- Set a service control policy that denies kms:ScheduleKeyDeletion and kms:DisableKey except for a break-glass role.
- Use IAM Access Analyzer to find keys shared with external accounts, and review the findings.
- Send CloudTrail to a protected bucket in another account, and alert on key policy changes.
- Prefer customer managed keys for sensitive data, so that you can disable them and show their policy.
- Use multi-Region keys only where you need them, and give each replica the policy it needs, not a copy of the primary’s.
Governance & compliance
Guardrails
- A shared Terraform module for KMS keys with rotation on, an alias, a tagged owner and a standard key policy
- A service control policy that blocks key deletion and key disabling outside a break-glass role
- A naming and tagging rule: one key per application and environment, with an owner and a data classification tag
- A list of approved data classes and which key type each may use (for example, customer managed keys for restricted data)
Continuous checks (AWS Config)
- “cmk-backing-key-rotation-enabled” on every customer managed symmetric key
- “kms-cmk-not-scheduled-for-deletion” to catch keys on the way out
- “s3-default-encryption-kms” on buckets that must use KMS
- “encrypted-volumes” and “rds-storage-encrypted” for the data stores that rely on keys
- Security Hub’s KMS controls for key policies and rotation
AWS CloudTrail records every KMS call, AWS Config checks the rules above, IAM Access Analyzer reports keys shared outside the account, and AWS Artifact holds compliance reports. AWS runs the HSMs and the service, and AWS says the HSMs hold a FIPS 140-3 Level 3 validation. You own the key policies, the rotation settings, who may use each key and the decision to delete.
Reduce carbon footprint
- Cache data keys and decrypted values, so fewer requests travel to the KMS endpoint.
- Turn on S3 Bucket Keys, which cuts request volume for object-heavy buckets.
- Delete test keys and old multi-Region replicas that you no longer use.
- Where data rules allow and latency doesn’t matter, run in a Region with a cleaner power grid.
- Keep asymmetric operations for places that need them, since they use more compute than symmetric ones.
- The Customer Carbon Footprint Tool reports emissions per account. It doesn’t break out KMS, so don’t put a number on it.
Pricing
Purchase options
Customer managed keys About $1 per key per month
Billed hourly. Symmetric, asymmetric, HMAC and imported-material keys all carry the fee, and each multi-Region replica counts as a key.
AWS managed and AWS owned keys No monthly fee
Created for you by services such as S3 and EBS. You pay only for the requests that exceed the free tier.
Requests From $0.03 per 10,000
A free tier of 20,000 requests a month applies. Asymmetric operations cost more, and the price depends on the key spec.
Rotation and extra features Varies
Rotated key material is billed as additional versions of the key, and custom key stores need a CloudHSM cluster that you pay for separately.
What you actually pay for
- Each customer managed key and each multi-Region replica
- Requests beyond the monthly free tier, from services and from your own code
- Older versions of rotated key material, according to AWS’s pricing page
- CloudHSM clusters behind a custom key store, and the infrastructure behind an external key store
- CloudTrail storage and data transfer for logs and cross-Region traffic
Rates differ by Region and key type, and sources disagree on small details such as how rotated key material is billed. See the official AWS KMS pricing page and the AWS Pricing Calculator.
Important code references
An orders-prod key for an orders service: a customer managed key whose policy separates the administrator role from the application role, rotating every 180 days, with an S3 bucket encrypted under it and Bucket Keys switched on. The AWS CLI tab creates it step by step and Terraform builds the same set. The Python tab encrypts a payload with a data key (envelope encryption) and decrypts it again, and the C# tab audits every customer managed key in an account for rotation, state and sharing. Replace the account number and the role names with your own. The key policy is the part to read twice.
# Placeholders: replace the account, role names and bucket with your own.
REGION=ap-south-1
ACCOUNT=111122223333
BUCKET=orders-prod-data-example
# 1. The key policy. Admins manage the key but cannot use it for data. The app role can use it but cannot manage it.
cat > key-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{"Sid": "EnableIamPolicies", "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::$ACCOUNT:root"}, "Action": "kms:*", "Resource": "*"},
{"Sid": "KeyAdministration", "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::$ACCOUNT:role/kms-key-admin"},
"Action": ["kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*", "kms:Put*", "kms:Update*", "kms:Revoke*",
"kms:Disable*", "kms:Get*", "kms:TagResource", "kms:UntagResource", "kms:ScheduleKeyDeletion", "kms:CancelKeyDeletion"], "Resource": "*"},
{"Sid": "KeyUsage", "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::$ACCOUNT:role/orders-app"},
"Action": ["kms:Decrypt", "kms:GenerateDataKey", "kms:DescribeKey"], "Resource": "*",
"Condition": {"StringEquals": {"kms:EncryptionContext:app": "orders"}}}
]
}
EOF
# 2. Create the key, give it an alias and turn on rotation every 180 days.
KEY_ID=$(aws kms create-key --region $REGION --description "orders-prod data key" --key-usage ENCRYPT_DECRYPT --key-spec SYMMETRIC_DEFAULT \
--policy file://key-policy.json --tags TagKey=app,TagValue=orders TagKey=env,TagValue=prod --query KeyMetadata.KeyId --output text)
aws kms create-alias --region $REGION --alias-name alias/orders-prod --target-key-id "$KEY_ID"
aws kms enable-key-rotation --region $REGION --key-id "$KEY_ID" --rotation-period-in-days 180
aws kms get-key-rotation-status --region $REGION --key-id "$KEY_ID"
# 3. Encrypt a bucket with the key, and use S3 Bucket Keys so S3 doesn't call KMS for every object.
aws s3api put-bucket-encryption --bucket $BUCKET --server-side-encryption-configuration '{
"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "aws:kms", "KMSMasterKeyID": "alias/orders-prod"}, "BucketKeyEnabled": true}]}'
# 4. A data key for envelope encryption: you get a plain copy to encrypt with, and an encrypted copy to store.
aws kms generate-data-key --region $REGION --key-id alias/orders-prod --key-spec AES_256 --encryption-context app=orders \
--query '{encrypted:CiphertextBlob,plain:Plaintext}'
# 5. A grant lets a role use the key for one task, without editing the policy.
aws kms create-grant --region $REGION --key-id "$KEY_ID" --grantee-principal arn:aws:iam::$ACCOUNT:role/orders-batch \
--operations Decrypt GenerateDataKey --constraints EncryptionContextSubset={app=orders}
# 6. A multi-Region key for data that must be readable in a second Region.
DR_KEY=$(aws kms create-key --region $REGION --multi-region --description "orders-dr data key" --query KeyMetadata.KeyId --output text)
aws kms replicate-key --region $REGION --key-id "$DR_KEY" --replica-region ap-southeast-1
# 7. Ending a key: disable it first and watch for failures. Deletion waits 30 days and cannot be undone after that.
aws kms disable-key --region $REGION --key-id "$KEY_ID"
aws kms schedule-key-deletion --region $REGION --key-id "$KEY_ID" --pending-window-in-days 30
aws kms cancel-key-deletion --region $REGION --key-id "$KEY_ID"
# Placeholders: pass in your own account number and role names.
provider "aws" {
region = "ap-south-1"
}
provider "aws" {
alias = "singapore"
region = "ap-southeast-1"
}
variable "account_id" {
type = string
}
variable "admin_role_name" {
type = string
default = "kms-key-admin"
}
variable "app_role_name" {
type = string
default = "orders-app"
}
data "aws_iam_policy_document" "orders_key" {
statement {
sid = "EnableIamPolicies"
actions = ["kms:*"]
resources = ["*"]
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${var.account_id}:root"]
}
}
statement {
sid = "KeyAdministration"
actions = [
"kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*", "kms:Put*", "kms:Update*",
"kms:Revoke*", "kms:Disable*", "kms:Get*", "kms:TagResource", "kms:UntagResource",
"kms:ScheduleKeyDeletion", "kms:CancelKeyDeletion",
]
resources = ["*"]
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${var.account_id}:role/${var.admin_role_name}"]
}
}
statement {
sid = "KeyUsage"
actions = ["kms:Decrypt", "kms:GenerateDataKey", "kms:DescribeKey"]
resources = ["*"]
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${var.account_id}:role/${var.app_role_name}"]
}
condition {
test = "StringEquals"
variable = "kms:EncryptionContext:app"
values = ["orders"]
}
}
}
resource "aws_kms_key" "orders" {
description = "orders-prod data key"
key_usage = "ENCRYPT_DECRYPT"
customer_master_key_spec = "SYMMETRIC_DEFAULT"
enable_key_rotation = true
rotation_period_in_days = 180
deletion_window_in_days = 30
policy = data.aws_iam_policy_document.orders_key.json
tags = {
app = "orders"
env = "prod"
}
}
resource "aws_kms_alias" "orders" {
name = "alias/orders-prod"
target_key_id = aws_kms_key.orders.key_id
}
resource "aws_s3_bucket" "data" {
bucket = "orders-prod-data-example"
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
bucket_key_enabled = true
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.orders.arn
}
}
}
# A multi-Region primary key and a replica, for data that must be readable in a second Region.
resource "aws_kms_key" "orders_dr" {
description = "orders-dr data key"
multi_region = true
enable_key_rotation = true
deletion_window_in_days = 30
}
resource "aws_kms_replica_key" "orders_dr_singapore" {
provider = aws.singapore
description = "orders-dr replica"
primary_key_arn = aws_kms_key.orders_dr.arn
deletion_window_in_days = 30
}
output "orders_key_arn" {
value = aws_kms_key.orders.arn
}
# pip install boto3 cryptography
# Envelope encryption: KMS makes a data key, AES-GCM encrypts the payload locally, and only the encrypted data key is stored with it.
import json
import os
import boto3
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
kms = boto3.client("kms", region_name="ap-south-1")
KEY = "alias/orders-prod"
def encrypt(payload, tenant):
context = {"app": "orders", "tenant": tenant}
data_key = kms.generate_data_key(KeyId=KEY, KeySpec="AES_256", EncryptionContext=context)
nonce = os.urandom(12)
ciphertext = AESGCM(data_key["Plaintext"]).encrypt(nonce, payload, json.dumps(context, sort_keys=True).encode())
return { # the plain data key is never stored
"key": data_key["CiphertextBlob"].hex(),
"nonce": nonce.hex(),
"data": ciphertext.hex(),
"context": context,
}
def decrypt(envelope):
context = envelope["context"]
plain_key = kms.decrypt(CiphertextBlob=bytes.fromhex(envelope["key"]), EncryptionContext=context)["Plaintext"]
return AESGCM(plain_key).decrypt(bytes.fromhex(envelope["nonce"]), bytes.fromhex(envelope["data"]),
json.dumps(context, sort_keys=True).encode())
if __name__ == "__main__":
sealed = encrypt(b'{"order": 1042, "card_last4": "4242"}', tenant="acme")
print("stored:", {k: (v[:16] + "...") if isinstance(v, str) else v for k, v in sealed.items()})
print("read back:", decrypt(sealed).decode())
// dotnet add package AWSSDK.KeyManagementService
// Audits every customer managed key in the Region: state, rotation, age and whether the key policy lets an outside principal in.
using System.Text.Json;
using Amazon.KeyManagementService;
using Amazon.KeyManagementService.Model;
using var kms = new AmazonKeyManagementServiceClient();
int problems = 0;
string? marker = null;
do
{
var page = await kms.ListKeysAsync(new ListKeysRequest { Marker = marker, Limit = 100 });
foreach (var item in page.Keys)
{
KeyMetadata key = (await kms.DescribeKeyAsync(new DescribeKeyRequest { KeyId = item.KeyId })).KeyMetadata;
if (key.KeyManager != KeyManagerType.CUSTOMER) continue;
var notes = new List<string>();
if (key.KeyState == KeyState.PendingDeletion) notes.Add($"scheduled for deletion on {key.DeletionDate:yyyy-MM-dd}");
if (key.KeyState == KeyState.Disabled) notes.Add("disabled");
bool symmetric = key.KeySpec == KeySpec.SYMMETRIC_DEFAULT && key.Origin == OriginType.AWS_KMS;
if (symmetric && key.KeyState == KeyState.Enabled)
{
var rotation = await kms.GetKeyRotationStatusAsync(new GetKeyRotationStatusRequest { KeyId = key.KeyId });
if (rotation.KeyRotationEnabled != true) notes.Add("automatic rotation is off");
}
var policy = (await kms.GetKeyPolicyAsync(new GetKeyPolicyRequest { KeyId = key.KeyId, PolicyName = "default" })).Policy;
using var doc = JsonDocument.Parse(policy);
foreach (var st in doc.RootElement.GetProperty("Statement").EnumerateArray())
{
if (!st.TryGetProperty("Principal", out var p)) continue;
string text = p.ToString();
if (text == "*" || text.Contains("\"AWS\":\"*\"")) { notes.Add("key policy allows any principal"); break; }
}
string name = key.Description.Length > 0 ? key.Description : key.KeyId;
Console.WriteLine($"{key.KeyId} {key.KeyState,-16} created {key.CreationDate:yyyy-MM-dd} {name}");
foreach (var n in notes) { Console.WriteLine($" ! {n}"); problems++; }
}
marker = page.Truncated == true ? page.NextMarker : null;
} while (marker != null);
Console.WriteLine(problems == 0 ? "No problems found." : $"{problems} problem(s) found.");
return problems == 0 ? 0 : 1;
Best videos to explore
Videos picked for this service. Each one is labelled with its source, opens on YouTube if you prefer, and loads only when you press play.
Interview questions
BasicWhat is AWS KMS?
It’s the AWS service that creates and controls encryption keys. The keys live in hardware security modules, and you and AWS services ask KMS to encrypt, decrypt, sign or verify, so the key material itself is never handed out in plain form. Every request is logged in CloudTrail.
BasicWhat is the difference between AWS owned, AWS managed and customer managed keys?
AWS owned keys are used inside service accounts and you can’t see them. AWS managed keys, such as aws/s3, appear in your account and are free of a monthly fee, but you can’t edit their policy. Customer managed keys are the ones you create, so you control the policy, rotation and deletion, and you pay about a dollar a month for each.
BasicWhy can’t I encrypt a large file directly with KMS?
A direct Encrypt call accepts at most 4,096 bytes. For bigger data you use envelope encryption: ask KMS for a data key, encrypt the file locally, and store the encrypted data key with it.
IntermediateHow does envelope encryption work with KMS?
Your code calls GenerateDataKey and receives a plain key and a copy encrypted under the KMS key. It encrypts the data with the plain key, discards that key, and stores the encrypted copy next to the ciphertext. To read the data it sends the encrypted key to Decrypt, gets the plain key back, and decrypts locally. That keeps large data away from KMS and keeps requests low.
IntermediateHow do key policies and IAM policies work together?
Every KMS key has a key policy, and KMS checks it first. If the key policy has the statement that trusts the account root, IAM policies can then grant access too. Without that statement, only principals named in the key policy can use the key, whatever their IAM permissions say. Cross-account use needs both the key policy and the other account’s IAM policy to allow it.
IntermediateWhat is an encryption context and why use it?
It’s a set of non-secret key and value pairs that KMS attaches to the encryption as additional authenticated data. Decryption fails unless the same pairs are given, so it ties ciphertext to a tenant or record. It also appears in CloudTrail and can be used in policy conditions.
AdvancedHow would you design KMS keys for a multi-tenant application?
Decide the isolation you need. A key per environment and application is cheap and normal. A key per tenant gives strong isolation and the ability to disable one tenant, at the cost of key count and management. A common middle path is one key per application with the tenant ID in the encryption context and in the policy conditions, and per-tenant keys only for tenants with a contractual need.
AdvancedHow do you handle disaster recovery with KMS?
Single-Region keys can’t decrypt in another Region, so replicated data would be unreadable there. Use multi-Region keys, which share key ID and material across Regions, and replicate the key before you need it. Each replica has its own key policy, so set it deliberately, and test a restore in the second Region.
AdvancedWhat goes wrong when you delete a KMS key, and how do you prevent it?
After the waiting period (7 to 30 days) the key material is destroyed, and anything encrypted under it, such as EBS snapshots, S3 objects or database backups, can’t be read. Prevent it by disabling the key first and watching for errors, using the 30-day window, alerting on ScheduleKeyDeletion, and blocking the action with a service control policy for everyone but a break-glass role.
AdvancedWhen would you use a custom key store or an external key store instead of standard KMS keys?
Use a custom key store, backed by CloudHSM, when a rule demands a single-tenant HSM under your control. Use an external key store when the key material must stay outside AWS, in a key manager you run. Both come with trade-offs: more operations, higher latency, lower availability that depends on your side, and limits such as no automatic rotation for keys in a custom key store. Most workloads don’t need either.
Similar or alternative services on other clouds
| Capability | AWS | Azure | Google Cloud |
|---|---|---|---|
| Service | AWS KMS | Azure Key Vault (keys) and Managed HSM | Cloud KMS |
| Holds secrets and certificates too | No: AWS Secrets Manager and AWS Certificate Manager | Yes: keys, secrets and certificates in one vault | No: Secret Manager and Certificate Manager |
| Key containers | Flat: keys in an account and Region, found by alias | Vaults, with keys inside | Key rings, which hold keys, which hold versions |
| Hardware protection | HSMs in the service, plus CloudHSM key stores | Software keys, HSM-backed keys (Premium), or a Managed HSM pool | Software, HSM (Cloud HSM) or external (Cloud EKM) protection levels |
| Access model | Key policy plus IAM and grants | Azure RBAC (or older access policies) | IAM roles on the key ring or key |
| Rotation | Automatic every 90 to 2,560 days, or on demand | Rotation policy on keys, set by time | Rotation schedule on a key creates new versions |
| Deleting a key | Wait 7 to 30 days, then the material is gone | Soft delete, with optional purge protection | Versions are scheduled for destruction, and key rings and keys can’t be deleted |
| Fixed cost | About $1 per customer managed key per month | Operations-based, plus per-key fees for HSM-backed keys | Per key version per month, higher for HSM and external |
For passwords and tokens look at AWS Secrets Manager, which stores them encrypted under a KMS key. Server disks that use KMS keys are on Amazon EC2, and object data on Amazon S3. Databases that encrypt under KMS include Amazon RDS.
Did you find this article helpful?
Your answer helps us improve this page for the next reader.
Sources and further reading
CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.
- What is AWS Key Management Service?Amazon Web Services
- AWS KMS key policiesAmazon Web Services
- Rotate AWS KMS keysAmazon Web Services
- Multi-Region keys in AWS KMSAmazon Web Services
- Request quotasAmazon Web Services
- Deleting AWS KMS keysAmazon Web Services
- AWS KMS pricingAmazon Web Services
- AWS KMS cryptographic detailsAmazon Web Services
- Terraform AWS provider: aws_kms_keyHashiCorp
