Skip to main content

Roles and grants

Customer Connect leans on the central NetFoundry authorization service for every authorization decision. What sits in this codebase is a small layer on top: three roles (Admin, Read-Only and Member) pre-provisioned on every provider, customer, and location, plus a thin grants API for handing those roles to identities.

This page explains the model: what a role is, where it lives, how grants cascade, and how the lifecycle is wired into the resource lifecycle.

What a role is

A role is a named bundle of permissions on a specific resource. Customer Connect defines exactly three of them:

Wire namePermissions on the target resource
Adminread, create, update, delete, connectivity, enroll, and the same on every child
Read-Onlyread, and the same on every child
Memberread, connectivity, enroll, and the same on every child

The three values are case-sensitive on the wire and are the only valid name inputs anywhere in the role-grants surface. Anything else is rejected with 400 Bad Request. Member is additionally rejected on a provider — see Operators and members below.

Operators and members

The three roles fall into two disjoint populations, and the split is about who the person works for rather than how much they can do:

  • OperatorsAdmin and Read-Only. These are the provider's own staff. A Provider Admin, a Customer Admin and a Location Admin are the same job at three different scopes; a Customer Admin is not the customer's own administrator but a provider employee whose authority has been narrowed to that one account.
  • MembersMember. This is an employee of the provider's end customer, who connects to the applications made available to them. The role carries read, connectivity and enroll: enough to use the network, never to change its shape.

Each resource exposes the two populations separately — /operators and /members listings — and an identity's operator scope tag in the Identity Service is set when it holds any operator role across all of its grants.

Because a member belongs to one end customer, Member can only be granted on a customer or a location. Granting it on a provider is rejected with 400 Bad Request: provider-wide is by definition the provider's own staff.

Beyond create/read/update/delete

Two of the actions in the Admin bundle go past the usual CRUD verbs, and are deliberately kept separate from update so that an operator can be granted one without the other:

  • connectivity gates pausing and resuming a resource — the .../pause and .../resume endpoints on connectors, locations, and customers. It lets an operator suspend or restore traffic on a resource without being able to edit its definition, and vice versa.
  • enroll gates a connector's enrollment material — reissuing an enrollment (POST /connectors/{id}/reissue) and even seeing the enrollmentJwt on a connector read response. A caller with read but not enroll gets the connector back with the JWT omitted.

Both are included in Admin and excluded from Read-Only, and both cascade to children exactly like the CRUD actions.

Member carries both of these alongside read, on the resource it is granted on and on that resource's children — which is what lets an end customer's employee enrol a connector and pause or resume it without being able to redefine anything.

Where roles live

Roles attach to the parent resource (a provider, a customer, or a location), not to the identity. An identity gets a role by being granted the role on a specific resource:

Each provider has its own Admin/Read-Only roles; each customer and location has those plus its own Member. They're distinct objects with distinct UUIDs. Granting Admin on customer A gives the identity Admin authority on customer A and everything beneath it, but says nothing about customer B.

Each named tier — a role granted at a given resource level — has the following scope and capabilities:

RoleScopeCan do
Provider AdminEntire providerRead and manage all resources under the provider
Provider Read-OnlyEntire providerRead all resources; cannot create, update, or delete
Customer AdminOne customerRead and manage that customer's locations, connectors, and applications
Customer Read-OnlyOne customerRead that customer's subtree; cannot create, update, or delete
Customer MemberOne customerRead that customer's subtree, plus pause/resume and connector enrollment; cannot create, update, or delete
Location AdminOne locationRead and manage that location's connectors and applications
Location Read-OnlyOne locationRead that location's subtree; cannot create, update, or delete
Location MemberOne locationRead that location's subtree, plus pause/resume and connector enrollment; cannot create, update, or delete

The cascade

Grants on a parent resource implicitly cover its children:

  • Granting Admin on a provider confers Admin authority on that provider, on every customer of the provider, and on everything beneath those customers: every location, connector, application, and access policy.
  • Granting Admin on a customer confers Admin authority on that customer, on every location of the customer, and on every connector / application / access policy beneath those locations, but not on the parent provider or its other customers.
  • Granting Admin on a location confers Admin authority on that location and on the connectors / applications / access policies beneath it, but not on the parent customer or its other locations.
  • Granting Read-Only at any level cascades the same way, but only conveys read actions.
  • Granting Member on a customer or location cascades the same way, conveying read, connectivity and enroll — the end customer's employee can use and enrol what is beneath the grant, but cannot change its definition.

Practical implication: revoke at the level you granted at. If an identity holds Admin granted at the provider level and a separate Admin granted at one of that provider's customers, revoking the provider-level grant doesn't take away the customer-level grant. You'd need to revoke each independently.

Lifecycle

The roles themselves are managed by Customer Connect, not by API callers:

  1. Creation. When a provider, customer, or location is created, the service creates its Admin and Read-Only roles automatically. The grants API never creates the roles themselves; it only manipulates which identities hold them.
  2. Grants. Identities are granted a role via POST /providers/{id}/grants, POST /customers/{id}/grants, or POST /locations/{id}/grants. Grants are additive and idempotent. Re-issuing the same grant confirms the existing state without erroring. An identity can hold both Admin and Read-Only simultaneously; the union of the two is whatever Admin already provides.
  3. Listing. GET /providers/{id}/grants, GET /customers/{id}/grants, and GET /locations/{id}/grants return every grant currently in force on the resource. Add ?identityId=… to filter to a single identity. The role-definition endpoints (/providers/{id}/roles, /customers/{id}/roles, /locations/{id}/roles) describe the two roles themselves; the /grants sub-resources describe who holds them.
  4. Revocation. Revoking via DELETE /{resource}/{id}/grants?name=…&identityId=… removes every grant of that role on that resource for the given identity. Revoking a role the identity doesn't hold is also idempotent. It returns 204 No Content.
  5. Deletion. When a provider, customer, or location is deleted, its roles are cleaned up along with it. Any grants tied to those roles are removed transitively.

What's not here

A few things the role-grants surface deliberately doesn't do:

  • No custom roles. The three roles are the entire role catalog. There's no API to define a third role with a different permission bundle. If a use case needs finer-grained permissions, talk to the central authorization service team. Customer Connect is a consumer of that service, not the place to add the capability.
  • No identity management. The grants API takes an identityId as a UUID and trusts that the identity exists in the central auth system. Creating, listing, or modifying identities themselves is outside this service.

Authorization to use the API

The grants API is itself authorized by the standard auth Customer Connect uses everywhere:

  • Listing roles on a provider, customer, or location requires read on that resource.
  • Granting and revoking require update on that resource.
  • The cross-resource GET /grants?identityId=… listing requires read on provider.

The auth layer rejects attempts to grant a role the caller couldn't otherwise reach. A caller without update on the customer can't grant Admin on it.

More info