Skip to content

vMCP AuthzConfig struct missing GroupEntityType, GroupClaimName, RoleClaimName — Cedar group/role policies fail silently #5277

@jhrozek

Description

@jhrozek

Background

PR #5121 added GroupEntityType to cedar.ConfigOptions so deployments can configure the entity type the Cedar authorizer uses when building principal parent UIDs from JWT group/role claims. GroupClaimName and RoleClaimName were already present. All three fields are read from authz.json at runtime by MCPServer and MCPRemoteProxy, which load the file directly via LoadConfig()ConfigOptions.

The enterprise controller writes all three into authz.json:

{
  "cedar": {
    "group_entity_type": "ClaimGroup",
    "group_claim_name":  "groups",
    "role_claim_name":   "roles"
  }
}

Problem

The vmcp internal AuthzConfig struct (pkg/vmcp/config/config.go) only carries:

type AuthzConfig struct {
    Type                    string   `json:"type"`
    Policies                []string `json:"policies,omitempty"`
    PrimaryUpstreamProvider string   `json:"primaryUpstreamProvider,omitempty"`
}

GroupEntityType, GroupClaimName, and RoleClaimName are absent. The operator converter (pkg/vmcpconfig/converter.go) builds this struct manually for both the inline and ConfigMap paths, and has nowhere to put these values. They are silently dropped.

As a result, the Cedar authorizer inside the vmcp binary is always constructed with:

  • GroupEntityType defaulting to "THVGroup" (the upstream hardcoded legacy value)
  • GroupClaimName defaulting to the well-known fallback list (groups, roles, cognito:groups)
  • RoleClaimName empty

For deployments using the enterprise controller, the static entity store uses ClaimGroup entities. Because GroupEntityType is never forwarded, the runtime Cedar authorizer builds THVGroup:: parents for the principal while the static entity store has ClaimGroup:: entities — severing the Client → ClaimGroup → PlatformRole hierarchy. Cedar in checks silently evaluate to false and all group/role-scoped policies deny.

This affects both the inline path today and the ConfigMap path once #5208 lands.

Fix

  1. Add GroupEntityType, GroupClaimName, and RoleClaimName to pkg/vmcp/config/config.go's AuthzConfig struct.
  2. Wire them through the Cedar authorizer factory so the vmcp binary passes them to NewCedarAuthorizer via ConfigOptions.
  3. For the ConfigMap path (vMCP: Load authz config from ConfigMap (policies + primaryUpstreamProvider) #5208): extract all three from the parsed authz.json and populate them into AuthzConfig.
  4. For the inline path: either add these fields to InlineAuthzConfig (CRD change), or lift them to AuthzConfigRef as part of vMCP: Load authz config from ConfigMap (policies + primaryUpstreamProvider) #5208's Option B schema decision — the approach should be coordinated with that issue.

Related

Acceptance criteria

  • A VirtualMCPServer with Cedar group/role policies enforces them correctly at runtime
  • group_entity_type, group_claim_name, and role_claim_name from an enterprise authz.json ConfigMap are forwarded into the vmcp config.yaml and reach the Cedar authorizer

Metadata

Metadata

Assignees

Labels

authorizationbugSomething isn't workinggoPull requests that update go codeoperatorvmcpVirtual MCP Server related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions