Skip to content

Commit

Permalink
docs: merge pull request #236 from mattsb42-aws/mkp-examples
Browse files Browse the repository at this point in the history
docs: add master key provider examples
  • Loading branch information
mattsb42-aws committed Apr 6, 2020
2 parents cbce224 + c5d3a94 commit 5abbf9c
Show file tree
Hide file tree
Showing 13 changed files with 603 additions and 1 deletion.
6 changes: 6 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,32 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
* Using AWS Key Management Service (AWS KMS)
* How to use one AWS KMS CMK
* [with keyrings](./src/keyring/aws_kms/single_cmk.py)
* [with master key providers](./src/master_key_provider/aws_kms/single_cmk.py)
* How to use multiple AWS KMS CMKs in different regions
* [with keyrings](./src/keyring/aws_kms/multiple_regions.py)
* [with master key providers](./src/master_key_provider/aws_kms/multiple_regions.py)
* How to decrypt when you don't know the CMK
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt.py)
* [with master key providers](./src/master_key_provider/aws_kms/discovery_decrypt.py)
* How to decrypt within a region
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt_in_region_only.py)
* How to decrypt with a preferred region but failover to others
* [with keyrings](./src/keyring/aws_kms/discovery_decrypt_with_preferred_regions.py)
* Using raw wrapping keys
* How to use a raw AES wrapping key
* [with keyrings](./src/keyring/raw_aes/raw_aes.py)
* [with master key providers](./src/master_key_provider/raw_aes/raw_aes.py)
* How to use a raw RSA wrapping key
* [with keyrings](./src/keyring/raw_rsa/private_key_only.py)
* How to use a raw RSA wrapping key when the key is PEM or DER encoded
* [with keyrings](./src/keyring/raw_rsa/private_key_only_from_pem.py)
* [with master key providers](./src/master_key_provider/raw_rsa/private_key_only_from_pem.py)
* How to encrypt with a raw RSA public key wrapping key without access to the private key
* [with keyrings](./src/keyring/raw_rsa/public_private_key_separate.py)
* Combining wrapping keys
* How to combine AWS KMS with an offline escrow key
* [with keyrings](./src/keyring/multi/aws_kms_with_escrow.py)
* [with master key providers](./src/master_key_provider/multi/aws_kms_with_escrow.py)

### Keyrings

