AWS SDK for Java + KMS で S3 暗号化

備忘録。前回の続き。

AWS SDK for Java で署名付き URL 生成 - kntmr-blog

Key Management Service (KMS) と AWS SDK for Java で、クライアントサイドで暗号化して S3 にアップロードする。

キー作成 (CMS)

事前に Key Management Service > カスタマー管理型のキー でキーを作成する。今回はダウンロードして復号したいので、キーのタイプには 対称 を選択する。

AWS Encryption SDK

AWS Encryption SDK for Java - AWS Encryption SDK

暗号化に必要なライブラリを追加。これがないと AmazonS3EncryptionV2 を初期化する際に実行時エラーが発生する。

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-encryption-sdk-java</artifactId>
    <version>2.0.0</version>
</dependency>

暗号化&アップロード

パターン1

AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
        .withCredentials(new ProfileCredentialsProvider())
        .withCryptoConfiguration(new CryptoConfigurationV2()
                .withCryptoMode(CryptoMode.StrictAuthenticatedEncryption))
        .withEncryptionMaterialsProvider(new KMSEncryptionMaterialsProvider(keyId))
        .build();

try {
    s3Encryption.putObject(bucketName, objectKey, file);
} finally {
    s3Encryption.shutdown();
}

パターン2

SDK から KMS のキーを作成してアップロードするパターン。ついでにキーの削除スケジュールをリクエストする。ScheduleKeyDeletionRequest#withPendingWindowInDays にはキーが削除可能になるまでの待機日数を指定する。(7〜30)

AWSKMS kmsClient = AWSKMSClientBuilder.standard()
        .withCredentials(new ProfileCredentialsProvider())
        .build();

CreateKeyRequest createKeyRequest = new CreateKeyRequest();
CreateKeyResult createKeyResult = kmsClient.createKey(createKeyRequest);
String keyId = createKeyResult.getKeyMetadata().getKeyId();

AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
        .withCredentials(new ProfileCredentialsProvider())
        .withCryptoConfiguration(new CryptoConfigurationV2()
                .withCryptoMode(CryptoMode.StrictAuthenticatedEncryption))
        .withEncryptionMaterialsProvider(new KMSEncryptionMaterialsProvider(keyId))
        .build();

try {
    s3Encryption.putObject(bucketName, objectKey, file);

    ScheduleKeyDeletionRequest scheduleKeyDeletionRequest = new ScheduleKeyDeletionRequest()
            .withKeyId(keyId)
            .withPendingWindowInDays(7);
    kmsClient.scheduleKeyDeletion(scheduleKeyDeletionRequest);
} finally {
    s3Encryption.shutdown();
    kmsClient.shutdown();
}

ダウンロード&復号

AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
        .withCredentials(new ProfileCredentialsProvider())
        .withCryptoConfiguration(new CryptoConfigurationV2()
                .withCryptoMode(CryptoMode.StrictAuthenticatedEncryption))
        .withEncryptionMaterialsProvider(new KMSEncryptionMaterialsProvider(keyId))
        .build();

try {
    GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectKey);
    s3Encryption.getObject(getObjectRequest, file);
} finally {
    s3Encryption.shutdown();
}

その他

暗号化したときの keyId 以外を指定した場合、AmazonS3EncryptionV2#getObject でエラーが発生する。(status code 400)

com.amazonaws.services.kms.model.IncorrectKeyException: The key ID in the request does not identify a CMK that can perform this operation.

暗号化してアップロードしたファイルは AmazonS3#getObject でもダウンロードできるが、暗号化されているため開けない。マネジメントコンソールからダウンロードした場合も同様に開けない。

暗号化したファイルのコピーや削除では keyId の指定は不要で、AmazonS3#copyObject or AmazonS3.deleteObject が使える。もちろん、暗号化したままコピーされる。