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 57 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
93 changes: 93 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# AWS Encryption SDK Examples

Here you can find some examples that show you
how to use the AWS Encryption SDK.
We demonstrate how to use the high-level APIs
as well as how to set up some common configuration patterns.

## APIs

The AWS Encryption SDK provides two high-level APIs:
one-shot 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 root.

## Configuration

In order to use the library APIs,
you must provide some configuration that defines
how you want to protect your data keys.

### Keyrings

Keyrings are the most common way for you to configure that AWS Encryption SDK.
These let you define how you want the AWS Encryption SDK to protect your data keys.
You can find these examples in [`examples/src/keyring`](./src/keyring).

### Cryptographic Materials Managers

Keyrings define how you want to protect your data keys,
but there is more going on here than just 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 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

These are any examples that were already defined
before we started revamping our examples.
We are keeping them around for anyone who needs them as reference material,
but we recommend looking at the newer examples
that should provide a clearer picture of how to use this library.
You can find these examples in [`examples/src/legacy`](./src/legacy).

# Writing Examples

If you want to write a new example, that's awesome!
There are a couple things you need to keep in mind, though.
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_child_cmks` (`List[str]`) : A list of AWS KMS CMK ARNs to use as child 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.
79 changes: 79 additions & 0 deletions examples/src/file_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 when working with files.

For the purposes of this example, we demonstrate using AWS KMS,
but you can use other key management options with the AWS Encryption SDK.
Look in the ``keyring`` and ``master_key_provider`` directories
for examples that demonstrate how to use other key management configurations.
"""
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 to work with files.

:param str aws_kms_cmk: AWS KMS CMK ARN to use to protect data keys
:param str source_plaintext_filename: Path to plaintext file to encrypt
"""
# We assume that you can also write in 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.
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 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 you with a context manager
# that you can read from similar to how you would read from a file.
with aws_encryption_sdk.stream(
mode="encrypt", source=plaintext, encryption_context=encryption_context, keyring=keyring
) as encryptor:
# Iterate through the chunks in the context manager
# and write the results to the ciphertext.
for chunk in encryptor:
ciphertext.write(chunk)

# 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.
#
# We do not need to specify the encryption context on decrypt
# because the header message includes the encryption context.
with aws_encryption_sdk.stream(mode="decrypt", source=ciphertext, keyring=keyring) as decryptor:
# One benefit of using the streaming API is that
# we can check the encryption context in the header before we start decrypting.
#
# Verify that the encryption context used in the decrypt operation matches what you expect.
# 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 confident that the message is what we think it should be,
# we can start decrypting.
for chunk in decryptor:
decrypted.write(chunk)

# Verify that the "cycled" (encrypted then decrypted) plaintext
# is identical to the original plaintext.
assert filecmp.cmp(source_plaintext_filename, decrypted_filename)
75 changes: 75 additions & 0 deletions examples/src/in_memory_streaming_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# 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 in memory.

For the purposes of this example, we demonstrate using AWS KMS,
but you can use other key management options with the AWS Encryption SDK.
Look in the ``keyring`` and ``master_key_provider`` directories
for examples that demonstrate how to use other key management configurations.
"""
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: AWS KMS CMK ARN to use to protect data keys
:param bytes source_plaintext: Plaintext to encrypt
"""
# Prepare your 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 keys are protected.
keyring = KmsKeyring(generator_key_id=aws_kms_cmk)

ciphertext = io.BytesIO()

# The streaming API provides you with a context manager
# that you can read from similar to how you would 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 chunks in the context manager
# and write the results to the ciphertext.
for chunk in encryptor:
ciphertext.write(chunk)

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.
#
# 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:
# One benefit of using the streaming API is that
# we can check the encryption context in the header before we start decrypting.
#
# Verify that the encryption context used in the decrypt operation matches what you expect.
# 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 confident that the message is what we think it should be,
# we can start decrypting.
for chunk in decryptor:
decrypted.write(chunk)

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

These are any examples that were already defined
before we started revamping our examples.
We are keeping them around for anyone who needs them as reference material,
but we recommend looking at the newer examples
that should provide a clearer picture of how to use this 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.
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Example showing basic encryption and decryption of a value already 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 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