Demystifying AWS KMS key rotation
Find the right strategy to rotate your KMS Keys securely without any data loss.
- Works with most AWS Services.
- It's simple to set-up.
- Offers a good balance between simplicity of management and key control.
- AWS owned key: Keys owned and managed by AWS. They are the simplest to use but they offer no control to the customer. Also these keys are shared between customers.
- AWS managed key: Keys owned by the customer but managed by AWS. Usually associated with a single AWS Service. These keys live only in the customer AWS account and are not shared with other customers.
- Customer managed key: Keys owned and managed by the customer, a.k.a. us, who are responsible of the lifecycle for the key, where it is used and the key security (configuration of its key policy).
- KMS: It's the recommended approach. AWS creates and manages the key material for the KMS key.
- External (Import Key material): You create and import the key material for the KMS key.
- AWS CloudHSM key store: AWS KMS creates key material in the AWS CloudHSM cluster of your AWS CloudHSM key store.
- External key store: The key material for the KMS key is in an external key manager outside of AWS.
ee740549-6491-47b0-810d-1365b9b52792
with alias my-key
to generate data keys that we will use to encrypt our files. 1
2
3
4
5
6
7
8
9
10
11
12
% aws kms list-aliases
{
"Aliases": [
{
"AliasName": "alias/my-key",
"AliasArn": "arn:aws:kms:us-east-1:372922107867:alias/my-key",
"TargetKeyId": "ee740549-6491-47b0-810d-1365b9b52792",
"CreationDate": "2024-01-23T15:06:33.424000+01:00",
"LastUpdatedDate": "2024-01-23T15:06:33.424000+01:00"
}
]
}
1
2
3
4
5
6
% aws kms generate-data-key --key-id alias/my-key --key-spec AES_256
{
"CiphertextBlob": "AQIDAHgzqwxkDivbMS0RKdvlqyaQj/+MMUb4yxnnJYe+A6nwCQF8JkM9izf5rY6uVnY4n/uxAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMUhGbd0AHxyS5TcwGAgEQgDvOECsCoq/uGWnt8N4QlS3lXvdKGuwUTRkdPoKaZuwbTQgkyd6rCZ/ez1xuobFGfnesf0yFnc34AnRYuw==",
"Plaintext": "8RqgnZ3G+c5YzQTK3o9DnZAguHFbpWCoYC2aCNPg0lo=",
"KeyId": "arn:aws:kms:us-east-1:372922107867:key/ee740549-6491-47b0-810d-1365b9b52792"
}
1
2
3
4
5
6
% aws kms decrypt --ciphertext-blob AQIDAHgzqwxkDivbMS0RKdvlqyaQj/+MMUb4yxnnJYe+A6nwCQF8JkM9izf5rY6uVnY4n/uxAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMUhGbd0AHxyS5TcwGAgEQgDvOECsCoq/uGWnt8N4QlS3lXvdKGuwUTRkdPoKaZuwbTQgkyd6rCZ/ez1xuobFGfnesf0yFnc34AnRYuw==
{
"KeyId": "arn:aws:kms:us-east-1:372922107867:key/ee740549-6491-47b0-810d-1365b9b52792",
"Plaintext": "8RqgnZ3G+c5YzQTK3o9DnZAguHFbpWCoYC2aCNPg0lo=",
"EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
9772c95e-c9c5-43fb-bfcd-f8c4678f9e49
and point the alias my-key
to it.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
% aws kms update-alias --alias-name alias/my-key --target-key-id 9772c95e-c9c5-43fb-bfcd-f8c4678f9e49
% aws kms list-aliases
{
"Aliases": [
{
"AliasName": "alias/my-key",
"AliasArn": "arn:aws:kms:us-east-1:372922107867:alias/my-key",
"TargetKeyId": "9772c95e-c9c5-43fb-bfcd-f8c4678f9e49",
"CreationDate": "2024-01-23T15:06:33.424000+01:00",
"LastUpdatedDate": "2024-01-23T16:54:02.384000+01:00"
}
]
}
% aws kms re-encrypt --ciphertext-blob AQIDAHgzqwxkDivbMS0RKdvlqyaQj/+MMUb4yxnnJYe+A6nwCQF8JkM9izf5rY6uVnY4n/uxAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMUhGbd0AHxyS5TcwGAgEQgDvOECsCoq/uGWnt8N4QlS3lXvdKGuwUTRkdPoKaZuwbTQgkyd6rCZ/ez1xuobFGfnesf0yFnc34AnRYuw== --destination-key-id alias/my-key
{
"CiphertextBlob": "AQICAHjupf6EVUcdZoJA0fyIbMmGwu8KRy7wa/C4PTQSmct1SgGGvw309CV/AUGYhIa3SWSdAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMDsd/aY/QTctxYJ9uAgEQgDvZIU5u53bQyGHNwt1pKW+ylH6J4KIyGKV1whOA7SCkUBY3eaQgQbXWOSBgYe8Z5Fy/8gOBSl6SElwBUg==",
"SourceKeyId": "arn:aws:kms:us-east-1:372922107867:key/ee740549-6491-47b0-810d-1365b9b52792",
"KeyId": "arn:aws:kms:us-east-1:372922107867:key/9772c95e-c9c5-43fb-bfcd-f8c4678f9e49",
"SourceEncryptionAlgorithm": "SYMMETRIC_DEFAULT",
"DestinationEncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
1
% aws kms disable-key --key-id ee740549-6491-47b0-810d-1365b9b52792
1
2
3
% aws kms decrypt --ciphertext-blob AQIDAHgzqwxkDivbMS0RKdvlqyaQj/+MMUb4yxnnJYe+A6nwCQF8JkM9izf5rY6uVnY4n/uxAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMUhGbd0AHxyS5TcwGAgEQgDvOECsCoq/uGWnt8N4QlS3lXvdKGuwUTRkdPoKaZuwbTQgkyd6rCZ/ez1xuobFGfnesf0yFnc34AnRYuw==
An error occurred (DisabledException) when calling the Decrypt operation: arn:aws:kms:us-east-1:372922107867:key/ee740549-6491-47b0-810d-1365b9b52792 is disabled.
1
2
3
4
5
6
% aws kms decrypt --ciphertext-blob AQICAHjupf6EVUcdZoJA0fyIbMmGwu8KRy7wa/C4PTQSmct1SgGGvw309CV/AUGYhIa3SWSdAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMDsd/aY/QTctxYJ9uAgEQgDvZIU5u53bQyGHNwt1pKW+ylH6J4KIyGKV1whOA7SCkUBY3eaQgQbXWOSBgYe8Z5Fy/8gOBSl6SElwBUg==
{
"KeyId": "arn:aws:kms:us-east-1:372922107867:key/9772c95e-c9c5-43fb-bfcd-f8c4678f9e49",
"Plaintext": "8RqgnZ3G+c5YzQTK3o9DnZAguHFbpWCoYC2aCNPg0lo=",
"EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
% aws s3api get-bucket-encryption --bucket my-bucket-102353703712
{
"ServerSideEncryptionConfiguration": {
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:us-east-1:102353703712:key/93237725-c352-41c7-a762-3f001e97c9af"
},
"BucketKeyEnabled": false
}
]
}
}
1
2
3
4
5
% cat my-file.txt
File content
% aws s3 cp my-file.txt s3://my-bucket-102353703712
upload: ./my-file.txt to s3://my-bucket-102353703712/my-file.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
% aws s3api get-object --bucket my-bucket-102353703712 --key my-file.txt my-file.txt
{
"AcceptRanges": "bytes",
"LastModified": "2024-01-26T15:48:09+00:00",
"ContentLength": 13,
"ETag": "\"9c2d5a5c8d2d27ca8308ad71310ade58\"",
"ContentType": "text/plain",
"ServerSideEncryption": "aws:kms",
"Metadata": {},
"SSEKMSKeyId": "arn:aws:kms:us-east-1:102353703712:key/93237725-c352-41c7-a762-3f001e97c9af"
}
% cat my-file.txt
File content
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
% aws s3api put-bucket-encryption \
--bucket my-bucket-102353703712 \
--server-side-encryption-configuration '{"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "aws:kms","KMSMasterKeyID": "1e51777f-fefd-4bc5-8671-c1851e7d07b3"}}]}'
% aws s3api get-bucket-encryption --bucket my-bucket-102353703712
{
"ServerSideEncryptionConfiguration": {
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "1e51777f-fefd-4bc5-8671-c1851e7d07b3"
},
"BucketKeyEnabled": false
}
]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
plaintext
% aws s3 cp --recursive s3://my-bucket-102353703712 s3://my-bucket-102353703712
copy: s3://my-bucket-102353703712/my-file.txt to s3://my-bucket-102353703712/my-file.txt
% aws s3api get-object --bucket my-bucket-102353703712 --key my-file.txt my-file.txt
{
"AcceptRanges": "bytes",
"LastModified": "2024-01-26T16:13:22+00:00",
"ContentLength": 13,
"ETag": "\"6b856ce783e96cac811638a2a071fc22\"",
"ContentType": "text/plain",
"ServerSideEncryption": "aws:kms",
"Metadata": {},
"SSEKMSKeyId": "arn:aws:kms:us-east-1:102353703712:key/1e51777f-fefd-4bc5-8671-c1851e7d07b3"
}
% cat my-file.txt
File content
1
% aws kms disable-key --key-id 93237725-c352-41c7-a762-3f001e97c9af
d6f8b1ee-032c-4244-9d44-827861e6f9fa
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
% aws ec2 describe-volumes --volume-id vol-09be7ec8867c85f21
{
"Volumes": [
{
"Attachments": [],
"AvailabilityZone": "us-east-1a",
"CreateTime": "2024-01-27T17:56:36.159000+00:00",
"Encrypted": true,
"KmsKeyId": "arn:aws:kms:us-east-1:386088430154:key/d6f8b1ee-032c-4244-9d44-827861e6f9fa",
"Size": 10,
"SnapshotId": "",
"State": "available",
"VolumeId": "vol-09be7ec8867c85f21",
"Iops": 3000,
"VolumeType": "gp3",
"MultiAttachEnabled": false,
"Throughput": 125
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
% aws ec2 create-snapshot --volume-id vol-09be7ec8867c85f21
{
"Description": "",
"Encrypted": true,
"OwnerId": "386088430154",
"Progress": "",
"SnapshotId": "snap-0a908c9b806fbadc5",
"StartTime": "2024-01-27T18:06:13.864000+00:00",
"State": "pending",
"VolumeId": "vol-09be7ec8867c85f21",
"VolumeSize": 10,
"Tags": []
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
% aws ec2 create-volume --availability-zone us-east-1a --encrypted --kms-key-id 3d70f1b8-7a3b-4e9e-a6b9-6db1a6471f5d --snapshot-id snap-0a908c9b806fbadc5 --volume-type gp3
{
"AvailabilityZone": "us-east-1a",
"CreateTime": "2024-01-27T18:15:47+00:00",
"Encrypted": true,
"KmsKeyId": "3d70f1b8-7a3b-4e9e-a6b9-6db1a6471f5d",
"Size": 10,
"SnapshotId": "snap-0a908c9b806fbadc5",
"State": "creating",
"VolumeId": "vol-017bbdf1b17c1c8b6",
"Iops": 3000,
"Tags": [],
"VolumeType": "gp3",
"MultiAttachEnabled": false,
"Throughput": 125
}
1
2
3
4
5
% aws kms disable-key --key-id d6f8b1ee-032c-4244-9d44-827861e6f9fa
% aws ec2 delete-volume --volume-id vol-09be7ec8867c85f21
% aws ec2 delete-snapshot --snapshot-id snap-0a908c9b806fbadc5