Getting Started with the XDR Python SDK
Note
Use the following region or environment identifiers, depending on your tenant region:
US1
orcharlie
orproduction
for https://ctpx.secureworks.com/US2
ordelta
for https://delta.taegis.secureworks.com/US3
orfoxtrot
for https://foxtrot.taegis.secureworks.com/EU
orecho
for https://echo.taegis.secureworks.com/
Install the Python SDK ⫘
Assuming you have Python 3.8+ already installed, install the Python SDK:
python -m pip install taegis-sdk-python
Authenticate ⫘
The install will ask to authenticate with your Secureworks® Taegis™ XDR account. This requires a password and MFA token, unless your organization has registered your organization with SSO authentication. If SSO is enabled, you will be presented with a device code authentication link.
For more information, see Authentication With the Taegis™ XDR Python SDK.
Example Usage ⫘
from taegis_sdk_python import GraphQLService
from pprint import pprint as pp
service = GraphQLService()
results = service.users.query.current_tdruser()
pp(results)
Exploring the SDK ⫘
Standard Python help
is built into XDR’s Python SDK. You can use it on any object in the GraphQLService
object structure to find out what is available and how to call it.
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.alerts.types import SearchRequestInput
service = GraphQLService()
# Find available services (Service Endpoints)
help(service)
# Find available service queries (or mutations or subscriptions)
help(service.alerts.query)
help(service.alerts.mutation)
help(service.alerts.subscription)
# Reference documentation on specific endpoint
help(service.alerts.query.alerts_service_search)
# Help on an Input variable
help(SearchRequestInput)
# service
class GraphQLService(builtins.object)
| GraphQLService(*, environment: Optional[str] = None, tenant_id: Optional[str] = None, environments: Optional[Dict[str, str]] = None, gateway: Optional[str] = None)
...
| agent
| Events Service Endpoint.
|
| alerts
| Alerts2 Service Endpoint.
|
| assets
| Assets
...
# Alerts Query
class TaegisSDKAlertsQuery(builtins.object)
| TaegisS
...
| alerts_service_aggregate_alerts_by_severity(self, in_: 'Optional[AggregateAlertsBySeverityInputInput]' = None) -> 'AlertsAggregateResponse'
| Pull alert severity aggregates based on `group_by` parameters: domain, watchlist, hostname, detector, user..
|
| alerts_service_alerts_dashboard_triage(self, in_: 'Optional[TriageDashboardInputInput]' = None) -> 'TriageDashboardOutput'
| None.
|
| alerts_service_poll(self, in_: 'Optional[PollRequestInput]' = None) -> 'AlertsResponse'
| Poll for results for a specific `search
...
# SearchRequestInput
class SearchRequestInput(builtins.object)
| SearchRequestInput(cql_query: Optional[str] = None, offset: Optional[int] = None, limit: Optional[int] = None) -> None
...
Context Manager ⫘
The service object is also a context manager to help temporarily override default values when you make
an API call. This can include fields like the environment
, tenant_id
, output
, or access_token
.
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.alerts.types import SearchRequestInput
service = GraphQLService()
with service(
environment="delta",
tenant_id="00000",
output="""
reason
alerts {
total_results
list {
id
tenant_id
metadata {
title
severity
}
status
}
}
""",
):
result = service.alerts.query.alerts_service_search(SearchRequestInput(
offset=0,
limit=10,
cql_query="""
FROM alert
WHERE
severity >= 0.6
EARLIEST=-1d
"""
))
Pruning the GraphQL Output ⫘
The XDR Python SDK provides all available fields returned by the GraphQL API by default. This aids in exploration, but you can define which fields you want returned.
To help determine what you need, you can use the build_output_string
utility, which returns a string representation of the output object with all possible fields for the return type. You can use that as a reference to build your own, and remove fields that you don’t need.
from taegis_sdk_python import build_output_string
from taegis_sdk_python.services.alerts.types import AlertsResponse
print(build_output_string(AlertsResponse))
reason search_id status alerts { previous_offset total_parts list { reference_details { reference {
description url type } } parent_tenant_id entities { entities relationships { relationship to_entity
from_entity type } } sensor_types suppression_rules { id version } resolution_history { timestamp {
nanos seconds } user_id status num_alerts_affected id reason } enrichment_details {
business_email_compromise { user_name source_address_geo_summary { country { confidence iso_code
geoname_id code } city { confidence locale_names { record { value key } } geoname_id name } location {
timezone latitude longitude us_metro_code radius metro_code gmt_offset } asn { autonomous_system_no
autonomous_system_org } continent { code geoname_id } } source_address }
...
The service object is called as a context manager; output
is assigned with the new GraphQL output fields. The same object is returned, any undefined fields are assigned a value of None
.
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.alerts.types import SearchRequestInput
from pprint import pprint as pp
service = GraphQLService()
with service(output="search_id alerts { list { id status metadata { title severity confidence } } }")
results = service.alerts.query.alerts_service_search(
SearchRequestInput(
offset=0,
limit=10,
cql_query="""
FROM alert
WHERE
severity >= 0.6
EARLIEST=-1d
""",
)
)
pp(results)
Arbitrary Queries ⫘
You can craft your own API call for a query, mutation, or subscription. Note that certain services may be configured differently; it is recommended to use the service endpoint you want to query against when available.
execute_query
execute_mutation
execute_subscription
from taegis_sdk_python import GraphQLService
from pprint import pprint as pp
service = GraphQLService()
results = service.alerts.execute_query(
endpoint="alertsServiceSearch",
variables={
"in": {
"limit": 3,
"offset": 0,
"cql_query": """
FROM alert
WHERE
severity >= 0.6
EARLIEST=-1d
"""
}
},
output="""
search_id
alerts {
list {
id
tenant_id
metadata {
title
severity
}
status
}
}
"""
)
pp(results)
Raw Queries ⫘
You can also run your own raw GraphQL strings. This provides the most flexibility but least amount of guard rails.
execute
subscribe
from taegis_sdk_python import GraphQLService
from pprint import pprint as pp
service = GraphQLService()
results = service.investigations.execute("""
query investigationsStatusCount
{
investigationsStatusCount
{
open closed active awaiting_action suspended total
}
}
""")
pp(results)
Helpers ⫘
build_output_string
Utility ⫘
The build_output_string
utility returns a string representation of the output object with all possible fields for the return type.
from taegis_sdk_python import build_output_string
from taegis_sdk_python.services.alerts.types import AlertsResponse
print(build_output_string(AlertsResponse))
_build_output_query
Utility ⫘
The _build_output_query
service endpoint helps build complete GraphQL query strings. It builds the query from the schema, so make sure you are pulling the schema from the correct service endpoint.
from taegis_sdk_python import GraphQLService, build_output_string
from taegis_sdk_python.services.investigations.types import InvestigationStatusCountResponse
service = GraphQLService()
schema = service.alerts.get_sync_schema()
print(service.alerts._build_output_query(
operation_type="query",
endpoint="investigationsStatusCount",
graphql_field=schema.query_type.fields.get("investigationsStatusCount"),
output=build_output_string(InvestigationStatusCountResponse)
))