一. KMS介绍
AWS Key Management Service (AWS KMS) 是一项AWS托管服务,可让您轻松创建和控制用于加密数据的加密密钥。我们创建的AWS KMS密钥永远不会以未加密的方式离开,要使用或管理KMS密钥,需要与AWS KMS服务进行交互。
详细介绍可以参考官方文档:AWS KMS官方文档-开发人员指南
二. KMS密钥类型
AWS托管密钥
由AWS服务创建、管理和使用,密钥策略由AWS服务控制,我们只能查看,不能修改;
客户托管密钥
我们创建的KMS密钥是客户托管密钥,密钥策略完全由客户控制;
AWS拥有的密钥
由AWS管理的KMS密钥的集合,用来保护我们AWS账户中的资源,免费以及不计入配额管理;


1.进入KMS UI后,只能看到AWS托管密钥和客户管理密钥;我们重点关注客户托管密钥。
2.密钥由密钥材料和元数据组成,密钥材料可以理解为KMS加密过的对称密钥或者非对称密钥,而元数据包含密钥策略、密码配置、标签、别名等。

三. KMS存储方式
标准密钥库
标准密钥库是由KMS服务管理的密钥库,默认情况下,KMS密钥使用标准密钥库。而密钥材料可以有两种方式创建:
1.默认由KMS创建密钥材料;
2.自己生成密钥材料并导入标准密钥库;
自定义密钥库
完全由客户自己控制;多数为了满足某些监管要求;
自定义密钥库目前不支持非对称密钥;自动密钥轮换;具有导入密钥材料的KMS密钥等功能;
以下是AWS提供的几种自定义密钥库的架构示例:


四. KMS注意事项
1.生产环境中尽量不要删除KMS密钥,如果不需要,可以先禁用KMS密钥,需要的时候再重新启用被禁用的KMS密钥。无法恢复彻底删除的KMS。
2.任何密钥材料都不能导出;这也意味着由KMS创建的密钥材料不能采取常规的备份方式,它的安全性完全由AWS来保障;
3.密钥的删除有7-30天的Pending deletion设置;“等待期”内可以随时取消删除,并重新启用密钥;
4.最小权限原则:重要的密钥策略中显式拒绝kms:ScheduleKeyDeletion和 kms:DeleteImportedKeyMaterial等IAM权限;
5.由以上几点我们不难发现,在生产环境中应该设置监控项,检测KMS删除事件,发现告警后及时处理;
我们以Cloudwatch/Event Bridge集成SNS/Lambda的方式,做一个简单示例(当然也可以调用AWS api等方式集成到Prometheus体系中):
配置项




告警效果

