Skip to content

Commit 5f1858d

Browse files
committed
added samples
1 parent 5f4e5e2 commit 5f1858d

5 files changed

+201
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Azure EASM samples for Python client
2+
3+
The sample programs here demonstrate some common use case scenarios for the Azure EASM Python SDK Client.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'''
2+
This sample demonstrates how to create and manage discovery runs in a workspace using the discovery_groups module of the EasmClient
3+
'''
4+
import itertools
5+
from azure.identity import InteractiveBrowserCredential
6+
from azure.defender.easm import EasmClient
7+
8+
9+
#To create an EasmClient, you need your subscription ID, region, and some sort of credential.
10+
sub_id = '<your subscription ID here>'
11+
workspace_name = '<your workspace name here>'
12+
resource_group = '<your resource group here>'
13+
region = '<your region here>'
14+
15+
endpoint = f'{region}.easm.defender.microsoft.com'
16+
17+
# For the purposes of this demo, I've chosen the InteractiveBrowserCredential but any credential will work.
18+
browser_credential = InteractiveBrowserCredential()
19+
client = EasmClient(endpoint, resource_group, sub_id, workspace_name, browser_credential)
20+
21+
# in order to start discovery runs, we must first create a discovery group, which is a collection of known assets that we can pivot off of. these are created using the `discovery_groups.put` method
22+
name = '<your discovery group name here>'
23+
assets = [
24+
{'kind': 'domain', 'name': '<a domain you want to run discovery against>'},
25+
{'kind': 'host', 'name': '<a host you want to run discovery against>'}
26+
]
27+
request = {
28+
'description': '<a description for your discovery group>',
29+
'seeds': assets
30+
}
31+
32+
response = client.discovery_groups.put(name, request)
33+
34+
# Discovery groups created through the API's `put` method aren't run automatically, so we need to start the run ourselves.
35+
client.discovery_groups.run(name)
36+
37+
for group in client.discovery_groups.list():
38+
print(group['name'])
39+
runs = client.discovery_groups.list_runs(group['name'])
40+
for run in itertools.islice(runs, 5):
41+
print(f" - started: {run['startedDate']}, finished: {run['completedDate']}, assets found: {run['totalAssetsFoundCount']}")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'''
2+
This sample shows you how to use the discovery_groups module to create discovery groups using templates provided by the discovery_templates module of the EasmClient
3+
'''
4+
from azure.identity import InteractiveBrowserCredential
5+
from azure.defender.easm import EasmClient
6+
7+
8+
#To create an EasmClient, you need your subscription ID, region, and some sort of credential.
9+
sub_id = '<your subscription ID here>'
10+
workspace_name = '<your workspace name here>'
11+
resource_group = '<your resource group here>'
12+
region = '<your region here>'
13+
14+
endpoint = f'{region}.easm.defender.microsoft.com'
15+
16+
# For the purposes of this demo, I've chosen the InteractiveBrowserCredential but any credential will work.
17+
browser_credential = InteractiveBrowserCredential()
18+
client = EasmClient(endpoint, resource_group, sub_id, workspace_name, browser_credential)
19+
20+
# The discovery_templates.list method can be used to find a discovery template using a filter.
21+
# The endpoint will return templates based on a partial match on the name field.
22+
partial_name = 'taco'
23+
templates = client.discovery_templates.list(filter=partial_name)
24+
25+
for template in templates:
26+
print(f'{template["id"]}: {template["displayName"]}')
27+
28+
# To get more detail about a disco template, we can use the discovery_templates.get method.
29+
# From here, we can see the names and seeds which would be used in a discovery run.
30+
template_id = '<your chosen template id>'
31+
template = client.discovery_templates.get(template_id)
32+
33+
for name in template['names']:
34+
print(name)
35+
36+
for seed in template['seeds']:
37+
print(f'{seed["kind"]}, {seed["name"]}')
38+
39+
#The discovery template can be used to create a discovery group with using a DiscoGroupRequest and the EasmClient's discovery_groups.put method. Don't forget to run your new disco group with discovery_groups.run
40+
group_name = '<your group name here>'
41+
42+
request = {'templateId': template_id}
43+
response = client.discovery_groups.put(group_name, body=request)
44+
45+
client.discovery_groups.run(group_name)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'''
2+
Saved Filters are used to store a query within EASM, these saved queries can be used to synchronize exact queries across multiple scripts, or to ensure a team is looking at the same assets
3+
In this example, we'll go over how a saved filter could be used to synchronize the a query across multiple scripts
4+
'''
5+
from azure.identity import InteractiveBrowserCredential
6+
from azure.defender.easm import EasmClient
7+
8+
sub_id = '<your subscription ID here>'
9+
workspace_name = '<your workspace name here>'
10+
resource_group = '<your resource group here>'
11+
region = '<your region here>'
12+
13+
endpoint = f'{region}.easm.defender.microsoft.com'
14+
15+
browser_credential = InteractiveBrowserCredential()
16+
client = EasmClient(endpoint, resource_group, sub_id, workspace_name, browser_credential)
17+
18+
# To create a Saved Filter, we need to send a filter, name, and description to the `saved_filters.put` endpoint
19+
saved_filter_name = '<your saved filter name here>'
20+
request = {
21+
'filter': 'IP Address = 151.101.192.67',
22+
'description': 'Monitored Addresses',
23+
}
24+
client.saved_filters.put(saved_filter_name, body=request)
25+
26+
# The saved filter can now be used in scripts to monitor the assets
27+
# First, retrieve the saved filter by name, then use it in an asset list or update call
28+
29+
# A sample asset list call that could be used to monitor the assets:
30+
def monitor(asset):
31+
pass #your monitor logic here
32+
33+
monitor_filter = client.saved_filters.get(saved_filter_name)['filter']
34+
35+
for asset in client.assets.list(filter=monitor_filter):
36+
monitor(asset)
37+
38+
# A sample asset update call, which could be used to update the monitored assets:
39+
monitor_filter = client.saved_filters.get(saved_filter_name)['filter']
40+
41+
body = {
42+
#your asset update request body here
43+
}
44+
45+
client.assets.update(body, filter=asset_filter)
46+
47+
# Should your needs change, the filter can be updated with no need to update the scripts it's used in
48+
# Simply submit a new `saved_filters.put` request to replace the old description and filter with a new set
49+
request = {'filter': 'IP Address = 0.0.0.0', 'description': 'Monitored Addresses'}
50+
client.saved_filters.put(saved_filter_name, body=request)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'''
2+
External IDs can be a useful method of keeping track of assets in multiple systems, but it can be time consuming to manually tag each asset. In this example, we'll take a look at how you can, with a map of name/kind/external id, tag each asset in your inventory with an external id automatically using the SDK
3+
'''
4+
from azure.identity import InteractiveBrowserCredential
5+
from azure.defender.easm import EasmClient
6+
7+
#To create an EasmClient, you need your subscription ID, region, and some sort of credential.
8+
sub_id = '<your subscription ID here>'
9+
workspace_name = '<your workspace name here>'
10+
resource_group = '<your resource group here>'
11+
region = '<your region here>'
12+
13+
endpoint = f'{region}.easm.defender.microsoft.com'
14+
15+
# For the purposes of this demo, I've chosen the InteractiveBrowserCredential but any credential will work.
16+
browser_credential = InteractiveBrowserCredential()
17+
client = EasmClient(endpoint, resource_group, sub_id, workspace_name, browser_credential)
18+
19+
# Assets in EASM can be uniquely distinguished by `name` and `kind`, so we can create a simple dictionary containing `name`, `kind`, and `external_id`. In a more realistic case, this could be generated using an export from the external system we're using for tagging, but for our purposes, we can manually write it out
20+
external_id_mapping = [
21+
{
22+
'name': 'example.com',
23+
'kind': 'host',
24+
'external_id': 'EXT040'
25+
},
26+
{
27+
'name': 'example.com',
28+
'kind': 'domain',
29+
'external_id': 'EXT041'
30+
},
31+
{
32+
'name': '93.184.216.34',
33+
'kind': 'ipAddress',
34+
'external_id': 'EXT042'
35+
},
36+
{
37+
'name': 'example.org',
38+
'kind': 'host',
39+
'external_id': 'EXT050'
40+
},
41+
]
42+
# Using the `assets` client, we can update each asset and append the tracking id of the update to our update ID list, so that we can keep track of the progress on each update later
43+
update_ids = []
44+
45+
for asset in external_id_mapping:
46+
update_request = {'external_id': asset['external_id']}
47+
asset_filter = f"kind = {asset['kind']} AND name = {asset['name']}"
48+
update = client.assets.update(body=update_request, filter=asset_filter)
49+
update_ids.append(update['id'])
50+
51+
# Using the `tasks` client, we can view the progress of each update using the `get` method
52+
for update_id in update_ids:
53+
update = client.tasks.get(update_id)
54+
print(f'{update["id"]}: {update["state"]}')
55+
56+
# The updates can be viewed using the `assets.list` method by creating a filter that matches on each external id using an `in` query
57+
ids = ', '.join([f'"{asset["external_id"]}"' for asset in external_id_mapping])
58+
asset_filter = f'External ID in ({ids})'
59+
60+
for asset in client.assets.list(filter=asset_filter):
61+
print(f'{asset["externalId"]}, {asset["name"]}')
62+

0 commit comments

Comments
 (0)