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

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.