Skip to content

Commit 8640d9a

Browse files
committed
Parallelised key retrieval
1 parent 01e013c commit 8640d9a

File tree

2 files changed

+20
-23
lines changed

2 files changed

+20
-23
lines changed

ScoutSuite/providers/azure/facade/keyvault.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from azure.mgmt.keyvault import KeyVaultManagementClient
22

33
from ScoutSuite.core.console import print_exception
4-
from ScoutSuite.providers.utils import run_concurrently
4+
from ScoutSuite.providers.utils import map_concurrently, run_concurrently
55
from ScoutSuite.utils import get_user_agent
66

77

@@ -33,7 +33,14 @@ async def get_keys(self, subscription_id: str, resourcegroup_name: str, keyvault
3333
print_exception(f'Failed to retrieve keys from key vault {keyvault_name}: {e}')
3434
return []
3535

36-
async def get_key(self, subscription_id: str, resourcegroup_name: str, keyvault_name: str, key_name: str):
36+
async def get_detailed_keys(self, subscription_id: str, resourcegroup_name: str, keyvault_name: str, key_names: list[str]):
37+
try:
38+
return await map_concurrently(self.get_key, key_names, subscription_id=subscription_id, resourcegroup_name=resourcegroup_name, keyvault_name=keyvault_name)
39+
except Exception as e:
40+
print_exception(f'Failed to retrieve keys from key vault {keyvault_name}: {e}')
41+
return []
42+
43+
async def get_key(self, key_name: str, subscription_id: str, resourcegroup_name: str, keyvault_name: str):
3744
try:
3845
client = self.get_client(subscription_id)
3946
return await run_concurrently(

ScoutSuite/providers/azure/resources/keyvault/vaults.py

+11-21
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from itertools import islice
12
from ScoutSuite.core.console import print_warning, print_exception
23
from ScoutSuite.providers.azure.facade.base import AzureFacade
34
from ScoutSuite.providers.azure.resources.base import AzureResources
@@ -13,7 +14,6 @@ def __init__(self, facade: AzureFacade, subscription_id: str):
1314
self.subscription_id = subscription_id
1415
# Hardcoded limit of keys per key vault.
1516
self.KEY_FETCH_LIMIT = 3
16-
self.keys_detailed_fetched = 0
1717

1818
async def fetch_all(self):
1919
for raw_vault in await self.facade.keyvault.get_key_vaults(self.subscription_id):
@@ -25,30 +25,20 @@ async def fetch_all(self):
2525
async def fetch_keys(self, resource_group_name, keyvault_name):
2626
keys = []
2727
try:
28-
self.keys_detailed_fetched = 0
29-
for raw_key in await self.facade.keyvault.get_keys(self.subscription_id, resource_group_name, keyvault_name):
30-
raw_key_extra = await self.fetch_key(resource_group_name, keyvault_name, raw_key.name, raw_key.attributes.enabled)
31-
key = self._parse_key(raw_key, raw_key_extra)
28+
raw_keys = await self.facade.keyvault.get_keys(self.subscription_id, resource_group_name, keyvault_name)
29+
# Retrieve a list of
30+
key_detailed_names = list(islice((k.name for k in raw_keys if k.attributes.enabled), self.KEY_FETCH_LIMIT))
31+
raw_key_details = await self.facade.keyvault.get_detailed_keys(self.subscription_id, resource_group_name, keyvault_name, key_detailed_names)
32+
raw_key_details = dict((k.id, k) for k in raw_key_details)
33+
for raw_key in raw_keys:
34+
raw_key_detailed = raw_key_details.get(raw_key.id)
35+
key = self._parse_key(raw_key, raw_key_detailed)
3236
keys.append(key)
3337
except Exception as e:
3438
print_exception(f'Failed to list Keys in Key Vault {keyvault_name}: {e}')
3539
return []
3640
return keys
3741

38-
async def fetch_key(self, resource_group_name, keyvault_name, key_name, is_key_enabled):
39-
if not is_key_enabled:
40-
return None
41-
if self.keys_detailed_fetched >= self.KEY_FETCH_LIMIT:
42-
print_warning(f'Did not fetch details for Key {keyvault_name}/{key_name}. Some results may be incomplete.')
43-
return None
44-
try:
45-
raw_key_extra = await self.facade.keyvault.get_key(self.subscription_id, resource_group_name, keyvault_name, key_name)
46-
self.keys_detailed_fetched = self.keys_detailed_fetched + 1
47-
except Exception as e:
48-
print_exception(f'Failed to fetch Keys {keyvault_name}/{key_name}: {e}')
49-
return None
50-
return raw_key_extra
51-
5242
async def fetch_secrets(self, resource_group_name, keyvault_name):
5343
secrets = []
5444
try:
@@ -84,7 +74,7 @@ def _parse_key_vault(self, raw_vault):
8474
def _is_public_access_allowed(self, raw_vault):
8575
return raw_vault.properties.network_acls is None or raw_vault.properties.network_acls.default_action == 'Allow'
8676

87-
def _parse_key(self, raw_key, raw_key_extra):
77+
def _parse_key(self, raw_key, raw_key_detailed):
8878
raw_attrs = raw_key.attributes
8979
key = {}
9080
key['id'] = get_non_provider_id(raw_key.id)
@@ -94,7 +84,7 @@ def _parse_key(self, raw_key, raw_key_extra):
9484
key['not_before'] = datetime.fromtimestamp(raw_attrs.not_before, tz=timezone.utc) if raw_attrs.not_before else None
9585
key['exportable'] = raw_attrs.exportable
9686
key['recovery_level'] = raw_attrs.recovery_level
97-
key['auto_rotation_enabled'] = self._is_auto_rotation_enabled(raw_key_extra.rotation_policy) if raw_key_extra else None
87+
key['auto_rotation_enabled'] = self._is_auto_rotation_enabled(raw_key_detailed.rotation_policy) if raw_key_detailed else None
9888
return key
9989

10090
def _parse_secret(self, raw_secret):

0 commit comments

Comments
 (0)