API Gateway overview

Tanium™ API Gateway provides a single and stable API integration point for various Tanium solutions. It is designed for Tanium partners and customers interested in building integrated solutions with the Tanium™ Core Platform.

API Gateway topology

The API Gateway service runs on the Tanium™ Module Server in your Tanium™ Cloud instance, and requires the System User Service to run background processes. The API Gateway service passes user requests to Tanium™ Data Service or the Tanium™ Server Tanium Core Platform; the Tanium Server Tanium Core Platform collects data from Tanium™ Clients or updates data based on the request, and returns the results to the API Gateway service. The API Gateway service passes the results to the user that submitted the request.

API Gateway topology (click image to enlarge)
API Gateway topology (click image to enlarge)

With the API Gateway, information passes between users and the Tanium Server Tanium Core Platform through the following workflow (matching the numbers in API Gateway topology API Gateway topology):

  1. The API Gateway requires the System User Service to be running to perform background functions.
  2. Users send requests to the API Gateway to be performed on endpoints, such as action deployment and queries for question results.
  3. By default, the API Gateway relays user queries to the Tanium Data Service, which continuously collects results for all registered sensors through the Tanium Server Tanium Core Platform. Continuous collection from endpoints ensures that results are available in the Tanium Data Service cache for both online and offline endpoints.
  4. Users can optionally specify queries that go directly from the API Gateway to the Tanium Server Tanium Core Platform for collecting live results from endpoints that are currently online.
  5. Users can specify requests that go from the API Gateway to Tanium solutions to be performed on endpoints. For example, a user might request Tanium™ Direct Connect to establish a direct connection to a specific endpoint.
  6. The Tanium Server Tanium Core Platform issues questions and deploys actions (and associated content such as packages) to Tanium Clients.
  7. Tanium Clients return the question results or action statuses to the Tanium Server Tanium Core Platform. The server responds to the request with the results and statuses. If the user sent the request through the API Gateway query explorer, the results pane displays the response.

Query explorer

API Gateway includes an interactive query explorer that you can use to write and run queries and mutations in the Tanium Console. Use the query explorer to try new queries and discover what data is available.

You can find the query explorer on the API Gateway Overview page:

Query explorer

If the query explorer does not appear on the API Gateway Overview page, click Customize Page and make sure the Query Explorer option is selected.

 

Query variables

If a query or mutation uses variables, expand the QUERY VARIABLES pane and include the variables in the pane that expands.

 

 

For the best results, use query variables when passing arguments, such as when you use pagination or filtering in your request. For more information, see Pagination and Filters.

Schema reference

API Gateway contains a schema reference that documents all queries, mutations, and objects that are available in API Gateway. The schema reference is generated directly from the schema; refer to the schema reference in API Gateway for the most up-to-date documentation.

To view the schema reference in the query explorer, click Docs to expand the Documentation Explorer pane of the query explorer.

 

 

The query explorer uses the GraphiQL interactive browser to send GraphQL queries and mutations to the Tanium ServerTanium™ Cloud. For more information about the options that are available in GraphiQL, see https://graphql.org/learn/.

Authentication

Requests that are sent from the query explorer in the Tanium Console are authenticated and authorized with the session ID of the user who is signed in. The Tanium ServerTanium Cloud uses the role-based access control (RBAC) permissions of the user account to determine which content you can query and mutate.

Requests that are sent from outside the Tanium Console are authenticated and authorized with either session IDs or API tokens. You must include an API token or session ID in the authorization header of all requests that are sent to API Gateway. API Gateway uses the RBAC permissions of the requesting user to determine content access for all queries and mutations. For an example cURL query that shows the authorization header, see Example cURL syntax.

Use API tokens to send requests through API Gateway instead of session IDs. While session IDs time out after five minutes of inactivity, you can set a longer timeout for API tokens. You can create API tokens in the Tanium Console, through the Tanium Core Platform REST API, or using the API Gateway. For more information on creating API tokens in the Tanium Console, see Tanium Console User Guide: Managing API tokens. For more information on creating tokens using API Gateway, see API token examples.

