Java 데이터 키 캐싱 예제 - AWS 암호화 SDK

문서의 영문과 번역 사이에 충돌이 있는 경우에는 영문 버전을 따릅니다. 번역 버전은 기계 번역을 사용하여 제공합니다.

Java 데이터 키 캐싱 예제

이 코드 예제는 local cache Java에서. AWS 암호화 SDK의 Java 구현에 대한 자세한 내용은 Java용 AWS 암호화 SDK 단원을 참조하십시오.

이 코드는 local cache의 인스턴스 두 개를 만듭니다. 하나는 데이터를 암호화하는 데이터 생산자용 인스턴스이고, 다른 하나는 데이터를 해독하는 소비자(AWS Lambda 함수)용 인스턴스입니다. 자세한 구현 방법은 AWS 암호화 SDK용 Javadoc을 참조하십시오.

Producer

생산자는 맵을 받아 JSON으로 변환하고 AWS 암호화 SDK를 사용하여 암호화한 후, 각 AWS 리전의 Kinesis 스트림에 암호화 텍스트 레코드를 푸시합니다.

이 코드는 암호화 자료 관리자 캐싱(CMM 캐싱)를 정의하고 local cache 및 기본 AWS KMS 마스터 키 공급자와 연결합니다. CMM 캐싱은 마스터 키 공급자의 데이터 키(및 관련 암호화 자료)를 캐싱합니다. 또한 SDK를 대신하여 캐시와 상호 작용하고 사용자가 설정한 보안 임계값을 적용합니다.

encryptData 메서드를 호출하면 일반 암호화 자료 관리자(CMM) 또는 마스터 키 공급자 대신에 CMM 캐싱이 지정되므로, 이 메서드에는 데이터 키 캐싱이 사용됩니다.

/* * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except * in compliance with the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package com.amazonaws.crypto.examples.kinesisdatakeycaching; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoResult; import com.amazonaws.encryptionsdk.MasterKeyProvider; import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager; import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache; import com.amazonaws.encryptionsdk.kms.KmsMasterKey; import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider; import com.amazonaws.encryptionsdk.multi.MultipleProviderFactory; import com.amazonaws.regions.Region; import com.amazonaws.services.kinesis.AmazonKinesis; import com.amazonaws.services.kinesis.AmazonKinesisClientBuilder; import com.amazonaws.util.json.Jackson; /** * Pushes data to Kinesis Streams in multiple Regions. */ public class MultiRegionRecordPusher { private static long MAX_ENTRY_AGE_MILLISECONDS = 300000; private static long MAX_ENTRY_USES = 100; private static int MAX_CACHE_ENTRIES = 100; private final String streamName_; private ArrayList<AmazonKinesis> kinesisClients_; private CachingCryptoMaterialsManager cachingMaterialsManager_; private AwsCrypto crypto_; /** * Creates an instance of this object with Kinesis clients for all target Regions * and a cached key provider containing KMS master keys in all target Regions. */ public MultiRegionRecordPusher(final Region[] regions, final String kmsAliasName, final String streamName){ streamName_ = streamName; crypto_ = new AwsCrypto(); kinesisClients_ = new ArrayList<AmazonKinesis>(); DefaultAWSCredentialsProviderChain credentialsProvider = new DefaultAWSCredentialsProviderChain(); ClientConfiguration clientConfig = new ClientConfiguration(); // Build KmsMasterKey and AmazonKinesisClient objects for each target region List<KmsMasterKey> masterKeys = new ArrayList<KmsMasterKey>(); for (Region region : regions) { kinesisClients_.add(AmazonKinesisClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(region.getName()) .build()); KmsMasterKey regionMasterKey = new KmsMasterKeyProvider( credentialsProvider, region, clientConfig, kmsAliasName ).getMasterKey(kmsAliasName); masterKeys.add(regionMasterKey); } // Collect KmsMasterKey objects into single provider and add cache MasterKeyProvider<?> masterKeyProvider = MultipleProviderFactory.buildMultiProvider( KmsMasterKey.class, masterKeys ); cachingMaterialsManager_ = CachingCryptoMaterialsManager.newBuilder() .withMasterKeyProvider(masterKeyProvider) .withCache(new LocalCryptoMaterialsCache(MAX_CACHE_ENTRIES)) .withMaxAge(MAX_ENTRY_AGE_MILLISECONDS, TimeUnit.MILLISECONDS) .withMessageUseLimit(MAX_ENTRY_USES) .build(); } /** * JSON serializes and encrypts the received record data and pushes it to all target streams. */ public void putRecord(final Map<Object, Object> data){ String partitionKey = UUID.randomUUID().toString(); Map<String, String> encryptionContext = new HashMap<String, String>(); encryptionContext.put("stream", streamName_); // JSON serialize data String jsonData = Jackson.toJsonString(data); // Encrypt data CryptoResult<byte[], ?> result = crypto_.encryptData( cachingMaterialsManager_, jsonData.getBytes(), encryptionContext ); byte[] encryptedData = result.getResult(); // Put records to Kinesis stream in all Regions for (AmazonKinesis regionalKinesisClient : kinesisClients_) { regionalKinesisClient.putRecord( streamName_, ByteBuffer.wrap(encryptedData), partitionKey ); } } }

Consumer

데이터 소비자는 AWS Lambda 트리거되는 기능 Kinesis 이벤트. 각 레코드를 해독하고 역직렬화하며 일반 텍스트 레코드를 동일 리전의 Amazon DynamoDB 테이블에 씁니다.

Producer 코드와 마찬가지로 소비자 코드는 암호화 자료 관리자 캐싱 (CMM 캐싱)에 대한 통화 decryptData 방법.

/* * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except * in compliance with the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package com.amazonaws.crypto.examples.kinesisdatakeycaching; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoResult; import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager; import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache; import com.amazonaws.encryptionsdk.kms.KmsMasterKey; import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; import com.amazonaws.services.dynamodbv2.document.DynamoDB; import com.amazonaws.services.dynamodbv2.document.Item; import com.amazonaws.services.dynamodbv2.document.Table; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.events.KinesisEvent; import com.amazonaws.services.lambda.runtime.events.KinesisEvent.KinesisEventRecord; import com.amazonaws.util.BinaryUtils; /** * Decrypts all incoming Kinesis records and writes records to DynamoDB. */ public class LambdaDecryptAndWrite { private static final long MAX_ENTRY_AGE_MILLISECONDS = 600000; private static final int MAX_CACHE_ENTRIES = 100; private CachingCryptoMaterialsManager cachingMaterialsManager_; private AwsCrypto crypto_; private Table table_; /** * Because the cache is used only for decryption, the code doesn't set * the max bytes or max message security thresholds that are enforced * only on on data keys used for encryption. */ public LambdaDecryptAndWrite() { String cmkArn = System.getenv("CMK_ARN"); cachingMaterialsManager_ = CachingCryptoMaterialsManager.newBuilder() .withMasterKeyProvider(new KmsMasterKeyProvider(cmkArn)) .withCache(new LocalCryptoMaterialsCache(MAX_CACHE_ENTRIES)) .withMaxAge(MAX_ENTRY_AGE_MILLISECONDS, TimeUnit.MILLISECONDS) .build(); crypto_ = new AwsCrypto(); String tableName = System.getenv("TABLE_NAME"); DynamoDB dynamodb = new DynamoDB(AmazonDynamoDBClientBuilder.defaultClient()); table_ = dynamodb.getTable(tableName); } /** * * @param event * @param context */ public void handleRequest(KinesisEvent event, Context context) throws UnsupportedEncodingException{ for (KinesisEventRecord record : event.getRecords()) { ByteBuffer ciphertextBuffer = record.getKinesis().getData(); byte[] ciphertext = BinaryUtils.copyAllBytesFrom(ciphertextBuffer); // Decrypt and unpack record CryptoResult<byte[], ?> plaintextResult = crypto_.decryptData(cachingMaterialsManager_, ciphertext); // Verify the encryption context value String streamArn = record.getEventSourceARN(); String streamName = streamArn.substring(streamArn.indexOf("/") + 1); if (!streamName.equals(plaintextResult.getEncryptionContext().get("stream"))) { throw new IllegalStateException("Wrong Encryption Context!"); } // Write record to DynamoDB String jsonItem = new String(plaintextResult.getResult(), "UTF-8"); System.out.println(jsonItem); table_.putItem(Item.fromJSON(jsonItem)); } } }