一、KMS介绍
密钥管理服务(Key Management Service)是针对云上数据加密需求精心设计的密码应用服务,可以为应用提供符合国密要求的密钥服务及极简应用加解密服务,可以帮助我们轻松使用密钥来加密保护敏感的数据资产。
1. 适用场景
- 加密和解密数据,使用 AWS Encryption SDK 安全地处理应用程序中的加密操作。
- 签名并验证数字签名,使用非对称 KMS 密钥保护通过 AWS KMS 执行的签名操作。
- 使用 HMAC 验证 JSON Web 令牌,使用 AWS KMS 生成 HMAC,以验证消息的完整性和身份验证。
- 与其他AWS服务集成使用,比如:可选择使用 AWS KMS 中的 KMS 密钥为 Amazon RDS实例上存储的数据加密。
2. 优势
- 完全托管,具有可扩展性、持久性和高可用性;
- 提供了单一控制点,集中式管理密钥,可以随时创建新密钥,以及对密钥的生命周期和权限进行集中控制;
- KMS与AWS服务集成,可简化密钥使用以加密AWS工作负载中的数据;
- 成本低廉,使用KMS服务不需要事先承诺用量,也没有预付费用。
3. 费用
- 每 10000 个请求0.03 USD
- 每 10000 个涉及 RSA 2048 密钥的请求0.03 USD
- 每 10000 个 ECC GenerateDataKeyPair 请求0.10 USD
- 每 10000 个非对称请求0.15 USD, RSA 2048 除外
- 每 10,000 个 RSA GenerateDataKeyPair 请求12.00 USD
二、如何使用创建密钥
1. 配置密钥
2. 添加标签
3. 定义密钥管理权限
在创建页面定义密钥管理权限。
4. 定义密钥使用权限
在创建页面定义密钥使用权限。
三、Java Api
1. 引入pom
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-kms</artifactId>
<version>1.12.405</version>
</dependency>
2. 测试代码
注意:所有api中的algorithm参数都要和创建密钥所选匹配,代码中的keyId要替换为自己创建的。
2.1 使用非对称加密算法RSA加密数据。
/**
* 数据加解密 公钥加密 私钥解密
*
* https://docs.aws.amazon.com/zh_cn/kms/latest/APIReference/API_Encrypt.html
* https://docs.aws.amazon.com/zh_cn/kms/latest/APIReference/API_Decrypt.html
**/
public class RSA {
private static final String algorithm = "RSAES_OAEP_SHA_256";
private static final String keyId = "your-keyId";
public static void main(String[] args) {
AWSKMS kmsClient = AWSKMSClientBuilder.standard()
.withRegion(Regions.US_EAST_1)
.build();
String originalText = "hello world !!!";
ByteBuffer plaintext = ByteBuffer.wrap(originalText.getBytes(StandardCharsets.UTF_8));
// 加密
EncryptRequest encryptRequest = new EncryptRequest()
.withEncryptionAlgorithm(algorithm)
.withKeyId(keyId)
.withPlaintext(plaintext);
ByteBuffer cipherText = kmsClient.encrypt(encryptRequest).getCiphertextBlob();
System.out.println("加密前: " + originalText);
System.out.println("加密后: " + StringUtils.fromByteBuffer(cipherText));
// 解密
DecryptRequest decryptRequest = new DecryptRequest()
.withEncryptionAlgorithm(algorithm)
.withKeyId(keyId)
.withCiphertextBlob(cipherText);
ByteBuffer plainText = kmsClient.decrypt(decryptRequest).getPlaintext();
String str = StandardCharsets.UTF_8.decode(plainText).toString();
System.out.println("解密后: " + str);
}
}
2.2 使用 HMAC 验证 JSON Web 令牌
/**
* https://docs.aws.amazon.com/zh_cn/kms/latest/APIReference/API_GenerateMac.html
* https://docs.aws.amazon.com/zh_cn/kms/latest/APIReference/API_VerifyMac.html
*/
public class HMAC {
private static final String algorithm = "HMAC_SHA_224";
private static final String keyId = "your-keyId";
public static void main(String[] args) {
AWSKMS kmsClient = AWSKMSClientBuilder.standard()
.withRegion(Regions.US_EAST_1)
.build();
String originalText = "hello world !!!";
ByteBuffer plaintext = ByteBuffer.wrap(originalText.getBytes(StandardCharsets.UTF_8));
// 计算hmac
GenerateMacRequest generateMacRequest = new GenerateMacRequest()
.withMacAlgorithm(algorithm)
.withMessage(plaintext)
.withKeyId(keyId);
ByteBuffer mac = kmsClient.generateMac(generateMacRequest).getMac();
String str = String.valueOf(Base64Decoder.decode(mac.array()));
System.out.println("生成的mac为:" + str);
// 验证hmac
VerifyMacRequest verifyMacRequest = new VerifyMacRequest()
.withMac(mac)
.withMacAlgorithm(algorithm)
.withMessage(plaintext)
.withKeyId(keyId);
Boolean macValid = kmsClient.verifyMac(verifyMacRequest).getMacValid();
System.out.println("验证mac结果: " + macValid);
}
}
2.3 签名认证
/**
* 私钥加签 公钥验签 用于身份认证
* <p>
* https://docs.aws.amazon.com/zh_cn/kms/latest/APIReference/API_Sign.html
* https://docs.aws.amazon.com/zh_cn/kms/latest/APIReference/API_Verify.html
**/
public class VerifySign {
private static final String algorithm = "RSASSA_PSS_SHA_256";
private static final String keyId = "your-keyId";
public static void main(String[] args) {
AWSKMS kmsClient = AWSKMSClientBuilder.standard()
.withRegion(Regions.US_EAST_1)
.build();
String originalText = "hello world !!!";
ByteBuffer plaintext = ByteBuffer.wrap(originalText.getBytes(StandardCharsets.UTF_8));
// 私钥加密
SignRequest signRequest = new SignRequest()
.withSigningAlgorithm(algorithm)
.withKeyId(keyId)
.withMessage(plaintext);
ByteBuffer signature = kmsClient.sign(signRequest).getSignature();
System.out.println("签名前: " + originalText);
System.out.println("签名后: " + StringUtils.fromByteBuffer(signature));
// 公钥验证
VerifyRequest verifyRequest = new VerifyRequest()
.withMessage(plaintext)
.withSignature(signature)
.withSigningAlgorithm(algorithm)
.withKeyId(keyId);
VerifyResult verifyResult = kmsClient.verify(verifyRequest);
System.out.println("验证结果: " + verifyResult.getSignatureValid());
}
}
四、总结
我们平时自己写代码去完成RSA加解密、HMAC验证等算法,不可避免要将私钥给前端或者对接方,可能会有密钥暴露给别人的风险。而kms只需要使用keyId就可以完成加解密,而且kms由aws iam做权限控制,可以做到对密钥使用方的精细权限控制,安全性比较高。