Skip to main content

AWS KMS Specific Cmk Remediation

Triage and Remediation​

Remediation​

Using Console

Below are step‑by‑step console instructions to find and safely remove/disallow specific AWS KMS CMKs.


1. Identify the specific CMKs​

  1. Sign in to the AWS Management Console.
  2. Go to Key Management Service (KMS):
    • In the search bar, type KMS and select Key Management Service.
  3. In the left navigation, choose Customer managed keys.
  4. Use filters/search to locate the specific CMKs by:
    • Key ID, Key ARN, or
    • Alias (e.g., alias/old-key, alias/disallowed-key).

Record:

  • Key ID / ARN
  • Region
  • Alias
  • Key type (symmetric/asymmetric, single‑Region/multi‑Region)

2. Check what uses the key (to avoid breaking workloads)​

For each CMK you plan to remove:

  1. In KMS, click the key ID to open the key details.
  2. Review:
    • Key policy – see which IAM principals can use it.
    • Key rotation and tags – may hint at usage/owner.
  3. Check Key usage tab (if available) or use AWS services consoles to see dependencies:
    • EBS: EC2 → Volumes → check Encryption column and KMS key field.
    • RDS / Aurora: RDS → DB instances → each instance’s Configuration → KMS key.
    • S3: S3 → Bucket → Properties → Default encryption → KMS key.
    • CloudTrail: CloudTrail → Trails → Storage → KMS key.
    • CloudWatch Logs, EFS, EKS, Lambda env vars, Secrets Manager, SSM Parameter Store: open each resource and confirm which KMS key is configured.
  4. Make a list of all resources still using this key.

Do not delete/disable the CMK until all critical resources are migrated to an allowed key.


3. Create or select an allowed replacement CMK (if needed)​

If your policy requires different or restricted CMKs:

  1. In KMS console, under Customer managed keys, choose Create key.
  2. Choose:
    • Key type: symmetric (most common) or asymmetric as needed.
    • Key usage: e.g., Encrypt and decrypt.
  3. Configure:
    • Key administrators (who can manage the key).
    • Key users (who can use it to encrypt/decrypt).
    • Any key policy requirements from your security standard.
  4. Add a clear alias (e.g., alias/standard-data-key).
  5. Complete creation.

Repeat if multiple distinct CMKs are required.


4. Migrate services off the disallowed CMK​

For each service that uses the disallowed CMK, update it to use the new/approved key:

Example patterns (AWS console)​

  • EBS volumes (new):
    EC2 → Launch instance → Advanced details → Encryption → select new KMS key.

  • EBS volumes (existing; snapshot‑based):

    1. Create a snapshot of the encrypted volume.
    2. Copy the snapshot and choose Encrypt with the new CMK.
    3. Create a new volume from the copied snapshot.
    4. Attach the new volume and migrate data (or use AMI based approach for root volumes).
  • RDS:

    • You cannot change KMS key on an existing encrypted DB directly.
      Typical approach:
      1. Take a snapshot of the DB.
      2. Copy the snapshot and choose the new CMK for encryption.
      3. Restore a new DB instance from the copied snapshot.
      4. Cut over your application to the new DB.
  • S3 default bucket encryption:

    1. S3 → select bucket → Properties.
    2. Under Default encryption, click Edit.
    3. Choose AWS KMS key and select the new CMK.
    4. For existing objects, use S3 Batch Operations or lifecycle/automation to re‑encrypt if required by policy.
  • CloudTrail:

    1. CloudTrail → Trails → select trail → Edit.
    2. Under Log file SSE-KMS encryption, select the new KMS key.
    3. Save changes.
  • CloudWatch Logs:

    1. CloudWatch → Log groups → select log group.
    2. Actions → Edit (or Edit encryption).
    3. Select the new KMS key.
  • Secrets Manager:

    1. Secrets Manager → select secret.
    2. Edit → choose Encryption key → select new CMK → save.
  • SSM Parameter Store (SecureString):

    • For each parameter: Edit the parameter and choose the new CMK. (Some may require re‑creation; check the console options.)

