Skip to main content

Introduction to enterprise authorization

Stacklok Enterprise

Enterprise authorization is a capability of Stacklok Enterprise. For a full comparison of ToolHive Community and Stacklok Enterprise capabilities, see Stacklok Enterprise.

Enterprise authorization represents MCP access as declarative Kubernetes custom resources. Platform teams define reusable roles, and platform or namespace admins bind those roles to identity-provider groups and MCP servers. The operator compiles the resources into the Cedar policies ToolHive enforces at runtime.

The model

Enterprise authorization uses four custom resources modeled on Kubernetes role-based access control (RBAC).

  • ClusterPlatformRole (reference) defines what a role can do. It is product-agnostic. Per-product action vocabularies live under spec.productActions[], keyed by API group. The only supported product API group is toolhive.enterprise.stacklok.com. Wildcard "*" is allowed, which is how the built-in writer role grants every action.
  • ClusterPlatformRoleBinding (reference) defines who gets a role, cluster-wide. It maps identity-provider groups and roles (as carried in the JWT) to a ClusterPlatformRole.
  • PlatformRoleBinding (reference) is the namespaced sibling of ClusterPlatformRoleBinding. It lets a namespace owner author grants for resources in their own namespace without involving the cluster admin. Cluster-scoped and namespace-scoped bindings combine with union semantics: a subject is granted a role if any matching binding says so.
  • ToolhiveAuthorizationPolicy (reference) defines where access applies. It attaches one or more role bindings to a specific MCP target: an MCPServer or MCPRemoteProxy. It also supports optional ruleRestrictions (narrow the bound role to a specific tool, prompt, or resource), a toolHintFilter (gate by the readOnlyHint or destructiveHint annotations the server advertises), and a deny[] list that compiles to a Cedar forbid rule and overrides every grant. Multiple ToolhiveAuthorizationPolicy objects can attach to the same target; their effective principal sets and deny lists are unioned.

Claim mapping

Bindings refer to identity-provider groups and roles. Those values come from claims in the JWT that ToolHive validates on every request. By default, the platform derives the claim names from the IdP type it detects, so a cluster admin typically does not need to configure them. For Microsoft Entra ID, the defaults are the roles claim (the app-role claim) and the groups claim.

To override the defaults, set the groupsClaim and rolesClaim keys on the platform identity-provider ConfigMap. The enterprise installer creates this ConfigMap with a release-specific name in the platform namespace, for example stacklok-enterprise-platform-enterprise-manager-idp-config. Find it with kubectl get configmap -A | grep idp-config, then edit the keys to match the claims your IdP emits. For the identity-provider side of this setup, where you configure the IdP to emit those group and role claims, see Configure platform identity.

Inside each binding, the from[] field is a list of PrincipalCondition objects. Each condition has two arrays: groups[] and roles[]. The two arrays inside one condition are AND-ed: the subject must satisfy both the groups list and the roles list to match. Across multiple conditions in the same from[], the conditions are OR-ed: a subject matches the binding if any one of them matches. At least one of groups[] or roles[] must be non-empty in every condition, which the CRD enforces with a CEL validation rule.

For example, this binding matches users who are in the mcp-engineers group and hold the mcp-viewer role, or anyone who holds the mcp-admin role:

from:
- groups: [mcp-engineers]
roles: [mcp-viewer]
- roles: [mcp-admin]

For the broader picture of how ToolHive verifies tokens and integrates with an OIDC provider, see Authentication and authorization.

Built-in roles

The operator includes two ClusterPlatformRole objects.

  • reader grants the MCP read operations and call_tool. The call_tool actions can be narrowed at bind time with toolHintFilter.readOnlyHint: true, which restricts the binding to tools the MCP server itself annotates as read-only.
  • writer grants every action via wildcard.

You can list them with kubectl get clusterplatformroles (or the short form, kubectl get cpr). Build a custom ClusterPlatformRole only when you need a narrower action vocabulary than reader and writer offer.

Next steps