关于 aws-sdk-java-v2-kms
面向 Java 开发者的技能,提供使用 AWS SDK for Java 2.x 操作 AWS KMS 的实现模式。内容包括密钥管理、加密解密、信封加密、数字签名及 Spring Boot 集成。
主要功能
- 01创建和管理 KMS 密钥
- 02加密与解密数据
- 03使用信封加密处理大数据
- 04生成并验证数字签名
- 05集成 Spring Boot
适用场景
- 01为数据保护配置对称密钥
- 02使用数据密钥加密较大数据
- 03为应用设置数字签名
- 04将加密服务接入 Spring Boot
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill aws-sdk-java-v2-kms安装后在 Claude Code 中输入/aws-sdk-java-v2-kms确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/best-practices.mdspring-boot-integration.mdtechnical-guide.mdtesting.md详细介绍
AWS SDK for Java 2.x - AWS KMS(密钥管理服务)
概述
使用 AWS SDK for Java 2.x 提供 AWS KMS 模式。涵盖密钥管理、加密/解密、信封加密、数字签名和 Spring Boot 集成。
说明
- 设置 IAM 权限 - 以最小权限原则授予 kms:* 操作权限
- 创建 KMS 客户端 - 使用区域和凭证实例化 KmsClient
- 创建密钥 - 使用 createKey() → 继续前请确认密钥状态为 ENABLED
- 设置密钥策略 - 定义密钥使用权限 → 投入生产前测试访问权限
- 加密数据 - 对小于 4KB 的数据使用 encrypt();确认密文不为空
- 信封加密 - 对于较大的数据,使用 generateDataKey() → 确认数据密钥生成成功
- 数字签名 - 创建签名密钥 → 签名/验证后确认 signatureValid=true
- 密钥轮换 - 启用自动轮换 → 确认轮换计划已启用
适用场景
- 创建/管理用于数据保护的对称加密密钥
- 为大型数据实现信封加密
- 使用由 KMS 管理的密钥生成用于本地加密的数据密钥
- 使用非对称密钥设置数字签名
- 将加密功能集成到 Spring Boot 应用程序中
依赖项
Maven
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kms</artifactId>
</dependency>
Gradle
implementation 'software.amazon.awssdk:kms:2.x.x'
客户端设置
基本同步客户端
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.kms.KmsClient;
KmsClient kmsClient = KmsClient.builder()
.region(Region.US_EAST_1)
.build();
基本异步客户端
import software.amazon.awssdk.services.kms.KmsAsyncClient;
KmsAsyncClient kmsAsyncClient = KmsAsyncClient.builder()
.region(Region.US_EAST_1)
.build();
高级客户端配置
KmsClient kmsClient = KmsClient.builder()
.region(Region.of(System.getenv("AWS_REGION")))
.credentialsProvider(DefaultCredentialsProvider.create())
.overrideConfiguration(c -> c.retryPolicy(RetryPolicy.builder()
.numRetries(3)
.build()))
.build();
基本密钥管理
创建加密密钥
public String createEncryptionKey(KmsClient kmsClient, String description) {
CreateKeyRequest request = CreateKeyRequest.builder()
.description(description)
.keyUsage(KeyUsageType.ENCRYPT_DECRYPT)
.build();
CreateKeyResponse response = kmsClient.createKey(request);
return response.keyMetadata().keyId();
}
描述密钥
public KeyMetadata getKeyMetadata(KmsClient kmsClient, String keyId) {
DescribeKeyRequest request = DescribeKeyRequest.builder()
.keyId(keyId)
.build();
return kmsClient.describeKey(request).keyMetadata();
}
启用/禁用密钥
public void toggleKeyState(KmsClient kmsClient, String keyId, boolean enable) {
if (enable) {
kmsClient.enableKey(EnableKeyRequest.builder().keyId(keyId).build());
} else {
kmsClient.disableKey(DisableKeyRequest.builder().keyId(keyId).build());
}
}
基本加密与解密
加密数据
public String encryptData(KmsClient kmsClient, String keyId, String plaintext) {
SdkBytes plaintextBytes = SdkBytes.fromString(plaintext, StandardCharsets.UTF_8);
EncryptRequest request = EncryptRequest.builder()
.keyId(keyId)
.plaintext(plaintextBytes)
.build();
EncryptResponse response = kmsClient.encrypt(request);
return Base64.getEncoder().encodeToString(
response.ciphertextBlob().asByteArray());
}
解密数据
public String decryptData(KmsClient kmsClient, String ciphertextBase64) {
byte[] ciphertext = Base64.getDecoder().decode(ciphertextBase64);
SdkBytes ciphertextBytes = SdkBytes.fromByteArray(ciphertext);
DecryptRequest request = DecryptRequest.builder()
.ciphertextBlob(ciphertextBytes)
.build();
DecryptResponse response = kmsClient.decrypt(request);
return response.plaintext().asString(StandardCharsets.UTF_8);
}
信封加密模式
生成并使用数据密钥
public DataKeyResult encryptWithEnvelope(KmsClient kmsClient, String masterKeyId, byte[] data) {
try {
GenerateDataKeyRequest keyRequest = GenerateDataKeyRequest.builder()
.keyId(masterKeyId)
.keySpec(DataKeySpec.AES_256)
.build();
GenerateDataKeyResponse keyResponse = kmsClient.generateDataKey(keyRequest);
// Validate response
if (keyResponse.plaintext() == null || keyResponse.ciphertextBlob() == null) {
throw new IllegalStateException("Data key generation returned null");
}
byte[] encryptedData = encryptWithAES(data, keyResponse.plaintext().asByteArray());
// Clear plaintext key from memory
Arrays.fill(keyResponse.plaintext().asByteArray(), (byte) 0);
return new DataKeyResult(encryptedData, keyResponse.ciphertextBlob().asByteArray());
} catch (KmsException e) {
throw new RuntimeException("Envelope encryption failed: " + e.awsErrorDetails().errorCode(), e);
}
}
public byte[] decryptWithEnvelope(KmsClient kmsClient, DataKeyResult encryptedEnvelope) {
try {
DecryptRequest keyDecryptRequest = DecryptRequest.builder()
.ciphertextBlob(SdkBytes.fromByteArray(encryptedEnvelope.encryptedKey()))
.build();
DecryptResponse keyDecryptResponse = kmsClient.decrypt(keyDecryptRequest);
// Validate response
if (keyDecryptResponse.plaintext() == null) {
throw new IllegalStateException("Key decryption returned null");
}
byte[] decryptedData = decryptWithAES(
encryptedEnvelope.encryptedData(),
keyDecryptResponse.plaintext().asByteArray());
// Clear plaintext key from memory
Arrays.fill(keyDecryptResponse.plaintext().asByteArray(), (byte) 0);
return decryptedData;
} catch (KmsException e) {
throw new RuntimeException("Envelope decryption failed: " + e.awsErrorDetails().errorCode(), e);
}
}
数字签名
创建签名密钥并签名数据
public String createAndSignData(KmsClient kmsClient, String description, String message) {
// Create signing key
CreateKeyRequest keyRequest = CreateKeyRequest.builder()
.description(description)
.keySpec(KeySpec.RSA_2048)
.keyUsage(KeyUsageType.SIGN_VERIFY)
.build();
CreateKeyResponse keyResponse = kmsClient.createKey(keyRequest);
String keyId = keyResponse.keyMetadata().keyId();
// Sign data
SignRequest signRequest = SignRequest.builder()
.keyId(keyId)
.message(SdkBytes.fromString(message, StandardCharsets.UTF_8))
.signingAlgorithm(SigningAlgorithmSpec.RSASSA_PSS_SHA_256)
.build();
SignResponse signResponse = kmsClient.sign(signRequest);
return Base64.getEncoder().encodeToString(
signResponse.signature().asByteArray());
}
验证签名
public boolean verifySignature(KmsClient kmsClient,
String keyId,
String message,
String signatureBase64) {
byte[] signature = Base64.getDecoder().decode(signatureBase64);
VerifyRequest verifyRequest = VerifyRequest.builder()
.keyId(keyId)
.message(SdkBytes.fromString(message, StandardCharsets.UTF_8))
.signature(SdkBytes.fromByteArray(signature))
.signingAlgorithm(SigningAlgorithmSpec.RSASSA_PSS_SHA_256)
.build();
VerifyResponse verifyResponse = kmsClient.verify(verifyRequest);
return verifyResponse.signatureValid();
}
Spring Boot 集成
配置类
@Configuration
public class KmsConfiguration {
@Bean
public KmsClient kmsClient() {
return KmsClient.builder()
.region(Region.US_EAST_1)
.build();
}
@Bean
public KmsAsyncClient kmsAsyncClient() {
return KmsAsyncClient.builder()
.region(Region.US_EAST_1)
.build();
}
}
加密服务
@Service
@RequiredArgsConstructor
public class KmsEncryptionService {
private final KmsClient kmsClient;
@Value("${kms.encryption-key-id}")
private String keyId;
public String encrypt(String plaintext) {
try {
EncryptRequest request = EncryptRequest.builder()
.keyId(keyId)
.plaintext(SdkBytes.fromString(plaintext, StandardCharsets.UTF_8))
.build();
EncryptResponse response = kmsClient.encrypt(request);
return Base64.getEncoder().encodeToString(
response.ciphertextBlob().asByteArray());
} catch (KmsException e) {
throw new RuntimeException("Encryption failed", e);
}
}
public String decrypt(String ciphertextBase64) {
try {
byte[] ciphertext = Base64.getDecoder().decode(ciphertextBase64);
DecryptRequest request = DecryptRequest.builder()
.ciphertextBlob(SdkBytes.fromByteArray(ciphertext))
.build();
DecryptResponse response = kmsClient.decrypt(request);
return response.plaintext().asString(StandardCharsets.UTF_8);
} catch (KmsException e) {
throw new RuntimeException("Decryption failed", e);
}
}
}
示例
基本加密示例
public class BasicEncryptionExample {
public static void main(String[] args) {
KmsClient kmsClient = KmsClient.builder()
.region(Region.US_EAST_1)
.build();
// Create key
String keyId = createEncryptionKey(kmsClient, "Example encryption key");
System.out.println("Created key: " + keyId);
// Encrypt and decrypt
String plaintext = "Hello, World!";
String encrypted = encryptData(kmsClient, keyId, plaintext);
String decrypted = decryptData(kmsClient, encrypted);
System.out.println("Original: " + plaintext);
System.out.println("Decrypted: " + decrypted);
}
}
信封加密示例
public class EnvelopeEncryptionExample {
public static void main(String[] args) {
KmsClient kmsClient = KmsClient.builder()
.region(Region.US_EAST_1)
.build();
String masterKeyId = "alias/your-master-key";
String largeData = "This is a large amount of data that needs encryption...";
byte[] data = largeData.getBytes(StandardCharsets.UTF_8);
// Encrypt using envelope pattern
DataKeyResult encryptedEnvelope = encryptWithEnvelope(
kmsClient, masterKeyId, data);
// Decrypt
byte[] decryptedData = decryptWithEnvelope(
kmsClient, encryptedEnvelope);
String result = new String(decryptedData, StandardCharsets.UTF_8);
System.out.println("Decrypted: " + result);
}
}
最佳实践
安全
- 大型数据始终使用信封加密 - 在本地加密数据,仅使用 KMS 加密数据密钥
- 使用加密上下文 - 添加上下文信息,以便跟踪和审计使用情况
- 切勿记录敏感数据 - 避免记录明文或加密密钥
- 实施适当的密钥生命周期管理 - 启用自动轮换并设置删除策略
- 针对不同用途使用不同密钥 - 不要在多个应用程序之间重复使用密钥
性能
- 缓存已加密的数据密钥 - 通过缓存数据密钥减少 KMS API 调用
- 使用异步操作 - 利用异步客户端实现非阻塞 I/O
- 重复使用客户端实例 - 不要为每次操作都创建新客户端
- 实施连接池 - 配置适当的连接池设置
错误处理
- 实施重试逻辑 - 使用指数退避处理限流异常
- 检查密钥状态 - 执行操作前确认密钥已启用
- 使用熔断器 - 在 KMS 中断期间防止故障级联
- 全面记录错误 - 包含 KMS 错误代码和上下文信息
参考资料
有关详细的实现模式、高级技术和全面示例,请参阅:
- @references/technical-guide.md - 完整的技术实现模式
- @references/spring-boot-integration.md - Spring Boot 集成模式
- @references/testing.md - 测试策略和示例
- @references/best-practices.md - 安全和运维最佳实践
相关技能
@aws-sdk-java-v2-core - AWS SDK 核心模式和配置@aws-sdk-java-v2-dynamodb - DynamoDB 集成模式@aws-sdk-java-v2-secrets-manager - 密钥管理模式@spring-boot-dependency-injection - Spring 依赖注入模式
外部参考
限制和警告
- 数据大小限制:直接加密的数据大小限制为 4KB;更大的数据请使用信封加密
- 密钥使用限制:KMS 对每秒 API 调用次数设有配额
- 密钥材料:AWS 无法管理已导入密钥材料的轮换
- 密钥删除:删除密钥需要等待 7-30 天
- 区域边界:KMS 密钥无法跨区域使用
- 成本注意事项:KMS 按 API 调用次数和密钥存储收费
- 非对称密钥:并非所有区域都支持非对称密钥类型
- 密钥策略:更改密钥策略前需要仔细审核 IAM
- 信封加密:必须正确实施,确保数据密钥安全
- 日志记录:启用 CloudTrail,以审计所有 KMS API 使用情况
评论
支持 Markdown