-
Notifications
You must be signed in to change notification settings - Fork 130
mcp: JWT scope based authorization #1482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
fe8b571
a242497
76f8729
f3196ca
bc62a62
d8b87e6
1d2c9d2
fcb2985
1964232
24fd0ac
4e33aa4
e2d6c2c
30d41ea
56443ef
bf067aa
9e4df68
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -177,6 +177,8 @@ type MCPBackendAPIKey struct { | |||||
| } | ||||||
|
|
||||||
| // MCPRouteSecurityPolicy defines the security policy for a MCPRoute. | ||||||
| // | ||||||
| // +kubebuilder:validation:XValidation:rule="!has(self.authorization) || has(self.oauth)",message="oauth must be configured when authorization is set" | ||||||
| type MCPRouteSecurityPolicy struct { | ||||||
| // OAuth defines the configuration for the MCP spec compatible OAuth authentication. | ||||||
| // | ||||||
|
|
@@ -192,6 +194,11 @@ type MCPRouteSecurityPolicy struct { | |||||
| // | ||||||
| // +optional | ||||||
| ExtAuth *egv1a1.ExtAuth `json:"extAuth,omitempty"` | ||||||
|
|
||||||
| // Authorization defines the configuration for the MCP spec compatible authorization. | ||||||
| // | ||||||
| // +optional | ||||||
| Authorization *MCPRouteAuthorization `json:"authorization,omitempty"` | ||||||
| } | ||||||
|
|
||||||
| // MCPRouteOAuth defines a MCP spec compatible OAuth authentication configuration for a MCPRoute. | ||||||
|
|
@@ -227,6 +234,87 @@ type MCPRouteOAuth struct { | |||||
| ProtectedResourceMetadata ProtectedResourceMetadata `json:"protectedResourceMetadata"` | ||||||
| } | ||||||
|
|
||||||
| // MCPRouteAuthorization defines the authorization configuration for a MCPRoute. | ||||||
| type MCPRouteAuthorization struct { | ||||||
| // Rules defines a list of authorization rules. | ||||||
| // | ||||||
| // Requests that match any rule and satisfy the rule's conditions will be allowed. | ||||||
| // Requests that do not match any rule or fail to satisfy the matched rule's conditions will be denied. | ||||||
| // If no rules are defined, all requests will be denied. | ||||||
| // | ||||||
| // +optional | ||||||
| Rules []MCPRouteAuthorizationRule `json:"rules,omitempty"` | ||||||
| } | ||||||
|
|
||||||
| // MCPRouteAuthorizationRule defines an authorization rule for MCPRoute based on the MCP authorization spec. | ||||||
| // Reference: https://modelcontextprotocol.io/specification/draft/basic/authorization#scope-challenge-handling | ||||||
| type MCPRouteAuthorizationRule struct { | ||||||
| // Source defines the authorization source for this rule. | ||||||
| // | ||||||
| // +kubebuilder:validation:Required | ||||||
| Source MCPAuthorizationSource `json:"source"` | ||||||
|
|
||||||
| // Target defines the authorization target for this rule. | ||||||
| // | ||||||
| // +kubebuilder:validation:Required | ||||||
| Target MCPAuthorizationTarget `json:"target"` | ||||||
| } | ||||||
|
|
||||||
| // MCPAuthorizationTarget defines the target of an authorization rule. | ||||||
| type MCPAuthorizationTarget struct { | ||||||
| // Tools defines the list of tools this rule applies to. | ||||||
| // | ||||||
| // +kubebuilder:validation:Required | ||||||
| // +kubebuilder:validation:MinItems=1 | ||||||
| // +kubebuilder:validation:MaxItems=16 | ||||||
| Tools []ToolCall `json:"tools"` | ||||||
| } | ||||||
|
|
||||||
| // MCPAuthorizationSource defines the source of an authorization rule. | ||||||
| type MCPAuthorizationSource struct { | ||||||
| // JWTSource defines the JWT scopes required for this rule to match. | ||||||
| // | ||||||
| // +kubebuilder:validation:Required | ||||||
| JWTSource JWTSource `json:"jwtSource"` | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd just call it
Suggested change
|
||||||
|
|
||||||
| // TODO: JWTSource can be optional in the future when we support more source types. | ||||||
| } | ||||||
|
|
||||||
| // JWTSource defines the MCP authorization source for JWT tokens. | ||||||
| type JWTSource struct { | ||||||
| // Scopes defines the list of JWT scopes required for the rule. | ||||||
| // If multiple scopes are specified, all scopes must be present in the JWT for the rule to match. | ||||||
| // | ||||||
| // +kubebuilder:validation:Required | ||||||
| // +kubebuilder:validation:MinItems=1 | ||||||
| // +kubebuilder:validation:MaxItems=16 | ||||||
| Scopes []egv1a1.JWTScope `json:"scopes"` | ||||||
zhaohuabing marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| // TODO : we can add more fields in the future, e.g., audiences, claims, etc. | ||||||
| } | ||||||
|
|
||||||
| // ToolCall represents a tool call in the MCP authorization target. | ||||||
| type ToolCall struct { | ||||||
| // BackendName is the name of the backend this tool belongs to. | ||||||
| // | ||||||
| // +kubebuilder:validation:Required | ||||||
| BackendName string `json:"backendName"` | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simplify the names for a less verbose and easier to write/read YAML API?
Suggested change
|
||||||
|
|
||||||
| // ToolName is the name of the tool. | ||||||
| // | ||||||
| // +kubebuilder:validation:Required | ||||||
| ToolName string `json:"toolName"` | ||||||
|
|
||||||
| // Arguments is a CEL expression that must evaluate to true for the rule to match. | ||||||
| // The expression is evaluated with a single variable "args" bound to the tool call arguments as a dynamic object. | ||||||
| // Guard against missing fields with null checks (e.g., args["foo"] != null && args["foo"]["bar"] == "val"). | ||||||
| // | ||||||
| // +kubebuilder:validation:Optional | ||||||
| // +kubebuilder:validation:MaxLength=4096 | ||||||
| // +optional | ||||||
| Arguments *string `json:"arguments,omitempty"` | ||||||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After discussing this with @nacx offline, we chose CEL for argument evaluation. CEL is easier to write and understand than regex evaluation when the arguments are complex object types. For example: To check against this argument: {
"key-level1": {
"key-level2": {
"key-level3": "value"
}
}
}The regex match: The CEL match:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WDYT about renaming this to |
||||||
| } | ||||||
|
|
||||||
| // JWKS defines how to obtain JSON Web Key Sets (JWKS) either from a remote HTTP/HTTPS endpoint or from a local source. | ||||||
| // +kubebuilder:validation:XValidation:rule="has(self.remoteJWKS) || has(self.localJWKS)", message="either remoteJWKS or localJWKS must be specified." | ||||||
| // +kubebuilder:validation:XValidation:rule="!(has(self.remoteJWKS) && has(self.localJWKS))", message="remoteJWKS and localJWKS cannot both be specified." | ||||||
|
|
||||||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for this limitation?