Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion api/v1alpha1/gateway_extensions_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ type GatewayExtension struct {
// +kubebuilder:validation:XValidation:message="ExtAuth must not be set when type is not ExtAuth",rule="self.type == 'ExtAuth' || !has(self.extAuth)"
// +kubebuilder:validation:XValidation:message="ExtProc must not be set when type is not ExtProc",rule="self.type == 'ExtProc' || !has(self.extProc)"
// +kubebuilder:validation:XValidation:message="RateLimit must not be set when type is not RateLimit",rule="self.type == 'RateLimit' || !has(self.rateLimit)"
// +kubebuilder:validation:XValidation:message="JwtProviders must not be set when type is not JWT",rule="self.type == 'JWTProviders' || !has(self.jwtProviders)"
type GatewayExtensionSpec struct {
// Type indicates the type of the GatewayExtension to be used.
// +kubebuilder:validation:Enum=ExtAuth;ExtProc;RateLimit
// +kubebuilder:validation:Enum=ExtAuth;ExtProc;RateLimit;JWTProviders
// +required
Type GatewayExtensionType `json:"type"`

Expand All @@ -48,6 +49,11 @@ type GatewayExtensionSpec struct {
// RateLimit configuration for RateLimit extension type.
// +optional
RateLimit *RateLimitProvider `json:"rateLimit,omitempty"`

// JWTProviders configures a map of unique JWTProvider name to JWTProviders
// +optional
// +kubebuilder:validation:MaxProperties=32
JWTProviders map[string]JWTProvider `json:"jwtProviders,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the name used for here?
can we use a list of map type instead of map? i think it renders more consistently?
is there a way to configure if this is pre or post ext auth?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the provider name needs to be unique, but that can be enforced at the plugin level. We might want to add a way to configure pre/post ext auth using the kgateway.dev/policy-weight?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can validate uniqueness of a list in CEL as well FWIW

}

// GatewayExtensionType indicates the type of the GatewayExtension.
Expand All @@ -60,6 +66,8 @@ const (
GatewayExtensionTypeExtProc GatewayExtensionType = "ExtProc"
// GatewayExtensionTypeRateLimit is the type for RateLimit extensions.
GatewayExtensionTypeRateLimit GatewayExtensionType = "RateLimit"
// GatewayExtensionTypeJWTProvider is the type for the JWT Provider extensions
GatewayExtensionTypeJWTProvider GatewayExtensionType = "JWTProviders"
)

// ExtGrpcService defines the GRPC service that will handle the processing.
Expand Down
129 changes: 129 additions & 0 deletions api/v1alpha1/jwt_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package v1alpha1

import corev1 "k8s.io/api/core/v1"

// JWTValidation defines the providers used to configure JWT validation
type JWTValidation struct {
// ExtensionRef references a GatewayExtension that provides the jwt providers
// +required
ExtensionRef *NamespacedObjectReference `json:"extensionRef"`

// TODO: add support for ValidationMode here (REQUIRE_VALID,ALLOW_MISSING,ALLOW_MISSING_OR_FAILED)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add the allow_missing.required/allow_missing_or_failed option here as well.


// TODO(npolshak): Add option to disable all jwt filters.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want this as well now that there is a pattern for it: https://github.com/kgateway-dev/kgateway/blob/main/api/v1alpha1/ext_auth_types.go#L27

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't straightforward for jwt. would require composite filter similar to extproc.

the alternative is to disable using RBAC

}

// JWTProvider configures the JWT Provider
// If multiple providers are specified for a given JWT policy, the providers will be `OR`-ed together and will allow validation to any of the providers.
type JWTProvider struct {
// Issuer of the JWT. the 'iss' claim of the JWT must match this.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=2048
// +optional
Issuer string `json:"issuer"`

// Audiences is the list of audiences to be used for the JWT provider.
// If specified an incoming JWT must have an 'aud' claim, and it must be in this list.
// If not specified, the audiences will not be checked in the token.
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=100
// +optional
Audiences []string `json:"audiences,omitempty"`

// TokenSource configures where to find the JWT of the current provider.
// +optional
TokenSource *JWTTokenSource `json:"tokenSource,omitempty"`

// ClaimsToHeaders is the list of claims to headers to be used for the JWT provider.
// Optionally set the claims from the JWT payload that you want to extract and add as headers
// to the request before the request is forwarded to the upstream destination.
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=100
// +optional
ClaimsToHeaders []JWTClaimToHeader `json:"claimsToHeaders,omitempty"`

// JWKS is the source for the JSON Web Keys to be used to validate the JWT.
JWKS JWKS `json:"jwks"`

// KeepToken configures if the token is forwarded upstream.
// If Remove, the header containing the token will be removed.
// If Forward, the header containing the token will be forwarded upstream.
// +kubebuilder:validation:Enum=Forward;Remove
// +kubebuilder:default=Remove
// +optional
KeepToken *KeepToken `json:"keepToken,omitempty"`
}

// KeepToken configures if the token is forwarded upstream.
type KeepToken string

const (
TokenForward KeepToken = "Forward"
TokenRemove KeepToken = "Remove"
)

// HeaderSource configures how to retrieve a JWT from a header
type HeaderSource struct {
// Header is the name of the header. for example, "Authorization"
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=2048
// +optional
Header *string `json:"header,omitempty"`
// Prefix before the token. for example, "Bearer "
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=2048
// +optional
Prefix *string `json:"prefix,omitempty"`
}

// JWTTokenSource configures the source for the JWTToken
type JWTTokenSource struct {
// HeaderSource configures retrieving token from the headers
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=100
// +optional
HeaderSource []HeaderSource `json:"headers,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need a list for this and query params? seems like you only want to fetch from one place generally?

// QueryParams configures retrieving token from these query params
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=100
// +optional
QueryParams []string `json:"queryParams,omitempty"`
}

// JWTClaimToHeader allows copying verified claims to headers sent upstream
type JWTClaimToHeader struct {
// Name is the JWT claim name, for example, "sub".
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=2048
Name string `json:"name"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claims can be nested (they are JSON). do we support that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it technically would work using dot-separated paths


// Header is the header the claim will be copied to, for example, "x-sub".
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=2048
Header string `json:"header"`
}

// JWKS (JSON Web Key Set) configures the source for the JWKS
type JWKS struct {
// LocalJWKS configures getting the public keys to validate the JWT from a Kubernetes configmap,
// or inline (raw string) JWKS.
// +optional
LocalJWKS *LocalJWKS `json:"local,omitempty"`

// TODO: Add support for remote JWKS
}

// LocalJWKS configures getting the public keys to validate the JWT from a Kubernetes ConfigMap,
// or inline (raw string) JWKS.
// +kubebuilder:validation:ExactlyOneOf=key;configMapRef
type LocalJWKS struct {
// InlineKey is the JWKS key as the raw, inline JWKS string
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=2048
// +optional
InlineKey *string `json:"key,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: key is probably an inaccurate name. Its a keyset, not a key

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we support PEM format here? or only JWKS format?
(asking as gloo edge supported PEM)


// ConfigMapRef configures storing the JWK in a Kubernetes ConfigMap in the same namespace as the JWTValidationPolicy.
// +optional
ConfigMapRef *corev1.LocalObjectReference `json:"configMapRef,omitempty"`
}
5 changes: 5 additions & 0 deletions api/v1alpha1/traffic_policy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ type TrafficPolicySpec struct {
// Agentgateway-based Gateway supports cumulative RBAC policies across different attachment points, such that
// an RBAC policy attached to a route augments policies applied to the gateway or listener without overriding them.
RBAC *Authorization `json:"rbac,omitempty"`

// JWT specifies the JWT validation configuration for the policy.
// This defines the JWT providers and their configurations.
// +optional
JWT *JWTValidation `json:"jwt,omitempty"`
}

// TransformationPolicy config is used to modify envoy behavior at a route level.
Expand Down
180 changes: 180 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ require sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect

require (
github.com/anthropics/anthropic-sdk-go v1.13.0
github.com/go-jose/go-jose/v3 v3.0.4
github.com/golang/protobuf v1.5.4
github.com/kagent-dev/mockllm v0.0.2-0.20251008144831-c6105837f767
github.com/openai/openai-go v1.12.0
Expand Down
Loading
Loading