Skip to content

Commit 0814dff

Browse files
author
Joshua Williams
committed
Proxying all calls to a KMS client
This is needed to remove the client from the regional client cache if a error is detected that indicates the client has been misconfigured. and running black on the file
1 parent 1dedaca commit 0814dff

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

src/aws_encryption_sdk/key_providers/kms.py

+33-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# ANY KIND, either express or implied. See the License for the specific
1212
# language governing permissions and limitations under the License.
1313
"""Master Key Providers for use with AWS KMS"""
14+
import functools
1415
import logging
1516

1617
import attr
@@ -128,15 +129,44 @@ def _process_config(self):
128129
if self.config.key_ids:
129130
self.add_master_keys_from_list(self.config.key_ids)
130131

132+
def _wrap_client(self, region_name, method, *args, **kwargs):
133+
"""Proxies all calls to a kms clients methods and removes misbehaving clients
134+
135+
:param str region_name: AWS Region ID (ex: us-east-1)
136+
:param callable method: a method on the KMS client to proxy
137+
:param tuple args: list of arguments to pass to the provided `method`
138+
:param dict kwargs: dictonary of keyword arguments to pass to the provided `method`
139+
"""
140+
try:
141+
return method(*args, **kwargs)
142+
except botocore.exceptions.BotoCoreError:
143+
self._regional_clients.pop(region_name)
144+
_LOGGER.error(
145+
'Removing regional client "%s" from cache due to BotoCoreError on %s call', region_name, method.__name__
146+
)
147+
raise
148+
149+
def _register_client(self, client, region_name):
150+
"""Uses functools.partial to wrap all methods on a client with the self._wrap_client method
151+
152+
:param botocore.client.BaseClient client: the client to proxy
153+
:param str region_name: AWS Region ID (ex: us-east-1)
154+
"""
155+
for item in client.meta.method_to_api_mapping:
156+
method = getattr(client, item)
157+
wrapped_method = functools.partial(self._wrap_client, region_name, method)
158+
setattr(client, item, wrapped_method)
159+
131160
def add_regional_client(self, region_name):
132161
"""Adds a regional client for the specified region if it does not already exist.
133162
134163
:param str region_name: AWS Region ID (ex: us-east-1)
135164
"""
136165
if region_name not in self._regional_clients:
137-
self._regional_clients[region_name] = boto3.session.Session(
138-
region_name=region_name, botocore_session=self.config.botocore_session
139-
).client("kms", config=self._user_agent_adding_config)
166+
session = boto3.session.Session(region_name=region_name, botocore_session=self.config.botocore_session)
167+
client = session.client("kms", config=self._user_agent_adding_config)
168+
self._register_client(client, region_name)
169+
self._regional_clients[region_name] = client
140170

141171
def add_regional_clients_from_list(self, region_names):
142172
"""Adds multiple regional clients for the specified regions if they do not already exist.

test/unit/test_providers_kms_master_key_provider.py

+11
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import botocore.client
1717
import pytest
1818
import six
19+
from botocore.exceptions import BotoCoreError
1920
from mock import ANY, MagicMock, call, patch, sentinel
2021

2122
from aws_encryption_sdk.exceptions import UnknownRegionError
@@ -144,3 +145,13 @@ def test_new_master_key(self, mock_client):
144145
key = test._new_master_key(key_info)
145146
check_key = KMSMasterKey(key_id=key_info, client=self.mock_boto3_client_instance)
146147
assert key != check_key
148+
149+
150+
def test_remove_bad_client():
151+
test = KMSMasterKeyProvider()
152+
test.add_regional_client("us-fakey-12")
153+
154+
with pytest.raises(BotoCoreError):
155+
test._regional_clients["us-fakey-12"].list_keys()
156+
157+
assert len(test._regional_clients) == 0

0 commit comments

Comments
 (0)