AWS KMS 계층적 키링 - AWS Encryption SDK

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

AWS KMS 계층적 키링

중요

AWS KMS 계층적 키링은 버전 4에서만 지원됩니다. 형태의 x. AWS Encryption SDK NET및 버전 3. 의 x AWS Encryption SDK for Java.

AWS KMS 계층적 키링을 사용하면 데이터를 암호화하거나 복호화할 AWS KMS 때마다 전화를 걸지 않고도 대칭형 암호화 KMS 키로 암호화 자료를 보호할 수 있습니다. 이는 AWS KMS호출을 최소화해야 하는 애플리케이션과, 보안 요구 사항을 위반하지 않으면서 일부 암호화 자료를 재사용할 수 있는 애플리케이션에 적합합니다.

계층적 키링은 Amazon DynamoDB 테이블에 AWS KMS 유지되는 보호된 분기 키를 사용하고 암호화 및 복호화 작업에 사용되는 분기 키 자료를 로컬에 캐싱함으로써 AWS KMS 호출 횟수를 줄이는 암호화 자료 캐싱 솔루션입니다. DynamoDB 테이블은 브랜치 키를 관리하고 보호하는 브랜치 키 스토어 역할을 합니다. 활성 브랜치 키와 모든 이하 버전의 브랜치 키를 저장합니다. 활성 브랜치 키는 최신 버전의 브랜치 키입니다. 계층적 키링은 고유한 데이터 키를 사용하여 각 메시지를 암호화하고 활성 브랜치 키에서 파생된 고유한 래핑 키로 각 데이터 키를 암호화합니다. 계층적 키링은 활성 브랜치 키와 파생된 래핑 키 사이에 설정된 계층 구조에 따라 달라집니다.

계층적 키링은 일반적으로 각 브랜치 키 버전을 사용하여 여러 요청을 충족합니다. 하지만 활성 브랜치 키의 재사용 범위를 제어하고 활성 브랜치 키의 교체 빈도를 결정할 수 있습니다. 브랜치 키의 활성 버전은 교체할 때까지 활성 상태로 유지됩니다. 이하 버전의 활성 브랜치 키는 암호화 작업을 수행하는 데 사용되지 않지만 여전히 쿼리를 통해 복호화 작업에 사용할 수 있습니다.

계층적 키링을 인스턴스화하면 로컬 캐시가 생성됩니다. 캐시 제한을 지정하고 브랜치 키 자료가 만료되어 캐시에서 제거되기 전에 로컬 캐시에 저장되는 최대 시간을 정의합니다. 계층적 키링은 작업에서 a가 처음 지정될 때 한 번의 AWS KMS 호출을 통해 분기 키를 해독하고 분기 키 자료를 조합합니다. branch-key-id 그러면 브랜치 키 자료가 로컬 캐시에 저장되고 캐시 제한이 만료될 때까지 branch-key-id를 지정하는 모든 암호화 및 복호화 작업에 브랜치 키 자료가 재사용됩니다. 브랜치 키 자료를 로컬 캐시에 저장하면 호출 횟수가 줄어듭니다. AWS KMS 예를 들어, 캐시 한도를 15분으로 가정해 보겠습니다. 해당 캐시 한도 내에서 10,000개의 암호화 작업을 수행하는 경우 기존 AWS KMS 키링은 10,000개의 암호화 작업을 처리하기 위해 AWS KMS 10,000번의 호출을 수행해야 합니다. branch-key-id활성화된 키링이 하나라도 있는 경우 계층 키링을 한 번만 AWS KMS 호출하면 10,000개의 암호화 작업을 처리할 수 있습니다.

로컬 캐시는 두 개의 파티션으로 구성되어 있는데, 하나는 암호화 작업용이고 다른 하나는 복호화 작업용입니다. 암호화 파티션은 활성 브랜치 키에서 조합된 브랜치 키 자료를 저장하고 캐시 제한이 만료될 때까지 모든 암호화 작업에 이를 재사용합니다. 복호화 파티션에는 복호화 작업에서 식별된 다른 브랜치 키 버전용으로 조합된 브랜치 키 자료가 저장됩니다. 복호화 파티션은 한 번에 여러 활성 브랜치 키 자료 버전을 저장할 수 있습니다. 멀티테넌트 환경에서 브랜치 키 ID 공급자를 사용하도록 구성된 경우 암호화 파티션은 한 번에 여러 브랜치 키 자료 버전을 저장할 수도 있습니다. 자세한 내용은 멀티테넌트 환경에서 계층적 키링 사용 단원을 참조하십시오.

참고

계층적 키링에 대한 모든 언급은 계층적 키링을 참조합니다. AWS Encryption SDK AWS KMS

작동 방식

다음 연습에서는 계층적 키링이 암호화 및 복호화 자료를 조합하는 방법과 암호화 및 복호화 작업에 대해 키링이 수행하는 다양한 호출을 설명합니다. 래핑 키 파생 및 일반 텍스트 데이터 키 암호화 프로세스에 대한 기술 세부 정보는 AWS KMS 계층적 키링 기술 세부 정보를 참조하세요.

암호화 및 서명

