mcpField
A
aws-sdk-java-v2-kms

aws-sdk-java-v2-kms

github.com/giuseppe-trisciuoglio安全3653.7k 次安装7 周前更新
代码仓库

关于 aws-sdk-java-v2-kms

面向 Java 开发者的技能,提供使用 AWS SDK for Java 2.x 操作 AWS KMS 的实现模式。内容包括密钥管理、加密解密、信封加密、数字签名及 Spring Boot 集成。

主要功能

  1. 01创建和管理 KMS 密钥
  2. 02加密与解密数据
  3. 03使用信封加密处理大数据
  4. 04生成并验证数字签名
  5. 05集成 Spring Boot

适用场景

  1. 01为数据保护配置对称密钥
  2. 02使用数据密钥加密较大数据
  3. 03为应用设置数字签名
  4. 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.md
spring-boot-integration.md
technical-guide.md
testing.md

详细介绍

AWS SDK for Java 2.x - AWS KMS(密钥管理服务)

概述

使用 AWS SDK for Java 2.x 提供 AWS KMS 模式。涵盖密钥管理、加密/解密、信封加密、数字签名和 Spring Boot 集成。

说明

  1. 设置 IAM 权限 - 以最小权限原则授予 kms:* 操作权限
  2. 创建 KMS 客户端 - 使用区域和凭证实例化 KmsClient
  3. 创建密钥 - 使用 createKey() → 继续前请确认密钥状态为 ENABLED
  4. 设置密钥策略 - 定义密钥使用权限 → 投入生产前测试访问权限
  5. 加密数据 - 对小于 4KB 的数据使用 encrypt();确认密文不为空
  6. 信封加密 - 对于较大的数据,使用 generateDataKey() → 确认数据密钥生成成功
  7. 数字签名 - 创建签名密钥 → 签名/验证后确认 signatureValid=true
  8. 密钥轮换 - 启用自动轮换 → 确认轮换计划已启用

适用场景

  • 创建/管理用于数据保护的对称加密密钥
  • 为大型数据实现信封加密
  • 使用由 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