Repeat for all services that referenced the disallowed key.


5. Disable key usage (soft stop) for the disallowed CMKs​

Once you are sure no active workloads need the CMK:

  1. KMS → Customer managed keys → select the specific CMK.
  2. On the key details page, click Disable.
  3. Confirm Disable.

Effects:

  • New encrypt/decrypt operations will fail with this key.
  • Existing encrypted data remains encrypted; you can still re‑enable the key if you discover a missed dependency.

Keep the key disabled for a safety period your organization approves (e.g., 7–30 days) and monitor for failures in CloudWatch/CloudTrail.


6. Schedule CMK deletion (hard removal)​

When fully confident the key is no longer needed:

  1. In KMS → Customer managed keys, select the CMK.
  2. On the key details page, choose Schedule key deletion.
  3. Choose a waiting period (7–30 days; choose the maximum allowed if you want a safer rollback window).
  4. Confirm.

During the waiting period, you can Cancel deletion from the same key page if needed.

After the waiting period:

  • The key material and metadata are permanently deleted.
  • Any data still encrypted under this key becomes unrecoverable.

7. Prevent future creation/use of disallowed CMKs​

To keep the environment compliant:

  1. Use IAM policies and/or Service Control Policies (SCPs) (if using AWS Organizations) to:
    • Deny creation of CMKs that don’t adhere to your standards (based on tags, aliases, or regions).
    • Deny use of specific key ARNs (the ones you just removed or disallowed patterns).
  2. Optionally:
    • Centralize key creation and management to a limited admin group.
    • Enforce tagging or alias conventions for approved keys.

If you share the exact policy requirement (e.g., “no CMKs in account X”, or “no CMKs with alias starting with X”), I can tailor the console steps and example IAM/SCP snippets to that specific control.

Using CLI

Below are step‑by‑step AWS CLI–based instructions to remediate a finding that flags the existence of specific AWS KMS customer managed keys (CMKs) (for example: legacy, unused, non‑compliant, or shadow keys).

I’ll assume the goal is to identify those CMKs and securely decommission them (disable → schedule deletion), while avoiding breaking workloads.


1. Identify the Specific CMKs​

If you already have the Key IDs / ARNs from the finding, you can skip to step 3. Otherwise, list and filter.

# List all customer managed keys in the account
aws kms list-keys --query 'Keys[].KeyId' --output text

For each key, get details and tags (to identify the “specific” ones):

KEY_ID=<your-key-id>

aws kms describe-key --key-id "$KEY_ID"
aws kms list-resource-tags --key-id "$KEY_ID"

Common filters you might apply:

  • Key alias (e.g., alias/legacy-*, alias/test-*)
  • Tags (e.g., Environment=Dev, Owner=DeprecatedApp)
  • Creation date (CreationDate in describe-key output)
  • Key state (Enabled, Disabled, etc.)

You can get aliases to match keys more easily:

aws kms list-aliases

2. Confirm No Active Dependencies​

Before disabling or deleting a key, verify nothing critical uses it.

2.1. Check CloudTrail for usage (recent period)​

# Example: last 7 days, region-specific, adjust time as needed
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=$KEY_ID \
--max-results 50

Or search for the key ARN instead of KEY_ID if you have it.

If you see recent Encrypt, Decrypt, GenerateDataKey, etc., you must first migrate dependent workloads to another key (e.g., update services to use a new CMK).


3. Disable the Specific CMKs (Safe First Step)​

Disabling is reversible and is safer than immediate deletion.

# Disable the key
aws kms disable-key --key-id "$KEY_ID"

Verify:

aws kms describe-key --key-id "$KEY_ID" \
--query 'KeyMetadata.KeyState' --output text
# Should return: Disabled

If something breaks after disabling, you can re‑enable:

aws kms enable-key --key-id "$KEY_ID"

4. Schedule Deletion (Permanent Remediation)​

Once you’ve confirmed the CMK is not needed:

