Amazon Web Services 한국 블로그

Amazon DynamoDB 데이터 암호화 및 서명 방법

민감한 데이터나 기밀 데이터를 Amazon DynamoDB에 저장하는 경우, 해당 데이터를 암호화하여 데이터 수명 주기동안 보호할 수 있습니다. DynamoDB Encryption Client를 사용하여 DynamoDB로 전송하기 전에 테이블 데이터를 보호할 수 있습니다. 민감한 데이터를 전송 중(In Transit) 및 유휴 시(At Rest) 암호화하면 AWS를 포함하여 제 3자는 평문 데이터의 사용이 불가능 합니다.

DynamoDB Encryption Client를 사용하려면, 여러분이 암호 전문가일 필요는 없습니다. 암호화 및 서명 요건들은 기존 DynamoDB 어플리케이션과 함께 동작하도록 설계되어 있습니다. 필요한 컴포넌트들을 생성하고 구성을 적용한 뒤, DynamoDB Encryption Client는 PutItem을 호출시 테이블 항목을 투명하게 암호화하고 서명하며, GetItem을 호출할때 검증하고 복호화 합니다.

고유한 사용자 정의 컴포턴트(Component)를 생성하거나 라이브러리에 포함된 기본 구현을 사용할 수도 있습니다.  AWS에서 제공하는 클래스는 강력하고 안전한 암호화를 구현할 수 있도록 되어 있습니다.

DynamoDB Encryption Client는 AWS Key Management Service (Aws KMS) 또는 AWS CloudHSM과 함께 사용이 가능하지만, 라이브러리가 AWS 또는 다른 AWS 서비스를 필요로 하지는 않습니다.

현재 DynamoDB Encryption Client는 Java 뿐만 아니라 Python에서도 사용이 가능 합니다. 지원되는 언어의 구현은 상호 호환이 가능합니다. 예를 들어, 테이블 데이터를 Python 라이브러리를 이용하여 암호화 할수 있으며, Java 라이브러리를 이용하여 복호화 할수도 있습니다.

DynamoDB Encryption Client는 오픈 소스 프로젝트입니다. 여러분도 각종 소스 및 라이브러리 개발 및 문서 작성에 동참하기를 희망합니다.

동작 방법

DynamoDB Encryption Client는 한번에 하나의 테이블 항목만 처리 합니다. 첫째, 지정한 속성의 값(이름이 아님)을 암호화 합니다. 그리고 나서, 지정한 속성의 서명을 계산하여 속성의 추가 또는 삭제, 또는 다른 암호화된 값으로의 대체와 같은 항목 전체에 대한 인가되지 않은 변경을 탐지할 수 있습니다.

그러나, 속성 이름과 Primary Key (존재하는 경우, 파티션 키 및 정렬 키)내의 속성 값 및 이름은 반드시 항목이 발견될 수 있도록 평문 형태로 남아 있어야 합니다.

주의 : 테이블 이름, 속성 값, Primary key 속성의 이름이나 값, 또는 암호화 하지 않도록 고객에게 지정한 속성 값에 민감한 데이터를 포함하여서는 안됩니다.

사용방법

간단한 샘플 예제를 통하여 Python을 사용하여 DynamoDB Encryption Client를 어떻게 사용하는지 시연해 보이도록 하겠습니다. 하나의 테이블 항목을 암호화 및 서명할 것이며, 그리고 난뒤 기존 테이블에 추가 하겠습니다. 이 예제에서는 축약된 데이터의 테스트 항목을 사용하지만, 고객의 개인정보와 같은 굉장히 민감한 데이터가 포함된 테이블 항목을 보호하기 위해 유사한 과정을 사용할 수 있습니다.

예제 코드aws-dynamodb-encryption-python 저장소의 샘플 디렉토리 내에서 확인할 수 있습니다.

Step 1: 테이블 생성

먼저 기존 테이블을 대표하는 DynamoDB 테이블 리소스를 생성 합니다. 코드를 사용할 때는 유효한 테이블 이름을 사용해야 합니다.

# Create a DynamoDB table
table = boto3.resource('dynamodb').Table(table_name)

Step 2: 암호화 자료 공급자(Cryptographic materials provider) 생성하기

우선 Cryptographic materials provider(CMP)의 인스턴스를 생성 합니다. CMP는 테이블 항목을 암호화 하고 서명하기 위해 사용되는 암호화 및 서명 키를 수집하는 컴포넌트 입니다. 또한, CMP는 사용될 암호화 알고리즘의 결정과 함께, 모든 항목에 대해 고유의 키를 생성할지 재 사용할지를 결정합니다. 

DynamoDB Encryption Client는 여러 CMP를 포함하고 있으며, 고유의 CMP를 직접 생성할 수도 있습니다. 이에 대해 조금의 의심이라고 생긴다면, 응용 프로그램과 보안 요구사항에 맞는 CMP를 선택하는데 도움을 줄수 있습니다.

이 예제에서는 AWS Key Management Service (AWS KMS)에서 암호화 자료를 가져오는 Direct KMS Provider를 사용할 것 입니다. 암호화 및 서명 키는 AWS account내 customer master key에 의해 보호되며, 암호화되지 않은 상태로는AWS KMS를 벗어나지 않습니다.

Direct KMS Provider를 생성하려면 AWS KMS 고객 마스터 키를 지정해야 합니다. 이 예제의 가상 마스터 키 ID (aws-cmk-id 값)를 유효한 것으로 바꿔야 함을 유의 하시기 바랍니다.

# Create a Direct KMS provider. Pass in a valid KMS customer master key.
aws_cmk_id = '1234abcd-12ab-34cd-56ef-1234567890ab'
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)

Step 3: 속성 작업 객체(Attribute actions object)의 생성