五. 备份元数据
这里我们先根据存储方式归纳几种备份:
1.自定义密钥库。很显然,这种方式的备份是完全由用户自行处理的,备份数据源头在自定义密钥库中;
2.标准密钥库,并且用户来生成密钥材料并导入。很显然,这种方式的备份依然是完全由用户自行处理的,备份数据源头就在导入密钥材料的源头;
3.标准密钥库,由KMS创建密钥材料。没有可备份数据。
可以看到,针对KMS服务本身的完整备份是没有的,而对KMS服务本身的备份只能备份元数据(密钥策略、密码配置、标签、别名等信息)。需要注意的是,备份元数据并不能用来恢复密钥材料;只能用来查看一些属性的设置;
备份元数据示例
import boto3
import json
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
kms = boto3.client('kms')
def backup_kms_keys():
all_keys = []
paginator = kms.get_paginator('list_keys')
for page in paginator.paginate():
for key in page['Keys']:
key_id = key['KeyId']
try:
meta = kms.describe_key(KeyId=key_id)['KeyMetadata']
# 只处理客户管理密钥
if meta['KeyManager'] != 'CUSTOMER':
logging.info(f"Skipping AWS managed key {key_id}")
continue
try:
policy = kms.get_key_policy(KeyId=key_id, PolicyName='default')['Policy']
policy_json = json.loads(policy)
except kms.exceptions.ClientError as e:
logging.error(f"Failed to get policy for key {key_id}: {e}")
policy_json = {}
try:
aliases = kms.list_aliases(KeyId=key_id).get('Aliases', [])
except kms.exceptions.ClientError as e:
logging.error(f"Failed to list aliases for key {key_id}: {e}")
aliases = []
try:
tags = kms.list_resource_tags(KeyId=key_id).get('Tags', [])
except kms.exceptions.ClientError as e:
logging.error(f"Failed to list tags for key {key_id}: {e}")
tags = []
try:
rotation = kms.get_key_rotation_status(KeyId=key_id)
except kms.exceptions.UnsupportedOperationException:
rotation = {}
except kms.exceptions.ClientError as e:
logging.error(f"Failed to get rotation status for key {key_id}: {e}")
rotation = {}
all_keys.append({
"KeyMetadata": meta,
"Policy": policy_json,
"Aliases": aliases,
"Tags": tags,
"Rotation": rotation
})
except kms.exceptions.ClientError as e:
logging.error(f"Failed to describe key {key_id}: {e}")
continue
# 写文件
with open('/backup/kms_keys_backup.json', 'w') as f:
json.dump(all_keys, f, indent=2,default=str)
logging.info(f"Backup finished. {len(all_keys)} keys saved to /backup/kms_keys_backup.json")
if __name__ == '__main__':
backup_kms_keys()
备份文件内容片段:
{
"KeyMetadata": {
"AWSAccountId": "xxx",
"KeyId": "ffdafe27-d9d8-411a-8c99-96d8385c9644",
"Arn": "arn:aws:kms:ap-xxx-1:xxx:key/ffdafe27-d9d8-411a-8c99-96d8385c9644",
"CreationDate": "2025-07-23 17:51:54.794000+00:00",
"Enabled": true,
"Description": "Imported from my servers: test:private",
"KeyUsage": "SIGN_VERIFY",
"KeyState": "Enabled",
"Origin": "EXTERNAL",
"ExpirationModel": "KEY_MATERIAL_DOES_NOT_EXPIRE",
"KeyManager": "CUSTOMER",
"CustomerMasterKeySpec": "ECC_SECG_P256K1",
"KeySpec": "ECC_SECG_P256K1",
"SigningAlgorithms": [
"ECDSA_SHA_256"
],
"MultiRegion": false
},
"Policy": {
"Version": "2012-10-17",
"Id": "key-default-1",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxx:root"
},
"Action": "kms:*",
"Resource": "*"
}
]
},
"Aliases": [],
"Tags": [],
"Rotation": {
"KeyRotationEnabled": false,
"KeyId": "arn:aws:kms:ap-xxx-1:xxx:key/ffdafe27-d9d8-411a-8c99-96d8385c9644",
"ResponseMetadata": {
"RequestId": "ffc41ac7-b6c2-47ff-9fa9-c7c6251e7aab",
"HTTPStatusCode": 200,
"HTTPHeaders": {
"x-amzn-requestid": "ffc41ac7-b6c2-47ff-9fa9-c7c6251e7aab",
"cache-control": "no-cache, no-store, must-revalidate, private",
"expires": "0",
"pragma": "no-cache",
"date": "Tue, 23 Sep 2025 08:46:03 GMT",
"content-type": "application/x-amz-json-1.1",
"content-length": "119",
"connection": "keep-alive"
},
"RetryAttempts": 0
}
}
},
六. KMS使用方式
KMS密钥有对称密钥和非对称密钥两种;每种类型下面可以选择使用场景,常用的使用场景是加密解密;登录并验证;


默认创建的是加密解密的key,使用示例如下:
#创建KMS
$ aws kms create-key --tags TagKey=CreatedBy,TagValue=my-demo-service --output json
#加密数据
$ aws kms encrypt --key-id xxxxxxxxxxxxxxx --plaintext fileb://<(echo -n "HelloWorld") --output json
登录并验证功能key的使用示例如下:
$ echo -n "hello kms" > message.bin
#签名
$ aws kms sign --key-id d159e148-bc21-4656-8650-b5c34256ed2e --message-type RAW --message fileb://message.bin --signing-algorithm ECDSA_SHA_256
{
"KeyId": "arn:aws:kms:ap-xxxxxx-1:xxxxxx:key/d159e148-bc21-4656-8650-b5c34256ed2e",
"Signature": "MEQCIGXB7TYCEUhDXJZk43yAa+oPZE1KKQhJQws5cPz+rf3OAiBxyn1fkW8qNKvPorT7vO0JJIisPLSZMKvLkZG2vUHqVg==",
"SigningAlgorithm": "ECDSA_SHA_256"
}
$ echo -n "MEQCIGXB7TYCEUhDXJZk43yAa+oPZE1KKQhJQws5cPz+rf3OAiBxyn1fkW8qNKvPorT7vO0JJIisPLSZMKvLkZG2vUHqVg==" | base64 -d > signature.bin#验签
$ aws kms verify --key-id d159e148-bc21-4656-8650-b5c34256ed2e --message fileb://message.bin --signature fileb://signature.bin --signing-algorithm ECDSA_SHA_256 --message-type RAW
{
"KeyId": "arn:aws:kms:ap-xxxxxx-1:xxxxxx:key/d159e148-bc21-4656-8650-b5c34256ed2e",
"SignatureValid": true,
"SigningAlgorithm": "ECDSA_SHA_256"
}
895

被折叠的 条评论
为什么被折叠?



