Skip to content

Examples refresh, take 1 #219

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

Merged
merged 68 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
0938325
Update PR template
johnwalker Jul 15, 2019
ee1b4cc
Added a check for max_age being greater than 0 (#172)
caitlin-tibbetts Jul 22, 2019
9351933
Merge branch 'master' into prtemplate
mattsb42-aws Jul 22, 2019
3b62bc3
Testing something, want AppVeyor to run
caitlin-tibbetts Jul 23, 2019
626d5ba
Quick change
caitlin-tibbetts Jul 23, 2019
83f4ff8
Running AppVeyor
caitlin-tibbetts Jul 23, 2019
d3383c6
Merge pull request #171 from johnwalker/prtemplate
johnwalker Jul 23, 2019
534e225
Added example for using multiple keyrings in multiple regions
caitlin-tibbetts Jul 24, 2019
42e86ab
Undid something quickly
caitlin-tibbetts Jul 24, 2019
6b84d3a
Merge branch 'master' into a1b1c1-example
caitlin-tibbetts Jul 24, 2019
2dfe2d0
Merge branch 'master' of github.com:aws/aws-encryption-sdk-python int…
caitlin-tibbetts Jul 24, 2019
fabc5e3
Fixed importerror
caitlin-tibbetts Jul 24, 2019
67f0ddc
Merge branch 'a1b1c1-example' of github.com:caitlin-tibbetts/aws-encr…
caitlin-tibbetts Jul 24, 2019
30eab33
Formatting fix
caitlin-tibbetts Jul 24, 2019
453b82d
Update tox.ini
caitlin-tibbetts Jul 25, 2019
2208890
Update tox.ini
caitlin-tibbetts Jul 25, 2019
d724335
Made some changes to the multiple_kms_cmk_regions example/test
caitlin-tibbetts Jul 25, 2019
306d1a9
This is my next interation of the code for the example; however, I am…
caitlin-tibbetts Jul 25, 2019
bde7a56
Changed the example to test two CMKs in the same region until Issue #…
caitlin-tibbetts Jul 26, 2019
b7e9dd1
Found out how to make a new valid test key, so now there are two vali…
caitlin-tibbetts Jul 26, 2019
4d8c7a0
Ran autoformat
caitlin-tibbetts Jul 26, 2019
1fdbb32
Added some docstrings
caitlin-tibbetts Jul 26, 2019
d3240eb
Formatting will be the death of me
caitlin-tibbetts Jul 26, 2019
4eb5fde
Used correct keys in test
caitlin-tibbetts Jul 26, 2019
bb6c650
Updated some comments
caitlin-tibbetts Jul 29, 2019
1de8d5c
Fixed KMS master key provider tests when default AWS region is config…
ragona Aug 2, 2019
baf1164
Wrote example and test for using one kms cmk with an unsigned algorithm
caitlin-tibbetts Aug 2, 2019
d89e6dc
Merge branch 'master' into a2b1c1-example
caitlin-tibbetts Aug 2, 2019
3af7795
Merge branch 'master' of github.com:aws/aws-encryption-sdk-python int…
caitlin-tibbetts Aug 2, 2019
a833f52
Merge branch 'master' of github.com:aws/aws-encryption-sdk-python int…
caitlin-tibbetts Aug 2, 2019
9e5fcd4
Update the integration tests
caitlin-tibbetts Aug 5, 2019
38e2757
Small changes
caitlin-tibbetts Aug 5, 2019
a7fcb4a
Update one_kms_cmk_unsigned.py
caitlin-tibbetts Aug 6, 2019
862734a
Update examples/src/one_kms_cmk_unsigned.py
caitlin-tibbetts Aug 6, 2019
850d8c9
Merge branch 'a2b1c1-example' of github.com:caitlin-tibbetts/aws-encr…
caitlin-tibbetts Aug 6, 2019
4def8ba
isort-check now succeeds
caitlin-tibbetts Aug 7, 2019
f00fdd2
Merge pull request #180 from caitlin-tibbetts/a2b1c1-example
lizroth Aug 14, 2019
c232607
Merge branch 'master' of github.com:caitlin-tibbetts/aws-encryption-s…
caitlin-tibbetts Aug 16, 2019
81d79d3
chore: move existing examples into "legacy" directory
mattsb42-aws Mar 7, 2020
8026e31
chore: add automatic test runner for examples
mattsb42-aws Mar 7, 2020
9d07fde
chore: convert existing examples to work with automatic test runner
mattsb42-aws Mar 7, 2020
421e121
chore: move examples kwarg building into utils module
mattsb42-aws Mar 7, 2020
4c53891
Merge branch 'keyring' into a1b1c1-example
mattsb42-aws Mar 8, 2020
675c4dd
Merge branch 'caitlin-tibbetts/a1b1c1-example' into keyring-examples-…
mattsb42-aws Mar 8, 2020
ef475d7
chore: convert multi-CMK test runners to new configuration format
mattsb42-aws Mar 8, 2020
371daaf
fix: fix multi-CMK example logic
mattsb42-aws Mar 8, 2020
886341c
chore: convert multi-CMK example to new test runner signature and mov…
mattsb42-aws Mar 8, 2020
460e6e1
chore: make examples linting always run across both source and tests
mattsb42-aws Mar 9, 2020
7a81af4
fix: linting fixes
mattsb42-aws Mar 9, 2020
78484eb
docs: add docstring description for legacy examples module
mattsb42-aws Mar 9, 2020
a818ea5
chore: add initial new-format examples
mattsb42-aws Mar 9, 2020
52906eb
docs: add examples readme
mattsb42-aws Mar 9, 2020
7d7ddcc
chore: Merge branch 'keyring' into keyring-examples-reorg
mattsb42-aws Mar 9, 2020
36df978
docs: add instructions for writing examples
mattsb42-aws Mar 9, 2020
95047f1
chore: address PR comments
mattsb42-aws Mar 9, 2020
1815399
chore: change examples parameter from aws_kms_cmk_arn to aws_kms_cmk …
mattsb42-aws Mar 9, 2020
b0c7c80
docs: clarify integration tests readme
mattsb42-aws Mar 9, 2020
c54f21a
Apply suggestions from code review
mattsb42-aws Mar 9, 2020
727ebab
Apply suggestions from code review
mattsb42-aws Mar 10, 2020
0af1cf9
docs: change from "one-shot" term to "one-step"
mattsb42-aws Mar 10, 2020
68b35c3
chore: apply changes based on PR comments
mattsb42-aws Mar 10, 2020
f054b12
docs: reword parameter description
mattsb42-aws Mar 10, 2020
d31b40d
Apply suggestions from code review
mattsb42-aws Mar 10, 2020
57077b1
chore: rename examples input parameters to move from "child" to "addi…
mattsb42-aws Mar 10, 2020
f1469f1
docs: clarify configuration intro
mattsb42-aws Mar 10, 2020
586f88e
docs: apply examples comments consistently
mattsb42-aws Mar 10, 2020
bf2e6c9
chore: fix line length
mattsb42-aws Mar 10, 2020
3c19f1f
fix: fix typo
mattsb42-aws Mar 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# AWS Encryption SDK Examples

This section features examples that show you
how to use the AWS Encryption SDK.
We demonstrate how to use the encryption and decryption APIs
and how to set up some common configuration patterns.

## APIs

The AWS Encryption SDK provides two high-level APIs:
one-step APIs that process the entire operation in memory
and streaming APIs.

You can find examples that demonstrate these APIs
in the [`examples/src/`](./src) directory.

## Configuration

To use the library APIs,
you need to describe how you want the library to protect your data keys.
You can do this using
[keyrings][#keyrings] or [cryptographic materials managers][#cryptographic-materials-managers],
or using [master key providers][#master-key-providers].
These examples will show you how.

### Keyrings

Keyrings are the most common way for you to configure the AWS Encryption SDK.
They determine how the AWS Encryption SDK protects your data.
You can find these examples in [`examples/src/keyring`](./src/keyring).

### Cryptographic Materials Managers

Keyrings define how your data keys are protected,
but there is more going on here than just protecting data keys.

Cryptographic materials managers give you higher-level controls
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

higher-level or lower-level? I think of the CMM as lower-level.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Higher-level than keyrings.

over how the AWS Encryption SDK protects your data.
This can include things like
enforcing the use of certain algorithm suites or encryption context settings,
reusing data keys across messages,
or changing how you interact with keyrings.
You can find these examples in
[`examples/src/crypto_materials_manager`](./src/crypto_materials_manager).

### Master Key Providers

Before there were keyrings, there were master key providers.
Master key providers were the original configuration structure
that we provided for defining how you want to protect your data keys.
Keyrings provide a simpler experience and often more powerful configuration options,
but if you need to use master key providers,
need help migrating from master key providers to keyrings,
or simply want to see the difference between these configuration experiences,
you can find these examples in [`examples/src/master_key_provider`](./src/master_key_provider).

## Legacy

This section includes older examples, including examples of using master keys and master key providers in Java and Python.
You can use them as a reference,
but we recommend looking at the newer examples, which explain the preferred ways of using this library.
You can find these examples in [`examples/src/legacy`](./src/legacy).

# Writing Examples

If you want to contribute a new example, that's awesome!
To make sure that your example is tested in our CI,
please make sure that it meets the following requirements:

1. The example MUST be a distinct module in the [`examples/src/`](./src) directory.
1. The example MAY be nested arbitrarily deeply,
but every intermediate directory MUST contain a `__init__.py` file
so that CPython 2.7 will recognize it as a module.
1. Every example MUST be CPython 2.7 compatible.
1. Each example file MUST contain exactly one example.
1. Each example file MUST contain a function called `run` that runs the example.
1. If your `run` function needs any of the following inputs,
the parameters MUST have the following names:
* `aws_kms_cmk` (`str`) : A single AWS KMS CMK ARN.
* NOTE: You can assume that automatically discovered credentials have
`kms:GenerateDataKey`, `kms:Encrypt`, and `kms:Decrypt` permissions on this CMK.
* `aws_kms_generator_cmk` (`str`) : A single AWS KMS CMK ARN to use as a generator key.
* NOTE: You can assume that automatically discovered credentials have
`kms:GenerateDataKey`, `kms:Encrypt`, and `kms:Decrypt` permissions on this CMK.
* `aws_kms_additional_cmks` (`List[str]`) :
A list of AWS KMS CMK ARNs to use for encrypting and decrypting data keys.
* NOTE: You can assume that automatically discovered credentials have
`kms:Encrypt` and `kms:Decrypt` permissions on these CMKs.
* `source_plaintext` (`bytes`) : Plaintext data to encrypt.
* `source_plaintext_filename` (`str`) : A path to a file containing plaintext to encrypt.
* NOTE: You can assume that you have write access to the parent directory
and that anything you do in that directory will be cleaned up
by our test runners.
1. Any additional parameters MUST be optional.
82 changes: 82 additions & 0 deletions examples/src/file_streaming_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example shows how to use the streaming encrypt and decrypt APIs when working with files.

One benefit of using the streaming API is that
we can check the encryption context in the header before we start decrypting.

In this example, we use an AWS KMS customer master key (CMK),
but you can use other key management options with the AWS Encryption SDK.
For examples that demonstrate how to use other key management configurations,
see the ``keyring`` and ``master_key_provider`` directories.
"""
import filecmp

import aws_encryption_sdk
from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring


def run(aws_kms_cmk, source_plaintext_filename):
# type: (str, str) -> None
"""Demonstrate an encrypt/decrypt cycle using the streaming encrypt/decrypt APIs with files.

:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys
:param str source_plaintext_filename: Path to plaintext file to encrypt
"""
# We assume that you can also write to the directory containing the plaintext file,
# so that is where we will put all of the results.
ciphertext_filename = source_plaintext_filename + ".encrypted"
decrypted_filename = ciphertext_filename + ".decrypted"

# 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)

# Open the files you want to work with.
with open(source_plaintext_filename, "rb") as plaintext, open(ciphertext_filename, "wb") as ciphertext:
# The streaming API provides a context manager.
# You can read from it just as you read from a file.
with aws_encryption_sdk.stream(
mode="encrypt", source=plaintext, encryption_context=encryption_context, keyring=keyring
) as encryptor:
# Iterate through the segments in the context manager
# and write the results to the ciphertext.
for segment in encryptor:
ciphertext.write(segment)

# Verify that the ciphertext and plaintext are different.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of a low bar ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, but I'm not sure what else we can really make a concrete statement about to demonstrate that "yes, this is encrypted" without getting really complicated.

assert not filecmp.cmp(source_plaintext_filename, ciphertext_filename)

# Open the files you want to work with.
with open(ciphertext_filename, "rb") as ciphertext, open(decrypted_filename, "wb") as decrypted:
# 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 message header includes the encryption context.
with aws_encryption_sdk.stream(mode="decrypt", source=ciphertext, keyring=keyring) as decryptor:
# Check the encryption context in the header before we start decrypting.
#
# 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(decryptor.header.encryption_context.items())

# Now that we are more confident that we will decrypt the right message,
# we can start decrypting.
for segment in decryptor:
decrypted.write(segment)

# Verify that the decrypted plaintext is identical to the original plaintext.
assert filecmp.cmp(source_plaintext_filename, decrypted_filename)
79 changes: 79 additions & 0 deletions examples/src/in_memory_streaming_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example shows how to use the streaming encrypt and decrypt APIs on data in memory.

One benefit of using the streaming API is that
we can check the encryption context in the header before we start decrypting.

In this example, we use an AWS KMS customer master key (CMK),
but you can use other key management options with the AWS Encryption SDK.
For examples that demonstrate how to use other key management configurations,
see the ``keyring`` and ``mater_key_provider`` directories.
"""
import io

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 an encrypt/decrypt cycle using the streaming encrypt/decrypt APIs in-memory.

: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)

ciphertext = io.BytesIO()

# The streaming API provides a context manager.
# You can read from it just as you read from a file.
with aws_encryption_sdk.stream(
mode="encrypt", source=source_plaintext, encryption_context=encryption_context, keyring=keyring
) as encryptor:
# Iterate through the segments in the context manager
# and write the results to the ciphertext.
for segment in encryptor:
ciphertext.write(segment)

# Verify that the ciphertext and plaintext are different.
assert ciphertext.getvalue() != source_plaintext

# Reset the ciphertext stream position so that we can read from the beginning.
ciphertext.seek(0)

# 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 = io.BytesIO()
with aws_encryption_sdk.stream(mode="decrypt", source=ciphertext, keyring=keyring) as decryptor:
# Check the encryption context in the header before we start decrypting.
#
# 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(decryptor.header.encryption_context.items())

# Now that we are more confident that we will decrypt the right message,
# we can start decrypting.
for segment in decryptor:
decrypted.write(segment)

# Verify that the decrypted plaintext is identical to the original plaintext.
assert decrypted.getvalue() == source_plaintext
9 changes: 9 additions & 0 deletions examples/src/legacy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
Legacy examples.

We keep these older examples as reference material,
but we recommend that you use the new examples.
The new examples reflect our current guidance for using the library.
"""
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
# Copyright 2017 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.
"""Example showing basic encryption and decryption of a value already in memory."""
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Example showing how to encrypt and decrypt a value in memory."""
import aws_encryption_sdk


def cycle_string(key_arn, source_plaintext, botocore_session=None):
def run(aws_kms_cmk, source_plaintext, botocore_session=None):
"""Encrypts and then decrypts a string under a KMS customer master key (CMK).

:param str key_arn: Amazon Resource Name (ARN) of the KMS CMK
:param str aws_kms_cmk: Amazon Resource Name (ARN) of the AWS KMS CMK
:param bytes source_plaintext: Data to encrypt
:param botocore_session: existing botocore session instance
:type botocore_session: botocore.session.Session
"""
# Create a KMS master key provider
kms_kwargs = dict(key_ids=[key_arn])
kms_kwargs = dict(key_ids=[aws_kms_cmk])
if botocore_session is not None:
kms_kwargs["botocore_session"] = botocore_session
master_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(**kms_kwargs)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
# Copyright 2017 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.
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Example showing creation of a RawMasterKeyProvider, how to use multiple
master key providers to encrypt, and demonstrating that each master key
provider can then be used independently to decrypt the same encrypted message.
Expand Down Expand Up @@ -60,12 +50,12 @@ def _get_raw_key(self, key_id):
)


def cycle_file(key_arn, source_plaintext_filename, botocore_session=None):
def run(aws_kms_cmk, source_plaintext_filename, botocore_session=None):
"""Encrypts and then decrypts a file using a KMS master key provider and a custom static master
key provider. Both master key providers are used to encrypt the plaintext file, so either one alone
can decrypt it.

:param str key_arn: Amazon Resource Name (ARN) of the KMS Customer Master Key (CMK)
:param str aws_kms_cmk: Amazon Resource Name (ARN) of the KMS Customer Master Key (CMK)
(http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html)
:param str source_plaintext_filename: Filename of file to encrypt
:param botocore_session: existing botocore session instance
Expand All @@ -77,7 +67,7 @@ def cycle_file(key_arn, source_plaintext_filename, botocore_session=None):
cycled_static_plaintext_filename = source_plaintext_filename + ".static.decrypted"

# Create a KMS master key provider
kms_kwargs = dict(key_ids=[key_arn])
kms_kwargs = dict(key_ids=[aws_kms_cmk])
if botocore_session is not None:
kms_kwargs["botocore_session"] = botocore_session
kms_master_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(**kms_kwargs)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
# Copyright 2017 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.
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Example showing creation and use of a RawMasterKeyProvider."""
import filecmp
import os
Expand Down Expand Up @@ -48,7 +38,7 @@ def _get_raw_key(self, key_id):
)


def cycle_file(source_plaintext_filename):
def run(source_plaintext_filename):
"""Encrypts and then decrypts a file under a custom static master key provider.

:param str source_plaintext_filename: Filename of file to encrypt
Expand Down
Loading