속성 작업 객체는 DynamoDB Encryption Client에게 암호화 할 항목의 속성 값과 서명에 포함될 속성 값을 안내 합니다. 해당 옵션은 ENCRYPT_AND_SIGN, SIGN_ONLY, 그리고 DO_NOTHING 입니다.

이 샘폴 속성 작업은 테스트 속성 값을 제외한 모든 속성 값을 암호화 하고 서명 합니다. 테스트 속성 값은 암호화 되거나 서명에 포함되지 않습니다.

# Tell the encrypted table to encrypt and sign all attributes except one.
actions = AttributeActions(
    default_action=CryptoAction.ENCRYPT_AND_SIGN,
    attribute_actions={
        'test': CryptoAction.DO_NOTHING
    }
)

다음 단계에서 사용EncryptedTable 클래스와 같은 헬퍼 클래스를 사용하는 경우, primary key를 위한 속성 작업을 지정할 수 없습니다. 헬퍼 클래스는 primary key가 서명 되었으나 암호화가 되지 않았는지를 확인합니다. (SIGN_ONLY)

Step 4: 암호화된 테이블의 생성

이제 자료 공급자(materials provider) 및 속성 작업과 함께 원본 테이블 객체를 사용하여 암호화된 테이블을 생성할 수 있습니다.

# Use these objects to create an encrypted table resource.
encrypted_table = EncryptedTable(
    table=table,
    materials_provider=aws_kms_cmp,
    attribute_actions=actions
)

이 예제에서는 Python용 AWS SDK(Boto 3)내 DynamoDB 테이블 클래스에 암호화 기능을 추가하는 EncryptedTable 헬퍼 클래스를 사용합니다. Python의 DynamoDB 암호화 클라이언트에는 EncryptedClient 및 EncryptedResource 헬퍼 클래스도 포함되어 있습니다.

DynamoDB Encryption Client 헬퍼 클래스는 primary key를 찾기위한 DescribeTable 작업을 호출 합니다. 코드를 실행하는 응용 프로그램에는 작업을 호출하는 권한이 있어야 합니다.

클라이언트 구성을 마쳤습니다. 이제 테이블 항목의 암호화, 서명, 검증 및 복호화 할수 있습니다.

Step 5: 테이블에 항목의 생성

DynamoDB 테이블에 항목을 생성 합니다.

plaintext_item = {
    'partition_key': 'key1',
    'sort_key': 'key2'
    'example': 'data',
    'numbers': 99,
    'binary': Binary(b'\x00\x01\x02'),
    'test': 'test-value'
}

PutItem을 호출할때 이 항목은 서명되었으나 암호화되지 않은 primary key와 무시되는 테스트 속성은 제외하고 투명하게 암호화되고 서명됩니다.

encrypted_table.put_item(Item=plaintext_item)

GetItem을 호출하면 항목이 투명하게 확인되고 해독됩니다.

decrypted_item = encrypted_table.get_item(Key=partition_key)['Item']

암호화 된 항목을 보려면 encrypted_table 개체 대신 원본 테이블 개체에서 GetItem 작업을 호출하십시오. DynamoDB 테이블을 확인 및 해독하지 않고 항목을 가져옵니다.

encrypted_item = table.get_item(Key=partition_key)['Item']

아래는 암호화되고 서명된 항목을 표시하는 출력의 일부 입니다.

Output that displays the encrypted item

Figure 1: 암호화된 항목의 출력 표시 예

클라이언트 혹은 서버 기반 암호화 선택하기

DynamoDB Encryption Client는 클라이언트 측 암호화(client-side encryption)를 위해 설계되었으며, DynamoDB에 데이터를 전송하기 전에 암호화 합니다.

다른 옵션도 있습니다. DynamoDB는 유휴 시 암호화(Encryption At Rest) 즉, 서버 측 암호화(Server-side encryption)을 지원하여 디스크를 테이블에 저장할때 마다 투명하게 데이터를 암호화 할수 있습니다. DynamoDB Encryption Client와 유휴 시 암호화(Encryption At Rest) 방식을 함께 사용할 수도 있습니다.

클라이언트가 생성하는 암호화되고 서명된 항목은 표준 테이블 항목으로 그 속성 값에 이진 데이터가 포함되어 있습니다. 데이터의 민감도와 응용 프로그램의 보안 요건에 의하여 선택하여 사용이 가능합니다.

Java 및 Python 버전의 DynamoDB Encryption Client가 완벽하게 호환 가능하지만, DynamoDB Encryption Client는 AWS Encryption SDK 또는 S3 Encryption Client와 같은 다른 클라이언트 측 암호화 라이브러리와 호환되지 않습니다. 하나의 라이브러리로 데이터를 암호화하고 다른 라이브러리로 복호화할 수 는 없습니다. DynamoDB에 저장하는 데이터의 경우 DynamoDB Encryption Client의 사용을 권장 합니다.

암호화는 중요합니다.

DynamoDB Encryption Client와 같은 도구를 사용하면 테이블 데이터를 보호하고 애플리케이션의 보안 요구 사항을 준수할 수 있습니다. 해당 클라이언트를 사용하여 GitHub내 개발에 동참하기를 바랍니다.

이 게시물에 대한 의견이 있으시면 아래의 댓글 섹션에 의견을 제출하십시오. Amazon DynamoDB Encryption Client에 대한 질문이 있는 경우 Java 또는 Python 용 GitHub repos에 문제를 제출하거나 AWS Crypto Tools Discussion Forum에 의견을 보내 주시기바랍니다.

이 글은 AWS Security Blog에 게재된 How to encrypt and sign DynamoDB data in your application의 한국어 번역본으로서 유제광 AWS 보안 컨설턴트께서 번역해 주셨습니다.