다음 연습에서는 계층적 키링이 암호화 자료를 조합하고 고유한 래핑 키를 도출하는 방법을 설명합니다.

  1. 암호화 메서드는 계층적 키링에 암호화 자료를 요청합니다. 키링은 일반 텍스트 데이터 키를 생성한 다음 로컬 캐시에 유효한 브랜치 자료가 있는지 확인하여 래핑 키를 생성합니다. 유효한 브랜치 키 자료가 있는 경우 키링은 4단계로 진행됩니다.

  2. 유효한 브랜치 키 자료가 없는 경우 계층적 키링은 브랜치 키 저장소에 활성 브랜치 키를 쿼리합니다.

    1. 분기 키 저장소는 활성 분기 키를 AWS KMS 해독하도록 호출하고 일반 텍스트의 활성 분기 키를 반환합니다. 활성 분기 키를 식별하는 데이터는 직렬화되어 복호화 호출 시 인증된 추가 데이터 (AAD) 를 제공합니다. AWS KMS

    2. 브랜치 키 저장소는 일반 텍스트 브랜치 키와 이를 식별하는 데이터(예: 브랜치 키 버전)를 반환합니다.

  3. 계층적 키링은 브랜치 키 자료(일반 텍스트 브랜치 키 및 브랜치 키 버전)를 조합하여 로컬 캐시에 사본을 저장합니다.

  4. 계층적 키링은 일반 텍스트 브랜치 키와 16바이트 무작위 솔트에서 고유한 래핑 키를 가져옵니다. 파생된 래핑 키를 사용하여 일반 텍스트 데이터 키의 사본을 암호화합니다.

암호화 메서드로 암호화 자료를 사용하여 데이터를 암호화합니다. 자세한 내용은 AWS Encryption SDK 가 데이터를 암호화하는 방법을 참조하세요.

복호화 및 확인

다음 안내에서는 계층적 키링이 복호화 자료를 조합하고 암호화된 데이터 키를 복호화하는 방법을 설명합니다.

  1. 복호화 메서드는 암호화된 메시지에서 암호화된 데이터 키를 식별하여 계층적 키링에 전달합니다.

  2. 계층적 키링은 브랜치 키 버전, 16바이트 솔트 및 데이터 키가 암호화된 방법을 설명하는 기타 정보 등 암호화된 데이터 키를 식별하는 데이터를 역직렬화합니다.

    자세한 내용은 AWS KMS 계층적 키링 기술 세부 정보 섹션을 참조하세요.

  3. 계층적 키링은 2단계에서 식별한 브랜치 키 버전과 일치하는 유효한 브랜치 키 자료가 로컬 캐시에 있는지 확인합니다. 유효한 브랜치 키 자료가 있는 경우 키링은 6단계로 진행됩니다.

  4. 유효한 브랜치 키 자료가 없는 경우 계층적 키링은 2단계에서 식별한 브랜치 키 버전과 일치하는 브랜치 키를 브랜치 키 저장소에 쿼리합니다.

    1. 브랜치 키 저장소는 브랜치 키를 복호화하기 AWS KMS 위해 호출하고 일반 텍스트의 활성 브랜치 키를 반환합니다. 활성 분기 키를 식별하는 데이터는 직렬화되어 복호화 호출 시 인증된 추가 데이터 (AAD) 를 제공합니다. AWS KMS

    2. 브랜치 키 저장소는 일반 텍스트 브랜치 키와 이를 식별하는 데이터(예: 브랜치 키 버전)를 반환합니다.

  5. 계층적 키링은 브랜치 키 자료(일반 텍스트 브랜치 키 및 브랜치 키 버전)를 조합하여 로컬 캐시에 사본을 저장합니다.

  6. 계층적 키링은 조합된 브랜치 키 자료와 2단계에서 식별한 16바이트 솔트를 사용하여 데이터 키를 암호화한 고유 래핑 키를 재현합니다.

  7. 계층적 키링은 재생된 래핑 키를 사용하여 데이터 키를 복호화하고 일반 텍스트 데이터 키를 반환합니다.

복호화 메서드는 복호화 자료와 일반 텍스트 데이터 키를 사용하여 암호화된 메시지를 복호화합니다. 자세한 내용은 암호화된 메시지를 AWS Encryption SDK 복호화하는 방법을 참조하십시오.

사전 조건

a가 AWS Encryption SDK 필요하지 AWS 계정 않으며 어떤 것에도 의존하지 않습니다. AWS 서비스하지만 계층적 키링은 Amazon AWS KMS DynamoDB에 따라 달라집니다.

계층적 키링을 사용하려면 KMS:Decrypt 권한을 사용한 대칭 암호화가 필요합니다. AWS KMS key 대칭 암호화 다중 리전 키를 사용할 수도 있습니다. 권한에 대한 자세한 내용은 개발자 안내서의 인증 및 액세스 AWS KMS keys제어를 참조하십시오.AWS Key Management Service

계층적 키링을 생성하여 사용하려면 먼저 브랜치 키 스토어를 생성하고 첫 번째 활성 브랜치 키로 이를 채워야 합니다.

1단계: 새 키 스토어 서비스 구성

키 저장소 서비스는 계층적 키링 사전 요구 사항을 CreateKeyStore 조합하고 CreateKey 브랜치 키 저장소를 관리하는 데 도움이 되는 및 등의 여러 API 작업을 제공합니다.

