Skip to content

Commit b5be88f

Browse files
feat: deprecate master key providers (#242)
* feat: deprecate master key providers * docs: change main API examples from MKP to keyring * docs: add deprecation notices in MKP docstrings * docs: add future guidance in MKP deprecation comment * docs: remove examples from readme and replace concepts with dev guide concepts * docs: add link to dev guide concepts section * docs: update CHANGELOG.rst Co-Authored-By: Wesley Rosenblum <55108558+WesleyRosenblum@users.noreply.github.com> * docs: refine wording in MKP removal statements * docs: replace copy-paste concepts descriptions with links to developer guide Co-authored-by: Wesley Rosenblum <55108558+WesleyRosenblum@users.noreply.github.com>
1 parent cd2a171 commit b5be88f

File tree

7 files changed

+103
-187
lines changed

7 files changed

+103
-187
lines changed

CHANGELOG.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Major Features
1010

1111
* Add `keyrings`_.
1212
* Change one-step APIs to return a :class:`CryptoResult` rather than a tuple.
13+
1314
* Modified APIs: ``aws_encryption_sdk.encrypt`` and ``aws_encryption_sdk.decrypt``.
1415

1516
.. note::
@@ -20,6 +21,19 @@ Major Features
2021
so this change should not break any existing consumers
2122
unless you are specifically relying on the output being an instance of :class:`tuple`.
2223

24+
Deprecations
25+
------------
26+
27+
* Deprecate master key providers in favor of keyrings.
28+
29+
* We still support using master key providers and are not removing them yet.
30+
When we decide to remove them,
31+
we will communicate that as defined in our versioning policy.
32+
33+
* Deprecate support for Python 3.4.
34+
35+
* This does not mean that this library will no longer work or install with 3.4,
36+
but we are no longer testing against or advertising support for 3.4.
2337

2438
1.4.1 -- 2019-09-20
2539
===================

README.rst

Lines changed: 25 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Getting Started
3636
Required Prerequisites
3737
======================
3838

39-
* Python 2.7+ or 3.5+
39+
* Python 2.7 or 3.5+
4040
* cryptography >= 1.8.1
4141
* boto3
4242
* attrs
@@ -55,189 +55,42 @@ Installation
5555
5656
Concepts
5757
========
58-
There are four main concepts that you need to understand to use this library:
58+
There are three main concepts that are helpful to understand when using the AWS Encryption SDK.
59+
60+
For further information, see the `AWS Encryption SDK developer guide concepts`_.
5961

6062
Cryptographic Materials Managers
6163
--------------------------------
62-
Cryptographic materials managers (CMMs) are resources that collect cryptographic materials and prepare them for
63-
use by the Encryption SDK core logic.
64-
65-
An example of a CMM is the default CMM, which is automatically generated anywhere a caller provides a master
66-
key provider. The default CMM collects encrypted data keys from all master keys referenced by the master key
67-
provider.
68-
69-
An example of a more advanced CMM is the caching CMM, which caches cryptographic materials provided by another CMM.
64+
The cryptographic materials manager (CMM) assembles the cryptographic materials
65+
that are used to encrypt and decrypt data.
7066

71-
Master Key Providers
72-
--------------------
73-
Master key providers are resources that provide master keys.
74-
An example of a master key provider is `AWS KMS`_.
67+
`For more details,
68+
see the AWS Encryption SDK developer guide cryptographic materials manager concept.
69+
<https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#crypt-materials-manager>`_
7570

76-
To encrypt data in this client, a ``MasterKeyProvider`` object must contain at least one ``MasterKey`` object.
71+
Keyrings
72+
--------
7773

78-
``MasterKeyProvider`` objects can also contain other ``MasterKeyProvider`` objects.
74+
A keyring generates, encrypts, and decrypts data keys.
7975

80-
Master Keys
81-
-----------
82-
Master keys generate, encrypt, and decrypt data keys.
83-
An example of a master key is a `KMS customer master key (CMK)`_.
76+
`For more details,
77+
see the AWS Encryption SDK developer guide keyring concept.
78+
<https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#keyring>`_
8479

8580
Data Keys
8681
---------
87-
Data keys are the encryption keys that are used to encrypt your data. If your algorithm suite
88-
uses a key derivation function, the data key is used to generate the key that directly encrypts the data.
82+
83+
A data key is an encryption key that the AWS Encryption SDK uses to encrypt your data.
84+
85+
`For more details,
86+
see the AWS Encryption SDK developer guide data key concept.
87+
<https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#DEK>`_
8988

9089
*****
9190
Usage
9291
*****
93-
To use this client, you (the caller) must provide an instance of either a master key provider
94-
or a CMM. The examples in this readme use the ``KMSMasterKeyProvider`` class.
95-
96-
KMSMasterKeyProvider
97-
====================
98-
Because the ``KMSMasterKeyProvider`` uses the `boto3 SDK`_ to interact with `AWS KMS`_, it requires AWS Credentials.
99-
To provide these credentials, use the `standard means by which boto3 locates credentials`_ or provide a
100-
pre-existing instance of a ``botocore session`` to the ``KMSMasterKeyProvider``.
101-
This latter option can be useful if you have an alternate way to store your AWS credentials or
102-
you want to reuse an existing instance of a botocore session in order to decrease startup costs.
103-
104-
.. code:: python
105-
106-
import aws_encryption_sdk
107-
import botocore.session
108-
109-
kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider()
110-
111-
existing_botocore_session = botocore.session.Session()
112-
kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(botocore_session=existing_botocore_session)
113-
114-
115-
You can pre-load the ``KMSMasterKeyProvider`` with one or more CMKs.
116-
To encrypt data, you must configure the ``KMSMasterKeyProvider`` with as least one CMK.
117-
If you configure the the ``KMSMasterKeyProvider`` with multiple CMKs, the `final message`_
118-
will include a copy of the data key encrypted by each configured CMK.
119-
120-
.. code:: python
121-
122-
import aws_encryption_sdk
123-
124-
kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
125-
'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
126-
'arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333'
127-
])
128-
129-
You can add CMKs from multiple regions to the ``KMSMasterKeyProvider``.
130-
131-
.. code:: python
132-
133-
import aws_encryption_sdk
134-
135-
kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
136-
'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
137-
'arn:aws:kms:us-west-2:3333333333333:key/33333333-3333-3333-3333-333333333333',
138-
'arn:aws:kms:ap-northeast-1:4444444444444:key/44444444-4444-4444-4444-444444444444'
139-
])
140-
141-
142-
Encryption and Decryption
143-
=========================
144-
After you create an instance of a ``MasterKeyProvider``, you can use either of the two
145-
high-level ``encrypt``/``decrypt`` functions to encrypt and decrypt your data.
146-
147-
.. code:: python
148-
149-
import aws_encryption_sdk
150-
151-
kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
152-
'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
153-
'arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333'
154-
])
155-
my_plaintext = b'This is some super secret data! Yup, sure is!'
156-
157-
my_ciphertext, encryptor_header = aws_encryption_sdk.encrypt(
158-
source=my_plaintext,
159-
key_provider=kms_key_provider
160-
)
161-
162-
decrypted_plaintext, decryptor_header = aws_encryption_sdk.decrypt(
163-
source=my_ciphertext,
164-
key_provider=kms_key_provider
165-
)
166-
167-
assert my_plaintext == decrypted_plaintext
168-
assert encryptor_header.encryption_context == decryptor_header.encryption_context
169-
170-
You can provide an `encryption context`_: a form of additional authenticating information.
171-
172-
.. code:: python
173-
174-
import aws_encryption_sdk
175-
176-
kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
177-
'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
178-
'arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333'
179-
])
180-
my_plaintext = b'This is some super secret data! Yup, sure is!'
181-
182-
my_ciphertext, encryptor_header = aws_encryption_sdk.encrypt(
183-
source=my_plaintext,
184-
key_provider=kms_key_provider,
185-
encryption_context={
186-
'not really': 'a secret',
187-
'but adds': 'some authentication'
188-
}
189-
)
190-
191-
decrypted_plaintext, decryptor_header = aws_encryption_sdk.decrypt(
192-
source=my_ciphertext,
193-
key_provider=kms_key_provider
194-
)
195-
196-
assert my_plaintext == decrypted_plaintext
197-
assert encryptor_header.encryption_context == decryptor_header.encryption_context
198-
199-
200-
Streaming
201-
=========
202-
If you are handling large files or simply do not want to put the entire plaintext or ciphertext in
203-
memory at once, you can use this library's streaming clients directly. The streaming clients are
204-
file-like objects, and behave exactly as you would expect a Python file object to behave,
205-
offering context manager and iteration support.
206-
207-
.. code:: python
208-
209-
import aws_encryption_sdk
210-
import filecmp
211-
212-
kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
213-
'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
214-
'arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333'
215-
])
216-
plaintext_filename = 'my-secret-data.dat'
217-
ciphertext_filename = 'my-encrypted-data.ct'
218-
219-
with open(plaintext_filename, 'rb') as pt_file, open(ciphertext_filename, 'wb') as ct_file:
220-
with aws_encryption_sdk.stream(
221-
mode='e',
222-
source=pt_file,
223-
key_provider=kms_key_provider
224-
) as encryptor:
225-
for chunk in encryptor:
226-
ct_file.write(chunk)
227-
228-
new_plaintext_filename = 'my-decrypted-data.dat'
22992

