Skip to main content

Delegate authorization by namespace

Use PlatformRoleBinding to let namespace administrators grant approved roles on the MCP servers they manage. Cluster admins maintain the role catalog, while namespace admins maintain bindings in their namespaces.

When to use it

Use delegated authorization when a team owns the workload and has its own IdP group. The team can manage access in the same manifests as its MCPServer by selecting roles from the cluster admin's ClusterPlatformRole catalog.

How the trust model works

The effective principal set on a ToolhiveAuthorizationPolicy is the union of:

  • every matching ClusterPlatformRoleBinding at the cluster scope, and
  • every matching PlatformRoleBinding in the policy's own namespace.

Namespace bindings can only add principals to that union. They cannot remove a grant that a ClusterPlatformRoleBinding made cluster-wide. To deny an access path for a specific MCP target, use the policy's deny[] list, which compiles to a Cedar forbid rule and overrides every grant. The escalation direction is intentional: the cluster admin retains a clean override path through ClusterPlatformRoleBinding, and the team gets fast iteration on additive grants.

SourceScopeWho authors
ClusterPlatformRoleBindingCluster-wideCluster admin
PlatformRoleBindingOne namespaceNamespace owner
ToolhiveAuthorizationPolicyOne MCP targetNamespace owner

For full field details on each resource, see the ClusterPlatformRoleBinding, PlatformRoleBinding, and ToolhiveAuthorizationPolicy CRD references.

Walkthrough

This walkthrough builds on the Quickstart: GitHub MCP with Entra ID. The difference is the namespace: the team owns team-alpha and has deployed an MCPServer named alpha-tools-mcp there. The cluster admin has previously authored a read-only ClusterPlatformRole and granted the team's namespace RBAC to manage platformrolebindings and toolhiveauthorizationpolicies in team-alpha.

1. Bind the IdP role to the catalog role

Create a PlatformRoleBinding in team-alpha that maps the Entra app role mcp-team-alpha-engineers to the cluster-published read-only ClusterPlatformRole:

alpha-engineers-readonly.yaml
apiVersion: platform.enterprise.stacklok.com/v1alpha1
kind: PlatformRoleBinding
metadata:
name: alpha-engineers-readonly
namespace: team-alpha
spec:
bindings:
- roleRef:
kind: ClusterPlatformRole
name: read-only
from:
- roles:
- mcp-team-alpha-engineers
kubectl apply -f alpha-engineers-readonly.yaml

This binding only contributes principals to authorization policies in team-alpha. The roleRef points at a cluster-scoped role, so the team consumes the catalog without authoring verbs.

2. Attach the role to the MCP target

Create a ToolhiveAuthorizationPolicy in team-alpha that binds the read-only role to alpha-tools-mcp:

alpha-tools-readonly.yaml
apiVersion: toolhive.enterprise.stacklok.com/v1alpha1
kind: ToolhiveAuthorizationPolicy
metadata:
name: alpha-tools-readonly
namespace: team-alpha
spec:
targetRef:
name: alpha-tools-mcp
bindings:
- roleRef:
kind: ClusterPlatformRole
name: read-only
kubectl apply -f alpha-tools-readonly.yaml

targetRef.kind defaults to MCPServer, so it's omitted. The policy's namespace and the MCPServer's namespace must match.

3. Wait for the policy to compile

kubectl wait --for=condition=Compiled \
tap/alpha-tools-readonly -n team-alpha --timeout=60s

When the Compiled condition flips to True, the operator has turned the policy plus the matching PlatformRoleBinding into the Cedar policy bundle the proxy will enforce.

4. Verify with a token from the team's IdP group

Obtain a token for a user assigned to mcp-team-alpha-engineers and call a tool through the proxy at alpha-tools-mcp, following the pattern in step 6 of the Entra quickstart.

Expected outcome: tool calls that carry the readOnlyHint annotation return 200, and tool calls that don't carry it return 403. The read-only role's principal set was contributed entirely by the team's PlatformRoleBinding; no cluster-wide binding had to change.

Delegation boundaries

Namespace admins have these restrictions:

  • Subtract a cluster-wide grant. If a ClusterPlatformRoleBinding grants a role to a principal that also matches a ToolhiveAuthorizationPolicy in the team's namespace, the team cannot drop that principal locally. The options are a deny[] entry on the authorization policy to override grants for one specific MCP target, or a request to the cluster admin to change the ClusterPlatformRoleBinding.
  • Author or edit a ClusterPlatformRole. Roles live in the cluster-admin-owned catalog. The team consumes them by roleRef.
  • Bind across namespaces. A PlatformRoleBinding in team-alpha only contributes principals to authorization policies whose namespace is team-alpha. Cross-namespace effects require a ClusterPlatformRoleBinding, which only the cluster admin can author.

Limit the available roles

The access gate on namespace self-service is namespace-level Kubernetes RBAC on platformrolebindings and toolhiveauthorizationpolicies. A team with those permissions can reference any ClusterPlatformRole in the cluster. Publish a curated catalog of narrowly scoped roles that are safe for namespace admins to assign.

Next steps