Skip to content

Latest commit

 

History

History
184 lines (116 loc) · 10 KB

File metadata and controls

184 lines (116 loc) · 10 KB
title Safelisting with Persisted Queries
subtitle Secure your graph while minimizing request latency
description Secure your federated GraphQL API by creating an allowlist of trusted operations. Minimize request latency and enhance performance.
minVersion Router v1.25.0

Differences from automatic persisted queries

The Apollo Router Core also supports a related feature called automatic persisted queries (APQ). With APQ, clients can execute a GraphQL operation by sending the SHA256 hash of its operation string instead of the entire string. APQ doesn't support safelisting because the router updates its APQ cache over time with any operations it receives.

For more details on differences between APQ and this feature, see the GraphOS persisted queries documentation.

Implementation

Enabling operation safelisting has a few steps:

  1. PQL creation and linking
  2. Router configuration
  3. Operation registration
  4. Client updates

This article details the router configuration step. For more information on other configuration aspects, see the GraphOS persisted queries documentation.

Router configuration

Router security levels

Configuration options

The router provides four configuration options that you can combine to create the recommended security levels. This section details each configuration option. Refer to the security levels section for recommended combinations.

From version 1.25.0 to 1.32.0, the persisted_queries configuration option was named preview_persisted_queries. Upgrade your router to version 1.32.0 or later to use the generally available version of the feature and the example configuration snippets below.

persisted_queries

This base configuration enables the feature. All other configuration options build off this one.

persisted_queries:
  enabled: true

log_unknown

Adding log_unknown: true to persisted_queries configures the router to log any incoming operations not registered to the PQL.

persisted_queries:
  enabled: true
  log_unknown: true

If used with the safelist option, the router logs unregistered and rejected operations. With safelist.require_id off, the only rejected operations are unregistered ones. If safelist.require_id is turned on, operations can be rejected even when registered because they use operation IDs rather than operation strings.

experimental_prewarm_query_plan_cache

By default, the router prewarms the query plan cache using all operations on the PQL when a new schema is loaded, but not at startup. Using the experimental_prewarm_query_plan_cache option, you can tell the router to prewarm the cache using the PQL on startup as well, or tell it not to prewarm the cache when reloading the schema. (This does not affect whether the router prewarms the query plan cache with recently-used operations from its in-memory cache.) Prewarming the cache can reduce request latency by ensuring that operations are pre-planned when requests are received, but can make startup or schema reloads slower.

persisted_queries:
  enabled: true
  experimental_prewarm_query_plan_cache:
    on_startup: true   # default: false
    on_reload: false   # default: true

local_manifests

From version 1.50.0 to 1.54, the local_manifests configuration option was named experimental_local_manifests. Upgrade your router to version 1.55.0 or later to use the generally available version of the feature and the example configuration snippet below.

Adding local_manifests to your persisted-queries configuration lets you use local persisted query manifests instead of the hosted Uplink version. This is helpful when you're using an offline Enterprise license and can't use Uplink. With local_manifests, the router doesn't reload the manifest from the file system, so you need to restart the router to apply changes.

persisted_queries:
  enabled: true
  local_manifests: 
    - ./path/to/persisted-query-manifest.json

You can download a version of your manifest to use locally from GraphOS Studio. Open the PQL page for a graph by clicking the Go to persisted query lists to the left of the graph's name. Then, click the ••• menu under the Actions column to download a PQL's manifest as a JSON file. Save this file locally and update your local_manifests configuration with the path the file.

safelist

Adding safelist: true to persisted_queries causes the router to reject any operations that haven't been registered to your PQL.

persisted_queries:
  enabled: true
  safelist:
    enabled: true
apq:
  enabled: false

To enable safelisting, you must turn off automatic persisted queries (APQs). APQs let clients register arbitrary operations at runtime while safelisting restricts operations to those that have been explicitly registered.

By default, the require_id suboption is false, meaning the router accepts both operation IDs and operation strings as long as the operation is registered.

require_id

Adding require_id: true to the safelist option causes the router to reject any operations that either:

  • haven't been registered to your PQL
  • use a full operation string rather than the operation ID
persisted_queries:
  enabled: true
  safelist:
    enabled: true
    require_id: true
apq:
  enabled: false

To enable safelisting, you must turn off automatic persisted queries (APQs). APQs let clients register arbitrary operations at runtime while safelisting restricts operations to those that have been explicitly registered.

Customization via request context

GraphOS Router can be customized via several mechanisms such as Rhai scripts and coprocessors. These plugins can affect your router's persistent query processing by writing to the request context.

apollo_persisted_queries::client_name

When publishing operations to a PQL, you can specify a client name associated with the operation (by including a clientName field in the individual operation in your manifest, or by including the --for-client-name option to rover persisted-queries publish). If an operation has a client name, it will only be executed by requests that specify that client name. (Your PQL can contain multiple operations with the same ID and different client names.)

Your customization (Rhai script, coprocessor, etc) can examine a request during the Router Service stage of the request path and set the apollo_persisted_queries::client_name value in the request context to the request's client name.

If this context value is not set by a customization, your router will use the same client name used for client awareness in observability. This client name is read from an HTTP header specified by telemetry.apollo.client_name_header, or apollographql-client-name by default.

If your request specifies an ID and a client name but there is no operation in the PQL with that ID and client name, your router will look to see if there is an operation with that ID and no client name specified, and use that if it finds it.

apollo_persisted_queries::safelist::skip_enforcement

If safelisting is enabled, you can still opt out of safelist enforcement on a per-request basis.

Your customization (Rhai script, coprocessor, etc) can examine a request during the Router Service stage of the request path and set the apollo_persisted_queries::safelist::skip_enforcement value in the request context to the boolean value true.

For any request where you set this value, Router will skip safelist enforcement: requests with a full operation string will be allowed even if they are not in the safelist, and even if safelist.required_id is enabled.

This does not affect the behavior of the log_unknown option: unknown operations will still be logged if that option is set.

Limitations

  • Unsupported with offline license. An GraphOS Router using an offline Enterprise license cannot use safelisting with persisted queries. The feature relies on Apollo Uplink to fetch persisted query manifests, so it doesn't work as designed when the router is disconnected from Uplink.