# Schedule deletion with a waiting period (7–30 days)
aws kms schedule-key-deletion \
--key-id "$KEY_ID" \
--pending-window-in-days 30

Verify:

aws kms describe-key --key-id "$KEY_ID" \
--query 'KeyMetadata.[KeyState,DeletionDate]' --output text
# Should show: PendingDeletion <date>

If you scheduled deletion by mistake and need to cancel it:

aws kms cancel-key-deletion --key-id "$KEY_ID"

5. Remove or Update Aliases Pointing to These CMKs​

If the finding is related to aliases pointing to non‑compliant keys, repoint or delete aliases.

5.1. Repoint alias to a compliant CMK​

ALIAS_NAME="alias/your-alias"
NEW_KEY_ID="<new-compliant-key-id>"

aws kms update-alias \
--alias-name "$ALIAS_NAME" \
--target-key-id "$NEW_KEY_ID"

5.2. Delete alias if not needed​

ALIAS_NAME="alias/old-key"

aws kms delete-alias --alias-name "$ALIAS_NAME"

6. (Optional) Enforce Future Compliance​

If the finding is about certain “types” of CMKs existing (e.g., keys without rotation, with bad policies):

  • Enable rotation on compliant keys:
aws kms enable-key-rotation --key-id "$KEY_ID"
  • Restrict who can create CMKs via IAM policies.
  • Use tags and config rules / Security Hub controls to detect non‑compliant CMKs early.

If you share one example Key ARN or the exact rule text (e.g., from Security Hub or a CSPM), I can give you precise CLI commands tailored to that specific misconfiguration.

Using Python

Below is a concise, step‑by‑step way to remediate disallowed / misconfigured AWS KMS CMKs using Python (boto3). Adjust to your policy (e.g., delete specific CMKs, disable them, or remove aliases).


1. Prerequisites​

pip install boto3

Configure AWS credentials with permissions for KMS (e.g., kms:ListKeys, kms:DescribeKey, kms:DisableKey, kms:ScheduleKeyDeletion, kms:DeleteAlias, etc.).


2. Identify the CMKs to Remediate​

You need a rule to detect “bad” CMKs, for example:

  • Keys with a specific alias name/pattern (e.g., alias/bad-key-*)
  • Keys in a certain account/region that must not exist
  • Keys with specific tags or key policies

2.1. List all CMKs and filter by criteria​

import boto3

kms = boto3.client('kms', region_name='us-east-1')

def list_all_keys():
keys = []
paginator = kms.get_paginator('list_keys')
for page in paginator.paginate():
keys.extend(page['Keys'])
return keys

def find_disallowed_keys(alias_prefix="alias/bad-key-"):
disallowed_key_ids = []

# 1) Map aliases to key IDs
alias_paginator = kms.get_paginator('list_aliases')
alias_map = {} # key_id -> [aliases]
for page in alias_paginator.paginate():
for alias in page['Aliases']:
key_id = alias.get('TargetKeyId')
if key_id:
alias_map.setdefault(key_id, []).append(alias['AliasName'])

# 2) Filter keys by alias prefix (or other conditions)
for key in list_all_keys():
key_id = key['KeyId']
aliases = alias_map.get(key_id, [])
if any(a.startswith(alias_prefix) for a in aliases):
disallowed_key_ids.append(key_id)

return disallowed_key_ids

bad_keys = find_disallowed_keys()
print("Disallowed CMKs:", bad_keys)

Replace alias_prefix or add your own detection logic.


3. Disable the CMKs (Immediate Risk Reduction)​

Disabling stops cryptographic operations but preserves the key for investigation.

def disable_keys(key_ids):
for key_id in key_ids:
print(f"Disabling key: {key_id}")
kms.disable_key(KeyId=key_id)

disable_keys(bad_keys)

4. (Optional) Remove Disallowed Aliases​

If your policy requires removing specific aliases instead of (or prior to) deleting keys:

def delete_aliases_for_keys(key_ids):
key_ids_set = set(key_ids)

