Skip to content
This repository has been archived by the owner on Oct 30, 2024. It is now read-only.

Prep PQs for GA #565

Merged
merged 7 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/content/graphos/basics/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@
"Safelisting with persisted queries": [
"/operations/persisted-queries",
[
"enterprise",
"preview"
"enterprise"
]
]
},
Expand Down
66 changes: 31 additions & 35 deletions src/content/graphos/basics/operations/persisted-queries.mdx

Large diffs are not rendered by default.

6 changes: 1 addition & 5 deletions src/content/graphos/enterprise/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,8 @@
"preview"
]
],
"Safelisting with persisted queries": [
"Safelisting with persisted queries":
"https://www.apollographql.com/docs/router/configuration/persisted-queries",
[
"preview"
]
],
"Operation limits": "https://www.apollographql.com/docs/router/configuration/operation-limits",
"External coprocessing": "https://www.apollographql.com/docs/router/customizations/coprocessor"
}
Expand Down
4 changes: 2 additions & 2 deletions src/content/shared/client-pq-differences.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
The persisted queries feature requires operations to be preregistered in a **persisted query list** (**PQL**).
The persisted queries feature requires operations to be registered in a **persisted query list** (**PQL**).
This allows the PQL to act as an operation safelist made by your first-party apps. As such, persisted queries is a security feature as much as a performance one.

With APQs, if the server can't find the operation ID the client provides, the server returns an error indicating that it needs the full operation string. If an Apollo client receives this error, it automatically retries the operation with the full operation string.

If you _only_ want to improve request latency and bandwidth usage, APQ addresses your use case. If you _also_ want to secure your supergraph with operation safelisting, you should preregister operations in a PQL.
If you _only_ want to improve request latency and bandwidth usage, APQ addresses your use case. If you _also_ want to secure your supergraph with operation safelisting, you should register operations in a PQL.

For more details on differences between persisted queries and APQ, see the [GraphOS persisted queries documentation](/graphos/operations/persisted-queries#differences-from-automatic-persisted).
2 changes: 1 addition & 1 deletion src/content/shared/client-pq-intro.mdx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Apollo supports two separate but related features called **automatic persisted queries** (APQs) and **persisted queries**.
With both features, clients can execute a GraphQL operation by sending an operation's ID instead of the entire operation string. An operation's ID is a hash of the full query string. Querying by ID can significantly reduce latency and bandwidth usage for very large operation strings.
With both features, clients can execute a GraphQL operation by sending an operation's ID instead of the entire operation string. An operation's ID is a hash of the full operation string. Querying by ID can significantly reduce latency and bandwidth usage for very large operation strings.
10 changes: 6 additions & 4 deletions src/content/shared/pq-intro.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
With [GraphOS Enterprise](/graphos/enterprise/), you can enhance your supergraph's security by maintaining a **persisted query list** (**PQL**) for your supergraph's self-hosted router. The [Apollo Router](/router/) checks incoming requests against the PQL, an operation safelist made by your first-party apps.
With [GraphOS Enterprise](/graphos/enterprise/), you can enhance your supergraph's security by maintaining a **persisted query list** (**PQL**) for your supergraph's self-hosted router. The [Apollo Router](/router/) checks incoming requests against the PQL which acts as an operation safelist made by your first-party apps.

> You can include any kind of operation in your PQL, including queries, mutations, and subscriptions.

```mermaid
flowchart LR
Expand All @@ -20,12 +22,12 @@ flowchart LR
api2(["GraphQL API"]);
api3(["GraphQL API"]);
end
Apps -->|Queries| Router -->|Trusted<br/> queries| Supergraph
Apps -->|Requests| Router -->|Registered<br/> operations| Supergraph
```

Your router can use its persisted query list (PQL) to both **protect your supergraph** and **speed up your clients' operations**:

- When you enable **safelisting**, your router rejects any incoming operations not registered in its PQL.
- Client apps can execute an operation by providing its PQL-specified ID _instead of_ an entire operation string.
- Querying by ID can significantly reduce latency and bandwidth usage for very large operation strings.
- Client apps can execute an operation by providing its PQL-specified ID _instead of_ the entire operation string.
- Requesting by ID can significantly reduce latency and bandwidth usage for very large operation strings.
- Your router can _require_ that clients provide operations by ID and _reject_ full operation strings—even operation strings present in the PQL.
7 changes: 4 additions & 3 deletions src/content/shared/pq-router-configuration.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
As soon as a graph has an associated PQL, you can configure router instances to fetch and use the PQL by following these steps:

1. Ensure your router instances are ready to work with PQLs:
- Make sure you're using version `1.25.0` or later of the Apollo Router.
- Make sure your router instances are [connected to your GraphOS Enterprise organization](/graphos/enterprise-features/#enabling-enterprise-features) and that they're associated with a variant that your PQL is linked to.

- Make sure you're using version `1.xx.0` or later of the Apollo Router. (The feature was released in [preview](/resources/product-launch-stages/#preview) in version `1.25.0` and made [generally available](/resources/product-launch-stages/#general-availability) in `1.xx.0`.)
Meschreiber marked this conversation as resolved.
Show resolved Hide resolved
Meschreiber marked this conversation as resolved.
Show resolved Hide resolved
- Make sure your router instances are [connected to your GraphOS Enterprise organization](/graphos/enterprise-features/#enabling-enterprise-features) and that they're associated with a variant that your PQL is linked to.

2. Set your desired security level in your router's YAML config file. For supported options, see [router security levels](#router-security-levels). When first implementing persisted queries, it's best to start with [audit—or "dry run"—mode](#audit-mode-dry-run).

3. Deploy your updated router instances to begin using your PQL.

Once your organization's PQL has preregistered all your clients' operations and you've ensured your client apps are only sending preregistered operations, you can update your router configuration to the [safelisting security level](#safelisting).
Once your organization's PQL has registered all your clients' operations and you've ensured your client apps are only sending registered operations, you can update your router configuration to the [safelisting security level](#safelisting).
44 changes: 24 additions & 20 deletions src/content/shared/pq-security-levels.mdx
Original file line number Diff line number Diff line change
@@ -1,43 +1,47 @@
The Apollo Router supports the following security levels, in increasing order of restrictiveness:

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

When adopting persisted queries, you should start with a less restrictive security such as [audit mode](#audit-mode-dry-run). 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](/router/configuration/persisted-queries#configuration-options) for option details.

> From version `1.25.0` to `1.xx.0` the `persisted_queries` configuration option was called `preview_persisted_queries`. Upgrade your router to version `1.xx.0` or later to use the [generally available](/resources/product-launch-stages/#general-availability) version of the feature and the example configuration snippets below.
Meschreiber marked this conversation as resolved.
Show resolved Hide resolved

#### Allow operation IDs

To use persisted queries _only_ to reduce network bandwidth and latency (_not_ for safelisting), add the following minimal configuration:

```yaml title="router.yaml"
preview_persisted_queries:
persisted_queries:
enabled: true
```

> **Note:** You can use this security level with or without [automatic persisted queries](/router/configuration/in-memory-caching#caching-automatic-persisted-queries-apq) enabled.

This mode lets clients execute operations by providing their PQL-specified ID instead of the full operation string.
Your router 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 operations you need to either add to your PQL or stop your client apps from making.
Turning on logging is crucial for gauging your client apps' readiness for safelisting. The logs identify which operations you need to either add to your PQL or stop your client apps from making.

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

```yaml title="router.yaml"
preview_persisted_queries:
persisted_queries:
enabled: true
log_unknown: true
```

> **Note:** You can use audit mode with or without [automatic persisted queries](/router/configuration/in-memory-caching#caching-automatic-persisted-queries-apq) enabled.

Unregistered operations appear in your [router's logs](/router/logging).
Expand All @@ -48,9 +52,9 @@ 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 router receives an operation preregistered in the PQL, no log message will be output.
If your router receives an operation registered in the PQL, no log message will be output.

You can use these router logs to audit operations sent to your router and ask client teams to [add new ones](/graphos/operations/persisted-queries#3-preregister-operations) to your PQL if necessary.
You can use these router logs to audit operations sent to your router and ask client teams to [add new ones](/graphos/operations/persisted-queries#3-operation-registration) to your PQL if necessary.

#### Safelisting

Expand All @@ -59,17 +63,17 @@ You can use these router logs to audit operations sent to your router and ask cl
With the following configuration, your router allows _only_ GraphQL operations that are present in its PQL while rejecting all other operations:

```yaml title="router.yaml"
preview_persisted_queries:
persisted_queries:
enabled: true
log_unknown: true
safelist:
enabled: true
require_id: false
apq:
enabled: false # APQ must be turned off
enabled: false # APQ must be turned off
```

> **Note:** To enable safelisting, you _must_ turn off [automatic persisted queries](/router/configuration/in-memory-caching#caching-automatic-persisted-queries-apq) (APQs). APQs let clients [register arbitrary operations at runtime](#differences-from-automatic-persisted-queries) while safelisting restricts operations to those that have been explicitly preregistered.
> **Note:** To enable safelisting, you _must_ turn off [automatic persisted queries](/router/configuration/in-memory-caching#caching-automatic-persisted-queries-apq) (APQs). APQs let clients [register arbitrary operations at runtime](#differences-from-automatic-persisted-queries) while safelisting restricts operations to those that have been explicitly registered.

To execute an operation, clients can provide its PQL-specified ID _or_ full operation string.
The router rejects unregistered operations, and if `log_unknown` is true, those operations appear in your [router's logs](/router/logging).
Expand All @@ -80,23 +84,23 @@ The router rejects unregistered operations, and if `log_unknown` is true, those

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

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

```yaml title="router.yaml"
preview_persisted_queries:
persisted_queries:
enabled: true
log_unknown: true
safelist:
enabled: true
require_id: true #highlight-line
apq:
enabled: false # APQ must be turned off
enabled: false # APQ must be turned off
```

> **Note:** To enable safelisting, you _must_ turn off [automatic persisted queries](/router/configuration/in-memory-caching#caching-automatic-persisted-queries-apq) (APQs). APQs let clients [register arbitrary operations at runtime](#differences-from-automatic-persisted-queries) while safelisting restricts operations to those that have been explicitly preregistered.
> **Note:** To enable safelisting, you _must_ turn off [automatic persisted queries](/router/configuration/in-memory-caching#caching-automatic-persisted-queries-apq) (APQs). APQs let clients [register arbitrary operations at runtime](#differences-from-automatic-persisted-queries) while safelisting restricts operations 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](#safelisting). ID-only safelisting requires _all_ your clients to execute operations via PQL-specified ID instead of an operation string. While making those necessary changes, you can use the less restrictive [safelisting mode](#safelisting) in your router.

With `log_unknown` set to true, the router [logs](/router/logging) _all_ rejected operations, including those preregistered to your PQL but that used the full operation string rather than the PQL-specified ID.
With `log_unknown` set to true, the router [logs](/router/logging) _all_ rejected operations, including those registered to your PQL but that used the full operation string rather than the PQL-specified ID.

> So you can monitor the operations your router rejects, it's best to keep `log_unknown` as `true` while adopting safelisting. Once you're confident that all your clients are properly configured, you can turn it off to reduce noise in your logs.
> So you can monitor the operations your router rejects, it's best to keep `log_unknown` as `true` while adopting safelisting. Once you're confident that all your clients are properly configured, you can turn it off to reduce noise in your logs.
4 changes: 2 additions & 2 deletions src/content/shared/publish-pqms.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Ensure your Rover CLI version is `0.17.2` or later. Previous versions of Rover d

</blockquote>

After you [generate an operation manifest](/graphos/operations/persisted-queries#31-generate-persisted-queries-manifests), you publish it to your PQL with the [Rover CLI](/rover/) like so:
After you [generate an operation manifest](/graphos/operations/persisted-queries#31-generate-persisted-query-manifests), you publish it to your PQL with the [Rover CLI](/rover/) like so:

```bash title="Example command"
rover persisted-queries publish my-graph@my-variant \
Expand All @@ -27,7 +27,7 @@ rover persisted-queries publish my-graph@my-variant \

2. Updates any _other_ variants that the PQL is applied to so that routers associated with those variants can fetch their updated PQL.

As with [generating manifests](/graphos/operations/persisted-queries#31-generate-persisted-queries-manifests), it's best to execute this command in your CI/CD pipeline to publish new operations as part of your app release process. The API key you supply to Rover must have the [role](/graphos/org/members#graph-api-key-roles) of **Graph Admin** or **Persisted Query Publisher**. **Persisted Query Publisher** is a special role designed for use with the `rover persisted-queries publish` command; API keys with this role have no other access to your graph's data in GraphOS, and are appropriate for sharing with trusted third party client developers who should be allowed to publish operations to your graph's PQL but should not otherwise have access to your graph.
As with [generating manifests](/graphos/operations/persisted-queries#31-generate-persisted-query-manifests), it's best to execute this command in your CI/CD pipeline to publish new operations as part of your app release process. The API key you supply to Rover must have the [role](/graphos/org/members#graph-api-key-roles) of **Graph Admin** or **Persisted Query Publisher**. **Persisted Query Publisher** is a special role designed for use with the `rover persisted-queries publish` command; API keys with this role have no other access to your graph's data in GraphOS, and are appropriate for sharing with trusted third party client developers who should be allowed to publish operations to your graph's PQL but should not otherwise have access to your graph.

#### Test operations

Expand Down