Right, so you’ve decided to trust AWS with your most precious data. Good choice. But you’re not just going to use their default keys, are you? That’s like using the master key the landlord gave everyone in your apartment building. You want your own key, cut to your exact specifications. That’s where Customer Master Keys (CMKs) come in, and yes, I know they renamed them to just “KMS keys” in the console because someone at marketing thought “Master” was problematic, but the API still calls them CMKs everywhere. We’ll stick with CMK because a) it’s precise and b) I refuse to let AWS gaslight me into forgetting the old terminology.

A CMK is your root key in KMS. It’s not the key that directly encrypts your data—that job is usually handled by a data key that this key generates. The CMK is the boss key; it encrypts and decrypts those tiny, disposable data keys. And they come in two flavors: symmetric and asymmetric. Let’s break them down before you accidentally create the wrong one and have to refactor your entire IAM policy.

Symmetric CMKs: Your Workhorse

This is your default, your go-to, the key you’ll use 95% of the time. When you create a key in the console and don’t fiddle with the advanced options, this is what you get. A symmetric key means the same key is used to encrypt and decrypt. It’s a single, 256-bit secret key that never leaves AWS KMS’s hardware security modules (HSMs). You can’t download it. You can’t email it to yourself. It’s physically impossible, which is both a brilliant security feature and occasionally a massive pain in the neck when you want to decrypt something outside of AWS.

You use it by calling API operations like Encrypt, Decrypt, and GenerateDataKey. The beauty is in its simplicity. Here’s how you’d use the AWS CLI to encrypt a plaintext file. Notice I’m not specifying a key—I’m letting it use the default alias aws/secretsmanager. Don’t do this in real life. Always specify your key.

# Okay for a quick test, terrible for production. Use the key ID or ARN!
aws kms encrypt --key-id alias/my-app-key \
    --plaintext fileb://supersecret.txt \
    --output text --query CiphertextBlob \
    | base64 --decode > encrypted_secret.enc

And to decrypt? Same key, opposite day.

aws kms decrypt --ciphertext-blob fileb://encrypted_secret.enc \
    --output text --query Plaintext | base64 --decode > decrypted_secret.txt

The pitfall here? The Encrypt operation has a size limit—only 4KB of data directly. If you try to shove a 5KB file at it, it’ll laugh in your face. This is by design, to force you to use the proper pattern: generate a data key with KMS, use that key to encrypt your data locally, and then encrypt that data key with KMS. It’s more steps, but it’s how you handle large data efficiently.

Asymmetric CMKs: For When You Need to Share the Load

Now for the weird, less common, but incredibly important sibling: the asymmetric key. Unlike its symmetric counterpart, an asymmetric CMK is a key pair: a public key for encryption and a private key for decryption. The genius here is that you can download the public key and distribute it far and wide. Anyone can use it to encrypt data, but only those with permissions on the CMK in your AWS account can decrypt it. This is perfect for scenarios where you need to accept encrypted data from external clients or systems that shouldn’t have AWS credentials.

When you create one, you must choose a key usage: ENCRYPT_DECRYPT or SIGN_VERIFY. You can’t have a single key that does both, which is a mildly annoying but sane security decision. For encryption, you’d choose ENCRYPT_DECRYPT.

Here’s the catch, and it’s a big one: you cannot perform the Encrypt operation with an asymmetric CMK inside KMS. Let me repeat that. If you create an asymmetric CMK and try to call kms.encrypt() with its ARN, it will fail. It seems absurd, but there’s a method to the madness. The entire point is to download the public key and do the encryption outside of AWS. KMS’s job is to safeguard the private key for decryption.

# First, get the public key. You'll need the Key ID or ARN.
aws kms get-public-key --key-id <your-asymmetric-key-id> --output text --query PublicKey > public_key.der

# Now, use openssl to encrypt something with that public key.
openssl pkeyutl -encrypt -inkey public_key.der -pubin -in plaintext.txt -out encrypted.dat

To decrypt, you bring the ciphertext back to KMS, which uses the private key it holds.

aws kms decrypt --key-id <your-asymmetric-key-id> --ciphertext-blob fileb://encrypted.dat --output text --query Plaintext | base64 --decode > decrypted.txt

The primary pitfall with asymmetric keys is this indirection. Developers used to the symmetric flow often bang their heads against the wall wondering why Encrypt doesn’t work. Remember: symmetric for internal AWS work, asymmetric for external encryption where you need to offload the decryption to your AWS account.

The Critical Details: Aliases, Key Policy, and Deletion

First, aliases. Always use them. An alias like alias/my-app-prod is a pointer to a CMK ID (e.g., 1234abcd-12ab-34cd-56ef-1234567890ab). You can change what key the alias points to, which is invaluable for key rotation. In your code, use the alias ARN. This way, if you need to rotate the underlying key, you just point the alias to the new key and avoid a full redeploy. It’s like a symlink for your secrets.

Next, key policy. This is the most common “oh crap” moment. By default, the root user of the account has full access. If you’re using IAM users/roles, you must grant them access in the key policy itself. IAM policies alone are not enough. The key policy is the door, and IAM policies are just the list of people allowed to approach the door. You need both. A key policy that grants a role permission to use the key is non-negotiable.

Finally, deletion. When you schedule a key for deletion, there’s a mandatory 7-30 day waiting period. This isn’t AWS being difficult; it’s a crucial safety net. If you accidentally schedule a key deletion and it’s still being used to protect data, this is your only chance to cancel the deletion. Once it’s gone, it’s gone forever. Any data encrypted under that key is cryptographically shredded. No recovery. So set your waiting period to the max and treat the ScheduleKeyDeletion API call with the respect and fear it deserves.