paginator = kms.get_paginator('list_aliases')
for page in paginator.paginate():
for alias in page['Aliases']:
key_id = alias.get('TargetKeyId')
alias_name = alias['AliasName']
if key_id in key_ids_set:
print(f"Deleting alias {alias_name} for key {key_id}")
kms.delete_alias(AliasName=alias_name)

delete_aliases_for_keys(bad_keys)

5. Schedule Deletion of the CMKs (Permanent Remediation)​

Warning: After the waiting period, key material is permanently deleted and any data encrypted under these CMKs that doesn’t have a re‑encrypted copy becomes unrecoverable.

def schedule_key_deletion(key_ids, waiting_period_days=30):
for key_id in key_ids:
print(f"Scheduling deletion for key: {key_id}")
kms.schedule_key_deletion(
KeyId=key_id,
PendingWindowInDays=waiting_period_days # 7–30
)

schedule_key_deletion(bad_keys, waiting_period_days=30)

6. (Optional) Enforce “Good” CMK Configuration Instead​

If the misconfiguration is about how CMKs are configured (not just their existence), you may:

  • Ensure rotation is enabled:

    def enable_rotation(key_ids):
    for key_id in key_ids:
    print(f"Enabling rotation for key: {key_id}")
    kms.enable_key_rotation(KeyId=key_id)
  • Fix key policies or tags via put_key_policy and tag_resource.


7. End‑to‑End Script Skeleton​

import boto3

kms = boto3.client('kms', region_name='us-east-1')

def remediate_disallowed_kms_keys(alias_prefix="alias/bad-key-", delete_after_days=30):
# 1) Find disallowed CMKs
bad_keys = find_disallowed_keys(alias_prefix)
if not bad_keys:
print("No disallowed CMKs found.")
return

# 2) Disable them
disable_keys(bad_keys)

# 3) Remove aliases
delete_aliases_for_keys(bad_keys)

# 4) Schedule deletion
schedule_key_deletion(bad_keys, waiting_period_days=delete_after_days)

print("Remediation complete for keys:", bad_keys)

# Reuse helper functions defined above: list_all_keys, find_disallowed_keys,
# disable_keys, delete_aliases_for_keys, schedule_key_deletion.

if __name__ == "__main__":
remediate_disallowed_kms_keys(alias_prefix="alias/bad-key-", delete_after_days=30)

If you share your exact policy (e.g., “any CMK not tagged Environment=Prod must be deleted”), I can adapt the detection and remediation logic precisely to that.

Using Terraform
resource "aws_kms_key" "SPECIFIC_KMS_CMK" {
description = "CMK for SPECIFIC_PURPOSE (e.g., S3 bucket encryption, RDS, etc.)"
key_usage = "ENCRYPT_DECRYPT"
customer_master_key_spec = "SYMMETRIC_DEFAULT"

# Adjust as needed
deletion_window_in_days = 30
enable_key_rotation = true

tags = {
Name = "SPECIFIC_KMS_CMK"
Environment = "YOUR_ENVIRONMENT"
Owner = "YOUR_TEAM"
}
}

resource "aws_kms_alias" "SPECIFIC_KMS_CMK_ALIAS" {
name = "alias/YOUR_EXPECTED_ALIAS_NAME" # e.g., alias/app-data-key
target_key_id = aws_kms_key.SPECIFIC_KMS_CMK.key_id
}

Substitute:

  • SPECIFIC_KMS_CMK / SPECIFIC_KMS_CMK_ALIAS with your Terraform resource names.
  • SPECIFIC_PURPOSE, YOUR_ENVIRONMENT, YOUR_TEAM, and alias/YOUR_EXPECTED_ALIAS_NAME with your required values so that the expected CMKs and aliases “exist” as required by your control.

This creates the required CMKs; no existing key is replaced unless you change an immutable field (e.g., customer_master_key_spec), which would force replacement and could cause outage for workloads using the old key.

Verification: terraform plan should show + create for the aws_kms_key and aws_kms_alias resources corresponding to the keys that were previously missing.