Expand Down
2 changes: 1 addition & 1 deletion examples/src/keyring/raw_aes/raw_aes.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def run(source_plaintext):
# Create the keyring that determines how your data keys are protected.
keyring = RawAESKeyring(
# The key namespace and key name are defined by you
# and are used by the raw RSA keyring
# and are used by the raw AES keyring
# to determine whether it should attempt to decrypt
# an encrypted data key.
#
Expand Down
7 changes: 7 additions & 0 deletions examples/src/master_key_provider/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
Master key provider examples.
These examples show how to use master key providers.
"""
7 changes: 7 additions & 0 deletions examples/src/master_key_provider/aws_kms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
AWS KMS master key provider examples.
These examples show how to use the KMS master key provider.
"""
71 changes: 71 additions & 0 deletions examples/src/master_key_provider/aws_kms/discovery_decrypt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example is intended to serve as reference material for users migrating away from master key providers.
We recommend using keyrings rather than master key providers.
For examples using keyrings, see the ``examples/src/keyrings`` directory.
The KMS master key provider uses any key IDs that you specify on encrypt,
but attempts to decrypt *any* data keys that were encrypted under a KMS CMK.
This means that you do not need to know which CMKs were used to encrypt a message.
This example shows how to configure and use a KMS master key provider to decrypt without provider key IDs.
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
For an example of how to use the KMS master key with a single CMK,
see the ``master_key_provider/aws_kms/single_cmk`` example.
For an example of how to use the KMS master key provider with CMKs in multiple regions,
see the ``master_key_provider/aws_kms/multiple_regions`` example.
"""
import aws_encryption_sdk
from aws_encryption_sdk.key_providers.kms import KMSMasterKey, KMSMasterKeyProvider


def run(aws_kms_cmk, source_plaintext):
# type: (str, bytes) -> None
"""Demonstrate configuring a KMS master key provider for decryption.
:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys
:param bytes source_plaintext: Plaintext to encrypt
"""
# Prepare your encryption context.
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
encryption_context = {
"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",
}

# Create the master key that determines how your data keys are protected.
encrypt_master_key = KMSMasterKey(key_id=aws_kms_cmk)

# Create a KMS master key provider to use on decrypt.
decrypt_master_key_provider = KMSMasterKeyProvider()

# Encrypt your plaintext data.
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt(
source=source_plaintext, encryption_context=encryption_context, key_provider=encrypt_master_key
)

# Demonstrate that the ciphertext and plaintext are different.
assert ciphertext != source_plaintext

# Decrypt your encrypted data using the KMS master key provider.
#
# You do not need to specify the encryption context on decrypt
# because the header of the encrypted message includes the encryption context.
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, key_provider=decrypt_master_key_provider)

# Demonstrate that the decrypted plaintext is identical to the original plaintext.
assert decrypted == source_plaintext

# Verify that the encryption context used in the decrypt operation includes
# the encryption context that you specified when encrypting.
# The AWS Encryption SDK can add pairs, so don't require an exact match.
#
# In production, always use a meaningful encryption context.
assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items())
91 changes: 91 additions & 0 deletions examples/src/master_key_provider/aws_kms/multiple_regions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example is intended to serve as reference material for users migrating away from master key providers.
We recommend using keyrings rather than master key providers.
For examples using keyrings, see the ``examples/src/keyrings`` directory.
This example shows how to configure and use a KMS master key provider with with CMKs in multiple regions.
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
For an example of how to use the KMS master key with a single CMK,
see the ``master_key_provider/aws_kms/single_cmk`` example.
For an example of how to use the KMS master key provider in discovery mode on decrypt,
see the ``master_key_provider/aws_kms/discovery_decrypt`` example.
"""
import aws_encryption_sdk
from aws_encryption_sdk.key_providers.kms import KMSMasterKey, KMSMasterKeyProvider

try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Sequence # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
# We only actually need these imports when running the mypy checks
pass


def run(aws_kms_generator_cmk, aws_kms_additional_cmks, source_plaintext):
# type: (str, Sequence[str], bytes) -> None
"""Demonstrate an encrypt/decrypt cycle using a KMS master key provider with CMKs in multiple regions.
:param str aws_kms_generator_cmk: The ARN of the primary AWS KMS CMK
:param List[str] aws_kms_additional_cmks: Additional ARNs of secondary KMS CMKs
:param bytes source_plaintext: Plaintext to encrypt
"""
# Prepare your encryption context.
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
encryption_context = {
"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",
}

# Create the master key provider that will encrypt your data keys under all requested CMKs.
#
# The KMS master key provider generates the data key using the first key ID in the list.
key_ids = [aws_kms_generator_cmk]
key_ids.extend(aws_kms_additional_cmks)
master_key_provider = KMSMasterKeyProvider(key_ids=key_ids)

# Create master keys that each only use one of the CMKs.
# We will use these later to demonstrate that any of the CMKs can be used to decrypt the message.
single_cmk_master_key_that_generated = KMSMasterKey(key_id=aws_kms_generator_cmk)
single_cmk_master_key_that_encrypted = KMSMasterKey(key_id=aws_kms_additional_cmks[0])

# Encrypt your plaintext data using the master key provider that uses all requests CMKs.
ciphertext, encrypt_header = aws_encryption_sdk.encrypt(
source=source_plaintext, encryption_context=encryption_context, key_provider=master_key_provider
)

# Verify that the header contains the expected number of encrypted data keys (EDKs).
# It should contain one EDK for each CMK.
assert len(encrypt_header.encrypted_data_keys) == len(aws_kms_additional_cmks) + 1

# Demonstrate that the ciphertext and plaintext are different.
assert ciphertext != source_plaintext

# Decrypt your encrypted data separately using the single-CMK master keys.
#
# You do not need to specify the encryption context on decrypt
# because the header of the encrypted message includes the encryption context.
decrypted_1, decrypt_header_1 = aws_encryption_sdk.decrypt(
source=ciphertext, key_provider=single_cmk_master_key_that_generated
)
decrypted_2, decrypt_header_2 = aws_encryption_sdk.decrypt(
source=ciphertext, key_provider=single_cmk_master_key_that_encrypted
)

# Demonstrate that the decrypted plaintext is identical to the original plaintext.
assert decrypted_1 == source_plaintext
assert decrypted_2 == source_plaintext

# Verify that the encryption context used in the decrypt operation includes
# the encryption context that you specified when encrypting.
# The AWS Encryption SDK can add pairs, so don't require an exact match.
#
# In production, always use a meaningful encryption context.
assert set(encryption_context.items()) <= set(decrypt_header_1.encryption_context.items())
assert set(encryption_context.items()) <= set(decrypt_header_2.encryption_context.items())
64 changes: 64 additions & 0 deletions examples/src/master_key_provider/aws_kms/single_cmk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example is intended to serve as reference material for users migrating away from master key providers.
We recommend using keyrings rather than master key providers.
For examples using keyrings, see the ``examples/src/keyrings`` directory.
This example shows how to configure and use a KMS master key with a single KMS CMK.
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
For an example of how to use the KMS master key provider with CMKs in multiple regions,
see the ``master_key_provider/aws_kms/multiple_regions`` example.
For an example of how to use the KMS master key provider in discovery mode on decrypt,
see the ``master_key_provider/aws_kms/discovery_decrypt`` example.
"""
import aws_encryption_sdk
from aws_encryption_sdk.key_providers.kms import KMSMasterKey


def run(aws_kms_cmk, source_plaintext):
# type: (str, bytes) -> None
"""Demonstrate an encrypt/decrypt cycle using a KMS master key with a single CMK.
:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys
:param bytes source_plaintext: Plaintext to encrypt
"""
# Prepare your encryption context.
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
encryption_context = {
"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",
}

# Create the master key that determines how your data keys are protected.
master_key = KMSMasterKey(key_id=aws_kms_cmk)

# Encrypt your plaintext data.
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt(
source=source_plaintext, encryption_context=encryption_context, key_provider=master_key
)

# Demonstrate that the ciphertext and plaintext are different.
assert ciphertext != source_plaintext

# Decrypt your encrypted data using the same master key you used on encrypt.
#
# You do not need to specify the encryption context on decrypt
# because the header of the encrypted message includes the encryption context.
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, key_provider=master_key)

# Demonstrate that the decrypted plaintext is identical to the original plaintext.
assert decrypted == source_plaintext

# Verify that the encryption context used in the decrypt operation includes
# the encryption context that you specified when encrypting.
# The AWS Encryption SDK can add pairs, so don't require an exact match.
#
# In production, always use a meaningful encryption context.
assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items())
7 changes: 7 additions & 0 deletions examples/src/master_key_provider/multi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
Multi-master key provider examples.
These examples show how to combine master key providers.
"""

0 comments on commit 5abbf9c

Please sign in to comment.