XDR SDK for Python のはじめ方🔗
注意
お客様のテナントリージョンに応じて、以下のリージョンまたは環境識別子を使用してください。
US1またはcharlieまたはproductionは https://ctpx.secureworks.com/ 用US2またはdeltaは https://delta.taegis.secureworks.com/ 用US3またはfoxtrotは https://foxtrot.taegis.secureworks.com/ 用EU1またはechoは https://echo.taegis.secureworks.com/ 用EU2またはgolfは https://golf.taegis.secureworks.com/ 用
注意
production は、Tenants API を使用して複数のテナントに対してAPIコールを繰り返したい子テナントを持つパートナーに便利です。Tenants API は charlie や US1 ではなく production 識別子を使用しますが、SDKは正しいリージョンに誘導されます。
Taegis SDK for Python のインストール🔗
Python 3.8+ がすでにインストールされていることを前提に、Taegis SDK for Python をインストールします。
認証🔗
インストール時に、お客様の Secureworks® Taegis™ XDR アカウントで認証を求められます。これはパスワードとMFAトークンが必要ですが、組織がSSO認証を登録している場合は除きます。SSOが有効な場合は、デバイスコード認証リンクが表示されます。
詳細は Taegis SDK for Python での認証 をご覧ください。
使用例🔗
from taegis_sdk_python import GraphQLService
from pprint import pprint as pp
service = GraphQLService()
results = service.subjects.query.current_subject()
pp(results)
SDK の探索🔗
このSDKは、Pythonの組み込み help を活用することを前提に設計されています。GraphQLService オブジェクト構造内の任意のオブジェクトに対して help を使用することで、利用可能な内容や呼び出し方法を確認できます。helpメニューは入力型を判断するのに非常に役立ちます。各サービスは独立しているため、例えば SearchRequestInput のような入力が必要な場合は、taegis_sdk_python.services.<service>.types 配下で見つけることができます。
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
...
注: 出力は冗長性のため省略されています。
コンテキストマネージャ🔗
サービスオブジェクトはコンテキストマネージャとしても機能し、APIコール時にデフォルト値を一時的に上書きするのに役立ちます。これには environment、tenant_id、output、access_token などのフィールドが含まれます。
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.alerts.types import SearchRequestInput
service = GraphQLService()
with service(
environment="US2",
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
"""
))
テナントコンテキストの変更🔗
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.investigations.types import InvestigationsV2Arguments
service = GraphQLService()
# specify the output fields, and start the service context
with service(tenant_id="00000"):
result = service.investigations2.query.investigations_v2(InvestigationsV2Arguments(
page=1,
per_page=3,
cql="WHERE deleted_at IS NOT NULL EARLIEST=-90d"
))
pp(result)
環境の変更🔗
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.investigations.types import InvestigationsV2Arguments
service = GraphQLService()
# specify the output fields, and start the service context
with service(environment="US2"):
result = service.investigations2.query.investigations_v2(InvestigationsV2Arguments(
page=1,
per_page=3,
cql="WHERE deleted_at IS NOT NULL EARLIEST=-90d"
))
pp(result)
既存のアクセストークンを使用する🔗
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.investigations.types import InvestigationsV2Arguments
service = GraphQLService()
# specify the output fields, and start the service context
with service(access_token="<your access token>"):
result = service.investigations2.query.investigations_v2(InvestigationsV2Arguments(
page=1,
per_page=3,
cql="WHERE deleted_at IS NOT NULL EARLIEST=-90d"
))
pp(result)
GraphQL 出力の間引き🔗
GraphQL を使用する利点の一つは、返却されるフィールドを定義できることです。デフォルトでは、GraphQL の知識がほとんどない、または全くない方でも始められるよう、APIコールで全てのフィールドを提供していますが、特定のアプリケーションやレポート用途では不要な場合もあります。
これを支援するために、build_output_string というユーティリティを用意しています。これは、返却型の全ての可能なフィールドを含む出力オブジェクトの文字列表現を返します。これを参考にして独自の出力を作成したり、不要なフィールドを削除したりできます。
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 }
...
注: 出力は冗長性のため省略されています。
サービスオブジェクトは、output に新しいGraphQL出力フィールドを割り当ててコンテキストマネージャとして呼び出すことができます。同じオブジェクトが返されますが、定義されていないフィールドには 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)
カスケーディングコンテキスト🔗
Taegis SDK for Python サービスはカスケーディングコンテキストを扱うことができます。service コンテキストマネージャの各呼び出しは、スタックごとにコンテキストを上書きします。主なユースケースは、より大きなコンテキスト内で特定のAPIコールの output のみを変更したい場合です。新しいレベルは一時的に以前のコンテキスト定義を上書きし、現在のコンテキストを抜けると以前の定義が再び有効になります。
注記: 以下の例はコンテキストマネージャの説明用です。APIコールの組み合わせ自体は有用でない場合があります。
from taegis_sdk_python import GraphQLService
from taegis_sdk_python.services.investigations2.types import InvestigationsV2Arguments
from taegis_sdk_python.services.alerts.types import SearchRequestInput
service = GraphQLService()
with service(environment="US2", tenant_id="00000"):
# Context
# environment: US2
# tenant_id: 00000
with service(output="investigations { id alertsEvidence { id } }")
# Context
# environment: US2
# tenant_id: 00000
# output: investigations { id alertsEvidence { id } }
investigation_results = service.investigations2.query.investigations_v2(InvestigationsV2Arguments(
page=1,
per_page=3,
cql="WHERE deleted_at IS NOT NULL EARLIEST=-90d"
))
# Context
# environment: US2
# tenant_id: 00000
alert_ids = [
alert.id
result for result in investigation_results
alert for alert in result.alerts_evidence
]
with service(output="alerts { list { id metadata { title } status } }"):
# Context
# environment: US2
# tenant_id: 00000
# output: alerts { list { id metadata { title } status } }
alert_results = service.alerts.query.alerts_search_search(SearchRequestInput(
offset=0,
limit=10000,
cql_query=f"FROM alert WHERE resource_id IN ('{'\',\''.join(alert_ids)]}')"
))
# Context
# environment: US2
# tenant_id: 00000
# may be useful for users/applications that have access to a parent/child tenant relationship
with service(tenant_id="00001", output="alerts { list { id metadata { title } status } }"):
# Context
# environment: US2
# tenant_id: 00001
# output: alerts { list { id metadata { title } status } }
alert_results = service.alerts.query.alerts_search_search(SearchRequestInput(
offset=0,
limit=10000,
cql_query=f"FROM alert WHERE resource_id IN ('{'\',\''.join(alert_ids)]}')"
))
with service(environment="US1", output="email"):
# Context
# environment: US1
# tenant_id: 00001
# output: email
user = service.users.query.current_tdruser()
# Context
# environment: US2
# tenant_id: 00001
# output: alerts { list { id metadata { title } status } }
# Context
# environment: US2
# tenant_id: 00000
# Context is now completely cleared
任意のクエリ🔗
提供されているメソッドとは異なるAPIコールを実行したい場合や、SDKがサポートしていないAPIコールを実行したい場合は、自分でクエリ/ミューテーション/サブスクリプションを作成できます。サービスによっては設定が異なる場合があるため、利用したいサービスエンドポイントを指定することを推奨します。
execute_queryexecute_mutationexecute_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)
任意のミューテーション🔗
results = service.core.execute_mutation(
"createInvestigation",
variables={
"investigation": {
"description": "SDK Test Investigation",
"key_findings": "This is a test.",
"priority": 1
}
},
output="""
id
created_at
created_by_user {
id
given_name
family_name
}
description
key_findings
"""
)
print(results)
生クエリ🔗
独自の生のGraphQL文字列を実行することも可能です。これにより最大限の柔軟性が得られますが、ガードレールは最小限となります。
executesubscribe
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)
ヘルパー🔗
build_output_string ユーティリティ🔗
build_output_string というユーティリティがあります。これは、返却型の全ての可能なフィールドを含む出力オブジェクトの文字列表現を返します。
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 ユーティリティ🔗
完全なGraphQLクエリ文字列の作成を支援したい場合は、サービスエンドポイントの _build_output_query を呼び出すことでサポートできます。これはスキーマからクエリを構築するため、正しいサービスエンドポイントからスキーマを取得していることを確認してください。
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)
))
非推奨警告🔗
非推奨の入力フィールド、出力フィールド、エンドポイントは警告をログに記録するよう設定されています。詳細は Taegis SDK for Python の非推奨について をご覧ください。
例:
GraphQL Query `allInvestigations` is deprecated: 'replaced by investigationsSearch'
Output field `activity_logs` is deprecated: 'Not Supported - Use audit logs', removing from default output...
Output field `assignee` is deprecated: 'No longer supported', removing from default output...
スキーマの取得🔗
Taegis SDK for Python はスキーマを5分間キャッシュします。取得したスキーマはクエリ文字列の生成やエラーハンドリングに使用されます。時間に敏感なアプリケーションや大量のAPIコールを行う場合、この機能によりスキーマ取得にかかる時間を分散できます。GraphQLService の schema_expiry(分単位)属性で設定可能です。スキーマはサービスごとに取得され(alertsはinvestigationsとは別にスキーマをキャッシュします)、有効期限は最初のAPIコール時にコンテキストマネージャ経由でサービスごとに設定できます。
注意
有効期限が長いとエラーハンドリングに影響する場合があります。サーバー側のスキーマがキャッシュとAPIコールの間で破壊的に変更された場合、SDKはデプロイ済みスキーマと不整合なクエリ文字列を生成・検証する可能性があります。
from taegis_sdk_python import GraphQLService
# all schemas will be cached for 15 minutes
service = GraphQLService(schema_expiry=15)
with service(schema_expiry=30): # users schema will now be cached for 30 minutes
results = service.users.query.current_tdruser()
スキーマは service.<service>.clear_schema() メソッドでサービスごとにクリアできます。
from taegis_sdk_python import GraphQLService
service = GraphQLService()
user = service.users.query.current_tdruser() # schema will be cached for the users service
service.users.clear_schema() # local schema will be cleared and re-fetched on next call
サブスクリプションメッセージサイズ🔗
サブスクリプションの最大メッセージサイズは、全てのサブスクリプションで max_message_size パラメータで設定できます。個別の呼び出しはコンテキストマネージャ経由で変更可能です。デフォルトは0(制限なし)です。このオプションはサブスクリプションのみに影響し、クエリやミューテーションには影響しません。
メッセージサイズに到達または超過した場合、ConnectionResetError がスローされます。
from taegis_sdk_python import GraphQLService
service = GraphQLService(max_message_size=4194304) # sets default to 4MB
with service(max_message_size=5242880): # sets specific API call to 5MB
options = EventQueryOptions(
timestamp_ascending=True,
page_size=1000,
max_rows=1000,
skip_cache=True,
aggregation_off=False,
)
results = service.events.subscription.event_query("FROM process EARLIEST=-1d", options=options)
try:
results = service.events.subscription.event_query("FROM process EARLIEST=-1d", options=options)
except ConnectionResetError as exc:
# handle error