Docs
Launch GraphOS Studio
Since 1.25.0

Safelisting with persisted queries

Secure your graph while minimizing request latency


This feature is only available with a GraphOS Enterprise plan.
You can test it out by signing up for a free Enterprise trial.

With GraphOS Enterprise, you can enhance your 's security by maintaining a persisted query list (PQL) for your 's . To create and update the , first-party apps register trusted to the PQL at build time.

First-party apps
Register
trusted operations
Web client
Android client
iOS client
Persisted
Query List

NOTE

Clients can register any kind of to a , including queries, , and .

At runtime, the Apollo Router checks incoming requests against the , which can act as safelist, depending on your router configuration.

Supergraph
Registered
operations
Unregistered
operations
✅ Router executes
registered operations
❌ Router blocks
unregistered operations
Apollo Router
Graph
Router
Persisted
Query List
Subgraphs
Subgraph A
Subgraph B
Subgraph C
First-party apps
Web client
Android client
iOS client
Bad actor

Your can use its () to both protect your supergraph and speed up your clients' operations:

  • When you enable safelisting, your rejects any incoming not registered in its .

  • Client apps can execute an by providing its -specified ID instead of the entire operation string.

    • Requesting by ID can significantly reduce latency and bandwidth usage for large strings.
    • Your can require that clients provide by ID and reject full operation strings—even operation strings present in the .

Differences from automatic persisted queries

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

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

Implementation

Enabling safelisting has a few steps:

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

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

Router configuration

As soon as a has a linked , you can configure instances to fetch and use the PQL by following these steps:

  1. Ensure your instances are ready to work with :

    • Make sure you're using version 1.32.0 or later of the . (The feature was released in preview in version 1.25.0 and made generally available in 1.32.0.)
    • Make sure your instances are connected to your GraphOS Enterprise organization and that they're associated with a that your is linked to.
  2. Set your desired security level in your 's YAML config file. For supported options, see router security levels. When first implementing , it's best to start with audit—or "dry run"—mode.

  3. Deploy your updated instances to begin using your .

Once your organization's has registered all your clients' and you've ensured your client apps are only sending registered operations, you can update your configuration to the safelisting security level.

Router security levels

The supports the following security levels, in increasing order of restrictiveness:

  • Allow operation IDs: Clients can optionally execute an by providing the operation's -specified ID.
    • All other levels also provide this core capability.
    • This level doesn't provide safelisting.
  • Audit mode: Executing by providing a -specified ID is still optional, but the also logs any unregistered operations.
    • The level serves as a dry run and helps you identify you may still need to register before turning on safelisting.
  • Safelisting: The rejects any incoming not present in its . Requests can use either ID or operation string.
    • Before moving to this security level, ensure all your client are present in your .
  • Safelisting with IDs only: The rejects any freeform . Clients can only execute operations by providing their -specified IDs.
    • Before moving to this security level, ensure all your clients execute by providing their -specified ID.

When adopting , you should start with a less restrictive security such as audit mode. You can then enable increasingly restrictive levels after your teams have updated all clients.

See below for sample YAML configurations for each level. Refer to the router configuration options for option details.

NOTE

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

Allow operation IDs

To use only to reduce network bandwidth and latency (not for safelisting), add the following minimal configuration:

router.yaml
persisted_queries:
enabled: true

NOTE

You can use this security level with or without automatic persisted queries enabled.

This mode lets clients execute by providing their -specified ID instead of the full operation string. Your also continues to accept full operation strings, even for operations that don't appear in its PQL.

Audit mode (dry run)

Turning on logging is crucial for gauging your client apps' readiness for safelisting. The logs identify which you need to either add to your or stop your client apps from making.

To enable logging for unregistered queries, enable the log_unknown property:

router.yaml
persisted_queries:
enabled: true
log_unknown: true

NOTE

You can use audit mode with or without automatic persisted queries enabled.

Unregistered appear in your router's logs.

For example:

2023-08-02T11:51:59.833534Z WARN [trace_id=5006cef73e985810eb086e5900945807] unknown operation operation_body="query ExampleQuery {\n me {\n id\n }\n}\n"

If your receives an registered in the , no log message will be output.

You can use these logs to audit sent to your router and ask client teams to add new ones to your if necessary.

Safelisting

⚠️ CAUTION

Before applying this configuration, ensure your contains all that all active versions of your clients execute. If you enable safelisting without ensuring this, your will reject any unpublished client operations.

With the following configuration, your allows only that are present in its while rejecting all other operations:

router.yaml
persisted_queries:
enabled: true
log_unknown: true
safelist:
enabled: true
require_id: false
apq:
enabled: false # APQ must be turned off

NOTE

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

To execute an , clients can provide its -specified ID or full operation string. The rejects unregistered operations, and if log_unknown is true, those appear in your router's logs.

💡 TIP

It's best to keep log_unknown as true while adopting safelisting so you can monitor the your rejects. Once you're confident that all your clients are properly configured, you can turn it off to reduce noise in your logs.

Safelisting with IDs only

⚠️ CAUTION

Do not start with this configuration: It requires all your clients to execute by providing their -specified ID. If any clients still provide full operation strings, the rejects those operations, even if they're included in the safelist.

With the following configuration, your rejects all strings and only accepts registered operation IDs:

router.yaml
persisted_queries:
enabled: true
log_unknown: true
safelist:
enabled: true
require_id: true
apq:
enabled: false # APQ must be turned off

NOTE

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

If you want to use this security level, you should always first set up safelisting with operation strings allowed. ID-only safelisting requires all your clients to execute via -specified ID instead of an operation string. While making those necessary changes, you can use the less restrictive safelisting mode in your .

With log_unknown set to true, the logs all rejected , including those registered to your but that used the full operation string rather than the PQL-specified ID.

NOTE

It's best to keep log_unknown as true while adopting safelisting so you can monitor the your rejects. Once you're confident that all your clients are properly configured, you can turn it off to reduce noise in your logs.

Configuration options

The 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.

NOTE

From version 1.25.0 to 1.32.0, the persisted_queries configuration option was named preview_persisted_queries. Upgrade your 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.

router.yaml
persisted_queries:
enabled: true

log_unknown

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

router.yaml
persisted_queries:
enabled: true
log_unknown: true

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

safelist

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

router.yaml
persisted_queries:
enabled: true
safelist:
enabled: true
apq:
enabled: false

NOTE

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

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

require_id

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

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

NOTE

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

Limitations

  • Unsupported with offline license. An using an offline Enterprise license cannot use safelisting with . The feature relies on Apollo Uplink to fetch , so it doesn't work as designed when the is disconnected from Uplink.
Previous
Operation limits
Next
Privacy and data collection
Edit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc.

Privacy Policy

Company