|
11 | 11 | # ANY KIND, either express or implied. See the License for the specific
|
12 | 12 | # language governing permissions and limitations under the License.
|
13 | 13 | """Master Key Providers for use with AWS KMS"""
|
| 14 | +import functools |
14 | 15 | import logging
|
15 | 16 |
|
16 | 17 | import attr
|
@@ -128,15 +129,44 @@ def _process_config(self):
|
128 | 129 | if self.config.key_ids:
|
129 | 130 | self.add_master_keys_from_list(self.config.key_ids)
|
130 | 131 |
|
| 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 | + |
131 | 160 | def add_regional_client(self, region_name):
|
132 | 161 | """Adds a regional client for the specified region if it does not already exist.
|
133 | 162 |
|
134 | 163 | :param str region_name: AWS Region ID (ex: us-east-1)
|
135 | 164 | """
|
136 | 165 | 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 |
140 | 170 |
|
141 | 171 | def add_regional_clients_from_list(self, region_names):
|
142 | 172 | """Adds multiple regional clients for the specified regions if they do not already exist.
|
|
0 commit comments