Skip to main content

Role-Based Access Control

This tutorial demonstrates how to use role-based access control (RBAC) using Inigo's @access directive. This is an alternative approach to Inigo's declarative configurations for RBAC.

Configuration Setup

Service Configuration

To get started, Access-Control properties must be configured in the Service YAML that configures the Client Configuration, as shown in this example:

service.yaml
kind: Service
name: demo-service
spec:
path_client_info: "header.Client-Name"
path_user_id: jwt.email
path_organization_id: jwt.org_name
schema_files:
./schema.graphql

# required Access Control properties
path_user_profile: header.X-USER-PROFILE
path_user_role: header.X-USER-ROLES
anonymous_profile: guest
anonymous_roles: [guest]

As with all Inigo YAML configurations, use inigo apply to apply the configuration as such:

inigo apply service.yaml --label dev

Schema Separation Concept

Let's take a look at this example. We have 4 roles here: guest, viewer, pii and admin.

schema.graphql
type Query {
login(email: String!, password: String!): String! @access(role: ["guest"])
user: User! @access(role: ["viewer"])
admin: Admin! @access(role: ["admin"])
}

type User {
name: String!
address: String!
ssn: String! @access(role: ["pii"])
}

type Admin {
userCount: Int!
}

directive @access(depth: Int, role: [String]) on FIELD_DEFINITION

Here's what each role has access:

  1. guest - unauthorized user - has only access to Query.login
  2. viewer - authorized user - has access to Query.user and all fields inside the User, except User.ssn, which is restriced.
  3. pii - authorized user - has access to the User.ssn field.
  4. admin - authorized user - has access to Admin object.

Now let's assign access roles based on different personas. In this example, Inigo agent will enfore access-contorl based of the list rule provided in 'header.X-USER-ROLESwhich were confogired under Service Configuration'spath_user_role`. When Inigo agent sees the request it expects to see the list of roles in this header.

Now let's assign access roles based on different personas. In this example, the Inigo agent will enforce access-control based on the list of roles provided in the 'header.X-USER-ROLES', which were configured under the Service Configuration's path_user_role

  1. Unauthorized user
X-USER-ROLES=guest
  1. User
X-USER-ROLES=viewer
  1. User with PII access
X-USER-ROLES=viewer,pii
  1. Admin
X-USER-ROLES=viewer,admin

::: tip For top level objects Query, Mutation and Subscription - best practice would be to have @access directive for each field. Fields without this directive would not be accessible by anyone.

Access Denied Example

Should an unauthenticated client try to call User.name, they will see the following error:

{
"errors": [
{
"message": "invalid access",
"path": [
"user"
]
}
],
"data": null,
"extensions": {}
}

Federated schemas

For Federated schemas the @access directive will carry druing composition.

Introspection Configuration

In Access configuration we specify introspection mode per profile (not per role). In this way, it is decoupled from actual access control and gives you ability to build RBAC as per your specific business needs.

access.yaml
kind: Access
name: apollo-gateway-fed-2-demo
spec:
profiles:
- name: guest
introspection_mode: partial
- name: viewer
introspection_mode: partial
- name: admin
introspection_mode: full

Remember, that in service.yaml we configured path_user_profile to be header.X-USER-PROFILE. Let's attach this header to our personal requests so complete set of required headers would be:

  1. Unauthorized user
X-USER-ROLES=guest
X-USER-PROFILE=guest
  1. User
X-USER-ROLES=viewer
X-USER-PROFILE=viewer
  1. User with PII access
X-USER-ROLES=viewer,pii
X-USER-PROFILE=viewer
  1. Admin
X-USER-ROLES=viewer,admin
X-USER-PROFILE=admin

Use inigo apply to apply the configuration as such:

inigo apply access.yaml --label dev
How to disable introspection for everything?

With this configuration we are creating the default profile with introspection disabled, and we are telling Inigo to apply this configuration to all incoming calls. Since introspection control is part of the Access Control suite, configuring it requires the following steps:

  1. Create a file called service.yaml with the following content
service.yaml
kind: Service
name: <your-service-name>
spec:
path_user_profile: header.<header-name> # note: this configuration has to be present in order to trigger profile check
anonymous_profile: default
  1. Create a file called access.yaml with the following content
access.yaml
kind: Access
name: <your-service-name>
spec:
profiles:
- name: default
introspection_mode: block
  1. Install Inigo CLI: Inigo CLI Installation guide

  2. Apply configuration by running the following command

inigo apply service.yaml access.yaml

Conclusion

Inigo's RBAC using @access provides an easy way to add controls to how your GraphQL API is used and introspected. Finally, @access works with federated schemas, so RBAC can be used independently in each subgraph schema.