다음 예시에서는 키 저장소 서비스를 생성합니다. 분기 키 스토어의 이름, 분기 키 스토어의 논리적 이름, 분기 키를 보호할 키를 식별하는 KMS 키로 사용할 DynamoDB 테이블 이름을 지정해야 합니다. KMS ARN

논리적 키 스토어 이름은 테이블에 저장된 모든 데이터에 암호로 바인딩되어 DynamoDB 복원 작업을 간소화합니다. 논리적 키 스토어 이름은 DynamoDB 테이블 이름과 같을 수 있지만 반드시 같을 필요는 없습니다. 키 스토어 서비스를 처음 구성할 때 DynamoDB 테이블 이름을 논리적 테이블 이름으로 지정하는 것이 좋습니다. 항상 같은 논리적 테이블 이름을 지정해야 합니다. 백업에서 DynamoDB 테이블을 복원한 후 브랜치 키 스토어 이름이 변경된 경우, 계층적 키링이 브랜치 키 스토어에 계속 액세스할 수 있도록 논리적 키 스토어 이름이 지정한 DynamoDB 테이블 이름에 매핑됩니다.

참고

논리적 키 스토어 이름은 호출하는 모든 키 스토어 서비스 API 작업의 암호화 컨텍스트에 포함됩니다. AWS KMS암호화 컨텍스트는 비밀이 아니며, 논리적 키 저장소 이름을 비롯한 암호화 컨텍스트의 값은 로그에 일반 텍스트로 표시됩니다. AWS CloudTrail

C# / .NET
var kmsConfig = new KMSConfiguration { KmsKeyArn = kmsKeyArn }; var keystoreConfig = new KeyStoreConfig { KmsClient = new AmazonKeyManagementServiceClient(), KmsConfiguration = kmsConfig, DdbTableName = keyStoreName, DdbClient = new AmazonDynamoDBClient(), LogicalKeyStoreName = logicalKeyStoreName }; var keystore = new KeyStore(keystoreConfig);
Java
final KeyStore keystore = KeyStore.builder().KeyStoreConfig( KeyStoreConfig.builder() .ddbClient(DynamoDbClient.create()) .ddbTableName(keyStoreName) .logicalKeyStoreName(logicalKeyStoreName) .kmsClient(KmsClient.create()) .kmsConfiguration(KMSConfiguration.builder() .kmsKeyArn(kmsKeyArn) .build()) .build()).build();
2단계: CreateKeyStore 호출을 통한 브랜치 키 저장소 생성

다음 작업을 수행하면 브랜치 키를 유지하고 보호할 브랜치 키 스토어가 생성됩니다.

C# / .NET
var createKeyStoreOutput = keystore.CreateKeyStore(new CreateKeyStoreInput());
Java
keystore.CreateKeyStore(CreateKeyStoreInput.builder().build());

CreateKeyStore 작업을 수행하면 1단계에서 지정한 테이블 이름과 다음 필수 값을 사용하여 DynamoDB 테이블이 생성됩니다.

파티션 키 정렬 키
기본 테이블 branch-key-id type
참고

작업을 사용하는 대신 분기 키 스토어 역할을 하는 DynamoDB 테이블을 수동으로 생성할 수 있습니다. CreateKeyStore 브랜치 키 스토어를 수동으로 생성하기로 선택한 경우 파티션 및 정렬 키에 다음 문자열 값을 지정해야 합니다.

  • 파티션 키: branch-key-id

  • Sort key: type

3단계: CreateKey 호출을 통한 새 활성 브랜치 키 생성

다음 작업은 1단계에서 지정한 키를 사용하여 새 활성 분기 KMS 키를 생성하고 2단계에서 생성한 DynamoDB 테이블에 활성 분기 키를 추가합니다.

CreateKey를 호출할 때 다음과 같은 선택적 값을 지정하도록 선택할 수 있습니다.

  • 분기 키 식별자: 사용자 지정을 정의합니다. branch-key-id

    사용자 지정 branch-key-id를 만들려면 encryptionContext 파라미터에 추가 암호화 컨텍스트도 포함해야 합니다.

  • 암호화 컨텍스트: kms: 호출에 포함된 암호화 컨텍스트에 인증된 추가 데이터 (AAD) 를 제공하는 선택적 비비밀 키-값 쌍 세트를 정의합니다. GenerateDataKeyWithoutPlaintext

    이 추가 암호화 컨텍스트는 aws-crypto-ec: 접두사와 표시됩니다.

