-
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 35 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. | ||||||
|
||||||
You might use this | ||||||
if you need different credentials in different AWS regions. | ||||||
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 need these imports when running the mypy checks | ||||||
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. | ||||||
# | ||||||
# 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, 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 uses the default configurations | ||
for all KMS clients and uses the default discoverable credentials. | ||
If you need to change this configuration, | ||
you can configure the client supplier. | ||
|
||
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. | ||
# | ||
# 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, 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()) |
Uh oh!
There was an error while loading. Please reload this page.