w3resource

Securing your graph


How to secure your graph by enforcing a safelist of registered operations

Overview

Note: Operation safe listing is an Apollo Platform feature that is only available to subscribers of the Apollo Team and Enterprise plans.

Any API requires security and confidence prior to going to production. During development, GraphQL offers front-end engineers the ability to explore all the data available to them and fetch exactly what they need for the components they're building. However, in production, it can be unnecessary and undesirable to provide this flexibility.

The Apollo Platform comes with an operation registry and safelisting mechanism built into it, which allows organizations to:

  • Provide demand control for their production GraphQL APIs.
  • Permit the exact operations necessary for their client applications.
  • Eliminate the risk of unexpected, and possibly costly, operations being executed against their graph.

Operations defined within client applications can be extracted and uploaded to Apollo Graph Manager using the Apollo CLI. Apollo Server then fetches a manifest of these operations from Apollo Graph Manager and forbids the execution of any operations that were not in that manifest.

Prerequisites

  • Apollo Server 2.2.x (or newer).
  • A client application which utilizes gql tagged template literals for its operations or, alternatively, stores operations in .graphql files.

Installation steps

Setting up operation registration and safelisting is a full-stack process, so you will need to have access to the client code containing the operations you want to register, and to the server within which you want to enforce the safelist.

  • The Apollo CLI is used to search the client codebase for GraphQL operations and upload them to Apollo Graph Manager.
  • Apollo Server is then configured with a plugin which fetches the manifest from Apollo Graph Manager and enforces safelisting using that manifest. The following steps will walk through the steps necessary for both the client and server codebases.
  1. Install the Apollo CLI
  2. Push your schema to the Apollo schema registry
  3. Register operations from your client bundle
  4. Disable subscription support on Apollo Server
  5. Add the operation registry plugin to Apollo Server
  6. Start Apollo Server with Apollo Graph Manager enabled
  7. Verify

1. Install the apollo command line tool

Install the apollo command line tool as a development dependency of your client application:

npm install apollo --save-dev

2. Push your schema to the Apollo schema registry

Note: If this server's schema has already been registered using apollo service:push, you can skip this step. Else follow the steps below:

First, make sure Apollo Server is running and that introspection is enabled (it is often disabled in production).

Next, using the following command as a reference, replace the <ENGINE_API_KEY> with the Apollo Graph Manager API key from the appropriate service and specify the correct server endpoint with the --endpoint flag:

npx apollo service:push               \
    --key <ENGINE_API_KEY>            \
    --endpoint https://server/graphql

When successful, this command should return output similar to the following:

Copy
? Loading Apollo config
? Fetching current schema
? Publishing <service> to Apollo Engine
id      schema        tag
------  ------------- -------

3. Register operations from your client bundle

Now we'll use apollo client:push to locate operations within the client codebase and upload a manifest of those operations to Apollo operation registry. Once Apollo Server has been configured to respect the operation registry, only operations which have been included in the manifest will be permitted.

The apollo client:push command:

  • Supports multiple client bundles. Each bundle is identified by a clientName (e.g. react-web) and clientVersion.
  • Supports JavaScript, TypeScript and .graphql files.
  • Accepts a list of files as a glob (e.g. src/**/*.ts) to search for GraphQL operations.
  • By default, includes the __typename fields which are added by Apollo Client at runtime. (Add the --no-addTypeName flag to disable this behavior.)

To register operations, use the following command as a reference, taking care to replace the <ENGINE_API_KEY> with the appropriate Apollo Graph Manager API key, specifying a unique name for this application with <CLIENT_IDENTIFIER>, and indicating the correct glob of files to search:

npx apollo client:push \
    --key <ENGINE_API_KEY> \
    --clientName <CLIENT_IDENTIFIER> \
    --clientVersion <CLIENT_VERSION> \
    --includes="src/**/*.{ts,js,graphql}"

Note: Operations that are stored in the registry are legal for all clients. The client name and client version are collected as metadata to make debugging easier and provide more insights.

When successful, the output from this command should look similar to the following:

? Loading Apollo project
? Pushing client to Engine service <service>

Currently, once an operation is registered it will remain registered indefinitely. For production operation registration, it's recommended that operations be registered from a deployment pipeline step rather than manually.

4. Disable subscription support on Apollo Server

Subscription support is enabled by default in Apollo Server 2.x and provided by a separate server which does not utilize Apollo Server 2.x's primary request pipeline. Therefore, the operation registry plugin (and any plugin) is unable to be invoked during a request which comes into the subscription server and enforcement of operation safelisting is not possible. For proper enforcement of operation safelisting, subscriptions should be disabled.

Note: In the future, the subscription support will have its request pipeline unified with that of the main request pipeline, thus enabling plugin support and permitting the the operation registry to work with subscriptions in the same way that it works with regular GraphQL requests.

To disable subscriptions support on Apollo Server 2.x, a subscriptions: false setting should be included on the instantiation of Apollo Server, as follows:

const server = new ApolloServer({
  // Existing configuration
  typeDefs,
  resolvers,
  // Ensure that subscriptions are disabled.  subscriptions: false, // ...
});

5. Add the operation registry plugin to Apollo Server

Enable demand control by adding the operation registry to Apollo Server. To enable the operation registry within Apollo Server, it's necessary to install and enable the apollo-server-plugin-operation-registry plugin and ensure Apollo Server is configured to communicate with Apollo Graph Manager.

First, add the appropriate plugin to the Apollo Server's package.json:

npm install apollo-server-plugin-operation-registry

Next, the plugin must be enabled. This requires adding the appropriate module to the plugins parameter to the Apollo Server options:

Commonly, your application's staging and test environments use schemas that differ slightly from your production schema (especially if you're testing out updates to your schema).

Because these schemas represent different environments of the same application, it makes sense to associate them with each other. To achieve this, you can define variants of your graph.

Each variant of a graph functions as a standalone graph. It has its own change history, metrics, and operation registry.

Registering a schema to a variant

To register a schema to a variant, include the --tag=<VARIANT> flag in your apollo service:push command, like so:

const server = new ApolloServer({
  // Existing configuration
  typeDefs,
  resolvers,
  subscriptions: false,
  // ...
  // New configuration
  plugins:[require('apollo-server-plugin-operation-registry')({      forbidUnregisteredOperations: true,    }),  ],});

6. Start Apollo Server with Apollo Graph Manager enabled

If the server was already configured to use Apollo Graph Manager, no additional changes are necessary, but it's important to make sure that the server is configured to use the same service as the operations were registered with in step 3.

If the server was not previously configured with Apollo Graph Manager, be sure to start the server with the ENGINE_API_KEY variable set to the appropriate API key. For example:

ENGINE_API_KEY=<ENGINE_API_KEY> npm start

Alternatively, the API key can be specified with the engine parameter on the Apollo Server constructor options:

const server = new ApolloServer({
  // ...
  engine: '<ENGINE_API_KEY>', // ...
});

Note: For security, it's recommended to pass the Graph Manager API key as an environment variable so it will not be checked into version control (VCS).

7. Verification

With the operation registry enabled, only operations which have been registered will be permitted.

To confirm that everything is configured properly, try executing an operation against the server which was not registered from the client bundle in step 3.

For example, using curl this could be done with a command similar to:

curl 'http://server/graphql/' \
    -H 'Content-Type: application/json' \
    --data-binary '{"query":"query { likes{title} }"}'

If the server is configured properly, it should return:

Execution forbidden

Finally, to confirm that the server will allow permitted operations, try running an operation from the client.

Previous: Advanced topics for managed federation
Next: Graph Manager data privacy and compliance