Use API tokens to send requests through API Gateway. You can create API tokens in the Tanium Console, through the Tanium Core Platform REST API, or using the API Gateway. For more information on creating API tokens in the Tanium Console, see Tanium Console User Guide: Managing API tokens. For more information on creating tokens using API Gateway, see API token examples.

When requests are sent outside the Tanium Console, make sure to use the correct URL to send requests. See Root endpoint and Example cURL syntax for examples.

Rate limits

API Gateway has no specific rate limits.

Tanium Cloud imposes rate limits on incoming requests. If you exceed the rate limits, any mutations and queries return an HTTP 429 error. For information on rate limits in Tanium Cloud, see Getting started with Tanium Cloud.

Root endpoint

To send queries and mutations outside the Tanium Console, use the following address:

https://<server>/plugin/products/gateway/graphql

https://<customerName>-api.cloud.tanium.com/plugin/products/gateway/graphql

Example cURL syntax

curl --request POST \
   --url https://localhost/plugin/products/gateway/graphql \
   --header 'Content-Type: application/json' \
   --header 'session: token-356d5f5bbb3671f28e24f65be3bdd54d9d81001ca823efaabc5fbff251' \
   --data '{"query":"{\n  now\n}\n"}'
curl --request POST \
   --url https://acme-api.cloud.tanium.com/plugin/products/gateway/graphql \
   --header 'Content-Type: application/json' \
   --header 'session: token-356d5f5bbb3671f28e24f65be3bdd54d9d81001ca823efaabc5fbff251' \
   --data '{"query":"{\n  now\n}\n"}'

Pagination

Queries that return many results are paginated to reduce resource utilization. API Gateway uses the standard Relay GraphQL pagination specification to provide users the option to explicitly control pagination.

Paginated queries return a connection type that is prefixed with the name of the data type, such as EndpointConnection. Queries accept standard arguments to control the pagination. For more information on pagination syntax, see Reference: Paginated query syntax.

Example of a paginated query:

Copy
query paginationExample {
  endpoints {
    edges {
      node {
        id
        serialNumber
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Cursors

Use cursors to control relay pagination. Cursors are opaque strings that point to records within queried collections, and can be used to request the records after the cursor. All collections support forward traversal, and some also support backward traversal.

Cursors are valid only for the query for which they were returned. Cursors are generally valid for five minutes after their most recent use. Any queries that deviate from this policy are documented in the query field. It is a best practice to use query variables with cursors to quickly update the pagination in your request.

Connection results are stable and consistent when traversed with cursors unless documented in the query field.

Example of an endpoint query with cursors:

Copy
query useCursorsForEndpoints ($cursor: Cursor, $results: Int) {
  endpoints(after: $cursor, first: $results) {
    edges {
      node {
        name
        ipAddress
      }
    }
    pageInfo {
      startCursor
      endCursor
      hasPreviousPage
      hasNextPage
    }
  }
}

Include the pagination cursor and results variables in the QUERY VARIABLES panel:

Copy
{
  "cursor": "NTc2NTM4MDow",
  "results": 5
}

Connection and edges

The connection includes an edge field that returns a list of typed edges, such as EndpointEdge. Each edge contains at least two fields:

  • A node field with the actual data type, such as Endpoint
  • A cursor field with a cursor for the record

The connection type also includes a pageInfo field that contains at least two fields:

  • hasNextPage indicates if there are more records
  • endCursor is the cursor of the last record in the returned page, if any

Some connection types feature other metadata, such as totalRecords.

Arguments

Paginated queries support at least two arguments: first indicates the number of records to return, and after is the value of the record cursor that precedes the records in the requested page. When fully paginated, this value is the same as the endCursor value from the previous page. Both arguments have sensible defaults.

Paginated queries that support backward traversal allow two corresponding arguments: last and before. You must pass both arguments together to traverse backwards in a query.

A single query supports either forward or backward traversal, but not both. The server Tanium Cloud returns an error response for queries with arguments for both forward and backward traversals.

When a paginated request extends beyond the collection, the query returns only the available results.

For the best results, use query variables with the pagination arguments to quickly update the response results.

Example of a request for a page of data within a collection:

Copy
query getTenEndpointsAfterCursor ($cursor: Cursor, $results: Int) {
  endpoints(after: $cursor, first: $results) {
    edges {
      node {
        id
        serialNumber
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Include the pagination cursor and results variables in the QUERY VARIABLES panel:

Copy
{
  "cursor": "NTc2NTM4MDow",
  "results": 10
}

Refreshing Collections

The records returned and paginated over in a query are intended to be stable, ensuring callers are able to traverse the entire collection without gaps or duplicates. With certain collections, particularly the results of querying endpoints with the Tanium Server data source, new records may become available after the first stable paginated collection has been returned by the API Gateway. There are two primary use cases for needing these late-arriving data:

  • when fetching live data for a specific endpoint or small set of endpoints, and

  • when fetching live data about as many endpoints as practical.

When you want to obtain the latest data available for a paginated query, you can request a repopulation of the collection with the refresh argument, which takes a cursor as its value. If the gateway can obtain potentially new data for the collection, it obtains the data and returns a new pagination starting at the beginning of the collection. The old cursor values are no longer valid.

Since a common use case for this capability is when no records were initially available, queries that support the refresh argument provide a collectionInfo field on their connection type. This field includes a startCursor field, which is always defined as pointing to the beginning of the entire collection. The collectionInfo might include other fields which help the user decide if they would like to refresh the cursor or read the results.

You can always perform a new query with no cursor instead of using the refresh argument, but this does not take advantage of the ongoing effort to collect records from the previous query. Using the refresh argument is the most efficient and effective way to obtain as complete a collection as possible or required.

Example of an endpoint query against an endpoint that is slow to respond, with collectionInfo.startCursor included in the response:

Copy
query getSlowEndpoint($first: Int, $path: String, $value: String, $expectedCount: Int) {
  endpoints(
    first: $first
    filter: {path: $path, value: $value}
    source: {ts: {expectedCount: $expectedCount}}
  ) {
    edges {
      node {
        id
      }
    }
    collectionInfo {
      startCursor
      success
      active
    }
  }
}

Add the pagination and filter variables in the QUERY VARIABLES panel:

Copy
{
  "first": 1,
  "path": "name",
  "value": "slow-endpoint",
  "expectedCount": 1
}

Example response for an ongoing collection with a startCursor value:

Copy
{
  "data": {
    "endpoints": {
      "edges": [],
      "collectionInfo": {
        "startCursor": "4t2cB0ZGNPqy4J4P7O7opwz/24/5zgPi6OinDAA=:0",
        "success": false,
        "active": true
      }
    }
  }
}

Example request refreshing the collection using the returned startCursor value:

Copy
query getEndpointRefresh($refresh: Cursor, $first: Int, $path: String, $value: String, $expectedCount: Int) {
  endpoints(
    refresh: $refresh
    first: $first
    filter: {path: $path, value: $value}
    source: {ts: {expectedCount: $expectedCount}}
  ) {
    edges {
      node {
        id
      }
    }
    collectionInfo {
      startCursor
      success
      active
    }
  }
}

Add the pagination and filter variables in the QUERY VARIABLES panel:

Copy
{
  "refresh": "4t2cB0ZGNPqy4J4P7O7opwz/24/5zgPi6OinDAA=:0",
  "first": 1,
  "path": "name",
  "value": "slow-endpoint",
  "expectedCount": 1
}

Example response with a completed collection:

Copy
{
  "data": {
    "endpoints": {
      "edges": [
        {
          "node": {
            "id": 1
          }     
      ],
      "collectionInfo": {
        "startCursor": "4t2cB0ZGNPqy4J4P7O7opwz/24/5zgPi6OinDAA=:0",
        "success": true,
        "active": true
      }
    }
  }
}

Filters

Most queries that return multiple results provide support to filter the results. Such queries provide a filter argument.

It is a best practice to use query variables with filter arguments to quickly update the filter.

For more information on specific filter syntax, see Reference: Filter syntax.

Simple filters

Simple filters are single filters that constrain the values of fields that participate in the query. You can specify simple filters in the path property with a period to separate levels in the graph starting at the record type. For example:

Copy
query getEndpointsByEmail ($path:String, $value:String){
  endpoints(filter: {path: $path, value: $value}) {
    edges {
      node {
        id
        primaryUser {
          email
        }
      }
    }
  }
}

Include the path and value variables in the QUERY VARIABLES panel:

Copy
{
  "path": "primaryUser.email",
  "value": "[email protected]"
}

The query does not need to return the filtered path. Not all field paths are filterable. Refer to the schema to see which paths cannot be filtered.

Simple filters must also contain a string value property.

You can specify an operator in the op property, which is an enumerated type and defaults to the equality operator. For example:

Copy
query getGTE4ProcessorEndpoints($path: String, $value: String, $fieldfilterop: FieldFilterOp!) {
  endpoints(filter: {path: $path, value: $value, op: $fieldfilterop}) {
    edges {
      node {
        id
      }
    }
  }
}

Include the path, value, and operator variables in the QUERY VARIABLES panel:

Copy
{
  "path": "processor.logicalProcessors",
  "value": "4",
  "fieldfilterop": "GTE"
}

Not all operators are valid for all fields.

Compound filters

Compound filters contain multiple simple or compound filters that appear in the filters property. By default, all child filters must pass for a record to be included. If the or argument is given with a true value, then a record is included if any child filter matches.

Example of a simple compound filter:

Copy
query getEndpointsTwoFilters($path1: String, $path2: String, $value1: String, $value2: String) {
  endpoints(
    filter: {filters: [{path: $path1, value: $value1}, {path: $path2, value: $value2}]}
  ) {
    edges {
      node {
        id
      }
    }
  }
}

Include the path and value variables in the QUERY VARIABLES panel:

Copy
{
  "path1": "serialNumber",
  "value1": "x",
  "path2": "name",
  "value2": "y"
}

Negated filters

You can negate both simple and compound filters with a negated property of true. For example, the following query returns endpoints whose serial number does not contain the letter x:

Copy
query getEndpointsNegate($path: String, $value: String, $negated: Boolean!) {
  endpoints(
    filter: {filters: {path: $path, value: $value, negated: $negated}}
  ) {
    edges {
      node {
        id
      }
    }
  }
}

Include the path, value, and negated variables in the QUERY VARIABLES panel:

Copy
{
  "path": "serialNumber",
  "value": "x",
  "negated" : true
}

Field filters

Filters apply to the entire record. Some records contain fields that are collections; you can also filter these fields. When you filter a field, the filter applies to both the child collection and to the records. For example, if you search for endpoints with an installed application named Tanium Client with a filter on the field, API Gateway returns only those endpoints with such an application, as well as only the matching application:

Copy
query getEndpointsWithTC ($path: String, $value: String){
  endpoints {
    edges {
      node {
        installedApplications(filter: {path: $path, value: $value}) {
          name
          version
        }
      }
    }
  }
}

Include the path, value, and negated variables in the QUERY VARIABLES panel:

Copy
{
  "path": "name",
  "value": "Tanium Client"
}

Field filters can be simple or compound. Compound filters are limited to one level of children that must use the equality operator, and require all child filters. For example:

Copy
query getEndpointsMultipleFilters ($path1: String, $value1: String, $path2: String, $value2: String){
  endpoints {
    edges {
      node {
        installedApplications(
          filter: {
            filters: [
              {path: $path1, value: $value1},
              {path: $path2, value: $value2}
            ]
          }
        ) {
          name
          version
        }
      }
    }
  }
}

Include the path and value variables in the QUERY VARIABLES panel:

Copy
{
  "path1": "name",
  "value1": "Tanium Client",
  "path2": "version",
  "value2": "7.5.0.0"
}

Interoperability with other Tanium products

API Gateway works with the following solutions:

  • Tanium Core Platform
    • Actions
    • Action groups
    • Computer groups
    • Tanium™ Data Service
    • Tanium™ Direct Connect
    • Packages
    • Tanium™ Reporting
  • Tanium™ Asset
  • Tanium™ Blob
  • Tanium™ Comply
  • Tanium™ Deploy
  • Tanium™ Impact
  • Tanium™ Performance
  • Tanium™ Reveal
  • Tanium™ Risk/Benchmark
  • Tanium™ Threat Response