| name | kms |
| description | Manage AWS KMS keys, aliases, grants, key policies, and encryption/decryption operations via AWS CLI. |
| metadata | {"openclaw":{"emoji":"🔑","requires":{"bins":["aws"]}}} |
AWS KMS (Key Management Service)
Use this skill for encryption key management: creating and managing KMS keys, encrypting and decrypting data, managing key policies and grants, rotating keys, and configuring cross-account access.
Prerequisites
- AWS CLI v2 configured with valid credentials
- IAM permissions:
kms:* for full access, or scoped policies
Common Operations
List and Inspect (Read-Only)
aws kms list-keys --query 'Keys[*].KeyId' --output table
aws kms describe-key --key-id <key-id>
aws kms describe-key --key-id alias/<alias-name>
aws kms list-aliases \
--query 'Aliases[*].[AliasName,TargetKeyId]' --output table
aws kms list-aliases --key-id <key-id>
aws kms get-key-policy --key-id <key-id> --policy-name default --output text
aws kms get-key-rotation-status --key-id <key-id>
aws kms list-grants --key-id <key-id> \
--query 'Grants[*].[GrantId,GranteePrincipal,Operations]' --output table
aws kms list-key-policies --key-id <key-id>
aws kms list-resource-tags --key-id <key-id> --output table
Encrypt and Decrypt
aws kms encrypt \
--key-id <key-id> \
--plaintext fileb://secret.txt \
--query 'CiphertextBlob' --output text > encrypted.b64
aws kms decrypt \
--ciphertext-blob fileb://<(base64 -d encrypted.b64) \
--query 'Plaintext' --output text | base64 -d > decrypted.txt
aws kms encrypt \
--key-id <key-id> \
--plaintext "sensitive data" \
--encryption-context Purpose=config,Environment=prod \
--query 'CiphertextBlob' --output text
aws kms decrypt \
--ciphertext-blob fileb://<(echo '<ciphertext>' | base64 -d) \
--encryption-context Purpose=config,Environment=prod \
--query 'Plaintext' --output text | base64 -d
aws kms generate-data-key \
--key-id <key-id> \
--key-spec AES_256
aws kms generate-data-key-without-plaintext \
--key-id <key-id> \
--key-spec AES_256
aws kms re-encrypt \
--ciphertext-blob fileb://<ciphertext-file> \
--source-key-id <old-key-id> \
--destination-key-id <new-key-id>
Create and Configure
⚠️ Cost note: KMS charges $1.00/month per customer-managed key. API calls: $0.03 per 10,000 requests. AWS-managed keys (aws/*) are free.
aws kms create-key \
--description "Application encryption key" \
--key-usage ENCRYPT_DECRYPT \
--key-spec SYMMETRIC_DEFAULT \
--tags '[{"TagKey": "Environment", "TagValue": "production"}]'
aws kms create-key \
--description "Code signing key" \
--key-usage SIGN_VERIFY \
--key-spec RSA_2048
aws kms create-key \
--description "HMAC key" \
--key-usage GENERATE_VERIFY_MAC \
--key-spec HMAC_256
aws kms create-alias \
--alias-name alias/<alias-name> \
--target-key-id <key-id>
aws kms enable-key-rotation --key-id <key-id>
aws kms enable-key-rotation \
--key-id <key-id> \
--rotation-period-in-days 180
aws kms update-key-description \
--key-id <key-id> \
--description "Updated description"
aws kms create-grant \
--key-id <key-id> \
--grantee-principal <iam-role-arn> \
--operations Encrypt Decrypt GenerateDataKey \
--constraints '{"EncryptionContextSubset": {"Department": "Finance"}}'
aws kms put-key-policy \
--key-id <key-id> \
--policy-name default \
--policy file://key-policy.json
aws kms tag-resource \
--key-id <key-id> \
--tags '[{"TagKey": "Project", "TagValue": "MyApp"}]'
Key Lifecycle
aws kms disable-key --key-id <key-id>
aws kms enable-key --key-id <key-id>
aws kms get-parameters-for-import \
--key-id <key-id> \
--wrapping-algorithm RSAES_OAEP_SHA_256 \
--wrapping-key-spec RSA_2048
Delete / Destructive
🛑 DESTRUCTIVE — Always confirm with the user before executing any of these commands. Deleting a KMS key is irreversible and makes all data encrypted with it permanently unrecoverable.
aws kms schedule-key-deletion \
--key-id <key-id> \
--pending-window-in-days 30
aws kms cancel-key-deletion --key-id <key-id>
aws kms delete-alias --alias-name alias/<alias-name>
aws kms revoke-grant --key-id <key-id> --grant-id <grant-id>
aws kms retire-grant --grant-id <grant-id> --key-id <key-id>
Safety Rules
- NEVER schedule key deletion without explicit user confirmation — encrypted data becomes PERMANENTLY unrecoverable.
- NEVER expose or log plaintext key material, decrypted data, or AWS credentials.
- ALWAYS use the maximum pending window (30 days) for key deletion.
- ALWAYS recommend encryption context for all encrypt/decrypt operations.
- WARN that disabling a key prevents all encryption/decryption operations using it.
- WARN about the impact of key policy changes — can lock out all access.
Best Practices
- Use aliases to reference keys (easier to rotate and manage).
- Enable automatic key rotation for symmetric keys.
- Use encryption context to bind ciphertext to its intended use.
- Use grants for temporary, scoped access instead of broad key policies.
- Use envelope encryption (generate-data-key) for large data.
- Never use the same key for different purposes.
Common Patterns
Pattern: Envelope Encryption
DATA_KEY=$(aws kms generate-data-key \
--key-id alias/my-key \
--key-spec AES_256)
PLAINTEXT=$(echo $DATA_KEY | jq -r '.Plaintext')
ENCRYPTED_KEY=$(echo $DATA_KEY | jq -r '.CiphertextBlob')
echo "$PLAINTEXT" | base64 -d > /tmp/datakey.bin
openssl enc -aes-256-cbc -in largefile.dat -out largefile.enc -pass file:/tmp/datakey.bin
rm /tmp/datakey.bin
echo "$ENCRYPTED_KEY" > largefile.key
Pattern: Audit Key Usage
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=<key-id> \
--max-results 20 \
--query 'Events[*].[EventTime,EventName,Username]' --output table
Troubleshooting
| Error | Cause | Fix |
|---|
NotFoundException | Key doesn't exist or was deleted | Check list-keys; deleted keys can't be recovered |
DisabledException | Key is disabled | Enable with enable-key |
InvalidCiphertextException | Wrong key or missing encryption context | Verify key ID and encryption context match |
KMSAccessDeniedException | IAM or key policy blocks access | Check both IAM policy and key policy |
KMSInvalidStateException | Key is pending deletion or import | Check key state with describe-key |
KeyUnavailableException | Key is in a custom key store that's disconnected | Reconnect the custom key store |