230-
with open(ciphertext_filename, 'rb') as ct_file, open(new_plaintext_filename, 'wb') as pt_file:
231-
with aws_encryption_sdk.stream(
232-
mode='d',
233-
source=ct_file,
234-
key_provider=kms_key_provider
235-
) as decryptor:
236-
for chunk in decryptor:
237-
pt_file.write(chunk)
238-
239-
assert filecmp.cmp(plaintext_filename, new_plaintext_filename)
240-
assert encryptor.header.encryption_context == decryptor.header.encryption_context
93+
For examples of how to use these concepts to accomplish different tasks, see our `examples`_.
24194

24295
Performance Considerations
24396
==========================
@@ -249,6 +102,8 @@ to your use-case in order to obtain peak performance.
249102

250103

251104
.. _AWS Encryption SDK: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html
105+
.. _AWS Encryption SDK developer guide concepts:
106+
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html
252107
.. _cryptography: https://cryptography.io/en/latest/
253108
.. _cryptography installation guide: https://cryptography.io/en/latest/installation/
254109
.. _Read the Docs: http://aws-encryption-sdk-python.readthedocs.io/en/latest/
@@ -259,3 +114,4 @@ to your use-case in order to obtain peak performance.
259114
.. _standard means by which boto3 locates credentials: https://boto3.readthedocs.io/en/latest/guide/configuration.html
260115
.. _final message: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/message-format.html
261116
.. _encryption context: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context
117+
.. _examples: https://github.com/aws/aws-encryption-sdk-python/tree/master/examples

