Skip to content

Commit 734e8db

Browse files
JAORMXclaude
andcommitted
Add MCPAuthzConfig CRD for backend-agnostic authorization config
The existing AuthzConfigRef inline variant is Cedar-specific, with fields that only make sense for the Cedar authorizer. This adds a new MCPAuthzConfig CRD that accepts any registered authorizer backend configuration via a type discriminator and an opaque config blob. The MCPAuthzConfig CRD follows the established shared-config pattern (MCPOIDCConfig, MCPExternalAuthConfig) with status conditions, hash-based change detection, referencing workload tracking, and deletion protection. A new ConfigKey() method on the AuthorizerFactory interface enables the controller to reconstruct the full runtime config JSON from the CRD spec. The AuthzConfigRef field is added to MCPServer, MCPRemoteProxy, and VirtualMCPServer as a new option alongside the existing authzConfig field, enabling incremental migration with no breaking changes. Refs: #3157 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e2927e4 commit 734e8db

24 files changed

Lines changed: 1934 additions & 19 deletions
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package v1alpha1
5+
6+
import (
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
runtime "k8s.io/apimachinery/pkg/runtime"
9+
)
10+
11+
// Condition type and reasons for MCPAuthzConfig status (RFC-0023)
12+
const (
13+
// ConditionTypeAuthzConfigValid indicates whether the MCPAuthzConfig configuration is valid
14+
ConditionTypeAuthzConfigValid = ConditionTypeValid
15+
16+
// ConditionReasonAuthzConfigValid indicates spec validation passed
17+
ConditionReasonAuthzConfigValid = "ConfigValid"
18+
19+
// ConditionReasonAuthzConfigInvalid indicates spec validation failed
20+
ConditionReasonAuthzConfigInvalid = "ConfigInvalid"
21+
)
22+
23+
// MCPAuthzConfigSpec defines the desired state of MCPAuthzConfig.
24+
// MCPAuthzConfig resources are namespace-scoped and can only be referenced by
25+
// MCPServer, MCPRemoteProxy, or VirtualMCPServer resources in the same namespace.
26+
type MCPAuthzConfigSpec struct {
27+
// Type identifies the authorizer backend (e.g., "cedarv1", "httpv1").
28+
// Must match a registered authorizer type in the factory registry.
29+
// +kubebuilder:validation:Required
30+
// +kubebuilder:validation:MinLength=1
31+
Type string `json:"type"`
32+
33+
// Config contains the backend-specific authorization configuration.
34+
// The structure depends on the Type field:
35+
// - cedarv1: policies ([]string), entities_json (string), primary_upstream_provider (string), group_claim_name (string)
36+
// - httpv1: http ({url, timeout, insecure_skip_verify}), context ({include_args, include_operation}), claim_mapping (string)
37+
// +kubebuilder:pruning:PreserveUnknownFields
38+
// +kubebuilder:validation:Type=object
39+
Config runtime.RawExtension `json:"config"`
40+
}
41+
42+
// MCPAuthzConfigStatus defines the observed state of MCPAuthzConfig
43+
type MCPAuthzConfigStatus struct {
44+
// Conditions represent the latest available observations of the MCPAuthzConfig's state
45+
// +listType=map
46+
// +listMapKey=type
47+
// +optional
48+
Conditions []metav1.Condition `json:"conditions,omitempty"`
49+
50+
// ObservedGeneration is the most recent generation observed for this MCPAuthzConfig.
51+
// +optional
52+
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
53+
54+
// ConfigHash is a hash of the current configuration for change detection
55+
// +optional
56+
ConfigHash string `json:"configHash,omitempty"`
57+
58+
// ReferencingWorkloads is a list of workload resources that reference this MCPAuthzConfig.
59+
// Each entry identifies the workload by kind and name.
60+
// +listType=map
61+
// +listMapKey=name
62+
// +optional
63+
ReferencingWorkloads []WorkloadReference `json:"referencingWorkloads,omitempty"`
64+
}
65+
66+
// +kubebuilder:object:root=true
67+
// +kubebuilder:subresource:status
68+
// +kubebuilder:resource:shortName=authzcfg,categories=toolhive
69+
// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type`
70+
// +kubebuilder:printcolumn:name="Valid",type=string,JSONPath=`.status.conditions[?(@.type=='Valid')].status`
71+
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
72+
73+
// MCPAuthzConfig is the Schema for the mcpauthzconfigs API.
74+
// MCPAuthzConfig resources are namespace-scoped and can only be referenced by
75+
// MCPServer, MCPRemoteProxy, or VirtualMCPServer resources within the same namespace.
76+
// Cross-namespace references are not supported for security and isolation reasons.
77+
type MCPAuthzConfig struct {
78+
metav1.TypeMeta `json:",inline"` // nolint:revive
79+
metav1.ObjectMeta `json:"metadata,omitempty"`
80+
81+
Spec MCPAuthzConfigSpec `json:"spec,omitempty"`
82+
Status MCPAuthzConfigStatus `json:"status,omitempty"`
83+
}
84+
85+
// +kubebuilder:object:root=true
86+
87+
// MCPAuthzConfigList contains a list of MCPAuthzConfig
88+
type MCPAuthzConfigList struct {
89+
metav1.TypeMeta `json:",inline"` // nolint:revive
90+
metav1.ListMeta `json:"metadata,omitempty"`
91+
Items []MCPAuthzConfig `json:"items"`
92+
}
93+
94+
// MCPAuthzConfigReference references a shared MCPAuthzConfig resource.
95+
// The referenced MCPAuthzConfig must be in the same namespace as the referencing workload.
96+
type MCPAuthzConfigReference struct {
97+
// Name is the name of the MCPAuthzConfig resource in the same namespace.
98+
// +kubebuilder:validation:Required
99+
// +kubebuilder:validation:MinLength=1
100+
Name string `json:"name"`
101+
}
102+
103+
func init() {
104+
SchemeBuilder.Register(&MCPAuthzConfig{}, &MCPAuthzConfigList{})
105+
}