C# / .NET
var additionalEncryptionContext = new Dictionary<string, string>(); additionalEncryptionContext.Add("Additional Encryption Context for", "custom branch key id"); var branchKeyId = keystore.CreateKey(new CreateKeyInput { BranchKeyIdentifier = "custom-branch-key-id", // OPTIONAL EncryptionContext = additionalEncryptionContext // OPTIONAL });
Java
final Map<String, String> additionalEncryptionContext = Collections.singletonMap("Additional Encryption Context for", "custom branch key id"); final String BranchKey = keystore.CreateKey( CreateKeyInput.builder() .branchKeyIdentifier(custom-branch-key-id) //OPTIONAL .encryptionContext(additionalEncryptionContext) //OPTIONAL .build()).branchKeyIdentifier();

먼저, CreateKey 작업은 다음 값을 생성합니다.

그러면 CreateKey 작업은 다음 요청을 GenerateDataKeyWithoutPlaintext 사용하여 kms:를 호출합니다.

{ "EncryptionContext": { "branch-key-id" : "branch-key-id", "type" : "type", "create-time" : "timestamp", "logical-key-store-name" : "the logical table name for your branch key store", "kms-arn" : the KMS key ARN, "hierarchy-version" : "1", "aws-crypto-ec:contextKey": "contextValue" }, "KeyId": "the KMS key ARN you specified in Step 1", "NumberOfBytes": "32" }

그런 다음 CreateKey 작업은 ReEncryptkms:를 호출하여 암호화 컨텍스트를 업데이트하여 분기 키에 대한 활성 레코드를 생성합니다.

마지막으로 CreateKey 작업은 TransactWriteItemsddb:를 호출하여 2단계에서 만든 테이블에 분기 키를 유지할 새 항목을 작성합니다. 항목에는 다음 속성이 있습니다.

{ "branch-key-id" : branch-key-id, "type" : "branch:ACTIVE", "enc" : the branch key returned by the GenerateDataKeyWithoutPlaintext call, "version": "branch:version:the branch key version UUID", "create-time" : "timestamp", "kms-arn" : "the KMS key ARN you specified in Step 1", "hierarchy-version" : "1", "aws-crypto-ec:contextKey": "contextValue" }

계층적 키링 생성

계층적 키링을 초기화하려면 다음 값을 제공해야 합니다.

  • 브랜치 키 스토어 이름

    브랜치 키 스토어로 사용하기 위해 생성한 DynamoDB 테이블의 이름입니다.

  • 캐시 제한 지속 시간 () TTL

    로컬 캐시 내의 브랜치 키 자료 항목이 만료되기 전에 사용할 수 있는 시간(초) 입니다. 이 값은 0보다 커야 합니다. 캐시 제한이 TTL 만료되면 항목이 로컬 캐시에서 제거됩니다.

  • 브랜치 키 식별자

    branch-key-id는 브랜치 키 스토어의 활성 브랜치 키를 식별합니다.

    참고

    멀티테넌트 사용을 위한 계층적 키링을 초기화하려면 branch-key-id 대신 브랜치 키 ID 공급자를 지정해야 합니다. 자세한 내용은 멀티테넌트 환경에서 계층적 키링 사용 섹션을 참조하세요.

  • (선택 사항) 캐시

    캐시 유형이나 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목 수를 사용자 지정하려면 키링을 초기화할 때 캐시 유형과 항목 용량을 지정하세요.

    캐시 유형은 스레딩 모델을 정의합니다. 계층적 키링은 멀티테넌트 환경을 지원하는 세 가지 캐시 유형 (Default,,) 을 제공합니다. MultiThreaded StormTracking

    캐시를 지정하지 않으면 계층적 키링은 자동으로 기본 캐시 유형을 사용하고 항목 용량을 1,000으로 설정합니다.

    Default (Recommended)

    대부분 사용자의 경우 기본 캐시로 스레딩 요구 사항을 충족합니다. 기본 캐시는 멀티스레드가 많은 환경을 지원하도록 설계되었습니다. 분기 키 구성 요소 항목이 만료되면 기본 캐시는 분기 키 구성 요소 항목이 10초 전에 만료될 것임을 하나의 스레드에 알리므로 여러 스레드가 AWS KMS 호출되고 Amazon DynamoDB가 여러 스레드를 호출하는 것을 방지합니다. 이렇게 하면 하나의 스레드만 캐시 새로 고침 요청을 보낼 수 있습니다. AWS KMS

    기본 캐시를 사용하여 계층적 키링을 초기화하려면 다음 값을 지정하세요.

    • 항목 용량: 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목의 수를 제한합니다.

    C#/. NET
    CacheType defaultCache = new CacheType { Default = new DefaultCache{EntryCapacity = 100} };
    Java
    .cache(CacheType.builder() .Default(DefaultCache.builder() .entryCapacity(100) .build())

    기본 StormTracking 캐시와 캐시는 동일한 스레딩 모델을 지원하지만 기본 캐시를 사용하여 계층 키링을 초기화하려면 입력 용량만 지정하면 됩니다. 캐시를 더 세밀하게 사용자 지정하려면 캐시를 사용하십시오. StormTracking

    MultiThreaded

    MultiThreaded 캐시는 멀티스레드 환경에서 안전하게 사용할 수 있지만 Amazon AWS KMS DynamoDB 호출을 최소화하는 기능은 제공하지 않습니다. 따라서 브랜치 키 자료 입력이 만료되면 동시에 모든 스레드로 알림이 전송됩니다. 이로 인해 캐시 새로 고침을 위한 AWS KMS 호출이 여러 번 발생할 수 있습니다.

    캐시를 사용하여 계층적 키링을 초기화하려면 다음 값을 지정하십시오. MultiThreaded

    • 항목 용량: 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목의 수를 제한합니다.

    • 항목 정리 테일 크기: 항목 용량에 도달한 경우 정리할 항목 수를 정의합니다.

    C#/. NET
    CacheType multithreadedCache = new CacheType { MultiThreaded = new MultiThreadedCache { EntryCapacity = 100, EntryPruningTailSize = 1 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .build())
    StormTracking

    StormTracking 캐시는 멀티스레드가 많은 환경을 지원하도록 설계되었습니다. 분기 키 구성 요소 항목이 만료되면 StormTracking 캐시는 분기 키 구성 요소 항목이 만료될 것임을 한 스레드에 미리 알려 여러 스레드가 AWS KMS 호출하고 Amazon DynamoDB를 호출하는 것을 방지합니다. 이렇게 하면 하나의 스레드만 캐시 새로 고침 요청을 보낼 수 있습니다. AWS KMS

    StormTracking 캐시를 사용하여 계층적 키링을 초기화하려면 다음 값을 지정하십시오.

    • 항목 용량: 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목의 수를 제한합니다.

    • 항목 정리 테일 크기: 한 번에 정리할 브랜치 키 자료 항목의 수를 정의합니다.

      기본값: 항목 1개

    • 유예 기간: 브랜치 키 자료를 새로 고치려는 시도가 만료되기까지 걸리는 시간(초)을 정의합니다.

      기본값: 10초

    • 유예 간격: 브랜치 키 자료의 새로 고침 시도 간격(초)을 정의합니다.

      기본값: 1초

    • 팬아웃: 브랜치 키 자료를 새로 고칠 수 있는 동시 시도 횟수를 정의합니다.

      기본값: 20회 시도

    • In flight time to live (TTL): 브랜치 키 자료를 새로 고치려는 시도 시간이 초과될 때까지의 시간 (초) 을 정의합니다. GetCacheEntry에 대한 응답으로 캐시가 NoSuchEntry를 반환할 때마다 해당 브랜치 키는 PutCache 항목과 동일한 키가 기록될 때까지 전송 중인 것으로 간주됩니다.

      기본값: 20초

    • 절전: fanOut 초과 시 스레드가 절전 상태로 유지되는 시간(초)을 정의합니다.

      기본값: 20밀리초

    C#/. NET
    CacheType stormTrackingCache = new CacheType { StormTracking = new StormTrackingCache { EntryCapacity = 100, EntryPruningTailSize = 1, FanOut = 20, GraceInterval = 1, GracePeriod = 10, InFlightTTL = 20, SleepMilli = 20 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .gracePeriod(10) .graceInterval(1) .fanOut(20) .inFlightTTL(20) .sleepMilli(20) .build())
  • (선택 사항) 권한 부여 토큰 목록

    권한 부여를 통해 계층적 KMS 키링의 키에 대한 액세스를 제어하는 경우 키링을 초기화할 때 필요한 모든 부여 토큰을 제공해야 합니다.

다음 예제는 캐시 제한이 TLL 600초이고 입력 용량이 1000인 계층적 키링을 초기화합니다.

C# / .NET
// Instantiate the AWS Encryption SDK and material providers var mpl = new MaterialProviders(new MaterialProvidersConfig()); var esdk = new ESDK(new AwsEncryptionSdkConfig()); // Instantiate the keyring var createKeyringInput = new CreateAwsKmsHierarchicalKeyringInput { KeyStore = branchKeyStoreName, BranchKeyId = branch-key-id, Cache = new CacheType { Default = new DefaultCache{EntryCapacity = 1000} }, TtlSeconds = 600 };
Java
final MaterialProviders matProv = MaterialProviders.builder() .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) .build(); final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder() .keyStore(branchKeyStoreName) .branchKeyId(branch-key-id) .ttlSeconds(600) .cache(CacheType.builder() //OPTIONAL .Default(DefaultCache.builder() .entryCapacity(1000) .build()) .build(); final Keyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);

활성 브랜치 키 교체

각 브랜치 키에는 한 번에 하나의 활성 버전만 있을 수 있습니다. 계층적 키링은 일반적으로 각 활성 브랜치 키 버전을 사용하여 여러 요청을 충족합니다. 하지만 활성 브랜치 키의 재사용 범위를 제어하고 활성 브랜치 키의 교체 빈도를 결정할 수 있습니다.

브랜치 키는 일반 텍스트 데이터 키를 암호화하는 데 사용되지 않습니다. 이들은 일반 텍스트 데이터 키를 암호화하는 고유한 래핑 키를 도출하는 데 사용됩니다. 래핑 키 추출 프로세스는 28바이트의 무작위성을 갖는 고유한 32바이트 래핑 키를 생성합니다. 즉, 브랜치 키는 암호화 마모가 발생하기 전에 79옥틸리온(296) 이상의 고유한 래핑 키를 도출할 수 있습니다. 이렇게 소진 위험은 매우 낮지만 비즈니스 또는 계약 규칙이나 정부 규정으로 인해 활성 브랜치 키를 교체해야 할 수도 있습니다.

브랜치 키의 활성 버전은 교체할 때까지 활성 상태로 유지됩니다. 이하 버전의 활성 브랜치 키는 암호화 작업을 수행하는 데 사용되지 않으며 새 래핑 키를 도출하는 데 사용할 수 없습니다. 단, 여전히 쿼리가 가능하며 활성 상태에서 암호화한 데이터 키를 복호화하기 위한 래핑 키를 제공할 수 있습니다.

키 스토어 서비스 VersionKey 작업을 사용하여 활성 브랜치 키를 교체할 수 있습니다. 활성 브랜치 키를 교체하면 이하 버전을 대체하는 새 브랜치 키가 생성됩니다. 활성 브랜치 키를 교체해도 branch-key-id는 변경되지 않습니다. VersionKey를 호출할 때 현재 활성 브랜치 키를 식별하는 branch-key-id를 지정해야 합니다.

C# / .NET
keystore.VersionKey(new VersionKeyInput{BranchKeyIdentifier = branchKeyId});
Java
keystore.VersionKey( VersionKeyInput.builder() .branchKeyIdentifier("branch-key-id") .build() );

멀티테넌트 환경에서 계층적 키링 사용

활성 브랜치 키와 파생 래핑 키 사이에 설정된 키 계층 구조에 따라 사용자 환경의 각 테넌트에 대한 브랜치 키를 생성하여 멀티테넌트 환경을 지원할 수 있습니다. 그러면 계층적 키링이 고유한 브랜치 키를 사용하여 지정된 테넌트의 모든 데이터를 암호화합니다. 이를 통해 브랜치 키별로 테넌트 데이터를 분리할 수 있습니다.

각 테넌트에는 고유한 branch-key-id로 정의된 브랜치 키가 있습니다. 각 branch-key-id에는 한 번에 하나의 활성 버전만 있을 수 있습니다.

멀티테넌트 사용을 위한 계층적 키링을 초기화하려면 먼저 각 테넌트에 대한 브랜치 키를 생성하고 브랜치 키 ID 공급자를 생성해야 합니다. 브랜치 키 ID 공급자를 사용하여 테넌트에 맞는 올바른 branch-key-id를 쉽게 알아볼 수 있도록 친숙한 branch-key-ids 이름을 만드세요. 예를 들어 친숙한 이름을 사용하면 브랜치 키를 b3f61619-4d35-48ad-a275-050f87e15122 대신 tenant1로 참조할 수 있습니다.

복호화 작업의 경우 단일 계층적 키링을 정적으로 구성하여 복호화를 단일 테넌트로 제한하거나 브랜치 키 ID 공급자를 사용하여 메시지 복호화를 담당하는 테넌트를 식별할 수 있습니다.

먼저 사전 조건 절차의 1단계와 2단계를 따르세요. 그런 다음, 다음 절차를 사용하여 각 테넌트의 브랜치 키를 생성하고, 브랜치 키 ID 공급자를 생성하고, 멀티테넌트 사용을 위한 계층적 키링을 초기화합니다.

1단계: 환경에서 각 테넌트에 대한 브랜치 키 생성

각 테넌트에 대한 CreateKey를 호출하세요.

다음 작업은 키 스토어 서비스를 생성할 때 지정한 키를 사용하여 두 개의 브랜치 키를 생성하고, 브랜치 키 스토어로 사용하기 위해 생성한 DynamoDB 테이블에 브랜치 키를 추가합니다. KMS 동일한 KMS 키로 모든 분기 키를 보호해야 합니다.

C# / .NET
var branchKeyId1 = keystore.CreateKey(new CreateKeyInput()); var branchKeyId2 = keystore.CreateKey(new CreateKeyInput());
Java
CreateKeyOutput branchKeyId1 = keystore.CreateKey(CreateKeyInput.builder().build()); CreateKeyOutput branchKeyId2 = keystore.CreateKey(CreateKeyInput.builder().build());
2단계: 브랜치 키 ID 공급자 생성

다음 예시에서는 브랜치 키 ID 공급자를 생성합니다.

C# / .NET
var branchKeySupplier = new ExampleBranchKeySupplier(branchKeyId1.BranchKeyIdentifier, branchKeyId2.BranchKeyIdentifier);
Java
IBranchKeyIdSupplier branchKeyIdSupplier = new ExampleBranchKeyIdSupplier( branchKeyId1.branchKeyIdentifier(), branchKeyId2.branchKeyIdentifier());
3단계: 브랜치 키 ID 공급자를 통해 계층적 키링을 초기화합니다.

계층적 키링을 초기화하려면 다음 값을 제공해야 합니다.

  • 브랜치 키 스토어 이름

  • 캐시 제한 지속 시간 (TTL)

  • 브랜치 키 ID 공급자

  • (선택 사항) 캐시

    캐시 유형이나 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목 수를 사용자 지정하려면 키링을 초기화할 때 캐시 유형과 항목 용량을 지정하세요.

    캐시 유형은 스레딩 모델을 정의합니다. 계층적 키링은 멀티테넌트 환경을 지원하는 세 가지 캐시 유형 (Default,,) 을 제공합니다. MultiThreaded StormTracking

    캐시를 지정하지 않으면 계층적 키링은 자동으로 기본 캐시 유형을 사용하고 항목 용량을 1,000으로 설정합니다.

    Default (Recommended)

    대부분 사용자의 경우 기본 캐시로 스레딩 요구 사항을 충족합니다. 기본 캐시는 멀티스레드가 많은 환경을 지원하도록 설계되었습니다. 분기 키 구성 요소 항목이 만료되면 기본 캐시는 분기 키 구성 요소 항목이 10초 전에 만료될 것임을 하나의 스레드에 알리므로 여러 스레드가 AWS KMS 호출되고 Amazon DynamoDB가 여러 스레드를 호출하는 것을 방지합니다. 이렇게 하면 하나의 스레드만 캐시 새로 고침 요청을 보낼 수 있습니다. AWS KMS

    기본 캐시를 사용하여 계층적 키링을 초기화하려면 다음 값을 지정하세요.

    • 항목 용량: 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목의 수를 제한합니다.

    C#/. NET
    CacheType defaultCache = new CacheType { Default = new DefaultCache{EntryCapacity = 100} };
    Java
    .cache(CacheType.builder() .Default(DefaultCache.builder() .entryCapacity(100) .build())

    기본 StormTracking 캐시와 캐시는 동일한 스레딩 모델을 지원하지만 기본 캐시를 사용하여 계층 키링을 초기화하려면 입력 용량만 지정하면 됩니다. 캐시를 더 세밀하게 사용자 지정하려면 캐시를 사용하십시오. StormTracking

    MultiThreaded

    MultiThreaded 캐시는 멀티스레드 환경에서 안전하게 사용할 수 있지만 Amazon AWS KMS DynamoDB 호출을 최소화하는 기능은 제공하지 않습니다. 따라서 브랜치 키 자료 입력이 만료되면 동시에 모든 스레드로 알림이 전송됩니다. 이로 인해 캐시 새로 고침을 위한 AWS KMS 호출이 여러 번 발생할 수 있습니다.

    MultiThreaded 캐시를 사용하여 계층적 키링을 초기화하려면 다음 값을 지정하십시오.

    • 항목 용량: 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목의 수를 제한합니다.

    • 항목 정리 테일 크기: 항목 용량에 도달한 경우 정리할 항목 수를 정의합니다.

    C#/. NET
    CacheType multithreadedCache = new CacheType { MultiThreaded = new MultiThreadedCache { EntryCapacity = 100, EntryPruningTailSize = 1 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .build())
    StormTracking

    StormTracking 캐시는 멀티스레드가 많은 환경을 지원하도록 설계되었습니다. 분기 키 구성 요소 항목이 만료되면 StormTracking 캐시는 분기 키 구성 요소 항목이 만료될 것임을 한 스레드에 미리 알려 여러 스레드가 AWS KMS 호출하고 Amazon DynamoDB를 호출하는 것을 방지합니다. 이렇게 하면 하나의 스레드만 캐시 새로 고침 요청을 보낼 수 있습니다. AWS KMS

    StormTracking 캐시를 사용하여 계층적 키링을 초기화하려면 다음 값을 지정하십시오.

    • 항목 용량: 로컬 캐시에 저장할 수 있는 브랜치 키 자료 항목의 수를 제한합니다.

    • 항목 정리 테일 크기: 한 번에 정리할 브랜치 키 자료 항목의 수를 정의합니다.

      기본값: 항목 1개

    • 유예 기간: 브랜치 키 자료를 새로 고치려는 시도가 만료되기까지 걸리는 시간(초)을 정의합니다.

      기본값: 10초

    • 유예 간격: 브랜치 키 자료의 새로 고침 시도 간격(초)을 정의합니다.

      기본값: 1초

    • 팬아웃: 브랜치 키 자료를 새로 고칠 수 있는 동시 시도 횟수를 정의합니다.

      기본값: 20회 시도

    • In flight time to live (TTL): 브랜치 키 자료를 새로 고치려는 시도 시간이 초과될 때까지의 시간 (초) 을 정의합니다. GetCacheEntry에 대한 응답으로 캐시가 NoSuchEntry를 반환할 때마다 해당 브랜치 키는 PutCache 항목과 동일한 키가 기록될 때까지 전송 중인 것으로 간주됩니다.

      기본값: 20초

    • 절전: fanOut 초과 시 스레드가 절전 상태로 유지되는 시간(초)을 정의합니다.

      기본값: 20밀리초

    C#/. NET
    CacheType stormTrackingCache = new CacheType { StormTracking = new StormTrackingCache { EntryCapacity = 100, EntryPruningTailSize = 1, FanOut = 20, GraceInterval = 1, GracePeriod = 10, InFlightTTL = 20, SleepMilli = 20 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .gracePeriod(10) .graceInterval(1) .fanOut(20) .inFlightTTL(20) .sleepMilli(20) .build())
  • (선택 사항) 권한 부여 토큰 목록

    권한 부여를 통해 계층적 KMS 키링의 키에 대한 액세스를 제어하는 경우 키링을 초기화할 때 필요한 모든 부여 토큰을 제공해야 합니다.

다음 예제는 2단계에서 생성한 브랜치 키 ID 공급자를 사용하여 계층 키링을 초기화합니다. 이때 캐시 한도는 600초이고 입력 용량은 TLL 1000입니다.

C# / .NET
var createKeyringInput = new CreateAwsKmsHierarchicalKeyringInput { KeyStore = keystore, BranchKeyIdSupplier = branchKeySupplier, Cache = new CacheType { Default = new DefaultCache{EntryCapacity = 1000} }, TtlSeconds = 600 }; var keyring = mpl.CreateAwsKmsHierarchicalKeyring(createKeyringInput);
Java
final MaterialProviders matProv = MaterialProviders.builder() .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) .build(); final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder() .keyStore(branchKeyStoreName) .branchKeyIdSupplier(branchKeyIdSupplier) .ttlSeconds(600) .cache(CacheType.builder() //OPTIONAL .Default(DefaultCache.builder() .entryCapacity(100) .build()) .build(); final IKeyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
4단계: 각 브랜치 키에 친숙한 이름 생성

다음 예제에서는 1단계에서 만든 두 개의 분기 키에 대해 친숙한 이름을 생성합니다. AWS Encryption SDK 는 암호화 컨텍스트를 사용하여 정의한 친숙한 이름을 연결된 branch-key-id에 매핑합니다.

C# / .NET
// Create encryption contexts for the two branch keys created in Step 1 var encryptionContextA = new Dictionary<string, string>() { // We will encrypt with branchKeyTenantA {"tenant", "TenantA"}, {"encryption", "context"}, {"is not", "secret"}, {"but adds", "useful metadata"}, {"that can help you", "be confident that"}, {"the data you are handling", "is what you think it is"} }; var encryptionContextB = new Dictionary<string, string>() { // We will encrypt with branchKeyTenantB {"tenant", "TenantB"}, {"encryption", "context"}, {"is not", "secret"}, {"but adds", "useful metadata"}, {"that can help you", "be confident that"}, {"the data you are handling", "is what you think it is"} }; // Instantiate the AWS Encryption SDK var esdk = new ESDK(new AwsEncryptionSdkConfig()); var encryptInputA = new EncryptInput { Plaintext = plaintext, Keyring = keyring, // Encrypt with branchKeyId1 EncryptionContext = encryptionContextA }; var encryptInputB = new EncryptInput { Plaintext = plaintext, Keyring = keyring, // Encrypt with branchKeyId2 EncryptionContext = encryptionContextB }; var encryptOutput = esdk.Encrypt(encryptInputA); encryptOutput = esdk.Encrypt(encryptInputB); // Use the encryption contexts to define friendly names for each branch key public class ExampleBranchKeySupplier : IBranchKeyIdSupplier { private string branchKeyTenantA; private string branchKeyTenantB; public ExampleBranchKeySupplier(string branchKeyTenantA, string branchKeyTenantB) { this.branchKeyTenantA = branchKeyTenantA; this.branchKeyTenantB = branchKeyTenantB; } public GetBranchKeyIdOutput GetBranchKeyId(GetBranchKeyIdInput input) { Dictionary<string, string> encryptionContext = input.EncryptionContext; if (!encryptionContext.ContainsKey("tenant")) { throw new Exception("EncryptionContext invalid, does not contain expected tenant key value pair."); } string tenant = encryptionContext["tenant"]; string branchkeyId; if (tenant.Equals("TenantA")) { GetBranchKeyIdOutput output = new GetBranchKeyIdOutput(); output.BranchKeyId = branchKeyTenantA; return output; } else if (tenant.Equals("TenantB")) { GetBranchKeyIdOutput output = new GetBranchKeyIdOutput(); output.BranchKeyId = branchKeyTenantB; return output; } else { throw new Exception("Item does not have a valid tenantID."); } } }
Java
// Create encryption context for branchKeyTenantA Map<String, String> encryptionContextA = new HashMap<>(); encryptionContextA.put("tenant", "TenantA"); encryptionContextA.put("encryption", "context"); encryptionContextA.put("is not", "secret"); encryptionContextA.put("but adds", "useful metadata"); encryptionContextA.put("that can help you", "be confident that"); encryptionContextA.put("the data you are handling", "is what you think it is"); // Create encryption context for branchKeyTenantB Map<String, String> encryptionContextB = new HashMap<>(); encryptionContextB.put("tenant", "TenantB"); encryptionContextB.put("encryption", "context"); encryptionContextB.put("is not", "secret"); encryptionContextB.put("but adds", "useful metadata"); encryptionContextB.put("that can help you", "be confident that"); encryptionContextB.put("the data you are handling", "is what you think it is"); // Instantiate the AWS Encryption SDK final AwsCrypto crypto = AwsCrypto.builder().build(); final CryptoResult<byte[], ?> encryptResultA = crypto.encryptData(keyring, plaintext, encryptionContextA); final CryptoResult<byte[], ?> encryptResultB = crypto.encryptData(keyring, plaintext, encryptionContextB); // Use the encryption contexts to define friendly names for each branch key public class ExampleBranchKeyIdSupplier implements IBranchKeyIdSupplier { private static String branchKeyIdForTenantA; private static String branchKeyIdForTenantB; public ExampleBranchKeyIdSupplier(String tenant1Id, String tenant2Id) { this.branchKeyIdForTenantA = tenant1Id; this.branchKeyIdForTenantB = tenant2Id; } @Override public GetBranchKeyIdOutput GetBranchKeyId(GetBranchKeyIdInput input) { Map<String, String> encryptionContext = input.encryptionContext(); if (!encryptionContext.containsKey("tenant")) { throw new IllegalArgumentException("EncryptionContext invalid, does not contain expected tenant key value pair."); } String tenantKeyId = encryptionContext.get("tenant"); String branchKeyId; if (tenantKeyId.equals("TenantA")) { branchKeyId = branchKeyIdForTenantA; } else if (tenantKeyId.equals("TenantB")) { branchKeyId = branchKeyIdForTenantB; } else { throw new IllegalArgumentException("Item does not contain valid tenant ID"); } return GetBranchKeyIdOutput.builder().branchKeyId(branchKeyId).build(); } }