コンテンツにスキップ

Taegis SDK for Python スキーマの探索🔗

はじめに🔗

from taegis_sdk_python import GraphQLService

service = GraphQLService()
schema = service.core.get_sync_schema()

主な関心領域🔗

  • query_types
  • mutation_types
  • subscription_types
  • type_map

サポートされているGraphQLのクエリ/ミューテーション/サブスクリプションを確認するには、適切な *_types.fields アクセサを使用します。以下の例では query_types を使用しますが、mutation_typessubscription_types も同様に利用できます。

schema.query_type.fields
{'getAccessPoint': <GraphQLField <GraphQLObjectType 'AccessPoint'>>,
 'getAccessPointTemplate': <GraphQLField <GraphQLObjectType 'AccessPointCloudFormation'>>,
 'aggregatedAlertsPerEndpoint': <GraphQLField <GraphQLNonNull <GraphQLObjectType 'AggregatedAlertsPerEndpointResult'>>>,
 'aggregatedLicensedEndpointDeploymentRatio': <GraphQLField <GraphQLNonNull <GraphQLObjectType 'AggregatedLicensedEndpointDeploymentRatioResult'>>>,
 'aggregatedMeanTimeToAcknowledgeMetrics': <GraphQLField <GraphQLNonNull <GraphQLObjectType 'AggregatedMeanTimeToAcknowledgeResult'>>>,
 'aggregatedMeanTimeToResolveMetrics': <GraphQLField <GraphQLNonNull <GraphQLObjectType 'AggregatedMeanTimeToResolveResult'>>>,
...
<truncationed for readability>

戻り値フィールド名🔗

フィールドへのアクセスは、Pythonの辞書と同じ方法(ブラケット [] または .get() を使用)で行います。

schema.query_type.fields['alertsServiceSearch']

または

schema.query_type.fields.get('alertsServiceSearch')
<GraphQLField <GraphQLObjectType 'AlertsResponse'>>

ここでは、alertsServiceSearchAlertsResponse オブジェクトを返すことがわかります。

エンドポイント引数🔗

引数名の一覧を取得します。

schema.query_type.fields['alertsServiceSearch'].args
{'in': <graphql.type.definition.GraphQLArgument at 0x7f8ee52bf2e0>}

引数の型名を取得できます。

schema.query_type.fields['alertsServiceSearch'].args["in"].type

これは SearchRequestInput オブジェクトです。

<GraphQLInputObjectType 'SearchRequestInput'>

このエンドポイントは in という1つの引数を取りますが、この引数が受け入れるフィールドはまだわかりません。

schema.query_type.fields['alertsServiceSearch'].args["in"].type.fields
{'cql_query': <graphql.type.definition.GraphQLInputField at 0x7f8ee49f9490>,
 'offset': <graphql.type.definition.GraphQLInputField at 0x7f8ee49f94c0>,
 'limit': <graphql.type.definition.GraphQLInputField at 0x7f8ee49f94f0>,
 'search_id': <graphql.type.definition.GraphQLInputField at 0x7f8ee49f9520>}

すべてのフィールド型がGraphQLScalarTypeになるまでこの操作を繰り返します。一部の項目はリストや非null型の場合があり、これらは of_type アクセサで展開できます。

戻り値フィールド🔗

.type.fields を使って戻り値フィールドの辞書を取得できます。各フィールドに対して .type.of_type を組み合わせて使用し、スカラー型またはenum型に到達するまで繰り返すことで、リクエスト可能な内容を特定します。

schema.query_type.fields['alertsServiceSearch'].type.fields
{'status': <GraphQLField <GraphQLEnumType 'RPCResponseStatus'>>,
 'reason': <GraphQLField <GraphQLScalarType 'String'>>,
 'alerts': <GraphQLField <GraphQLObjectType 'AlertsList'>>,
 'search_id': <GraphQLField <GraphQLScalarType 'String'>>}
schema.query_type.fields['alertsServiceSearch'].type.fields["alerts"].type.fields
{'list': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'Alert2'>>>>,
 'total_results': <GraphQLField <GraphQLScalarType 'Int'>>,
 'next_offset': <GraphQLField <GraphQLScalarType 'Int'>>,
 'previous_offset': <GraphQLField <GraphQLScalarType 'Int'>>,
 'last_offset': <GraphQLField <GraphQLScalarType 'Int'>>,
 'first_offset': <GraphQLField <GraphQLScalarType 'Int'>>,
 'total_parts': <GraphQLField <GraphQLScalarType 'Int'>>,
 'part': <GraphQLField <GraphQLScalarType 'Int'>>,
 'group_by': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'AggregationResponse'>>>>}

list のようなフィールドの場合、複数の定義を展開する必要があることがわかります:GraphQLField (type) -> GraphQLList (of_type) -> GraphQLNonNull (of_type)

schema.query_type.fields['alertsServiceSearch'].type.fields["alerts"].type.fields["list"].type.of_type.of_type.fields
{'id': <GraphQLField <GraphQLNonNull <GraphQLScalarType 'ID'>>>,
 'group_key': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLScalarType 'String'>>>>,
 'metadata': <GraphQLField <GraphQLObjectType 'AlertsMetadata'>>,
 'visibility': <GraphQLField <GraphQLEnumType 'Visibility'>>,
 'attack_technique_ids': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLScalarType 'String'>>>>,
 'tenant_id': <GraphQLField <GraphQLScalarType 'String'>>,
 'parent_tenant_id': <GraphQLField <GraphQLScalarType 'String'>>,
 'suppressed': <GraphQLField <GraphQLScalarType 'Boolean'>>,
 'suppression_rules': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'AlertRuleReference'>>>>,
 'alerting_rules': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'AlertRuleReference'>>>>,
 'status': <GraphQLField <GraphQLEnumType 'ResolutionStatus'>>,
 'resolution_reason': <GraphQLField <GraphQLScalarType 'String'>>,
 'resolution_history': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'ResolutionMetadata'>>>>,
 'severity_history': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'SeverityUpdate'>>>>,
 'tags': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLScalarType 'String'>>>>,
 'sensor_types': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLScalarType 'String'>>>>,
 'entities': <GraphQLField <GraphQLObjectType 'EntityRelationships'>>,
 'key_entities': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'EntityMetadata'>>>>,
 'event_ids': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'AuxiliaryEvent'>>>>,
 'observation_ids': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'Observation'>>>>,
 'investigation_ids': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'Investigation'>>>>,
 'collection_ids': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'Collection'>>>>,
 'enrichment_details': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'EnrichmentDetail'>>>>,
 'third_party_details': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'ThirdPartyDetail'>>>>,
 'reference_details': <GraphQLField <GraphQLList <GraphQLNonNull <GraphQLObjectType 'ReferenceDetail'>>>>,
 'priority': <GraphQLField <GraphQLObjectType 'AlertPriority'>>,
 'threat_score': <GraphQLField <GraphQLScalarType 'Float32'>>,
 'events_metadata': <GraphQLField <GraphQLObjectType 'AlertEventMetadata'>>,
 'alertPrioritization': <GraphQLField <GraphQLObjectType 'AlertPrioritization'>>}

任意のクエリの構築🔗

ここまでで有効なGraphQLクエリを構築できるようになりました。例として alertsServiceSearch を使用します。変数は引数の調査から取得します。トップ引数 in のフィールド cql_query を使用します。戻り値フィールドにはクエリの status とアラートIDのリストを取得します。

任意のメソッドには以下が含まれます:

  • execute_query
  • execute_mutation
  • execute_subscription
service.core.execute_query(
    endpoint="alertsServiceSearch",
    variables={
        "in": {
            "cql_query": "FROM alert EARLIEST=-1d | head 10"
        }
    },
    output="""
    status
    alerts {
        list {
            id
        }
    }
    """
)
{'alertsServiceSearch': {'status': 'OK',
  'alerts': {'list': [{'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:email:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:email:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter-ql:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'}]}}}

生クエリの構築🔗

ここまでで有効なGraphQLクエリを構築できるようになりました。例として alertsServiceSearch を使用します。変数は引数の調査から取得します。トップ引数 in のフィールド cql_query を使用します。戻り値フィールドにはクエリの status とアラートIDのリストを取得します。GraphQLクエリ文字列の詳細については GraphQL Learn を参照してください。

execute() はクエリとミューテーションで動作します。subscribe() はサブスクリプションで使用します。

service.core.execute(
    query_string="""
    query MyAlertsServiceSearch($in: SearchRequestInput) {
        alertsServiceSearch(in: $in) {
            status
            alerts {
                list {
                    id
                }
            }
        }
    }
    """
    variables={
        "in": {
            "cql_query": "FROM alert EARLIEST=-1d | head 10"
        }
    },
)
{'alertsServiceSearch': {'status': 'OK',
  'alerts': {'list': [{'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:email:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:email:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter-ql:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
    {'id': 'alert://priv:event-filter:00000:0000000000000:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'}]}}}

スキーマファイル🔗

スキーマオブジェクトを schema.graphql 形式にパースできます。これにより GraphQLのドキュメント に従ったGraphQLスキーマ定義ドキュメントが生成されます。

from taegis_sdk_python import GraphQLService
from graphql.utilities import print_schema

service = GraphQLService()
schema = service.core.get_sync_schema()

print(print_schema(schema))
input AbsoluteTimeRedQLQueryInput {
  query: String!
  referenceTime: Time!
  currentTime: Time!
}

type AccessPoint {
  tenantID: String!
  arn: String!
  alias: String!
  principal: [String!]!
}
...
<truncated for readability>

特殊なケース🔗

すべてのAPIが同じ構成の背後にあるわけではありません。tenantsevents などのAPIは特別な構成がされている場合があります。探索や実行には core ではなく、これらのサービスを使用するのが最適です。特殊な構成のケースは、各サービスの __init__ クラスメソッド内の __init__.py ファイルで確認できます。構成はアップデートごとに変更される可能性があります。堅牢なコードのためには、適切なサービスを使用してクエリ、ミューテーション、サブスクリプションを実行してください。