src/aws_encryption_sdk/__init__.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ def encrypt(**kwargs):
3939
.. code:: python
4040
4141
>>> import aws_encryption_sdk
42-
>>> kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
43-
... 'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
44-
... 'arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333'
45-
... ])
42+
>>> from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring
43+
>>> keyring = KmsKeyring(
44+
... generator_key_id="arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222",
45+
... key_ids=["arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333"],
46+
... )
4647
>>> my_ciphertext, encryptor_header = aws_encryption_sdk.encrypt(
4748
... source=my_plaintext,
48-
... key_provider=kms_key_provider
49-
... )
49+
... keyring=keyring,
50+
>>> )
5051
5152
:param config: Client configuration object (config or individual parameters required)
5253
:type config: aws_encryption_sdk.streaming_client.EncryptorConfig
@@ -106,13 +107,14 @@ def decrypt(**kwargs):
106107
.. code:: python
107108
108109
>>> import aws_encryption_sdk
109-
>>> kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
110-
... 'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
111-
... 'arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333'
112-
... ])
113-
>>> my_ciphertext, encryptor_header = aws_encryption_sdk.decrypt(
110+
>>> from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring
111+
>>> keyring = KmsKeyring(
112+
... generator_key_id="arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222",
113+
... key_ids=["arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333"],
114+
... )
115+
>>> my_ciphertext, decryptor_header = aws_encryption_sdk.decrypt(
114116
... source=my_ciphertext,
115-
... key_provider=kms_key_provider
117+
... keyring=keyring,
116118
... )
117119
118120
:param config: Client configuration object (config or individual parameters required)
@@ -164,17 +166,18 @@ def stream(**kwargs):
164166
.. code:: python
165167
166168
>>> import aws_encryption_sdk
167-
>>> kms_key_provider = aws_encryption_sdk.KMSMasterKeyProvider(key_ids=[
168-
... 'arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222',
169-
... 'arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333'
170-
... ])
169+
>>> from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring
170+
>>> keyring = KmsKeyring(
171+
... generator_key_id="arn:aws:kms:us-east-1:2222222222222:key/22222222-2222-2222-2222-222222222222",
172+
... key_ids=["arn:aws:kms:us-east-1:3333333333333:key/33333333-3333-3333-3333-333333333333"],
173+
... )
171174
>>> plaintext_filename = 'my-secret-data.dat'
172175
>>> ciphertext_filename = 'my-encrypted-data.ct'
173176
>>> with open(plaintext_filename, 'rb') as pt_file, open(ciphertext_filename, 'wb') as ct_file:
174177
... with aws_encryption_sdk.stream(
175178
... mode='e',
176179
... source=pt_file,
177-
... key_provider=kms_key_provider
180+
... keyring=keyring,
178181
... ) as encryptor:
179182
... for chunk in encryptor:
180183
... ct_file.write(chunk)
@@ -183,7 +186,7 @@ def stream(**kwargs):
183186
... with aws_encryption_sdk.stream(
184187
... mode='d',
185188
... source=ct_file,
186-
... key_provider=kms_key_provider
189+
... keyring=keyring,
187190
... ) as decryptor:
188191
... for chunk in decryptor:
189192
... pt_file.write(chunk)

src/aws_encryption_sdk/key_providers/base.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"""Base class interface for Master Key Providers."""
1414
import abc
1515
import logging
16+
import warnings
1617

1718
import attr
1819
import six
@@ -51,6 +52,10 @@ class MasterKeyProviderConfig(object):
5152
class MasterKeyProvider(object):
5253
"""Parent interface for Master Key Provider classes.
5354
55+
.. versionadded:: 1.5.0
56+
Master key providers are deprecated.
57+
Use :class:`aws_encryption_sdk.keyrings.base.Keyring` instead.
58+
5459
:param config: Configuration object
5560
:type config: aws_encryption_sdk.key_providers.base.MasterKeyProviderConfig
5661
"""
@@ -78,6 +83,16 @@ def __new__(cls, **kwargs):
7883
"""Set key index and member set for all new instances here
7984
to avoid requiring child classes to call super init.
8085
"""
86+
# DeprecationWarning are ignored by default,
87+
# but because we are not yet removing master key providers,
88+
# I think this is the correct level of visibility.
89+
#
90+
# Once we decide that we are one X or Y version away from removing master key providers,
91+
# we should upgrade this to a UserWarning.
92+
warnings.warn(
93+
"Master key providers are deprecated as of 1.5.0. You should migrate to keyrings.", DeprecationWarning
94+
)
95+
8196
instance = super(MasterKeyProvider, cls).__new__(cls)
8297
config = kwargs.pop("config", None)
8398
if not isinstance(config, instance._config_class): # pylint: disable=protected-access
@@ -329,6 +344,10 @@ def __attrs_post_init__(self):
329344
class MasterKey(MasterKeyProvider):
330345
"""Parent interface for Master Key classes.
331346
347+
.. versionadded:: 1.5.0
348+
Master key providers are deprecated.
349+
Use :class:`aws_encryption_sdk.keyrings.base.Keyring` instead.
350+
332351
:param bytes key_id: Key ID for Master Key
333352
:param config: Configuration object
334353
:type config: aws_encryption_sdk.key_providers.base.MasterKeyConfig

0 commit comments

Comments
 (0)