Skip to content

Instantly share code, notes, and snippets.

@ritesh
Created October 1, 2020 10:28
Show Gist options
  • Save ritesh/efa756d8ba78d94055022360af6e2b13 to your computer and use it in GitHub Desktop.
Save ritesh/efa756d8ba78d94055022360af6e2b13 to your computer and use it in GitHub Desktop.
DynamoDB Client Side encryption using the DDB Encryption SDK
# Copyright 2020 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.
from dynamodb_encryption_sdk.encrypted import CryptoConfig
from dynamodb_encryption_sdk.encrypted.client import EncryptedClient
from dynamodb_encryption_sdk.identifiers import CryptoAction
from dynamodb_encryption_sdk.encrypted import CryptoConfig
from dynamodb_encryption_sdk.material_providers.aws_kms import AwsKmsCryptographicMaterialsProvider
from dynamodb_encryption_sdk.structures import AttributeActions
import boto3
from boto3.dynamodb.types import Binary
import uuid
from datetime import datetime
def encrypt_item(table_name, aws_cmk_id, index_key, plaintext_item, ignored_attributes):
"""Demonstrate use of EncryptedClient to transparently encrypt an item."""
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
# Collect all of the attributes that will not be encrypted (used later).
# Here, we leave out the index keys as we can't use them if they are encrypted client side!
unencrypted_attributes = set(index_key.keys())
for attrib in ignored_attributes:
encrypted_attributes.remove(attrib)
unencrypted_attributes.add(attrib)
# Add the index pairs back to the item.
plaintext_item.update(index_key)
# Create a normal client.
client = boto3.client("dynamodb")
# Create a crypto materials provider using the specified AWS KMS key.
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)
# Create attribute actions that tells the encrypted client to encrypt all attributes except one.
actions = AttributeActions(
default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={x: CryptoAction.DO_NOTHING for x in unencrypted_attributes}
)
# Use these objects to create an encrypted client.
encrypted_client = EncryptedClient(client=client, materials_provider=aws_kms_cmp, attribute_actions=actions)
# Put the item to the table, using the encrypted client to transparently encrypt it.
encrypted_client.put_item(TableName=table_name, Item=plaintext_item)
# Get the encrypted item using the standard client.
encrypted_item = client.get_item(TableName=table_name, Key=index_key)["Item"]
return encrypted_item
def decrypt_item(table_name, aws_cmk_id, index_key, ignored_attributes):
"""Demonstrate use of EncryptedClient to transparently decrypt an item."""
unencrypted_attributes = set(index_key.keys())
for attrib in ignored_attributes:
unencrypted_attributes.add(attrib)
actions = AttributeActions (
default_action = CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={x: CryptoAction.DO_NOTHING for x in unencrypted_attributes}
)
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)
client = boto3.client("dynamodb")
encrypted_client = EncryptedClient(client=client, materials_provider=aws_kms_cmp, attribute_actions = actions)
decrypted_item = encrypted_client.get_item(TableName=table_name, Key=index_key)["Item"]
return decrypted_item
if __name__ == '__main__':
index_key = {"CustomerID": {"S": uuid.uuid4().hex }}
plaintext_item = {
"DateOfLastContact": {"S": datetime.now().isoformat()},
"ChatToken": {"S": "datadatadatadata"},
"OtherMetadata": {"N": "99"},
"BinaryField": {"B": b"\x00\x01\x02"},
"leave me": {"S": "alone"}, # We want to ignore this attribute
}
# We will not encrypt or sign these attributes, everythign else gets encrypted and signed
ignored_attributes = ["leave me", "OtherMetadata"]
#Outputs from stack
table_name = "YOUR_TEST_DYNAMODB_TABLE_NAME"
aws_cmk_id = "AWS CMK ID FOR TESTING"
encrypted_item = encrypt_item(table_name, aws_cmk_id, index_key, plaintext_item, ignored_attributes)
print("encrypted item is {}".format(encrypted_item))
decrypted_item = decrypt_item(table_name, aws_cmk_id, index_key, ignored_attributes)
print ("decrypted: is {}".format(decrypted_item))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment