How-tos

5 mins read

Protecting GraphQL APIs

Cloudentity Istio Authorizer has the capability to discover your GraphQL APIs so that you can protect them with policies. You can either assign policies in Cloudentity or use the declarative approach and assign them directly in your GraphQL schema files, and this instruction explains how to do it.

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.

Prerequisites

  • Istio Authorizer up and running (other authorizers are not yet supported)
  • GraphQL service deployed in a k8s namespace monitored by Istio with the required annotations

GraphQL API Discovery

In order to be recognized by Cloudentity Istio Authorizer, your GraphQL service deployment must have the following metadata annotations in the manifest file:

  • services.k8s.cloudentity.com/spec-url pointing to the GraphQL schema definition
  • services.k8s.cloudentity.com/graphql-path pointing to the GraphQL endpoint path
apiVersion: apps/v1
kind: Deployment
metadata:
  name: countries
  labels:
    app: countries
  annotations:
    services.k8s.cloudentity.com/spec-url: "https://example.com/schema.graphql"
    services.k8s.cloudentity.com/graphql-path: "/graphql"

After you rollout your Istio Authorizer deployment, the GraphQL APIs are discovered and Cloudentity fetches them from your authorizer.

Sample services

To quickly set up a k8s cluster with Cloudentity, Istio Gateway, Istio Authorizer, and a GraphQL service, you can use the Cloudentity on k8s repository which provides simple deployment commands you can use out of the box as well as mock GraphQL services for you to try out.

Bind the GraphQL Service

Automatic Service Binding

If you selected the option to bind services automatically when creating the authorizer, your services should already be bound and you can skip this section.

  1. Go to Authorization » Gateways > YOUR_ISTIO_AUTHORIZER > APIs . A list of APIs discovered by your authorizer appears.

    APIs Not Visible

    If you cannot see your GraphQL service, make sure that:

    • The service is deployed.

    • Istio is actually scanning the service’s namespace (read Discovering APIs on Istio for more details). By default, Istio only scans the default namespace.

  2. Select Connect -> Connect to new service on your GraphQL API.

  3. Enter the name for the service and click Connect. Your service is now available from the APIs menu in Cloudentity.

Your GraphQL service discovered by the authorizer is now bound to the workspace. You can now assign policies to GraphQL objects and fields.

Assign GraphQL Policies in Cloudentity

  1. Go to APIs and find your GraphQL service in the API’s Management page.

  2. To apply a policy to the whole service, select the policy button (Unrestricted/Protected depending on the current status) from the API’sManagement page and assign an API policy.

  3. To apply a policy to individual GraphQL objects, select the GraphQL service. You can now see the service Types and Schema. The Schema page is read only - it simply shows what’s currently bound to Cloudentity.

    Query Highlighting

    If you’re not sure which policies will be evaluated on your query, enter the query into the Query box on the right. All queried objects are highlighted so that you know which items are controlled via policies!

Assign Policies Declaratively

As an alternative to managing GraphQL policies in Cloudentity, you can assign policies directly in the GraphQL schema.

GraphQL Syntax

Make sure that your GraphQL schema is correct, otherwise your service won’t be correctly bound and you may have issues with the authorizer going forward.

  1. First, you need to assign the following directive to your schema:

    directive @auth(
      policy: ID,
    ) on FIELD_DEFINITION | OBJECT | INTERFACE
    
  2. Annotate the fields, objects, and interfaces with an ID matching the Cloudentity API policy name (as in type Continent @auth(policy: "nist-aal-1_default_api")). Note that the policy names are workspace-specific and they will be different in your workspaces.

    directive @auth(policy: ID) on FIELD_DEFINITION | OBJECT | INTERFACE
    
    type Continent @auth(policy: "nist-aal-1_default_api") {
      code: ID!
      name: String!
      countries: [Country!]!
    }
    
    type Country @auth(policy: "nist-aal-1_default_api") {
      code: ID!
      name: String!
      native: String!
      phone: String! @auth(policy: "block_default_api")
      continent: Continent!
      capital: String
      currency: String
      languages: [Language!]!
      emoji: String!
      emojiU: String!
    }
    
    type Language @auth(policy: "nist-aal-1_default_api") {
      code: ID!
      name: String
      native: String
      rtl: Boolean!
    }
    
    type Query @auth(policy: "nist-aal-1_default_api") {
      continent(code: ID!): Continent
      country(code: ID!): Country
      language(code: ID!): Language
    }
    
  3. Rebuild your service. When the above GraphQL schema is picked up by the authorizer, policies are assigned out of the box, in accordance with your annotations. You cannot manage declarative policy assignments in Cloudentity - you need to update the schema to make changes.

GraphQL Examples and Schemas in acp-on-k8s Repository

Check the acp-on-k8s repository for sample services with more GraphQL examples, where you have the manifest file prepared out of the box, together with sample schemas. See the countries and resort examples. You can easily deploy both examples using Makefile commands - check the README for details.

Keep the following in mind:

  • These examples point to sample GitHub gists containing the GraphQL schema. Change the paths accordignly so that they point to your own schema.

  • The resort example schema is annotated with custom policies which do not exist in the default Cloudentity deployment. Change the policy names accordingly or create those policies in your workspace before deploying the service.

Verify GraphQL Policy

  1. Assign the Block API policy to any queried object (this policy is available in Cloudentity out of the box).

    Tip

    If you’re assigning the policy in Cloudentity, use the query highlighting to see which objects are queried.

  2. Run the query on your service

    Whitespace Characters

    Your curl request data must include the whitespace characters formatting present in the GraphQL syntax.

    curl 'http://example.com/graphql' --data-binary '{"query":"# Write your query or mutation here"}'
    

    Result

    Since you assigned the Block API policy, you should get a 403 Forbidden response with the following message:

    {"errors":[{"message":"policy validatation: block_default_api failed"}]}
    
  3. Remove the Block API policy. You should now get the 200 OK response with the data you queried for.

Updated: Nov 9, 2023