cmd/thv-operator/api/v1alpha1/mcpremoteproxy_types.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,18 @@ type MCPRemoteProxySpec struct {
8787
// +optional
8888
HeaderForward *HeaderForwardConfig `json:"headerForward,omitempty"`
8989

90-
// AuthzConfig defines authorization policy configuration for the proxy
90+
// AuthzConfig defines authorization policy configuration for the proxy.
91+
// Deprecated: Use AuthzConfigRef to reference a shared MCPAuthzConfig resource instead.
92+
// AuthzConfig and AuthzConfigRef are mutually exclusive.
9193
// +optional
9294
AuthzConfig *AuthzConfigRef `json:"authzConfig,omitempty"`
9395

96+
// AuthzConfigRef references a shared MCPAuthzConfig resource for authorization.
97+
// The referenced MCPAuthzConfig must exist in the same namespace as this MCPRemoteProxy.
98+
// Mutually exclusive with authzConfig.
99+
// +optional
100+
AuthzConfigRef *MCPAuthzConfigReference `json:"authzConfigRef,omitempty"`
101+
94102
// Audit defines audit logging configuration for the proxy
95103
// +optional
96104
Audit *AuditConfig `json:"audit,omitempty"`

cmd/thv-operator/api/v1alpha1/mcpserver_types.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,18 @@ type MCPServerSpec struct {
290290
// +optional
291291
OIDCConfigRef *MCPOIDCConfigReference `json:"oidcConfigRef,omitempty"`
292292

293-
// AuthzConfig defines authorization policy configuration for the MCP server
293+
// AuthzConfig defines authorization policy configuration for the MCP server.
294+
// Deprecated: Use AuthzConfigRef to reference a shared MCPAuthzConfig resource instead.
295+
// AuthzConfig and AuthzConfigRef are mutually exclusive.
294296
// +optional
295297
AuthzConfig *AuthzConfigRef `json:"authzConfig,omitempty"`
296298

299+
// AuthzConfigRef references a shared MCPAuthzConfig resource for authorization.
300+
// The referenced MCPAuthzConfig must exist in the same namespace as this MCPServer.
301+
// Mutually exclusive with authzConfig.
302+
// +optional
303+
AuthzConfigRef *MCPAuthzConfigReference `json:"authzConfigRef,omitempty"`
304+
297305
// Audit defines audit logging configuration for the MCP server
298306
// +optional
299307
Audit *AuditConfig `json:"audit,omitempty"`

cmd/thv-operator/api/v1alpha1/virtualmcpserver_types.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,17 @@ type IncomingAuthConfig struct {
133133
// +optional
134134
OIDCConfigRef *MCPOIDCConfigReference `json:"oidcConfigRef,omitempty"`
135135

136-
// AuthzConfig defines authorization policy configuration
137-
// Reuses MCPServer authz patterns
136+
// AuthzConfig defines authorization policy configuration.
137+
// Deprecated: Use AuthzConfigRef to reference a shared MCPAuthzConfig resource instead.
138+
// AuthzConfig and AuthzConfigRef are mutually exclusive.
138139
// +optional
139140
AuthzConfig *AuthzConfigRef `json:"authzConfig,omitempty"`
141+
142+
// AuthzConfigRef references a shared MCPAuthzConfig resource for authorization.
143+
// The referenced MCPAuthzConfig must exist in the same namespace as this VirtualMCPServer.
144+
// Mutually exclusive with authzConfig.
145+
// +optional
146+
AuthzConfigRef *MCPAuthzConfigReference `json:"authzConfigRef,omitempty"`
140147
}
141148

142149
// OutgoingAuthConfig configures authentication from Virtual MCP to backend MCPServers

cmd/thv-operator/api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 132 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)