-
Notifications
You must be signed in to change notification settings - Fork 86
docs: add keyring examples #221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 31 commits
558563f
7b6b920
05266a8
f368f09
4709409
5fb2d3e
f6af7ee
52f8312
0047ddf
5925b77
a6519d2
2fb99d0
154ce5d
3fc892a
47351a7
7770186
0186e61
23c3766
59b09df
9234c01
def80a5
d0cca29
ee23080
edc57ca
341c5b9
5a364b9
ad25893
8e44484
810eff2
9acd33d
b8fdf96
dd59a36
739ed47
5ea4e81
8b28bee
18007ed
c4aeaf7
dd63564
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
""" | ||
Keyring examples. | ||
|
||
These examples show how to use keyrings. | ||
""" |
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 keyring examples. | ||
|
||
These examples show how to use the KMS keyring. | ||
""" |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,115 @@ | ||||||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||||||
# SPDX-License-Identifier: Apache-2.0 | ||||||
""" | ||||||
By default, the KMS keyring uses a client supplier that | ||||||
supplies a client with the same configuration for every region. | ||||||
If you need different behavior, you can write your own client supplier. | ||||||
|
||||||
One use-case where you might need this is | ||||||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
if you need different credentials to talk to different AWS regions. | ||||||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
This might be because you are crossing partitions (ex: ``aws`` and ``aws-cn``) | ||||||
or if you are working with regions that have separate authentication silos | ||||||
like ``ap-east-1`` and ``me-south-1``. | ||||||
|
||||||
This example shows how to create a client supplier | ||||||
that will supply KMS clients with valid credentials for the target region | ||||||
even when working with regions that need different credentials. | ||||||
|
||||||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/choose-keyring.html#use-kms-keyring | ||||||
|
||||||
For an example of how to use the KMS keyring with CMKs in multiple regions, | ||||||
see the ``keyring/aws_kms/multiple_regions`` example. | ||||||
|
||||||
For another example of how to use the KMS keyring with a custom client configuration, | ||||||
see the ``keyring/aws_kms/custom_kms_client_config`` example. | ||||||
|
||||||
For examples of how to use the KMS keyring in discovery mode on decrypt, | ||||||
see the ``keyring/aws_kms/discovery_decrypt``, | ||||||
``keyring/aws_kms/discovery_decrypt_in_region_only``, | ||||||
and ``keyring/aws_kms/discovery_decrypt_with_preferred_region`` examples. | ||||||
""" | ||||||
from botocore.client import BaseClient | ||||||
from botocore.session import Session | ||||||
|
||||||
import aws_encryption_sdk | ||||||
from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring | ||||||
from aws_encryption_sdk.keyrings.aws_kms.client_suppliers import ClientSupplier, DefaultClientSupplier | ||||||
|
||||||
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules | ||||||
from typing import Union # noqa pylint: disable=unused-import | ||||||
except ImportError: # pragma: no cover | ||||||
# We only actually need these imports when running the mypy checks | ||||||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
pass | ||||||
|
||||||
|
||||||
class MultiPartitionClientSupplier(ClientSupplier): | ||||||
"""Client supplier that supplies clients across AWS partitions and identity silos.""" | ||||||
|
||||||
def __init__(self): | ||||||
"""Set up default client suppliers for identity silos.""" | ||||||
self._china_supplier = DefaultClientSupplier(botocore_session=Session(profile="china")) | ||||||
self._middle_east_supplier = DefaultClientSupplier(botocore_session=Session(profile="middle-east")) | ||||||
self._hong_kong_supplier = DefaultClientSupplier(botocore_session=Session(profile="hong-kong")) | ||||||
self._default_supplier = DefaultClientSupplier() | ||||||
|
||||||
def __call__(self, region_name): | ||||||
# type: (Union[None, str]) -> BaseClient | ||||||
"""Return a client for the requested region. | ||||||
|
||||||
:rtype: BaseClient | ||||||
""" | ||||||
if region_name.startswith("cn-"): | ||||||
return self._china_supplier(region_name) | ||||||
|
||||||
if region_name.startswith("me-"): | ||||||
return self._middle_east_supplier(region_name) | ||||||
|
||||||
if region_name == "ap-east-1": | ||||||
return self._hong_kong_supplier(region_name) | ||||||
|
||||||
return self._default_supplier(region_name) | ||||||
|
||||||
|
||||||
def run(aws_kms_cmk, source_plaintext): | ||||||
# type: (str, bytes) -> None | ||||||
"""Demonstrate an encrypt/decrypt cycle using a KMS keyring with a custom client supplier. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I ran into the same dilemma in the docs. Does the "custom" before client supplier imply a configured standard client supplier, or a different implementation of the client supplier interface? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would assume that "custom" means "something that is not provided out of the box". A configuration of a built-in feature does not say "custom" to me |
||||||
|
||||||
: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 keyring that determines how your data keys are protected. | ||||||
keyring = KmsKeyring(generator_key_id=aws_kms_cmk, client_supplier=MultiPartitionClientSupplier()) | ||||||
|
||||||
# Encrypt your plaintext data. | ||||||
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( | ||||||
source=source_plaintext, encryption_context=encryption_context, keyring=keyring | ||||||
) | ||||||
|
||||||
# Demonstrate that the ciphertext and plaintext are different. | ||||||
assert ciphertext != source_plaintext | ||||||
|
||||||
# Decrypt your encrypted data using the same keyring you used on encrypt. | ||||||
# | ||||||
# We do not need to specify the encryption context on decrypt | ||||||
# because the header message includes the encryption context. | ||||||
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, keyring=keyring) | ||||||
|
||||||
# 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()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
By default, the KMS keyring will use the default configurations | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for all KMS clients and will use the default discoverable credentials. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
If you need to change these configurations, | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
you can do that using the client supplier. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
This example shows how to use custom-configured clients with the KMS keyring. | ||
|
||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/choose-keyring.html#use-kms-keyring | ||
|
||
For an example of how to use the KMS keyring with CMKs in multiple regions, | ||
see the ``keyring/aws_kms/multiple_regions`` example. | ||
|
||
For another example of how to use the KMS keyring with custom client configuration, | ||
see the ``keyring/aws_kms/custom_client_supplier`` example. | ||
|
||
For examples of how to use the KMS keyring in discovery mode on decrypt, | ||
see the ``keyring/aws_kms/discovery_decrypt``, | ||
``keyring/aws_kms/discovery_decrypt_in_region_only``, | ||
and ``keyring/aws_kms/discovery_decrypt_with_preferred_region`` examples. | ||
""" | ||
from botocore.config import Config | ||
from botocore.session import Session | ||
|
||
import aws_encryption_sdk | ||
from aws_encryption_sdk.identifiers import USER_AGENT_SUFFIX | ||
from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring | ||
from aws_encryption_sdk.keyrings.aws_kms.client_suppliers import DefaultClientSupplier | ||
|
||
|
||
def run(aws_kms_cmk, source_plaintext): | ||
# type: (str, bytes) -> None | ||
"""Demonstrate an encrypt/decrypt cycle using a KMS keyring with custom KMS client configuration. | ||
|
||
: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", | ||
} | ||
|
||
# Prepare your custom configuration values. | ||
# | ||
# Set your custom connection timeout value. | ||
# https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html | ||
custom_client_config = Config(connect_timeout=10.0, user_agent_extra=USER_AGENT_SUFFIX) | ||
# For this example we will just use the default botocore session configuration | ||
# but if you need to, you can set custom credentials in the botocore session. | ||
custom_session = Session() | ||
|
||
# Use your custom configuration values to configure your client supplier. | ||
client_supplier = DefaultClientSupplier(botocore_session=custom_session, client_config=custom_client_config) | ||
|
||
# Create the keyring that determines how your data keys are protected, | ||
# providing the client supplier that you created. | ||
keyring = KmsKeyring(generator_key_id=aws_kms_cmk, client_supplier=client_supplier) | ||
|
||
# Encrypt your plaintext data. | ||
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( | ||
source=source_plaintext, encryption_context=encryption_context, keyring=keyring | ||
) | ||
|
||
# Demonstrate that the ciphertext and plaintext are different. | ||
assert ciphertext != source_plaintext | ||
|
||
# Decrypt your encrypted data using the same keyring you used on encrypt. | ||
# | ||
# We do not need to specify the encryption context on decrypt | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# because the header message includes the encryption context. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, keyring=keyring) | ||
|
||
# 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()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
When you give the KMS keyring specific key IDs it will use those CMKs and nothing else. | ||
This is true both on encrypt and on decrypt. | ||
However, sometimes you need more flexibility on decrypt, | ||
especially if you might not know beforehand which CMK was used to encrypt a message. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
To address this need, you can use a KMS discovery keyring. | ||
The KMS discovery keyring will do nothing on encrypt | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
but will attempt to decrypt *any* data keys that were encrypted under a KMS CMK. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
This example shows how to configure and use a KMS keyring in discovery mode. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/choose-keyring.html#use-kms-keyring | ||
|
||
For an example of how to use the KMS keyring with CMKs in multiple regions, | ||
see the ``keyring/aws_kms/multiple_regions`` example. | ||
|
||
For examples of how to use the KMS keyring with custom client configurations, | ||
see the ``keyring/aws_kms/custom_client_supplier`` | ||
and ``keyring/aws_kms/custom_kms_client_config`` examples. | ||
|
||
For examples of how to use the KMS keyring in discovery mode on decrypt, | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
see the ``keyring/aws_kms/discovery_decrypt_in_region_only`` | ||
and ``keyring/aws_kms/discovery_decrypt_with_preferred_region`` examples. | ||
""" | ||
import aws_encryption_sdk | ||
from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring | ||
|
||
|
||
def run(aws_kms_cmk, source_plaintext): | ||
# type: (str, bytes) -> None | ||
"""Demonstrate configuring a KMS keyring to use discovery mode for decryption. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
: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 keyring that determines how your data keys are protected. | ||
encrypt_keyring = KmsKeyring(generator_key_id=aws_kms_cmk) | ||
|
||
# Create the KMS discovery keyring that we will use on decrypt. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# | ||
# Because we do not specify any key IDs, this keyring is created in discovery mode. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
decrypt_keyring = KmsKeyring() | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Encrypt your plaintext data. | ||
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( | ||
source=source_plaintext, encryption_context=encryption_context, keyring=encrypt_keyring | ||
) | ||
|
||
# Demonstrate that the ciphertext and plaintext are different. | ||
assert ciphertext != source_plaintext | ||
|
||
# Decrypt your encrypted data using the KMS discovery keyring. | ||
# | ||
# We do not need to specify the encryption context on decrypt | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# because the header message includes the encryption context. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, keyring=decrypt_keyring) | ||
|
||
# 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()) |
Uh oh!
There was an error while loading. Please reload this page.