From 364710f447c9d1eaff07e56dc394204625c6c47f Mon Sep 17 00:00:00 2001 From: Huabing Zhao Date: Sat, 28 Oct 2023 00:25:58 +0800 Subject: [PATCH] feat: remove AuthenticationFilter in favor of SecurityPolicy (#2086) remove Authenticationfilter in favor of SecurityPolicy fix e2e fix test and add policies to egctl translate command add docs for jwt remove crd clear docs address comments update security policy status fix e2e test Signed-off-by: huabing zhao --- api/v1alpha1/cors_types.go | 24 + ...enticationfilter_types.go => jwt_types.go} | 87 +-- api/v1alpha1/securitypolicy_types.go | 108 ---- api/v1alpha1/shared_types.go | 40 ++ .../validation/authenticationfilter.go | 116 ---- .../validation/authenticationfilter_test.go | 451 --------------- api/v1alpha1/zz_generated.deepcopy.go | 106 ---- ...y.envoyproxy.io_authenticationfilters.yaml | 131 ----- charts/gateway-helm/templates/_rbac.tpl | 2 - .../kubernetes/{authn => jwt}/grpc-jwt.yaml | 22 +- examples/kubernetes/{authn => jwt}/jwks.json | 0 examples/kubernetes/{authn => jwt}/jwt.yaml | 35 +- examples/kubernetes/{authn => jwt}/test.jwt | 0 .../{authn => jwt}/with-different-claim.jwt | 0 ...jwt-single-route-single-match-to-xds.yaml} | 22 +- ...single-route-single-match-to-xds.all.json} | 0 ...single-route-single-match-to-xds.all.yaml} | 0 ...-route-single-match-to-xds.bootstrap.yaml} | 0 ...le-route-single-match-to-xds.cluster.yaml} | 0 ...e-route-single-match-to-xds.endpoint.yaml} | 0 ...e-route-single-match-to-xds.listener.yaml} | 0 ...ngle-route-single-match-to-xds.route.yaml} | 0 internal/cmd/egctl/translate.go | 48 +- internal/cmd/egctl/translate_test.go | 18 +- internal/gatewayapi/filters.go | 18 - internal/gatewayapi/helpers.go | 23 - internal/gatewayapi/helpers_test.go | 74 --- internal/gatewayapi/resource.go | 2 - internal/gatewayapi/route.go | 6 +- .../grpcroute-with-valid-authenfilter.in.yaml | 49 -- ...grpcroute-with-valid-authenfilter.out.yaml | 128 ----- ...with-non-existent-authenfilter-ref.in.yaml | 43 -- ...ith-non-existent-authenfilter-ref.out.yaml | 114 ---- ...with-non-matching-authenfilter-ref.in.yaml | 57 -- ...ith-non-matching-authenfilter-ref.out.yaml | 114 ---- .../httproute-with-valid-authenfilter.in.yaml | 55 -- ...httproute-with-valid-authenfilter.out.yaml | 138 ----- ...ith-valid-multi-match-authenfilter.in.yaml | 69 --- ...th-valid-multi-match-authenfilter.out.yaml | 175 ------ ...lid-multi-match-multi-authenfilter.in.yaml | 85 --- ...id-multi-match-multi-authenfilter.out.yaml | 179 ------ ...-multiple-gateways-multiple-routes.in.yaml | 19 - ...multiple-gateways-multiple-routes.out.yaml | 13 - internal/gatewayapi/zz_generated.deepcopy.go | 11 - internal/ir/xds.go | 45 -- internal/ir/xds_test.go | 2 +- internal/ir/zz_generated.deepcopy.go | 47 -- internal/provider/kubernetes/controller.go | 147 ++--- internal/provider/kubernetes/filters.go | 30 - .../provider/kubernetes/kubernetes_test.go | 327 +---------- internal/provider/kubernetes/predicates.go | 49 -- internal/provider/kubernetes/routes.go | 106 +--- internal/provider/kubernetes/routes_test.go | 185 ------- internal/provider/kubernetes/test/utils.go | 52 -- internal/xds/translator/authentication.go | 317 ----------- internal/xds/translator/httpfilters.go | 11 - .../authn-multi-route-multi-provider.yaml | 70 --- .../authn-multi-route-single-provider.yaml | 51 -- .../testdata/in/xds-ir/authn-ratelimit.yaml | 70 --- .../authn-single-route-single-match.yaml | 26 - ...ml => jwt-multi-route-multi-provider.yaml} | 0 ...l => jwt-multi-route-single-provider.yaml} | 0 ...uthn-ratelimit.yaml => jwt-ratelimit.yaml} | 0 ...aml => jwt-single-route-single-match.yaml} | 0 ...n-multi-route-multi-provider.clusters.yaml | 81 --- ...-multi-route-multi-provider.endpoints.yaml | 33 -- ...-multi-route-multi-provider.listeners.yaml | 113 ---- ...thn-multi-route-multi-provider.routes.yaml | 25 - ...-multi-route-single-provider.clusters.yaml | 59 -- ...multi-route-single-provider.endpoints.yaml | 22 - ...multi-route-single-provider.listeners.yaml | 93 ---- ...hn-multi-route-single-provider.routes.yaml | 25 - .../xds-ir/jwt-authn-ratelimit.clusters.yaml | 105 ---- .../xds-ir/jwt-authn-ratelimit.endpoints.yaml | 44 -- .../xds-ir/jwt-authn-ratelimit.listeners.yaml | 63 --- .../xds-ir/jwt-authn-ratelimit.routes.yaml | 46 -- ...hn-single-route-single-match.clusters.yaml | 45 -- ...n-single-route-single-match.endpoints.yaml | 11 - ...n-single-route-single-match.listeners.yaml | 53 -- ...uthn-single-route-single-match.routes.yaml | 16 - ...-multi-route-multi-provider.clusters.yaml} | 0 ...multi-route-multi-provider.endpoints.yaml} | 0 ...multi-route-multi-provider.listeners.yaml} | 0 ...wt-multi-route-multi-provider.routes.yaml} | 0 ...multi-route-single-provider.clusters.yaml} | 0 ...ulti-route-single-provider.endpoints.yaml} | 0 ...ulti-route-single-provider.listeners.yaml} | 0 ...t-multi-route-single-provider.routes.yaml} | 0 ...sters.yaml => jwt-ratelimit.clusters.yaml} | 0 ...ints.yaml => jwt-ratelimit.endpoints.yaml} | 0 ...ners.yaml => jwt-ratelimit.listeners.yaml} | 0 ....routes.yaml => jwt-ratelimit.routes.yaml} | 0 ...t-single-route-single-match.clusters.yaml} | 0 ...-single-route-single-match.endpoints.yaml} | 0 ...-single-route-single-match.listeners.yaml} | 0 ...jwt-single-route-single-match.routes.yaml} | 0 internal/xds/translator/translator.go | 5 - internal/xds/translator/translator_test.go | 24 +- site/content/en/latest/api/extension_types.md | 63 --- site/content/en/latest/design/rate-limit.md | 27 +- .../latest/design/request-authentication.md | 515 ------------------ .../user/{authn.md => jwt-authentication.md} | 45 +- .../testdata/ratelimit-based-jwt-claims.yaml | 39 +- tools/crd-ref-docs/config.yaml | 2 +- 104 files changed, 331 insertions(+), 5340 deletions(-) create mode 100644 api/v1alpha1/cors_types.go rename api/v1alpha1/{authenticationfilter_types.go => jwt_types.go} (54%) delete mode 100644 api/v1alpha1/validation/authenticationfilter.go delete mode 100644 api/v1alpha1/validation/authenticationfilter_test.go delete mode 100644 charts/gateway-helm/crds/generated/gateway.envoyproxy.io_authenticationfilters.yaml rename examples/kubernetes/{authn => jwt}/grpc-jwt.yaml (53%) rename examples/kubernetes/{authn => jwt}/jwks.json (100%) rename examples/kubernetes/{authn => jwt}/jwt.yaml (56%) rename examples/kubernetes/{authn => jwt}/test.jwt (100%) rename examples/kubernetes/{authn => jwt}/with-different-claim.jwt (100%) rename internal/cmd/egctl/testdata/translate/in/{authn-single-route-single-match-to-xds.yaml => jwt-single-route-single-match-to-xds.yaml} (83%) rename internal/cmd/egctl/testdata/translate/out/{authn-single-route-single-match-to-xds.all.json => jwt-single-route-single-match-to-xds.all.json} (100%) rename internal/cmd/egctl/testdata/translate/out/{authn-single-route-single-match-to-xds.all.yaml => jwt-single-route-single-match-to-xds.all.yaml} (100%) rename internal/cmd/egctl/testdata/translate/out/{authn-single-route-single-match-to-xds.bootstrap.yaml => jwt-single-route-single-match-to-xds.bootstrap.yaml} (100%) rename internal/cmd/egctl/testdata/translate/out/{authn-single-route-single-match-to-xds.cluster.yaml => jwt-single-route-single-match-to-xds.cluster.yaml} (100%) rename internal/cmd/egctl/testdata/translate/out/{authn-single-route-single-match-to-xds.endpoint.yaml => jwt-single-route-single-match-to-xds.endpoint.yaml} (100%) rename internal/cmd/egctl/testdata/translate/out/{authn-single-route-single-match-to-xds.listener.yaml => jwt-single-route-single-match-to-xds.listener.yaml} (100%) rename internal/cmd/egctl/testdata/translate/out/{authn-single-route-single-match-to-xds.route.yaml => jwt-single-route-single-match-to-xds.route.yaml} (100%) delete mode 100644 internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.in.yaml delete mode 100644 internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-authenfilter.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-authenfilter.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.out.yaml delete mode 100644 internal/xds/translator/authentication.go delete mode 100644 internal/xds/translator/testdata/in/xds-ir/authn-multi-route-multi-provider.yaml delete mode 100644 internal/xds/translator/testdata/in/xds-ir/authn-multi-route-single-provider.yaml delete mode 100644 internal/xds/translator/testdata/in/xds-ir/authn-ratelimit.yaml delete mode 100644 internal/xds/translator/testdata/in/xds-ir/authn-single-route-single-match.yaml rename internal/xds/translator/testdata/in/xds-ir/{jwt-authn-multi-route-multi-provider.yaml => jwt-multi-route-multi-provider.yaml} (100%) rename internal/xds/translator/testdata/in/xds-ir/{jwt-authn-multi-route-single-provider.yaml => jwt-multi-route-single-provider.yaml} (100%) rename internal/xds/translator/testdata/in/xds-ir/{jwt-authn-ratelimit.yaml => jwt-ratelimit.yaml} (100%) rename internal/xds/translator/testdata/in/xds-ir/{jwt-authn-single-route-single-match.yaml => jwt-single-route-single-match.yaml} (100%) delete mode 100755 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.clusters.yaml delete mode 100755 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.endpoints.yaml delete mode 100755 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.listeners.yaml delete mode 100755 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.routes.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.clusters.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.endpoints.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.listeners.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.routes.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.clusters.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.endpoints.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.listeners.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.routes.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.clusters.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.endpoints.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.listeners.yaml delete mode 100644 internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.routes.yaml rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-multi-provider.clusters.yaml => jwt-multi-route-multi-provider.clusters.yaml} (100%) mode change 100644 => 100755 rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-multi-provider.endpoints.yaml => jwt-multi-route-multi-provider.endpoints.yaml} (100%) mode change 100644 => 100755 rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-multi-provider.listeners.yaml => jwt-multi-route-multi-provider.listeners.yaml} (100%) mode change 100644 => 100755 rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-multi-provider.routes.yaml => jwt-multi-route-multi-provider.routes.yaml} (100%) mode change 100644 => 100755 rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-single-provider.clusters.yaml => jwt-multi-route-single-provider.clusters.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-single-provider.endpoints.yaml => jwt-multi-route-single-provider.endpoints.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-single-provider.listeners.yaml => jwt-multi-route-single-provider.listeners.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-multi-route-single-provider.routes.yaml => jwt-multi-route-single-provider.routes.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-ratelimit.clusters.yaml => jwt-ratelimit.clusters.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-ratelimit.endpoints.yaml => jwt-ratelimit.endpoints.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-ratelimit.listeners.yaml => jwt-ratelimit.listeners.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-ratelimit.routes.yaml => jwt-ratelimit.routes.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-single-route-single-match.clusters.yaml => jwt-single-route-single-match.clusters.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-single-route-single-match.endpoints.yaml => jwt-single-route-single-match.endpoints.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-single-route-single-match.listeners.yaml => jwt-single-route-single-match.listeners.yaml} (100%) rename internal/xds/translator/testdata/out/xds-ir/{authn-single-route-single-match.routes.yaml => jwt-single-route-single-match.routes.yaml} (100%) delete mode 100644 site/content/en/latest/design/request-authentication.md rename site/content/en/latest/user/{authn.md => jwt-authentication.md} (67%) diff --git a/api/v1alpha1/cors_types.go b/api/v1alpha1/cors_types.go new file mode 100644 index 00000000000..34a415f903b --- /dev/null +++ b/api/v1alpha1/cors_types.go @@ -0,0 +1,24 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// CORS defines the configuration for Cross-Origin Resource Sharing (CORS). +type CORS struct { + // AllowOrigins defines the origins that are allowed to make requests. + // +kubebuilder:validation:MinItems=1 + AllowOrigins []StringMatch `json:"allowOrigins,omitempty" yaml:"allowOrigins"` + // AllowMethods defines the methods that are allowed to make requests. + // +kubebuilder:validation:MinItems=1 + AllowMethods []string `json:"allowMethods,omitempty" yaml:"allowMethods"` + // AllowHeaders defines the headers that are allowed to be sent with requests. + AllowHeaders []string `json:"allowHeaders,omitempty" yaml:"allowHeaders,omitempty"` + // ExposeHeaders defines the headers that can be exposed in the responses. + ExposeHeaders []string `json:"exposeHeaders,omitempty" yaml:"exposeHeaders,omitempty"` + // MaxAge defines how long the results of a preflight request can be cached. + MaxAge *metav1.Duration `json:"maxAge,omitempty" yaml:"maxAge,omitempty"` +} diff --git a/api/v1alpha1/authenticationfilter_types.go b/api/v1alpha1/jwt_types.go similarity index 54% rename from api/v1alpha1/authenticationfilter_types.go rename to api/v1alpha1/jwt_types.go index 7907ddef2ea..f35ea8e087b 100644 --- a/api/v1alpha1/authenticationfilter_types.go +++ b/api/v1alpha1/jwt_types.go @@ -5,72 +5,22 @@ package v1alpha1 -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) +// JWT defines the configuration for JSON Web Token (JWT) authentication. +type JWT struct { -const ( - // KindAuthenticationFilter is the name of the AuthenticationFilter kind. - KindAuthenticationFilter = "AuthenticationFilter" -) - -// +kubebuilder:object:root=true -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` - -type AuthenticationFilter struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Spec defines the desired state of the AuthenticationFilter type. - Spec AuthenticationFilterSpec `json:"spec"` - - // Note: The status sub-resource has been excluded but may be added in the future. -} - -// ClaimToHeader defines a configuration to convert JWT claims into HTTP headers -type ClaimToHeader struct { - - // Header defines the name of the HTTP request header that the JWT Claim will be saved into. - Header string `json:"header"` - - // Claim is the JWT Claim that should be saved into the header : it can be a nested claim of type - // (eg. "claim.nested.key", "sub"). The nested claim name must use dot "." - // to separate the JSON name path. - Claim string `json:"claim"` -} - -// AuthenticationFilterSpec defines the desired state of the AuthenticationFilter type. -// +union -type AuthenticationFilterSpec struct { - // Type defines the type of authentication provider to use. Supported provider types - // are "JWT". + // Providers defines the JSON Web Token (JWT) authentication provider type. // - // +unionDiscriminator - Type AuthenticationFilterType `json:"type"` - - // JWT defines the JSON Web Token (JWT) authentication provider type. When multiple - // jwtProviders are specified, the JWT is considered valid if any of the providers - // successfully validate the JWT. For additional details, see - // https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter.html. + // When multiple JWT providers are specified, the JWT is considered valid if + // any of the providers successfully validate the JWT. For additional details, + // see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter.html. // + // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=4 - // +optional - JwtProviders []JwtAuthenticationFilterProvider `json:"jwtProviders,omitempty"` + Providers []JWTProvider `json:"providers"` } -// AuthenticationFilterType is a type of authentication provider. -// +kubebuilder:validation:Enum=JWT -type AuthenticationFilterType string - -const ( - // JwtAuthenticationFilterProviderType is a provider that uses JSON Web Token (JWT) - // for authenticating requests.. - JwtAuthenticationFilterProviderType AuthenticationFilterType = "JWT" -) - -// JwtAuthenticationFilterProvider defines the JSON Web Token (JWT) authentication provider type -// and how JWTs should be verified: -type JwtAuthenticationFilterProvider struct { +// JWTProvider defines how a JSON Web Token (JWT) can be verified. +type JWTProvider struct { // Name defines a unique name for the JWT provider. A name can have a variety of forms, // including RFC1123 subdomains, RFC 1123 labels, or RFC 1035 labels. // @@ -120,15 +70,14 @@ type RemoteJWKS struct { // TODO: Add TBD remote JWKS fields based on defined use cases. } -//+kubebuilder:object:root=true +// ClaimToHeader defines a configuration to convert JWT claims into HTTP headers +type ClaimToHeader struct { -// AuthenticationFilterList contains a list of AuthenticationFilter. -type AuthenticationFilterList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []AuthenticationFilter `json:"items"` -} + // Header defines the name of the HTTP request header that the JWT Claim will be saved into. + Header string `json:"header"` -func init() { - SchemeBuilder.Register(&AuthenticationFilter{}, &AuthenticationFilterList{}) + // Claim is the JWT Claim that should be saved into the header : it can be a nested claim of type + // (eg. "claim.nested.key", "sub"). The nested claim name must use dot "." + // to separate the JSON name path. + Claim string `json:"claim"` } diff --git a/api/v1alpha1/securitypolicy_types.go b/api/v1alpha1/securitypolicy_types.go index c64396bff3b..7adece4cbca 100644 --- a/api/v1alpha1/securitypolicy_types.go +++ b/api/v1alpha1/securitypolicy_types.go @@ -54,114 +54,6 @@ type SecurityPolicySpec struct { JWT *JWT `json:"jwt,omitempty"` } -// CORS defines the configuration for Cross-Origin Resource Sharing (CORS). -type CORS struct { - // AllowOrigins defines the origins that are allowed to make requests. - // +kubebuilder:validation:MinItems=1 - AllowOrigins []StringMatch `json:"allowOrigins,omitempty" yaml:"allowOrigins"` - // AllowMethods defines the methods that are allowed to make requests. - // +kubebuilder:validation:MinItems=1 - AllowMethods []string `json:"allowMethods,omitempty" yaml:"allowMethods"` - // AllowHeaders defines the headers that are allowed to be sent with requests. - AllowHeaders []string `json:"allowHeaders,omitempty" yaml:"allowHeaders,omitempty"` - // ExposeHeaders defines the headers that can be exposed in the responses. - ExposeHeaders []string `json:"exposeHeaders,omitempty" yaml:"exposeHeaders,omitempty"` - // MaxAge defines how long the results of a preflight request can be cached. - MaxAge *metav1.Duration `json:"maxAge,omitempty" yaml:"maxAge,omitempty"` -} - -// JWT defines the configuration for JSON Web Token (JWT) authentication. -type JWT struct { - - // Providers defines the JSON Web Token (JWT) authentication provider type. - // - // When multiple JWT providers are specified, the JWT is considered valid if - // any of the providers successfully validate the JWT. For additional details, - // see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter.html. - // - // +kubebuilder:validation:MinItems=1 - // +kubebuilder:validation:MaxItems=4 - Providers []JWTProvider `json:"providers"` -} - -// JWTProvider defines how a JSON Web Token (JWT) can be verified. -type JWTProvider struct { - // Name defines a unique name for the JWT provider. A name can have a variety of forms, - // including RFC1123 subdomains, RFC 1123 labels, or RFC 1035 labels. - // - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=253 - Name string `json:"name"` - - // Issuer is the principal that issued the JWT and takes the form of a URL or email address. - // For additional details, see https://tools.ietf.org/html/rfc7519#section-4.1.1 for - // URL format and https://rfc-editor.org/rfc/rfc5322.html for email format. If not provided, - // the JWT issuer is not checked. - // - // +kubebuilder:validation:MaxLength=253 - // +optional - Issuer string `json:"issuer,omitempty"` - - // Audiences is a list of JWT audiences allowed access. For additional details, see - // https://tools.ietf.org/html/rfc7519#section-4.1.3. If not provided, JWT audiences - // are not checked. - // - // +kubebuilder:validation:MaxItems=8 - // +optional - Audiences []string `json:"audiences,omitempty"` - - // RemoteJWKS defines how to fetch and cache JSON Web Key Sets (JWKS) from a remote - // HTTP/HTTPS endpoint. - RemoteJWKS RemoteJWKS `json:"remoteJWKS"` - - // ClaimToHeaders is a list of JWT claims that must be extracted into HTTP request headers - // For examples, following config: - // The claim must be of type; string, int, double, bool. Array type claims are not supported - // - ClaimToHeaders []ClaimToHeader `json:"claimToHeaders,omitempty"` - // TODO: Add TBD JWT fields based on defined use cases. -} - -// StringMatch defines how to match any strings. -// This is a general purpose match condition that can be used by other EG APIs -// that need to match against a string. -type StringMatch struct { - // Type specifies how to match against a string. - // - // +optional - // +kubebuilder:default=Exact - Type *MatchType `json:"type,omitempty"` - - // Value specifies the string value that the match must have. - // - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=1024 - Value string `json:"value"` -} - -// MatchType specifies the semantics of how a string value should be compared. -// Valid MatchType values are "Exact", "Prefix", "Suffix", "RegularExpression". -// -// +kubebuilder:validation:Enum=Exact;Prefix;Suffix;RegularExpression -type MatchType string - -const ( - // MatchExact :the input string must match exactly the match value. - MatchExact MatchType = "Exact" - - // MatchPrefix :the input string must start with the match value. - MatchPrefix MatchType = "Prefix" - - // MatchSuffix :the input string must end with the match value. - MatchSuffix MatchType = "Suffix" - - // MatchRegularExpression :The input string must match the regular expression - // specified in the match value. - // The regex string must adhere to the syntax documented in - // https://github.com/google/re2/wiki/Syntax. - MatchRegularExpression MatchType = "RegularExpression" -) - // SecurityPolicyStatus defines the state of SecurityPolicy type SecurityPolicyStatus struct { // Conditions describe the current conditions of the SecurityPolicy. diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index bbda8a16ec3..84938be0585 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -235,3 +235,43 @@ const ( XDSHTTPListener XDSTranslatorHook = "HTTPListener" XDSTranslation XDSTranslatorHook = "Translation" ) + +// StringMatch defines how to match any strings. +// This is a general purpose match condition that can be used by other EG APIs +// that need to match against a string. +type StringMatch struct { + // Type specifies how to match against a string. + // + // +optional + // +kubebuilder:default=Exact + Type *MatchType `json:"type,omitempty"` + + // Value specifies the string value that the match must have. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=1024 + Value string `json:"value"` +} + +// MatchType specifies the semantics of how a string value should be compared. +// Valid MatchType values are "Exact", "Prefix", "Suffix", "RegularExpression". +// +// +kubebuilder:validation:Enum=Exact;Prefix;Suffix;RegularExpression +type MatchType string + +const ( + // MatchExact :the input string must match exactly the match value. + MatchExact MatchType = "Exact" + + // MatchPrefix :the input string must start with the match value. + MatchPrefix MatchType = "Prefix" + + // MatchSuffix :the input string must end with the match value. + MatchSuffix MatchType = "Suffix" + + // MatchRegularExpression :The input string must match the regular expression + // specified in the match value. + // The regex string must adhere to the syntax documented in + // https://github.com/google/re2/wiki/Syntax. + MatchRegularExpression MatchType = "RegularExpression" +) diff --git a/api/v1alpha1/validation/authenticationfilter.go b/api/v1alpha1/validation/authenticationfilter.go deleted file mode 100644 index 378a63459fe..00000000000 --- a/api/v1alpha1/validation/authenticationfilter.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright Envoy Gateway Authors -// SPDX-License-Identifier: Apache-2.0 -// The full text of the Apache license is available in the LICENSE file at -// the root of the repo. - -package validation - -import ( - "errors" - "fmt" - "net/mail" - "net/url" - - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apimachinery/pkg/util/validation" - - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" -) - -// TODO zhaohuabing remove this file after deprecating authentication filter -// ValidateAuthenticationFilter validates the provided filter. The only supported -// ValidateAuthenticationFilter type is "JWT". -func ValidateAuthenticationFilter(filter *egv1a1.AuthenticationFilter) error { - var errs []error - if filter == nil { - return errors.New("filter is nil") - } - if err := validateAuthenticationFilterSpec(&filter.Spec); err != nil { - errs = append(errs, errors.New("filter is nil")) - } - - return utilerrors.NewAggregate(errs) -} - -// validateAuthenticationFilterSpec validates the provided spec. The only supported -// ValidateAuthenticationFilter type is "JWT". -func validateAuthenticationFilterSpec(spec *egv1a1.AuthenticationFilterSpec) error { - var errs []error - - switch { - case spec == nil: - errs = append(errs, errors.New("spec is nil")) - case spec.Type != egv1a1.JwtAuthenticationFilterProviderType: - errs = append(errs, fmt.Errorf("unsupported authenticationfilter type: %v", spec.Type)) - case len(spec.JwtProviders) == 0: - errs = append(errs, fmt.Errorf("at least one provider must be specified for type %v", spec.Type)) - } - - // Return early if any errors exist. - if len(errs) != 0 { - return utilerrors.NewAggregate(errs) - } - - if err := ValidateJwtProviders(spec.JwtProviders); err != nil { - errs = append(errs, err) - } - - return utilerrors.NewAggregate(errs) -} - -// ValidateJwtProviders validates the provided JWT authentication filter providers. -func ValidateJwtProviders(providers []egv1a1.JwtAuthenticationFilterProvider) error { - var errs []error - - var names []string - for _, provider := range providers { - switch { - case len(provider.Name) == 0: - errs = append(errs, errors.New("jwt provider cannot be an empty string")) - case len(provider.Issuer) != 0: - // Issuer can take the format of a URL or an email address. - if _, err := url.ParseRequestURI(provider.Issuer); err != nil { - _, err := mail.ParseAddress(provider.Issuer) - if err != nil { - errs = append(errs, fmt.Errorf("invalid issuer; must be a URL or email address: %v", err)) - } - } - case len(provider.RemoteJWKS.URI) == 0: - errs = append(errs, fmt.Errorf("uri must be set for remote JWKS provider: %s", provider.Name)) - } - if _, err := url.ParseRequestURI(provider.RemoteJWKS.URI); err != nil { - errs = append(errs, fmt.Errorf("invalid remote JWKS URI: %v", err)) - } - - if len(errs) == 0 { - if strErrs := validation.IsQualifiedName(provider.Name); len(strErrs) != 0 { - for _, strErr := range strErrs { - errs = append(errs, errors.New(strErr)) - } - } - // Ensure uniqueness among provider names. - if names == nil { - names = append(names, provider.Name) - } else { - for _, name := range names { - if name == provider.Name { - errs = append(errs, fmt.Errorf("provider name %s must be unique", provider.Name)) - } else { - names = append(names, provider.Name) - } - } - } - } - - for _, claimToHeader := range provider.ClaimToHeaders { - switch { - case len(claimToHeader.Header) == 0: - errs = append(errs, fmt.Errorf("header must be set for claimToHeader provider: %s", claimToHeader.Header)) - case len(claimToHeader.Claim) == 0: - errs = append(errs, fmt.Errorf("claim must be set for claimToHeader provider: %s", claimToHeader.Claim)) - } - } - } - - return utilerrors.NewAggregate(errs) -} diff --git a/api/v1alpha1/validation/authenticationfilter_test.go b/api/v1alpha1/validation/authenticationfilter_test.go deleted file mode 100644 index 86470be158f..00000000000 --- a/api/v1alpha1/validation/authenticationfilter_test.go +++ /dev/null @@ -1,451 +0,0 @@ -// Copyright Envoy Gateway Authors -// SPDX-License-Identifier: Apache-2.0 -// The full text of the Apache license is available in the LICENSE file at -// the root of the repo. - -package validation - -import ( - "testing" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" -) - -// TODO zhaohuabing remove this file after deprecating authentication filter -func TestValidateAuthenticationFilter(t *testing.T) { - testCases := []struct { - name string - filter *egv1a1.AuthenticationFilter - expected bool - }{ - { - name: "nil authentication filter", - filter: nil, - expected: false, - }, - { - name: "valid authentication filter with url", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: true, - }, - { - name: "valid authentication filter with email", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "test@test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: true, - }, - { - name: "valid authentication filter with jwtClaimToHeader", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "test@test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - ClaimToHeaders: []egv1a1.ClaimToHeader{ - { - Header: "test", - Claim: "test", - }, - }, - }, - }, - }, - }, - expected: true, - }, - { - name: "unqualified authentication provider name", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "unqualified_...", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "unspecified provider name", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "non unique provider names", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "unique", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - { - Name: "non-unique", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - { - Name: "non-unique", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "invalid issuer uri", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "http://invalid url.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "http://www.test.local", - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "inivalid issuer email", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "test@!123...", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "invalid remote jwks uri", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "http://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "invalid/local", - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "unspecified remote jwks uri", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "", - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "unspecified jwtClaimToHeader headerName", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "test@test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - ClaimToHeaders: []egv1a1.ClaimToHeader{ - { - Header: "", - Claim: "test", - }, - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "unspecified jwtClaimToHeader claimName", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "test@test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - ClaimToHeaders: []egv1a1.ClaimToHeader{ - { - Header: "test", - Claim: "", - }, - }, - }, - }, - }, - }, - expected: false, - }, - { - name: "unspecified issuer", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: true, - }, - { - name: "unspecified audiences", - filter: &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "https://www.test.local", - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - expected: true, - }, - } - - for i := range testCases { - tc := testCases[i] - t.Run(tc.name, func(t *testing.T) { - err := ValidateAuthenticationFilter(tc.filter) - if tc.expected { - require.NoError(t, err) - } else { - require.Error(t, err) - } - }) - } -} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 603df02472e..cfbcad0acb7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -17,86 +17,6 @@ import ( apisv1 "sigs.k8s.io/gateway-api/apis/v1" ) -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AuthenticationFilter) DeepCopyInto(out *AuthenticationFilter) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationFilter. -func (in *AuthenticationFilter) DeepCopy() *AuthenticationFilter { - if in == nil { - return nil - } - out := new(AuthenticationFilter) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *AuthenticationFilter) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AuthenticationFilterList) DeepCopyInto(out *AuthenticationFilterList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]AuthenticationFilter, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationFilterList. -func (in *AuthenticationFilterList) DeepCopy() *AuthenticationFilterList { - if in == nil { - return nil - } - out := new(AuthenticationFilterList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *AuthenticationFilterList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AuthenticationFilterSpec) DeepCopyInto(out *AuthenticationFilterSpec) { - *out = *in - if in.JwtProviders != nil { - in, out := &in.JwtProviders, &out.JwtProviders - *out = make([]JwtAuthenticationFilterProvider, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationFilterSpec. -func (in *AuthenticationFilterSpec) DeepCopy() *AuthenticationFilterSpec { - if in == nil { - return nil - } - out := new(AuthenticationFilterSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BackendTrafficPolicy) DeepCopyInto(out *BackendTrafficPolicy) { *out = *in @@ -1346,32 +1266,6 @@ func (in *JWTProvider) DeepCopy() *JWTProvider { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JwtAuthenticationFilterProvider) DeepCopyInto(out *JwtAuthenticationFilterProvider) { - *out = *in - if in.Audiences != nil { - in, out := &in.Audiences, &out.Audiences - *out = make([]string, len(*in)) - copy(*out, *in) - } - out.RemoteJWKS = in.RemoteJWKS - if in.ClaimToHeaders != nil { - in, out := &in.ClaimToHeaders, &out.ClaimToHeaders - *out = make([]ClaimToHeader, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JwtAuthenticationFilterProvider. -func (in *JwtAuthenticationFilterProvider) DeepCopy() *JwtAuthenticationFilterProvider { - if in == nil { - return nil - } - out := new(JwtAuthenticationFilterProvider) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubernetesContainerSpec) DeepCopyInto(out *KubernetesContainerSpec) { *out = *in diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_authenticationfilters.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_authenticationfilters.yaml deleted file mode 100644 index 8c85e6ca6d1..00000000000 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_authenticationfilters.yaml +++ /dev/null @@ -1,131 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.13.0 - name: authenticationfilters.gateway.envoyproxy.io -spec: - group: gateway.envoyproxy.io - names: - kind: AuthenticationFilter - listKind: AuthenticationFilterList - plural: authenticationfilters - singular: authenticationfilter - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of the AuthenticationFilter - type. - properties: - jwtProviders: - description: JWT defines the JSON Web Token (JWT) authentication provider - type. When multiple jwtProviders are specified, the JWT is considered - valid if any of the providers successfully validate the JWT. For - additional details, see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter.html. - items: - description: 'JwtAuthenticationFilterProvider defines the JSON Web - Token (JWT) authentication provider type and how JWTs should be - verified:' - properties: - audiences: - description: Audiences is a list of JWT audiences allowed access. - For additional details, see https://tools.ietf.org/html/rfc7519#section-4.1.3. - If not provided, JWT audiences are not checked. - items: - type: string - maxItems: 8 - type: array - claimToHeaders: - description: 'ClaimToHeaders is a list of JWT claims that must - be extracted into HTTP request headers For examples, following - config: The claim must be of type; string, int, double, bool. - Array type claims are not supported' - items: - description: ClaimToHeader defines a configuration to convert - JWT claims into HTTP headers - properties: - claim: - description: 'Claim is the JWT Claim that should be saved - into the header : it can be a nested claim of type (eg. - "claim.nested.key", "sub"). The nested claim name must - use dot "." to separate the JSON name path.' - type: string - header: - description: Header defines the name of the HTTP request - header that the JWT Claim will be saved into. - type: string - required: - - claim - - header - type: object - type: array - issuer: - description: Issuer is the principal that issued the JWT and - takes the form of a URL or email address. For additional details, - see https://tools.ietf.org/html/rfc7519#section-4.1.1 for - URL format and https://rfc-editor.org/rfc/rfc5322.html for - email format. If not provided, the JWT issuer is not checked. - maxLength: 253 - type: string - name: - description: Name defines a unique name for the JWT provider. - A name can have a variety of forms, including RFC1123 subdomains, - RFC 1123 labels, or RFC 1035 labels. - maxLength: 253 - minLength: 1 - type: string - remoteJWKS: - description: RemoteJWKS defines how to fetch and cache JSON - Web Key Sets (JWKS) from a remote HTTP/HTTPS endpoint. - properties: - uri: - description: URI is the HTTPS URI to fetch the JWKS. Envoy's - system trust bundle is used to validate the server certificate. - maxLength: 253 - minLength: 1 - type: string - required: - - uri - type: object - required: - - name - - remoteJWKS - type: object - maxItems: 4 - type: array - type: - description: Type defines the type of authentication provider to use. - Supported provider types are "JWT". - enum: - - JWT - type: string - required: - - type - type: object - required: - - spec - type: object - served: true - storage: true - subresources: {} diff --git a/charts/gateway-helm/templates/_rbac.tpl b/charts/gateway-helm/templates/_rbac.tpl index f0107bb6fe1..68cbe6be8fa 100644 --- a/charts/gateway-helm/templates/_rbac.tpl +++ b/charts/gateway-helm/templates/_rbac.tpl @@ -64,12 +64,10 @@ apiGroups: - gateway.envoyproxy.io resources: - envoyproxies -- authenticationfilters - envoypatchpolicies - clienttrafficpolicies - backendtrafficpolicies - securitypolicies -- ratelimitfilters verbs: - get - list diff --git a/examples/kubernetes/authn/grpc-jwt.yaml b/examples/kubernetes/jwt/grpc-jwt.yaml similarity index 53% rename from examples/kubernetes/authn/grpc-jwt.yaml rename to examples/kubernetes/jwt/grpc-jwt.yaml index 7fa0e048f85..a5da840eb66 100644 --- a/examples/kubernetes/authn/grpc-jwt.yaml +++ b/examples/kubernetes/jwt/grpc-jwt.yaml @@ -1,13 +1,17 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter +kind: SecurityPolicy metadata: name: jwt-example spec: - type: JWT - jwtProviders: - - name: example - remoteJWKS: - uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json + targetRef: + group: gateway.networking.k8s.io + kind: GRPCRoute + name: yages + jwt: + providers: + - name: example + remoteJWKS: + uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json --- apiVersion: gateway.networking.k8s.io/v1alpha2 kind: GRPCRoute @@ -27,9 +31,3 @@ spec: name: yages port: 9000 weight: 1 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: jwt-example - type: ExtensionRef diff --git a/examples/kubernetes/authn/jwks.json b/examples/kubernetes/jwt/jwks.json similarity index 100% rename from examples/kubernetes/authn/jwks.json rename to examples/kubernetes/jwt/jwks.json diff --git a/examples/kubernetes/authn/jwt.yaml b/examples/kubernetes/jwt/jwt.yaml similarity index 56% rename from examples/kubernetes/authn/jwt.yaml rename to examples/kubernetes/jwt/jwt.yaml index 86e78eb1b20..dcf580edde9 100644 --- a/examples/kubernetes/authn/jwt.yaml +++ b/examples/kubernetes/jwt/jwt.yaml @@ -1,18 +1,22 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter +kind: SecurityPolicy metadata: name: jwt-example spec: - type: JWT - jwtProviders: - - name: example - remoteJWKS: - uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: foo + jwt: + providers: + - name: example + remoteJWKS: + uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: - name: backend + name: foo spec: parentRefs: - name: eg @@ -25,16 +29,21 @@ spec: name: backend port: 3000 weight: 1 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: jwt-example - type: ExtensionRef matches: - path: type: PathPrefix value: /foo +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: bar +spec: + parentRefs: + - name: eg + hostnames: + - "www.example.com" + rules: - backendRefs: - group: "" kind: Service diff --git a/examples/kubernetes/authn/test.jwt b/examples/kubernetes/jwt/test.jwt similarity index 100% rename from examples/kubernetes/authn/test.jwt rename to examples/kubernetes/jwt/test.jwt diff --git a/examples/kubernetes/authn/with-different-claim.jwt b/examples/kubernetes/jwt/with-different-claim.jwt similarity index 100% rename from examples/kubernetes/authn/with-different-claim.jwt rename to examples/kubernetes/jwt/with-different-claim.jwt diff --git a/internal/cmd/egctl/testdata/translate/in/authn-single-route-single-match-to-xds.yaml b/internal/cmd/egctl/testdata/translate/in/jwt-single-route-single-match-to-xds.yaml similarity index 83% rename from internal/cmd/egctl/testdata/translate/in/authn-single-route-single-match-to-xds.yaml rename to internal/cmd/egctl/testdata/translate/in/jwt-single-route-single-match-to-xds.yaml index ca56711986b..2b41c1a3eb4 100644 --- a/internal/cmd/egctl/testdata/translate/in/authn-single-route-single-match-to-xds.yaml +++ b/internal/cmd/egctl/testdata/translate/in/jwt-single-route-single-match-to-xds.yaml @@ -71,15 +71,19 @@ spec: fieldPath: metadata.namespace --- apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter +kind: SecurityPolicy metadata: name: jwt-example spec: - type: JWT - jwtProviders: - - name: example - remoteJWKS: - uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: backend + jwt: + providers: + - name: example + remoteJWKS: + uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -97,12 +101,6 @@ spec: name: backend port: 3000 weight: 1 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: jwt-example - type: ExtensionRef matches: - path: type: PathPrefix diff --git a/internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.all.json b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.json similarity index 100% rename from internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.all.json rename to internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.json diff --git a/internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.all.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.yaml similarity index 100% rename from internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.all.yaml rename to internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.all.yaml diff --git a/internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.bootstrap.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.bootstrap.yaml similarity index 100% rename from internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.bootstrap.yaml rename to internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.bootstrap.yaml diff --git a/internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.cluster.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.cluster.yaml similarity index 100% rename from internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.cluster.yaml rename to internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.cluster.yaml diff --git a/internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.endpoint.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.endpoint.yaml similarity index 100% rename from internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.endpoint.yaml rename to internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.endpoint.yaml diff --git a/internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.listener.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.listener.yaml similarity index 100% rename from internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.listener.yaml rename to internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.listener.yaml diff --git a/internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.route.yaml b/internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.route.yaml similarity index 100% rename from internal/cmd/egctl/testdata/translate/out/authn-single-route-single-match-to-xds.route.yaml rename to internal/cmd/egctl/testdata/translate/out/jwt-single-route-single-match-to-xds.route.yaml diff --git a/internal/cmd/egctl/translate.go b/internal/cmd/egctl/translate.go index 5850f96a1fa..47ab944f424 100644 --- a/internal/cmd/egctl/translate.go +++ b/internal/cmd/egctl/translate.go @@ -738,34 +738,62 @@ func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayap Spec: typedSpec.(v1.ServiceSpec), } resources.Services = append(resources.Services, service) - case egv1a1.KindAuthenticationFilter: + case egv1a1.KindEnvoyPatchPolicy: typedSpec := spec.Interface() - authenticationFilter := &egv1a1.AuthenticationFilter{ + envoyPatchPolicy := &egv1a1.EnvoyPatchPolicy{ TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, + Kind: egv1a1.KindEnvoyPatchPolicy, APIVersion: egv1a1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: name, }, - Spec: typedSpec.(egv1a1.AuthenticationFilterSpec), + Spec: typedSpec.(egv1a1.EnvoyPatchPolicySpec), } - resources.AuthenticationFilters = append(resources.AuthenticationFilters, authenticationFilter) - case egv1a1.KindEnvoyPatchPolicy: + resources.EnvoyPatchPolicies = append(resources.EnvoyPatchPolicies, envoyPatchPolicy) + case egv1a1.KindClientTrafficPolicy: typedSpec := spec.Interface() - envoyPatchPolicy := &egv1a1.EnvoyPatchPolicy{ + clientTrafficPolicy := &egv1a1.ClientTrafficPolicy{ TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindEnvoyPatchPolicy, + Kind: egv1a1.KindClientTrafficPolicy, APIVersion: egv1a1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: name, }, - Spec: typedSpec.(egv1a1.EnvoyPatchPolicySpec), + Spec: typedSpec.(egv1a1.ClientTrafficPolicySpec), } - resources.EnvoyPatchPolicies = append(resources.EnvoyPatchPolicies, envoyPatchPolicy) + resources.ClientTrafficPolicies = append(resources.ClientTrafficPolicies, clientTrafficPolicy) + case egv1a1.KindBackendTrafficPolicy: + typedSpec := spec.Interface() + backendTrafficPolicy := &egv1a1.BackendTrafficPolicy{ + TypeMeta: metav1.TypeMeta{ + Kind: egv1a1.KindBackendTrafficPolicy, + APIVersion: egv1a1.GroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + Spec: typedSpec.(egv1a1.BackendTrafficPolicySpec), + } + resources.BackendTrafficPolicies = append(resources.BackendTrafficPolicies, backendTrafficPolicy) + case egv1a1.KindSecurityPolicy: + typedSpec := spec.Interface() + securityPolicy := &egv1a1.SecurityPolicy{ + TypeMeta: metav1.TypeMeta{ + Kind: egv1a1.KindSecurityPolicy, + APIVersion: egv1a1.GroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + Spec: typedSpec.(egv1a1.SecurityPolicySpec), + } + resources.SecurityPolicies = append(resources.SecurityPolicies, securityPolicy) } } diff --git a/internal/cmd/egctl/translate_test.go b/internal/cmd/egctl/translate_test.go index 03ab44345a1..d9cd598174a 100644 --- a/internal/cmd/egctl/translate_test.go +++ b/internal/cmd/egctl/translate_test.go @@ -111,27 +111,27 @@ func TestTranslate(t *testing.T) { expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: jsonOutput, expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: yamlOutput, expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: yamlOutput, @@ -139,7 +139,7 @@ func TestTranslate(t *testing.T) { expect: false, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: yamlOutput, @@ -147,7 +147,7 @@ func TestTranslate(t *testing.T) { expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: yamlOutput, @@ -155,7 +155,7 @@ func TestTranslate(t *testing.T) { expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: yamlOutput, @@ -163,7 +163,7 @@ func TestTranslate(t *testing.T) { expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: yamlOutput, @@ -171,7 +171,7 @@ func TestTranslate(t *testing.T) { expect: true, }, { - name: "authn-single-route-single-match-to-xds", + name: "jwt-single-route-single-match-to-xds", from: "gateway-api", to: "xds", output: yamlOutput, diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go index 961b2fd6ec4..73dcf54ca7f 100644 --- a/internal/gatewayapi/filters.go +++ b/internal/gatewayapi/filters.go @@ -13,7 +13,6 @@ import ( gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" "sigs.k8s.io/gateway-api/apis/v1alpha2" - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/ir" ) @@ -57,8 +56,6 @@ type HTTPFilterIR struct { Mirrors []*ir.RouteDestination - RequestAuthentication *ir.RequestAuthentication - ExtensionRefs []*ir.UnstructuredRef } @@ -662,21 +659,6 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjec } filterNs := filterContext.Route.GetNamespace() - // Set the filter context and return early if a matching AuthenticationFilter is found. - if string(extFilter.Kind) == egv1a1.KindAuthenticationFilter { - for _, authenFilter := range resources.AuthenticationFilters { - if authenFilter.Namespace == filterNs && - authenFilter.Name == string(extFilter.Name) { - filterContext.HTTPFilterIR.RequestAuthentication = &ir.RequestAuthentication{ - JWT: &ir.JwtRequestAuthentication{ - Providers: authenFilter.Spec.JwtProviders, - }, - } - return - } - } - } - // This list of resources will be empty unless an extension is loaded (and introduces resources) for _, res := range resources.ExtensionRefFilters { if res.GetKind() == string(extFilter.Kind) && res.GetName() == string(extFilter.Name) && res.GetNamespace() == filterNs { diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index fc221085af3..1c5392262a9 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -16,7 +16,6 @@ import ( gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" "sigs.k8s.io/gateway-api/apis/v1alpha2" - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/ir" ) @@ -189,9 +188,6 @@ func ValidateHTTPRouteFilter(filter *gwapiv1.HTTPRouteFilter, extGKs ...schema.G switch { case filter.ExtensionRef == nil: return errors.New("extensionRef field must be specified for an extended filter") - case string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter: - return nil default: for _, gk := range extGKs { if filter.ExtensionRef.Group == gwapiv1.Group(gk.Group) && @@ -206,14 +202,6 @@ func ValidateHTTPRouteFilter(filter *gwapiv1.HTTPRouteFilter, extGKs ...schema.G } } -// IsAuthnHTTPFilter returns true if the provided filter is an AuthenticationFilter. -func IsAuthnHTTPFilter(filter *gwapiv1.HTTPRouteFilter) bool { - return filter.Type == gwapiv1.HTTPRouteFilterExtensionRef && - filter.ExtensionRef != nil && - string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter -} - // ValidateGRPCRouteFilter validates the provided filter within GRPCRoute. func ValidateGRPCRouteFilter(filter *v1alpha2.GRPCRouteFilter, extGKs ...schema.GroupKind) error { switch { @@ -227,9 +215,6 @@ func ValidateGRPCRouteFilter(filter *v1alpha2.GRPCRouteFilter, extGKs ...schema. switch { case filter.ExtensionRef == nil: return errors.New("extensionRef field must be specified for an extended filter") - case string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter: - return nil default: for _, gk := range extGKs { if filter.ExtensionRef.Group == gwapiv1.Group(gk.Group) && @@ -244,14 +229,6 @@ func ValidateGRPCRouteFilter(filter *v1alpha2.GRPCRouteFilter, extGKs ...schema. } } -// IsAuthnGRPCFilter returns true if the provided filter is an AuthenticationFilter. -func IsAuthnGRPCFilter(filter *v1alpha2.GRPCRouteFilter) bool { - return filter.Type == v1alpha2.GRPCRouteFilterExtensionRef && - filter.ExtensionRef != nil && - string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter -} - // GatewayOwnerLabels returns the Gateway Owner labels using // the provided namespace and name as the values. func GatewayOwnerLabels(namespace, name string) map[string]string { diff --git a/internal/gatewayapi/helpers_test.go b/internal/gatewayapi/helpers_test.go index 6ded00f8c72..6c8f6623067 100644 --- a/internal/gatewayapi/helpers_test.go +++ b/internal/gatewayapi/helpers_test.go @@ -18,8 +18,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" ) func TestValidateGRPCFilterRef(t *testing.T) { @@ -92,42 +90,6 @@ func TestValidateGRPCFilterRef(t *testing.T) { }, expected: false, }, - { - name: "invalid authenticationfilter group", - filter: &gwapiv1a2.GRPCRouteFilter{ - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: "UnsupportedGroup", - Kind: egv1a1.KindAuthenticationFilter, - Name: "test", - }, - }, - expected: false, - }, - { - name: "invalid authenticationfilter kind", - filter: &gwapiv1a2.GRPCRouteFilter{ - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: "UnsupportedKind", - Name: "test", - }, - }, - expected: false, - }, - { - name: "valid authenticationfilter", - filter: &gwapiv1a2.GRPCRouteFilter{ - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: egv1a1.KindAuthenticationFilter, - Name: "test", - }, - }, - expected: true, - }, } for _, tc := range testCases { tc := tc @@ -195,42 +157,6 @@ func TestValidateHTTPFilterRef(t *testing.T) { }, expected: false, }, - { - name: "invalid authenticationfilter group", - filter: &gwapiv1.HTTPRouteFilter{ - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: "UnsupportedGroup", - Kind: egv1a1.KindAuthenticationFilter, - Name: "test", - }, - }, - expected: false, - }, - { - name: "invalid authenticationfilter kind", - filter: &gwapiv1.HTTPRouteFilter{ - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: "UnsupportedKind", - Name: "test", - }, - }, - expected: false, - }, - { - name: "valid authenticationfilter", - filter: &gwapiv1.HTTPRouteFilter{ - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: egv1a1.KindAuthenticationFilter, - Name: "test", - }, - }, - expected: true, - }, { name: "valid extension resource", filter: &gwapiv1.HTTPRouteFilter{ diff --git a/internal/gatewayapi/resource.go b/internal/gatewayapi/resource.go index 6bd0fc4f696..2251d346674 100644 --- a/internal/gatewayapi/resource.go +++ b/internal/gatewayapi/resource.go @@ -40,7 +40,6 @@ type Resources struct { ServiceImports []*mcsapi.ServiceImport `json:"serviceImports,omitempty" yaml:"serviceImports,omitempty"` EndpointSlices []*discoveryv1.EndpointSlice `json:"endpointSlices,omitempty" yaml:"endpointSlices,omitempty"` Secrets []*v1.Secret `json:"secrets,omitempty" yaml:"secrets,omitempty"` - AuthenticationFilters []*egv1a1.AuthenticationFilter `json:"authenticationFilters,omitempty" yaml:"authenticationFilters,omitempty"` EnvoyProxy *egv1a1.EnvoyProxy `json:"envoyProxy,omitempty" yaml:"envoyProxy,omitempty"` ExtensionRefFilters []unstructured.Unstructured `json:"extensionRefFilters,omitempty" yaml:"extensionRefFilters,omitempty"` EnvoyPatchPolicies []*egv1a1.EnvoyPatchPolicy `json:"envoyPatchPolicies,omitempty" yaml:"envoyPatchPolicies,omitempty"` @@ -60,7 +59,6 @@ func NewResources() *Resources { Secrets: []*v1.Secret{}, ReferenceGrants: []*gwapiv1b1.ReferenceGrant{}, Namespaces: []*v1.Namespace{}, - AuthenticationFilters: []*egv1a1.AuthenticationFilter{}, ExtensionRefFilters: []unstructured.Unstructured{}, EnvoyPatchPolicies: []*egv1a1.EnvoyPatchPolicy{}, ClientTrafficPolicies: []*egv1a1.ClientTrafficPolicy{}, diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index fed00642f59..90814694d50 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -314,9 +314,6 @@ func applyHTTPFiltersContextToIRRoute(httpFiltersContext *HTTPFiltersContext, ir if httpFiltersContext.Mirrors != nil { irRoute.Mirrors = httpFiltersContext.Mirrors } - if httpFiltersContext.RequestAuthentication != nil { - irRoute.RequestAuthentication = httpFiltersContext.RequestAuthentication - } if len(httpFiltersContext.ExtensionRefs) > 0 { irRoute.ExtensionRefs = httpFiltersContext.ExtensionRefs @@ -557,8 +554,9 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route DirectResponse: routeRoute.DirectResponse, URLRewrite: routeRoute.URLRewrite, Mirrors: routeRoute.Mirrors, - RequestAuthentication: routeRoute.RequestAuthentication, RateLimit: routeRoute.RateLimit, + CORS: routeRoute.CORS, + JWT: routeRoute.JWT, Timeout: routeRoute.Timeout, ExtensionRefs: routeRoute.ExtensionRefs, } diff --git a/internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.in.yaml b/internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.in.yaml deleted file mode 100644 index 9c46c74c843..00000000000 --- a/internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.in.yaml +++ /dev/null @@ -1,49 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - allowedRoutes: - namespaces: - from: All -grpcRoutes: -- apiVersion: gateway.networking.k8s.io/v1alpha2 - kind: GRPCRoute - metadata: - namespace: default - name: grpcroute-1 - spec: - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - backendRefs: - - name: service-1 - port: 8080 -authenticationFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: AuthenticationFilter - metadata: - namespace: default - name: test - spec: - type: JWT - jwtProviders: - - name: test - issuer: https://www.test.local - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.out.yaml b/internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.out.yaml deleted file mode 100644 index b36321651d8..00000000000 --- a/internal/gatewayapi/testdata/grpcroute-with-valid-authenfilter.out.yaml +++ /dev/null @@ -1,128 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -grpcRoutes: -- apiVersion: gateway.networking.k8s.io/v1alpha2 - kind: GRPCRoute - metadata: - creationTimestamp: null - name: grpcroute-1 - namespace: default - spec: - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - type: ExtensionRef - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*' - isHTTP2: true - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: grpcroute/default/grpcroute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: '*' - name: grpcroute/default/grpcroute-1/rule/0/match/-1/* - requestAuthentication: - jwt: - providers: - - issuer: https://www.test.local - name: test - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.in.yaml b/internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.in.yaml deleted file mode 100644 index 5785df85e16..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.in.yaml +++ /dev/null @@ -1,43 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: non-exist - diff --git a/internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.out.yaml b/internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.out.yaml deleted file mode 100644 index 919f22bf257..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-non-existent-authenfilter-ref.out.yaml +++ /dev/null @@ -1,114 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 0 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: non-exist - type: ExtensionRef - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: 'Reference default/non-exist not found for filter type: AuthenticationFilter' - reason: UnsupportedValue - status: "False" - type: Accepted - - lastTransitionTime: null - message: 'Reference default/non-exist not found for filter type: AuthenticationFilter' - reason: BackendNotFound - status: "False" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 diff --git a/internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.in.yaml b/internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.in.yaml deleted file mode 100644 index 86569b96053..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.in.yaml +++ /dev/null @@ -1,57 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test -authenticationFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: AuthenticationFilter - metadata: - name: example1 - namespace: default - spec: - type: JWT - jwtProviders: - - name: example1 - issuer: https://www.example1.com - audiences: - - foo.com - remoteJwks: - uri: https://foo.com/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.out.yaml b/internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.out.yaml deleted file mode 100644 index b61269b4370..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-non-matching-authenfilter-ref.out.yaml +++ /dev/null @@ -1,114 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 0 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - type: ExtensionRef - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: 'Reference default/test not found for filter type: AuthenticationFilter' - reason: UnsupportedValue - status: "False" - type: Accepted - - lastTransitionTime: null - message: 'Reference default/test not found for filter type: AuthenticationFilter' - reason: BackendNotFound - status: "False" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 diff --git a/internal/gatewayapi/testdata/httproute-with-valid-authenfilter.in.yaml b/internal/gatewayapi/testdata/httproute-with-valid-authenfilter.in.yaml deleted file mode 100644 index 9534510f851..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-authenfilter.in.yaml +++ /dev/null @@ -1,55 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test -authenticationFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: AuthenticationFilter - metadata: - namespace: default - name: test - spec: - type: JWT - jwtProviders: - - name: test - issuer: https://www.test.local - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/httproute-with-valid-authenfilter.out.yaml b/internal/gatewayapi/testdata/httproute-with-valid-authenfilter.out.yaml deleted file mode 100644 index ef2b7de94f8..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-authenfilter.out.yaml +++ /dev/null @@ -1,138 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - type: ExtensionRef - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - name: "" - prefix: / - requestAuthentication: - jwt: - providers: - - issuer: https://www.test.local - name: test - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.in.yaml b/internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.in.yaml deleted file mode 100644 index 2517962aefd..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.in.yaml +++ /dev/null @@ -1,69 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - type: Exact - value: "/test/path/1" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - - matches: - - path: - type: Exact - value: "/test/path/2" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test -authenticationFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: AuthenticationFilter - metadata: - namespace: default - name: test - spec: - type: JWT - jwtProviders: - - name: test - issuer: https://www.test.local - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.out.yaml b/internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.out.yaml deleted file mode 100644 index e88afb72488..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-authenfilter.out.yaml +++ /dev/null @@ -1,175 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - type: ExtensionRef - matches: - - path: - type: Exact - value: /test/path/1 - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - type: ExtensionRef - matches: - - path: - type: Exact - value: /test/path/2 - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - exact: /test/path/1 - name: "" - requestAuthentication: - jwt: - providers: - - issuer: https://www.test.local - name: test - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/1 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/1/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - exact: /test/path/2 - name: "" - requestAuthentication: - jwt: - providers: - - issuer: https://www.test.local - name: test - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.in.yaml b/internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.in.yaml deleted file mode 100644 index 22460f60151..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.in.yaml +++ /dev/null @@ -1,85 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - type: Exact - value: "/test/path/1" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test1 - - matches: - - path: - type: Exact - value: "/test/path/2" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test2 -authenticationFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: AuthenticationFilter - metadata: - namespace: default - name: test1 - spec: - type: JWT - jwtProviders: - - name: test1 - issuer: https://www.test1.local - remoteJWKS: - uri: https://test1.local/jwt/public-key/jwks.json -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: AuthenticationFilter - metadata: - namespace: default - name: test2 - spec: - type: JWT - jwtProviders: - - name: test2 - issuer: https://www.test2.local - remoteJWKS: - uri: https://test2.local/jwt/public-key/jwks.json - - name: test3 - issuer: https://www.test3.local - remoteJWKS: - uri: https://test3.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.out.yaml b/internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.out.yaml deleted file mode 100644 index 9cc518431ef..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-multi-match-multi-authenfilter.out.yaml +++ /dev/null @@ -1,179 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test1 - type: ExtensionRef - matches: - - path: - type: Exact - value: /test/path/1 - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test2 - type: ExtensionRef - matches: - - path: - type: Exact - value: /test/path/2 - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - exact: /test/path/1 - name: "" - requestAuthentication: - jwt: - providers: - - issuer: https://www.test1.local - name: test1 - remoteJWKS: - uri: https://test1.local/jwt/public-key/jwks.json - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/1 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/1/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - exact: /test/path/2 - name: "" - requestAuthentication: - jwt: - providers: - - issuer: https://www.test2.local - name: test2 - remoteJWKS: - uri: https://test2.local/jwt/public-key/jwks.json - - issuer: https://www.test3.local - name: test3 - remoteJWKS: - uri: https://test3.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml index aeca411f058..b88c25a8808 100644 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml @@ -60,12 +60,6 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: @@ -85,16 +79,3 @@ httpRoutes: backendRefs: - name: service-2 port: 8080 -authenticationFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: AuthenticationFilter - metadata: - namespace: default - name: test - spec: - type: JWT - jwtProviders: - - name: test - issuer: https://www.test.local - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml index 1f91380625f..b7a57690426 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml @@ -125,12 +125,6 @@ httpRoutes: - backendRefs: - name: service-1 port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: test - type: ExtensionRef matches: - path: value: / @@ -248,13 +242,6 @@ xdsIR: distinct: false name: "" prefix: / - requestAuthentication: - jwt: - providers: - - issuer: https://www.test.local - name: test - remoteJWKS: - uri: https://test.local/jwt/public-key/jwks.json - address: 0.0.0.0 hostnames: - '*' diff --git a/internal/gatewayapi/zz_generated.deepcopy.go b/internal/gatewayapi/zz_generated.deepcopy.go index 56969b4480a..56335dc5bc9 100644 --- a/internal/gatewayapi/zz_generated.deepcopy.go +++ b/internal/gatewayapi/zz_generated.deepcopy.go @@ -160,17 +160,6 @@ func (in *Resources) DeepCopyInto(out *Resources) { } } } - if in.AuthenticationFilters != nil { - in, out := &in.AuthenticationFilters, &out.AuthenticationFilters - *out = make([]*apiv1alpha1.AuthenticationFilter, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(apiv1alpha1.AuthenticationFilter) - (*in).DeepCopyInto(*out) - } - } - } if in.EnvoyProxy != nil { in, out := &in.EnvoyProxy, &out.EnvoyProxy *out = new(apiv1alpha1.EnvoyProxy) diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 6a7a0041918..c0aa13ffbf6 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -44,7 +44,6 @@ var ( ErrAddHeaderEmptyName = errors.New("header modifier filter cannot configure a header without a name to be added") ErrAddHeaderDuplicate = errors.New("header modifier filter attempts to add the same header more than once (case insensitive)") ErrRemoveHeaderDuplicate = errors.New("header modifier filter attempts to remove the same header more than once (case insensitive)") - ErrRequestAuthenRequiresJwt = errors.New("jwt field is required when request authentication is set") ErrLoadBalancerInvalid = errors.New("loadBalancer setting is invalid, only one setting can be set") ) @@ -273,8 +272,6 @@ type HTTPRoute struct { // RateLimit defines the more specific match conditions as well as limits for ratelimiting // the requests on this route. RateLimit *RateLimit `json:"rateLimit,omitempty" yaml:"rateLimit,omitempty"` - // RequestAuthentication defines the schema for authenticating HTTP requests. //TODO zhaohuabing remove this field - RequestAuthentication *RequestAuthentication `json:"requestAuthentication,omitempty" yaml:"requestAuthentication,omitempty"` // Timeout is the time until which entire response is received from the upstream. Timeout *metav1.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"` // load balancer policy to use when routing to the backend endpoints. @@ -296,28 +293,6 @@ type UnstructuredRef struct { Object *unstructured.Unstructured `json:"object,omitempty" yaml:"object,omitempty"` } -// RequestAuthentication defines the schema for authenticating HTTP requests. -// Only one of "jwt" can be specified. -// -// TODO: Add support for additional request authentication providers, i.e. OIDC. -// -// +k8s:deepcopy-gen=true -// TODO zhaohuabing remove this type -type RequestAuthentication struct { - // JWT defines the schema for authenticating HTTP requests using JSON Web Tokens (JWT). - JWT *JwtRequestAuthentication `json:"jwt,omitempty" yaml:"jwt,omitempty"` -} - -// JwtRequestAuthentication defines the schema for authenticating HTTP requests using -// JSON Web Tokens (JWT). -// -// +k8s:deepcopy-gen=true -// TODO zhaohuabing remove this type -type JwtRequestAuthentication struct { - // Providers defines a list of JSON Web Token (JWT) authentication providers. - Providers []egv1a1.JwtAuthenticationFilterProvider `json:"providers,omitempty" yaml:"providers,omitempty"` -} - // CORS holds the Cross-Origin Resource Sharing (CORS) policy for the route. // // +k8s:deepcopy-gen=true @@ -444,16 +419,6 @@ func (h HTTPRoute) Validate() error { } } } - if h.RequestAuthentication != nil { - switch { - case h.RequestAuthentication.JWT == nil: - errs = multierror.Append(errs, ErrRequestAuthenRequiresJwt) - default: - if err := h.RequestAuthentication.JWT.Validate(); err != nil { - errs = multierror.Append(errs, err) - } - } - } if h.LoadBalancer != nil { if err := h.LoadBalancer.Validate(); err != nil { errs = multierror.Append(errs, err) @@ -468,16 +433,6 @@ func (h HTTPRoute) Validate() error { return errs } -func (j *JwtRequestAuthentication) Validate() error { - var errs error - - if err := validation.ValidateJwtProviders(j.Providers); err != nil { - errs = multierror.Append(errs, err) - } - - return errs -} - func (j *JWT) validate() error { var errs error diff --git a/internal/ir/xds_test.go b/internal/ir/xds_test.go index 17ca9878751..2fb249ddcba 100644 --- a/internal/ir/xds_test.go +++ b/internal/ir/xds_test.go @@ -1067,7 +1067,7 @@ func TestValidateStringMatch(t *testing.T) { } } -func TestValidateJwtRequestAuthentication(t *testing.T) { +func TestValidateJWT(t *testing.T) { tests := []struct { name string input JWT diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 8044ec291a5..7ebe840dd5a 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -441,11 +441,6 @@ func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) { *out = new(RateLimit) (*in).DeepCopyInto(*out) } - if in.RequestAuthentication != nil { - in, out := &in.RequestAuthentication, &out.RequestAuthentication - *out = new(RequestAuthentication) - (*in).DeepCopyInto(*out) - } if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout *out = new(v1.Duration) @@ -607,28 +602,6 @@ func (in *JWT) DeepCopy() *JWT { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JwtRequestAuthentication) DeepCopyInto(out *JwtRequestAuthentication) { - *out = *in - if in.Providers != nil { - in, out := &in.Providers, &out.Providers - *out = make([]v1alpha1.JwtAuthenticationFilterProvider, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JwtRequestAuthentication. -func (in *JwtRequestAuthentication) DeepCopy() *JwtRequestAuthentication { - if in == nil { - return nil - } - out := new(JwtRequestAuthentication) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LeastRequest) DeepCopyInto(out *LeastRequest) { *out = *in @@ -926,26 +899,6 @@ func (in *Redirect) DeepCopy() *Redirect { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RequestAuthentication) DeepCopyInto(out *RequestAuthentication) { - *out = *in - if in.JWT != nil { - in, out := &in.JWT, &out.JWT - *out = new(JwtRequestAuthentication) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestAuthentication. -func (in *RequestAuthentication) DeepCopy() *RequestAuthentication { - if in == nil { - return nil - } - out := new(RequestAuthentication) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RoundRobin) DeepCopyInto(out *RoundRobin) { *out = *in diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 1980ba6b835..97ade72126b 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -42,23 +42,19 @@ import ( ) const ( - classGatewayIndex = "classGatewayIndex" - gatewayTLSRouteIndex = "gatewayTLSRouteIndex" - gatewayHTTPRouteIndex = "gatewayHTTPRouteIndex" - gatewayGRPCRouteIndex = "gatewayGRPCRouteIndex" - gatewayTCPRouteIndex = "gatewayTCPRouteIndex" - gatewayUDPRouteIndex = "gatewayUDPRouteIndex" - secretGatewayIndex = "secretGatewayIndex" - targetRefGrantRouteIndex = "targetRefGrantRouteIndex" - backendHTTPRouteIndex = "backendHTTPRouteIndex" - backendGRPCRouteIndex = "backendGRPCRouteIndex" - backendTLSRouteIndex = "backendTLSRouteIndex" - backendTCPRouteIndex = "backendTCPRouteIndex" - backendUDPRouteIndex = "backendUDPRouteIndex" - authenFilterHTTPRouteIndex = "authenHTTPRouteIndex" - rateLimitFilterHTTPRouteIndex = "rateLimitHTTPRouteIndex" - authenFilterGRPCRouteIndex = "authenGRPCRouteIndex" - rateLimitFilterGRPCRouteIndex = "rateLimitGRPCRouteIndex" + classGatewayIndex = "classGatewayIndex" + gatewayTLSRouteIndex = "gatewayTLSRouteIndex" + gatewayHTTPRouteIndex = "gatewayHTTPRouteIndex" + gatewayGRPCRouteIndex = "gatewayGRPCRouteIndex" + gatewayTCPRouteIndex = "gatewayTCPRouteIndex" + gatewayUDPRouteIndex = "gatewayUDPRouteIndex" + secretGatewayIndex = "secretGatewayIndex" + targetRefGrantRouteIndex = "targetRefGrantRouteIndex" + backendHTTPRouteIndex = "backendHTTPRouteIndex" + backendGRPCRouteIndex = "backendGRPCRouteIndex" + backendTLSRouteIndex = "backendTLSRouteIndex" + backendTCPRouteIndex = "backendTCPRouteIndex" + backendUDPRouteIndex = "backendUDPRouteIndex" ) type gatewayAPIReconciler struct { @@ -136,9 +132,6 @@ type resourceMappings struct { allAssociatedBackendRefs map[gwapiv1.BackendObjectReference]struct{} // Map for storing referenceGrant NamespaceNames for BackendRefs, SecretRefs. allAssociatedRefGrants map[types.NamespacedName]*gwapiv1b1.ReferenceGrant - // authenFilters is a map of AuthenticationFilters, where the key is the - // namespaced name of the AuthenticationFilter. - authenFilters map[types.NamespacedName]*v1alpha1.AuthenticationFilter // extensionRefFilters is a map of filters managed by an extension. // The key is the namespaced name of the filter and the value is the // unstructured form of the resource. @@ -150,7 +143,6 @@ func newResourceMapping() *resourceMappings { allAssociatedNamespaces: map[string]struct{}{}, allAssociatedBackendRefs: map[gwapiv1.BackendObjectReference]struct{}{}, allAssociatedRefGrants: map[types.NamespacedName]*gwapiv1b1.ReferenceGrant{}, - authenFilters: map[types.NamespacedName]*v1alpha1.AuthenticationFilter{}, extensionRefFilters: map[types.NamespacedName]unstructured.Unstructured{}, } } @@ -653,9 +645,6 @@ func addReferenceGrantIndexers(ctx context.Context, mgr manager.Manager) error { // addHTTPRouteIndexers adds indexing on HTTPRoute. // - For Service, ServiceImports objects that are referenced in HTTPRoute objects via `.spec.rules.backendRefs`. // This helps in querying for HTTPRoutes that are affected by a particular Service CRUD. -// - For AuthenticationFilter objects that are referenced in HTTPRoute objects via -// `.spec.rules[].filters`. This helps in querying for HTTPRoutes that are affected by a -// particular AuthenticationFilter CRUD. func addHTTPRouteIndexers(ctx context.Context, mgr manager.Manager) error { if err := mgr.GetFieldIndexer().IndexField(ctx, &gwapiv1.HTTPRoute{}, gatewayHTTPRouteIndex, gatewayHTTPRouteIndexFunc); err != nil { return err @@ -665,34 +654,9 @@ func addHTTPRouteIndexers(ctx context.Context, mgr manager.Manager) error { return err } - if err := mgr.GetFieldIndexer().IndexField(ctx, &gwapiv1.HTTPRoute{}, authenFilterHTTPRouteIndex, authenFilterHTTPRouteIndexFunc); err != nil { - return err - } - return nil } -func authenFilterHTTPRouteIndexFunc(rawObj client.Object) []string { - httproute := rawObj.(*gwapiv1.HTTPRoute) - var filters []string - for _, rule := range httproute.Spec.Rules { - for i := range rule.Filters { - filter := rule.Filters[i] - if gatewayapi.IsAuthnHTTPFilter(&filter) { - if err := gatewayapi.ValidateHTTPRouteFilter(&filter); err == nil { - filters = append(filters, - types.NamespacedName{ - Namespace: httproute.Namespace, - Name: string(filter.ExtensionRef.Name), - }.String(), - ) - } - } - } - } - return filters -} - func gatewayHTTPRouteIndexFunc(rawObj client.Object) []string { httproute := rawObj.(*gwapiv1.HTTPRoute) var gateways []string @@ -743,10 +707,6 @@ func addGRPCRouteIndexers(ctx context.Context, mgr manager.Manager) error { return err } - if err := mgr.GetFieldIndexer().IndexField(ctx, &gwapiv1a2.GRPCRoute{}, authenFilterGRPCRouteIndex, authenFilterGRPCRouteIndexFunc); err != nil { - return err - } - return nil } @@ -788,27 +748,6 @@ func backendGRPCRouteIndexFunc(rawObj client.Object) []string { return backendRefs } -func authenFilterGRPCRouteIndexFunc(rawObj client.Object) []string { - grpcroute := rawObj.(*gwapiv1a2.GRPCRoute) - var filters []string - for _, rule := range grpcroute.Spec.Rules { - for i := range rule.Filters { - filter := rule.Filters[i] - if gatewayapi.IsAuthnGRPCFilter(&filter) { - if err := gatewayapi.ValidateGRPCRouteFilter(&filter); err == nil { - filters = append(filters, - types.NamespacedName{ - Namespace: grpcroute.Namespace, - Name: string(filter.ExtensionRef.Name), - }.String(), - ) - } - } - } - } - return filters -} - // addTLSRouteIndexers adds indexing on TLSRoute, for Service objects that are // referenced in TLSRoute objects via `.spec.rules.backendRefs`. This helps in // querying for TLSRoutes that are affected by a particular Service CRUD. @@ -1288,6 +1227,36 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context) { ) r.log.Info("backendTrafficPolicy status subscriber shutting down") }() + + // SecurityPolicy object status updater + go func() { + message.HandleSubscription(message.Metadata{Runner: string(v1alpha1.LogComponentProviderRunner), Message: "securitypolicy-status"}, r.resources.SecurityPolicyStatuses.Subscribe(ctx), + func(update message.Update[types.NamespacedName, *v1alpha1.SecurityPolicyStatus], errChan chan error) { + // skip delete updates. + if update.Delete { + return + } + key := update.Key + val := update.Value + r.statusUpdater.Send(status.Update{ + NamespacedName: key, + Resource: new(v1alpha1.SecurityPolicy), + Mutator: status.MutatorFunc(func(obj client.Object) client.Object { + t, ok := obj.(*v1alpha1.SecurityPolicy) + if !ok { + err := fmt.Errorf("unsupported object type %T", obj) + errChan <- err + panic(err) + } + tCopy := t.DeepCopy() + tCopy.Status = *val + return tCopy + }), + }) + }, + ) + r.log.Info("securityPolicy status subscriber shutting down") + }() } // watchResources watches gateway api resources. @@ -1526,22 +1495,6 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M return err } - // Watch AuthenticationFilter CRUDs and enqueue associated HTTPRoute objects. - afPredicates := []predicate.Predicate{ - predicate.GenerationChangedPredicate{}, - predicate.NewPredicateFuncs(r.httpRoutesForAuthenticationFilter), - } - if len(r.namespaceLabels) != 0 { - afPredicates = append(afPredicates, predicate.NewPredicateFuncs(r.hasMatchingNamespaceLabels)) - } - if err := c.Watch( - source.Kind(mgr.GetCache(), &v1alpha1.AuthenticationFilter{}), - handler.EnqueueRequestsFromMapFunc(r.enqueueClass), - afPredicates..., - ); err != nil { - return err - } - // Watch EnvoyPatchPolicy if enabled in config eppPredicates := []predicate.Predicate{predicate.GenerationChangedPredicate{}} if len(r.namespaceLabels) != 0 { @@ -1586,6 +1539,20 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M return err } + // Watch SecurityPolicy + spPredicates := []predicate.Predicate{predicate.GenerationChangedPredicate{}} + if len(r.namespaceLabels) != 0 { + spPredicates = append(spPredicates, predicate.NewPredicateFuncs(r.hasMatchingNamespaceLabels)) + } + + if err := c.Watch( + source.Kind(mgr.GetCache(), &v1alpha1.SecurityPolicy{}), + handler.EnqueueRequestsFromMapFunc(r.enqueueClass), + spPredicates..., + ); err != nil { + return err + } + r.log.Info("Watching gatewayAPI related objects") // Watch any additional GVKs from the registered extension. diff --git a/internal/provider/kubernetes/filters.go b/internal/provider/kubernetes/filters.go index bd3266a7040..d526e06d12e 100644 --- a/internal/provider/kubernetes/filters.go +++ b/internal/provider/kubernetes/filters.go @@ -10,38 +10,8 @@ import ( "fmt" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" ) -func (r *gatewayAPIReconciler) getAuthenticationFilters(ctx context.Context) ([]egv1a1.AuthenticationFilter, error) { - authenList := new(egv1a1.AuthenticationFilterList) - if err := r.client.List(ctx, authenList); err != nil { - return nil, fmt.Errorf("failed to list AuthenticationFilters: %v", err) - } - - authens := authenList.Items - if len(r.namespaceLabels) != 0 { - var as []egv1a1.AuthenticationFilter - for _, a := range authens { - ns := a.GetNamespace() - ok, err := r.checkObjectNamespaceLabels(ns) - if err != nil { - // TODO: should return? or just proceed? - return nil, fmt.Errorf("failed to check namespace labels for AuthenicationFilter %s in namespace %s: %s", a.GetName(), ns, err) - } - - if ok { - as = append(as, a) - } - } - - authens = as - } - - return authens, nil -} - func (r *gatewayAPIReconciler) getExtensionRefFilters(ctx context.Context) ([]unstructured.Unstructured, error) { var resourceItems []unstructured.Unstructured for _, gvk := range r.extGVKs { diff --git a/internal/provider/kubernetes/kubernetes_test.go b/internal/provider/kubernetes/kubernetes_test.go index e15baa505ab..cc3763edc9a 100644 --- a/internal/provider/kubernetes/kubernetes_test.go +++ b/internal/provider/kubernetes/kubernetes_test.go @@ -73,7 +73,6 @@ func TestProvider(t *testing.T) { "gateway scheduled status": testGatewayScheduledStatus, "httproute": testHTTPRoute, "tlsroute": testTLSRoute, - "authentication filter": testAuthenFilter, "stale service cleanup route deletion": testServiceCleanupForMultipleRoutes, } for name, tc := range testcases { @@ -354,286 +353,6 @@ func testGatewayScheduledStatus(ctx context.Context, t *testing.T, provider *Pro assert.Equal(t, gw.Spec, res.Gateways[0].Spec) } -// Test that even when resources such as the Service/Deployment get hashed names (because of a gateway with a very long name) -func testLongNameHashedResources(ctx context.Context, t *testing.T, provider *Provider, resources *message.ProviderResources) { - cli := provider.manager.GetClient() - - gc := test.GetGatewayClass("envoy-gateway-class", egv1a1.GatewayControllerName) - require.NoError(t, cli.Create(ctx, gc)) - - // Ensure the GatewayClass reports "Ready". - require.Eventually(t, func() bool { - if err := cli.Get(ctx, types.NamespacedName{Name: gc.Name}, gc); err != nil { - return false - } - - for _, cond := range gc.Status.Conditions { - if cond.Type == string(gwapiv1.GatewayClassConditionStatusAccepted) && cond.Status == metav1.ConditionTrue { - return true - } - } - - return false - }, defaultWait, defaultTick) - - defer func() { - require.NoError(t, cli.Delete(ctx, gc)) - }() - - // Create the namespace for the Gateway under test. - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "envoy-gateway"}} - require.NoError(t, cli.Create(ctx, ns)) - - gw := &gwapiv1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gatewaywithaverylongnamethatwillresultinhashedresources", - Namespace: ns.Name, - }, - Spec: gwapiv1.GatewaySpec{ - GatewayClassName: gwapiv1.ObjectName(gc.Name), - Listeners: []gwapiv1.Listener{ - { - Name: "test", - Port: gwapiv1.PortNumber(int32(8080)), - Protocol: gwapiv1.HTTPProtocolType, - }, - }, - }, - } - require.NoError(t, cli.Create(ctx, gw)) - - // Ensure the Gateway is ready and gets an address. - ready := false - hasAddress := false - require.Eventually(t, func() bool { - if err := cli.Get(ctx, types.NamespacedName{Namespace: gw.Namespace, Name: gw.Name}, gw); err != nil { - return false - } - - for _, cond := range gw.Status.Conditions { - fmt.Printf("Condition: %v\n", cond) - if cond.Type == string(gwapiv1.GatewayConditionProgrammed) && cond.Status == metav1.ConditionTrue { - ready = true - } - } - - if gw.Status.Addresses != nil { - hasAddress = len(gw.Status.Addresses) >= 1 - } - - return ready && hasAddress - }, defaultWait, defaultTick) - - defer func() { - require.NoError(t, cli.Delete(ctx, gw)) - }() - - // Ensure the gatewayclass has been finalized. - require.Eventually(t, func() bool { - err := cli.Get(ctx, types.NamespacedName{Name: gc.Name}, gc) - return err == nil && slices.Contains(gc.Finalizers, gatewayClassFinalizer) - }, defaultWait, defaultTick) - - // Ensure the number of Gateways in the Gateway resource table is as expected. - require.Eventually(t, func() bool { - res, _ := resources.GatewayAPIResources.Load("envoy-gateway-class") - return len(res.Gateways) == 1 - }, defaultWait, defaultTick) - - // Ensure the test Gateway in the Gateway resources is as expected. - key := types.NamespacedName{ - Namespace: gw.Namespace, - Name: gw.Name, - } - require.Eventually(t, func() bool { - return cli.Get(ctx, key, gw) == nil - }, defaultWait, defaultTick) - res, _ := resources.GatewayAPIResources.Load("envoy-gateway-class") - // Only check if the spec is equal - // The watchable map will not store a resource - // with an updated status if the spec has not changed - // to eliminate this endless loop: - // reconcile->store->translate->update-status->reconcile - assert.Equal(t, gw.Spec, res.Gateways[0].Spec) -} - -func testAuthenFilter(ctx context.Context, t *testing.T, provider *Provider, resources *message.ProviderResources) { - cli := provider.manager.GetClient() - - gc := test.GetGatewayClass("authen-test", egv1a1.GatewayControllerName) - require.NoError(t, cli.Create(ctx, gc)) - - // Ensure the GatewayClass reports ready. - require.Eventually(t, func() bool { - if err := cli.Get(ctx, types.NamespacedName{Name: gc.Name}, gc); err != nil { - return false - } - - for _, cond := range gc.Status.Conditions { - if cond.Type == string(gwapiv1.GatewayClassConditionStatusAccepted) && cond.Status == metav1.ConditionTrue { - return true - } - } - - return false - }, defaultWait, defaultTick) - - defer func() { - require.NoError(t, cli.Delete(ctx, gc)) - }() - - // Create the namespace for the Gateway under test. - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "authen-test"}} - require.NoError(t, cli.Create(ctx, ns)) - - gw := &gwapiv1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "authen-test", - Namespace: ns.Name, - }, - Spec: gwapiv1.GatewaySpec{ - GatewayClassName: gwapiv1.ObjectName(gc.Name), - Listeners: []gwapiv1.Listener{ - { - Name: "test", - Port: gwapiv1.PortNumber(int32(8080)), - Protocol: gwapiv1.HTTPProtocolType, - }, - }, - }, - } - require.NoError(t, cli.Create(ctx, gw)) - - defer func() { - require.NoError(t, cli.Delete(ctx, gw)) - }() - - svc := test.GetService(types.NamespacedName{Namespace: ns.Name, Name: "test"}, nil, map[string]int32{ - "http": 80, - "https": 443, - }) - - require.NoError(t, cli.Create(ctx, svc)) - - defer func() { - require.NoError(t, cli.Delete(ctx, svc)) - }() - - authenFilter := test.GetAuthenticationFilter("test-authen", ns.Name) - - require.NoError(t, cli.Create(ctx, authenFilter)) - - defer func() { - require.NoError(t, cli.Delete(ctx, authenFilter)) - }() - - var testCases = []struct { - name string - route gwapiv1.HTTPRoute - }{ - { - name: "authenfilter-httproute", - route: gwapiv1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "httproute-authenfilter-test", - Namespace: ns.Name, - }, - Spec: gwapiv1.HTTPRouteSpec{ - CommonRouteSpec: gwapiv1.CommonRouteSpec{ - ParentRefs: []gwapiv1.ParentReference{ - { - Name: gwapiv1.ObjectName(gw.Name), - }, - }, - }, - Hostnames: []gwapiv1.Hostname{"test.hostname.local"}, - Rules: []gwapiv1.HTTPRouteRule{ - { - Matches: []gwapiv1.HTTPRouteMatch{ - { - Path: &gwapiv1.HTTPPathMatch{ - Type: ptr.To(gwapiv1.PathMatchPathPrefix), - Value: ptr.To("/authenfilter/"), - }, - }, - }, - BackendRefs: []gwapiv1.HTTPBackendRef{ - { - BackendRef: gwapiv1.BackendRef{ - BackendObjectReference: gwapiv1.BackendObjectReference{ - Name: "test", - Port: ptr.To(gwapiv1.PortNumber(80)), - }, - }, - }, - }, - Filters: []gwapiv1.HTTPRouteFilter{ - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindAuthenticationFilter), - Name: gwapiv1.ObjectName(authenFilter.Name), - }, - }, - }, - }, - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - require.NoError(t, cli.Create(ctx, &testCase.route)) - defer func() { - require.NoError(t, cli.Delete(ctx, &testCase.route)) - }() - - require.Eventually(t, func() bool { - return resources.GatewayAPIResources.Len() != 0 - }, defaultWait, defaultTick) - - // Ensure the test HTTPRoute in the HTTPRoute resources is as expected. - key := types.NamespacedName{ - Namespace: testCase.route.Namespace, - Name: testCase.route.Name, - } - require.Eventually(t, func() bool { - return cli.Get(ctx, key, &testCase.route) == nil - }, defaultWait, defaultTick) - - require.Eventually(t, func() bool { - res, ok := resources.GatewayAPIResources.Load("authen-test") - return ok && - len(res.HTTPRoutes) != 0 && - assert.Equal(t, testCase.route.Spec, res.HTTPRoutes[0].Spec) - }, defaultWait, defaultTick) - - // Ensure the AuthenticationFilter is in the resource map. - require.Eventually(t, func() bool { - res, ok := resources.GatewayAPIResources.Load("authen-test") - return ok && - len(res.AuthenticationFilters) != 0 && - assert.Equal(t, authenFilter.Spec, res.AuthenticationFilters[0].Spec) - }, defaultWait, defaultTick) - - // Update the authn filter. - authenFilter.Spec.JwtProviders = append(authenFilter.Spec.JwtProviders, test.GetAuthenticationProvider("test2")) - require.NoError(t, cli.Update(ctx, authenFilter)) - - // Ensure the AuthenticationFilter in the resource map has been updated. - require.Eventually(t, func() bool { - res, ok := resources.GatewayAPIResources.Load("authen-test") - return ok && - len(res.AuthenticationFilters) != 0 && - assert.Equal(t, 2, len(res.AuthenticationFilters[0].Spec.JwtProviders)) - }, defaultWait, defaultTick) - }) - } -} - func testHTTPRoute(ctx context.Context, t *testing.T, provider *Provider, resources *message.ProviderResources) { cli := provider.manager.GetClient() @@ -696,14 +415,6 @@ func testHTTPRoute(ctx context.Context, t *testing.T, provider *Provider, resour require.NoError(t, cli.Delete(ctx, svc)) }() - authenFilter := test.GetAuthenticationFilter("test-authen", ns.Name) - - require.NoError(t, cli.Create(ctx, authenFilter)) - - defer func() { - require.NoError(t, cli.Delete(ctx, authenFilter)) - }() - redirectHostname := gwapiv1.PreciseHostname("redirect.hostname.local") redirectPort := gwapiv1.PortNumber(8443) redirectStatus := 301 @@ -1645,18 +1356,6 @@ func TestNamespaceSelectorsProvider(t *testing.T) { _, ok := resources.GatewayStatuses.Load(types.NamespacedName{Name: "non-watched-gateway", Namespace: nonWatchedNS.Name}) require.Equal(t, false, ok) - watchedAuthenFilter := test.GetAuthenticationFilter("watched-authen", watchedNS.Name) - require.NoError(t, cli.Create(ctx, watchedAuthenFilter)) - defer func() { - require.NoError(t, cli.Delete(ctx, watchedAuthenFilter)) - }() - - nonWatchedAuthenFilter := test.GetAuthenticationFilter("non-watched-authen", nonWatchedNS.Name) - require.NoError(t, cli.Create(ctx, nonWatchedAuthenFilter)) - defer func() { - require.NoError(t, cli.Delete(ctx, nonWatchedAuthenFilter)) - }() - watchedSvc := test.GetService(types.NamespacedName{Namespace: watchedNS.Name, Name: "watched-service"}, nil, map[string]int32{ "http": 80, "https": 443, @@ -1684,16 +1383,7 @@ func TestNamespaceSelectorsProvider(t *testing.T) { }, watchedGateway.Name, types.NamespacedName{Name: watchedSvc.Name}, 80) - watchedHTTPRoute.Spec.Rules[0].Filters = []gwapiv1.HTTPRouteFilter{ - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: egv1a1.KindAuthenticationFilter, - Name: gwapiv1.ObjectName(watchedAuthenFilter.Name), - }, - }, - } + require.NoError(t, cli.Create(ctx, watchedHTTPRoute)) defer func() { require.NoError(t, cli.Delete(ctx, watchedHTTPRoute)) @@ -1706,16 +1396,6 @@ func TestNamespaceSelectorsProvider(t *testing.T) { }, nonWatchedGateway.Name, types.NamespacedName{Name: nonWatchedSvc.Name}, 8001) - nonWatchedHTTPRoute.Spec.Rules[0].Filters = []gwapiv1.HTTPRouteFilter{ - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: egv1a1.KindAuthenticationFilter, - Name: gwapiv1.ObjectName(nonWatchedAuthenFilter.Name), - }, - }, - } require.NoError(t, cli.Create(ctx, nonWatchedHTTPRoute)) defer func() { require.NoError(t, cli.Delete(ctx, nonWatchedHTTPRoute)) @@ -1848,9 +1528,4 @@ func TestNamespaceSelectorsProvider(t *testing.T) { return res != nil && len(res.GRPCRoutes) == 1 }, defaultWait, defaultTick) - require.Eventually(t, func() bool { - res, _ := resources.GatewayAPIResources.Load(gc.Name) - return res != nil && len(res.AuthenticationFilters) == 1 - }, defaultWait, defaultTick) - } diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 343ef469d1b..9a98bff1035 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -19,7 +19,6 @@ import ( gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" mcsapi "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/gatewayapi" "github.com/envoyproxy/gateway/internal/provider/utils" ) @@ -325,54 +324,6 @@ func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) return false } -// httpRoutesForAuthenticationFilter tries finding HTTPRoute referents of the provided -// AuthenticationFilter and returns true if any exist. -func (r *gatewayAPIReconciler) httpRoutesForAuthenticationFilter(obj client.Object) bool { - ctx := context.Background() - filter, ok := obj.(*egv1a1.AuthenticationFilter) - if !ok { - r.log.Info("unexpected object type, bypassing reconciliation", "object", obj) - return false - } - - // Check if the AuthenticationFilter belongs to a managed HTTPRoute. - httpRouteList := &gwapiv1.HTTPRouteList{} - if err := r.client.List(ctx, httpRouteList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(authenFilterHTTPRouteIndex, utils.NamespacedName(filter).String()), - }); err != nil { - r.log.Error(err, "unable to find associated HTTPRoutes") - return false - } - - httpRoutes := r.filterHTTPRoutesByNamespaceLabels(httpRouteList.Items) - - return len(httpRoutes) != 0 -} - -func (r *gatewayAPIReconciler) filterHTTPRoutesByNamespaceLabels(httpRoutes []gwapiv1.HTTPRoute) []gwapiv1.HTTPRoute { - if len(r.namespaceLabels) == 0 { - return httpRoutes - } - - var routes []gwapiv1.HTTPRoute - for _, route := range httpRoutes { - ns := route.GetNamespace() - ok, err := r.checkObjectNamespaceLabels(ns) - if err != nil { - r.log.Error(err, "failed to check namespace labels for HTTPRoute", - "namespace", ns, - "name", route.GetName(), - ) - continue - } - - if ok { - routes = append(routes, route) - } - } - return routes -} - // envoyDeploymentForGateway returns the Envoy Deployment, returning nil if the Deployment doesn't exist. func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1.Gateway) (*appsv1.Deployment, error) { key := types.NamespacedName{ diff --git a/internal/provider/kubernetes/routes.go b/internal/provider/kubernetes/routes.go index c8876e28166..a85277f9a29 100644 --- a/internal/provider/kubernetes/routes.go +++ b/internal/provider/kubernetes/routes.go @@ -17,7 +17,6 @@ import ( gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/gatewayapi" "github.com/envoyproxy/gateway/internal/provider/utils" ) @@ -108,17 +107,6 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam resourceMap *resourceMappings, resourceTree *gatewayapi.Resources) error { grpcRouteList := &gwapiv1a2.GRPCRouteList{} - // An GRPCRoute may reference an AuthenticationFilter, - // so add them to the resource map first (if they exist). - authenFilters, err := r.getAuthenticationFilters(ctx) - if err != nil { - return err - } - for i := range authenFilters { - filter := authenFilters[i] - resourceMap.authenFilters[utils.NamespacedName(&filter)] = &filter - } - if err := r.client.List(ctx, grpcRouteList, &client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(gatewayGRPCRouteIndex, gatewayNamespaceName), }); err != nil { @@ -202,34 +190,23 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam } if filter.Type == gwapiv1a2.GRPCRouteFilterExtensionRef { // NOTE: filters must be in the same namespace as the GRPCRoute - switch string(filter.ExtensionRef.Kind) { - case egv1a1.KindAuthenticationFilter: - key := types.NamespacedName{ - Namespace: grpcRoute.Namespace, - Name: string(filter.ExtensionRef.Name), - } - authFilter, ok := resourceMap.authenFilters[key] - if !ok { - r.log.Error(err, "AuthenticationFilter not found; bypassing rule", "index", i) - continue - } + // Check if it's a Kind managed by an extension and add to resourceTree + key := types.NamespacedName{ + Namespace: grpcRoute.Namespace, + Name: string(filter.ExtensionRef.Name), + } + extRefFilter, ok := resourceMap.extensionRefFilters[key] + if !ok { + r.log.Error( + errors.New("filter not found; bypassing rule"), + "Filter not found; bypassing rule", + "name", + filter.ExtensionRef.Name, "index", i) + continue + } - resourceTree.AuthenticationFilters = append(resourceTree.AuthenticationFilters, authFilter) - default: - // If the Kind does not match any Envoy Gateway resources, check if it's a Kind - // managed by an extension and add to resourceTree - key := types.NamespacedName{ - Namespace: grpcRoute.Namespace, - Name: string(filter.ExtensionRef.Name), - } - extRefFilter, ok := resourceMap.extensionRefFilters[key] - if !ok { - r.log.Error(err, "Filter not found; bypassing rule", "name", filter.ExtensionRef.Name, "index", i) - continue - } + resourceTree.ExtensionRefFilters = append(resourceTree.ExtensionRefFilters, extRefFilter) - resourceTree.ExtensionRefFilters = append(resourceTree.ExtensionRefFilters, extRefFilter) - } } } } @@ -250,17 +227,6 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam resourceMap *resourceMappings, resourceTree *gatewayapi.Resources) error { httpRouteList := &gwapiv1.HTTPRouteList{} - // An HTTPRoute may reference an AuthenticationFilter, or a filter managed - // by an extension so add them to the resource map first (if they exist). - authenFilters, err := r.getAuthenticationFilters(ctx) - if err != nil { - return err - } - for i := range authenFilters { - filter := authenFilters[i] - resourceMap.authenFilters[utils.NamespacedName(&filter)] = &filter - } - extensionRefFilters, err := r.getExtensionRefFilters(ctx) if err != nil { return err @@ -408,34 +374,22 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam } } else if filter.Type == gwapiv1.HTTPRouteFilterExtensionRef { // NOTE: filters must be in the same namespace as the HTTPRoute - switch string(filter.ExtensionRef.Kind) { - case egv1a1.KindAuthenticationFilter: - key := types.NamespacedName{ - Namespace: httpRoute.Namespace, - Name: string(filter.ExtensionRef.Name), - } - authFilter, ok := resourceMap.authenFilters[key] - if !ok { - r.log.Error(err, "AuthenticationFilter not found; bypassing rule", "index", i) - continue - } - - resourceTree.AuthenticationFilters = append(resourceTree.AuthenticationFilters, authFilter) - default: - // If the Kind does not match any Envoy Gateway resources, check if it's a Kind - // managed by an extension and add to resourceTree - key := types.NamespacedName{ - Namespace: httpRoute.Namespace, - Name: string(filter.ExtensionRef.Name), - } - extRefFilter, ok := resourceMap.extensionRefFilters[key] - if !ok { - r.log.Error(err, "Filter not found; bypassing rule", "name", filter.ExtensionRef.Name, "index", i) - continue - } - - resourceTree.ExtensionRefFilters = append(resourceTree.ExtensionRefFilters, extRefFilter) + // Check if it's a Kind managed by an extension and add to resourceTree + key := types.NamespacedName{ + Namespace: httpRoute.Namespace, + Name: string(filter.ExtensionRef.Name), } + extRefFilter, ok := resourceMap.extensionRefFilters[key] + if !ok { + r.log.Error( + errors.New("filter not found; bypassing rule"), + "Filter not found; bypassing rule", + "name", filter.ExtensionRef.Name, + "index", i) + continue + } + + resourceTree.ExtensionRefFilters = append(resourceTree.ExtensionRefFilters, extRefFilter) } } } diff --git a/internal/provider/kubernetes/routes_test.go b/internal/provider/kubernetes/routes_test.go index 681af679a93..cb126d3f2a1 100644 --- a/internal/provider/kubernetes/routes_test.go +++ b/internal/provider/kubernetes/routes_test.go @@ -63,7 +63,6 @@ func TestProcessHTTPRoutes(t *testing.T) { testCases := []struct { name string routes []*gwapiv1.HTTPRoute - authenFilters []*egv1a1.AuthenticationFilter extensionFilters []*unstructured.Unstructured extensionAPIGroups []schema.GroupVersionKind expected bool @@ -112,85 +111,6 @@ func TestProcessHTTPRoutes(t *testing.T) { }, expected: true, }, - { - name: "httproute with one authenticationfilter", - routes: []*gwapiv1.HTTPRoute{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: gwapiv1.HTTPRouteSpec{ - CommonRouteSpec: gwapiv1.CommonRouteSpec{ - ParentRefs: []gwapiv1.ParentReference{ - { - Name: "test", - }, - }, - }, - Rules: []gwapiv1.HTTPRouteRule{ - { - Matches: []gwapiv1.HTTPRouteMatch{ - { - Path: &gwapiv1.HTTPPathMatch{ - Type: ptr.To(gwapiv1.PathMatchPathPrefix), - Value: ptr.To("/"), - }, - }, - }, - Filters: []gwapiv1.HTTPRouteFilter{ - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindAuthenticationFilter), - Name: gwapiv1.ObjectName("test"), - }, - }, - }, - BackendRefs: []gwapiv1.HTTPBackendRef{ - { - BackendRef: gwapiv1.BackendRef{ - BackendObjectReference: gwapiv1.BackendObjectReference{ - Group: gatewayapi.GroupPtr(corev1.GroupName), - Kind: gatewayapi.KindPtr(gatewayapi.KindService), - Name: "test", - }, - }, - }, - }, - }, - }, - }, - }, - }, - authenFilters: []*egv1a1.AuthenticationFilter{ - { - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - }, - expected: true, - }, { name: "httproute with one filter_from_extension", routes: []*gwapiv1.HTTPRoute{ @@ -287,9 +207,6 @@ func TestProcessHTTPRoutes(t *testing.T) { for _, route := range tc.routes { objs = append(objs, route) } - for _, filter := range tc.authenFilters { - objs = append(objs, filter) - } for _, filter := range tc.extensionFilters { objs = append(objs, filter) } @@ -310,16 +227,6 @@ func TestProcessHTTPRoutes(t *testing.T) { require.NoError(t, err) // Ensure the resource tree and map are as expected. require.Equal(t, tc.routes, resourceTree.HTTPRoutes) - // NOTE: filters must be in the same namespace as the HTTPRoute - if tc.authenFilters != nil { - for i, filter := range tc.authenFilters { - key := types.NamespacedName{ - Namespace: tc.routes[i].Namespace, - Name: filter.Name, - } - require.Equal(t, filter, resourceMap.authenFilters[key]) - } - } if tc.extensionFilters != nil { for i, filter := range tc.extensionFilters { key := types.NamespacedName{ @@ -370,7 +277,6 @@ func TestProcessGRPCRoutes(t *testing.T) { testCases := []struct { name string routes []*gwapiv1a2.GRPCRoute - authenFilters []*egv1a1.AuthenticationFilter extensionAPIGroups []schema.GroupVersionKind expected bool }{ @@ -417,84 +323,6 @@ func TestProcessGRPCRoutes(t *testing.T) { }, expected: true, }, - { - name: "grpcroute with one authenticationfilter", - routes: []*gwapiv1a2.GRPCRoute{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: gwapiv1a2.GRPCRouteSpec{ - CommonRouteSpec: gwapiv1.CommonRouteSpec{ - ParentRefs: []gwapiv1.ParentReference{ - { - Name: "test", - }, - }, - }, - Rules: []gwapiv1a2.GRPCRouteRule{ - { - Matches: []gwapiv1a2.GRPCRouteMatch{ - { - Method: &gwapiv1a2.GRPCMethodMatch{ - Method: ptr.To("Ping"), - }, - }, - }, - Filters: []gwapiv1a2.GRPCRouteFilter{ - { - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindAuthenticationFilter), - Name: gwapiv1.ObjectName("test"), - }, - }, - }, - BackendRefs: []gwapiv1a2.GRPCBackendRef{ - { - BackendRef: gwapiv1.BackendRef{ - BackendObjectReference: gwapiv1.BackendObjectReference{ - Group: gatewayapi.GroupPtr(corev1.GroupName), - Kind: gatewayapi.KindPtr(gatewayapi.KindService), - Name: "test", - }, - }, - }, - }, - }, - }, - }, - }, - }, - authenFilters: []*egv1a1.AuthenticationFilter{ - { - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - }, - expected: true, - }, } for i := range testCases { @@ -518,9 +346,6 @@ func TestProcessGRPCRoutes(t *testing.T) { for _, route := range tc.routes { objs = append(objs, route) } - for _, filter := range tc.authenFilters { - objs = append(objs, filter) - } if len(tc.extensionAPIGroups) > 0 { r.extGVKs = append(r.extGVKs, tc.extensionAPIGroups...) } @@ -538,16 +363,6 @@ func TestProcessGRPCRoutes(t *testing.T) { require.NoError(t, err) // Ensure the resource tree and map are as expected. require.Equal(t, tc.routes, resourceTree.GRPCRoutes) - // NOTE: filters must be in the same namespace as the HTTPRoute - if tc.authenFilters != nil { - for i, filter := range tc.authenFilters { - key := types.NamespacedName{ - Namespace: tc.routes[i].Namespace, - Name: filter.Name, - } - require.Equal(t, filter, resourceMap.authenFilters[key]) - } - } } else { require.Error(t, err) } diff --git a/internal/provider/kubernetes/test/utils.go b/internal/provider/kubernetes/test/utils.go index 94e0e69dc0e..539b2ab594f 100644 --- a/internal/provider/kubernetes/test/utils.go +++ b/internal/provider/kubernetes/test/utils.go @@ -314,55 +314,3 @@ func GetEndpointSlice(nsName types.NamespacedName, svcName string) *discoveryv1. }, } } - -// GetAuthenticationFilter returns a pointer to an AuthenticationFilter with the -// provided ns/name. The AuthenticationFilter uses a JWT provider with dummy issuer, -// audiences, and remoteJWKS settings. -func GetAuthenticationFilter(name, ns string) *egv1a1.AuthenticationFilter { - provider := GetAuthenticationProvider("test") - return &egv1a1.AuthenticationFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: ns, - Name: name, - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{provider}, - }, - } -} - -// GetAuthenticationProvider returns a JwtAuthenticationFilterProvider using the provided name. -func GetAuthenticationProvider(name string) egv1a1.JwtAuthenticationFilterProvider { - return egv1a1.JwtAuthenticationFilterProvider{ - Name: name, - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - } -} - -func ContainsAuthenFilter(hroute *gwapiv1.HTTPRoute) bool { - if hroute == nil { - return false - } - - for _, rule := range hroute.Spec.Rules { - for _, filter := range rule.Filters { - if filter.Type == gwapiv1.HTTPRouteFilterExtensionRef && - filter.ExtensionRef != nil && - string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - filter.ExtensionRef.Kind == egv1a1.KindAuthenticationFilter { - return true - } - } - } - - return false -} diff --git a/internal/xds/translator/authentication.go b/internal/xds/translator/authentication.go deleted file mode 100644 index 17fd874edd4..00000000000 --- a/internal/xds/translator/authentication.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright Envoy Gateway Authors -// SPDX-License-Identifier: Apache-2.0 -// The full text of the Apache license is available in the LICENSE file at -// the root of the repo. - -package translator - -import ( - "errors" - "fmt" - "net" - "net/url" - "strconv" - "strings" - - corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" - routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" - jwtauthnv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/jwt_authn/v3" - hcmv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" - "github.com/envoyproxy/go-control-plane/pkg/resource/v3" - "google.golang.org/protobuf/types/known/anypb" - "google.golang.org/protobuf/types/known/durationpb" - - "github.com/envoyproxy/gateway/api/v1alpha1" - "github.com/envoyproxy/gateway/internal/ir" - "github.com/envoyproxy/gateway/internal/utils/ptr" - "github.com/envoyproxy/gateway/internal/xds/types" -) - -// TODO zhaohuabing remove this file after deprecating authentication filter -// patchHCMWithJwtAuthnFilter builds and appends the Jwt Filter to the HTTP -// Connection Manager if applicable, and it does not already exist. -func patchHCMWithJwtAuthnFilter(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListener) error { - if mgr == nil { - return errors.New("hcm is nil") - } - - if irListener == nil { - return errors.New("ir listener is nil") - } - - if !listenerContainsJwtAuthn(irListener) { - return nil - } - - // Return early if filter already exists. - for _, httpFilter := range mgr.HttpFilters { - if httpFilter.Name == jwtAuthnFilter { - return nil - } - } - - jwtFilter, err := buildHCMJwtFilter(irListener) - if err != nil { - return err - } - - // Ensure the authn filter is the first and the terminal filter is the last in the chain. - mgr.HttpFilters = append([]*hcmv3.HttpFilter{jwtFilter}, mgr.HttpFilters...) - - return nil -} - -// buildHCMJwtFilter returns a JWT authn HTTP filter from the provided IR listener. -func buildHCMJwtFilter(irListener *ir.HTTPListener) (*hcmv3.HttpFilter, error) { - jwtAuthnProto, err := buildJwtAuthn(irListener) - if err != nil { - return nil, err - } - - if err := jwtAuthnProto.ValidateAll(); err != nil { - return nil, err - } - - jwtAuthnAny, err := anypb.New(jwtAuthnProto) - if err != nil { - return nil, err - } - - return &hcmv3.HttpFilter{ - Name: jwtAuthnFilter, - ConfigType: &hcmv3.HttpFilter_TypedConfig{ - TypedConfig: jwtAuthnAny, - }, - }, nil -} - -// buildJwtAuthn returns a JwtAuthentication based on the provided IR HTTPListener. -func buildJwtAuthn(irListener *ir.HTTPListener) (*jwtauthnv3.JwtAuthentication, error) { - jwtProviders := make(map[string]*jwtauthnv3.JwtProvider) - reqMap := make(map[string]*jwtauthnv3.JwtRequirement) - - for _, route := range irListener.Routes { - if route != nil && routeContainsJwtAuthn(route) { - var reqs []*jwtauthnv3.JwtRequirement - for i := range route.RequestAuthentication.JWT.Providers { - irProvider := route.RequestAuthentication.JWT.Providers[i] - // Create the cluster for the remote jwks, if it doesn't exist. - jwksCluster, err := newJwksCluster(&irProvider) - if err != nil { - return nil, err - } - - remote := &jwtauthnv3.JwtProvider_RemoteJwks{ - RemoteJwks: &jwtauthnv3.RemoteJwks{ - HttpUri: &corev3.HttpUri{ - Uri: irProvider.RemoteJWKS.URI, - HttpUpstreamType: &corev3.HttpUri_Cluster{ - Cluster: jwksCluster.name, - }, - Timeout: &durationpb.Duration{Seconds: 5}, - }, - CacheDuration: &durationpb.Duration{Seconds: 5 * 60}, - AsyncFetch: &jwtauthnv3.JwksAsyncFetch{}, - RetryPolicy: &corev3.RetryPolicy{}, - }, - } - - claimToHeaders := []*jwtauthnv3.JwtClaimToHeader{} - for _, claimToHeader := range irProvider.ClaimToHeaders { - claimToHeader := &jwtauthnv3.JwtClaimToHeader{HeaderName: claimToHeader.Header, ClaimName: claimToHeader.Claim} - claimToHeaders = append(claimToHeaders, claimToHeader) - } - jwtProvider := &jwtauthnv3.JwtProvider{ - Issuer: irProvider.Issuer, - Audiences: irProvider.Audiences, - JwksSourceSpecifier: remote, - PayloadInMetadata: irProvider.Issuer, - ClaimToHeaders: claimToHeaders, - } - - providerKey := fmt.Sprintf("%s/%s", route.Name, irProvider.Name) - jwtProviders[providerKey] = jwtProvider - reqs = append(reqs, &jwtauthnv3.JwtRequirement{ - RequiresType: &jwtauthnv3.JwtRequirement_ProviderName{ - ProviderName: providerKey, - }, - }) - } - if len(reqs) == 1 { - reqMap[route.Name] = reqs[0] - } else { - orListReqs := &jwtauthnv3.JwtRequirement{ - RequiresType: &jwtauthnv3.JwtRequirement_RequiresAny{ - RequiresAny: &jwtauthnv3.JwtRequirementOrList{ - Requirements: reqs, - }, - }, - } - reqMap[route.Name] = orListReqs - } - } - } - - return &jwtauthnv3.JwtAuthentication{ - RequirementMap: reqMap, - Providers: jwtProviders, - }, nil -} - -// patchRouteWithJwtConfig patches the provided route with a JWT PerRouteConfig, if the -// route doesn't contain it. -func patchRouteWithJwtConfig(route *routev3.Route, irRoute *ir.HTTPRoute) error { - if route == nil { - return errors.New("xds route is nil") - } - if irRoute == nil { - return errors.New("ir route is nil") - } - - filterCfg := route.GetTypedPerFilterConfig() - if _, ok := filterCfg[jwtAuthnFilter]; !ok { - if !routeContainsJwtAuthn(irRoute) { - return nil - } - - routeCfgProto := &jwtauthnv3.PerRouteConfig{ - RequirementSpecifier: &jwtauthnv3.PerRouteConfig_RequirementName{RequirementName: irRoute.Name}} - - routeCfgAny, err := anypb.New(routeCfgProto) - if err != nil { - return err - } - - if filterCfg == nil { - route.TypedPerFilterConfig = make(map[string]*anypb.Any) - } - - route.TypedPerFilterConfig[jwtAuthnFilter] = routeCfgAny - } - - return nil -} - -// createJwksClusters creates JWKS clusters from the provided routes, if needed. -func createJwksClusters(tCtx *types.ResourceVersionTable, routes []*ir.HTTPRoute) error { - if tCtx == nil || - tCtx.XdsResources == nil || - tCtx.XdsResources[resource.ClusterType] == nil || - len(routes) == 0 { - return nil - } - - for _, route := range routes { - if routeContainsJwtAuthn(route) { - for i := range route.RequestAuthentication.JWT.Providers { - provider := route.RequestAuthentication.JWT.Providers[i] - jwks, err := newJwksCluster(&provider) - epType := DefaultEndpointType - if jwks.isStatic { - epType = Static - } - if err != nil { - return err - } - ds := &ir.DestinationSetting{ - Weight: ptr.To(uint32(1)), - Endpoints: []*ir.DestinationEndpoint{ir.NewDestEndpoint(jwks.hostname, jwks.port)}, - } - tSocket, err := buildXdsUpstreamTLSSocket() - if err != nil { - return err - } - if err := addXdsCluster(tCtx, &xdsClusterArgs{ - name: jwks.name, - settings: []*ir.DestinationSetting{ds}, - tSocket: tSocket, - protocol: DefaultProtocol, - endpointType: epType, - }); err != nil && !errors.Is(err, ErrXdsClusterExists) { - return err - } - } - } - } - - return nil -} - -// newJwksCluster returns a jwksCluster from the provided provider. -func newJwksCluster(provider *v1alpha1.JwtAuthenticationFilterProvider) (*jwksCluster, error) { - static := false - if provider == nil { - return nil, errors.New("nil provider") - } - - u, err := url.Parse(provider.RemoteJWKS.URI) - if err != nil { - return nil, err - } - - var strPort string - switch u.Scheme { - case "https": - strPort = "443" - default: - return nil, fmt.Errorf("unsupported JWKS URI scheme %s", u.Scheme) - } - - if u.Port() != "" { - strPort = u.Port() - } - - name := fmt.Sprintf("%s_%s", strings.ReplaceAll(u.Hostname(), ".", "_"), strPort) - - port, err := strconv.Atoi(strPort) - if err != nil { - return nil, err - } - - if ip := net.ParseIP(u.Hostname()); ip != nil { - if v4 := ip.To4(); v4 != nil { - static = true - } - } - - return &jwksCluster{ - name: name, - hostname: u.Hostname(), - port: uint32(port), - isStatic: static, - }, nil -} - -// listenerContainsJwtAuthn returns true if JWT authentication exists for the -// provided listener. -func listenerContainsJwtAuthn(irListener *ir.HTTPListener) bool { - if irListener == nil { - return false - } - - for _, route := range irListener.Routes { - if routeContainsJwtAuthn(route) { - return true - } - } - - return false -} - -// routeContainsJwtAuthn returns true if JWT authentication exists for the -// provided route. -func routeContainsJwtAuthn(irRoute *ir.HTTPRoute) bool { - if irRoute == nil { - return false - } - - if irRoute != nil && - irRoute.RequestAuthentication != nil && - irRoute.RequestAuthentication.JWT != nil && - irRoute.RequestAuthentication.JWT.Providers != nil && - len(irRoute.RequestAuthentication.JWT.Providers) > 0 { - return true - } - - return false -} diff --git a/internal/xds/translator/httpfilters.go b/internal/xds/translator/httpfilters.go index 4aba259b1e5..a9ddb99ad5a 100644 --- a/internal/xds/translator/httpfilters.go +++ b/internal/xds/translator/httpfilters.go @@ -100,12 +100,6 @@ func (t *Translator) patchHCMWithFilters( // https://github.com/envoyproxy/gateway/issues/882 t.patchHCMWithRateLimit(mgr, irListener) - // Add the jwt authn filter, if needed. - // TODO zhaohuabing remove this after deprecating authentication filter - if err := patchHCMWithJwtAuthnFilter(mgr, irListener); err != nil { - return err - } - // Add the cors filter, if needed if err := patchHCMWithCORSFilter(mgr, irListener); err != nil { return err @@ -135,11 +129,6 @@ func patchRouteWithFilters( return nil } - // Add the jwt per route config to the route, if needed. // TODO zhaohuabing remove this after deprecating authentication filter - if err := patchRouteWithJwtConfig(route, irRoute); err != nil { - return nil - } - // Add the cors per route config to the route, if needed. if err := patchRouteWithCORSConfig(route, irRoute); err != nil { return err diff --git a/internal/xds/translator/testdata/in/xds-ir/authn-multi-route-multi-provider.yaml b/internal/xds/translator/testdata/in/xds-ir/authn-multi-route-multi-provider.yaml deleted file mode 100644 index 6640b280be1..00000000000 --- a/internal/xds/translator/testdata/in/xds-ir/authn-multi-route-multi-provider.yaml +++ /dev/null @@ -1,70 +0,0 @@ -http: -- name: "first-listener" - address: "0.0.0.0" - port: 10080 - hostnames: - - "*" - routes: - - name: "first-route-www.test.com" - hostname: "*" - pathMatch: - exact: "foo/bar" - requestAuthentication: - jwt: - providers: - - name: example - issuer: https://www.example.com - audiences: - - foo.com - remoteJWKS: - uri: https://localhost/jwt/public-key/jwks.json - claimToHeaders: - - header: one-route-example-key1 - claim: claim.neteased.key - - name: example2 - issuer: https://www.two.example.com - audiences: - - one.foo.com - - two.foo.com - remoteJWKS: - uri: https://192.168.1.250:8080/jwt/public-key/jwks.json - claimToHeaders: - - header: one-route-example2-key1 - claim: claim.neteased.key - - header: one-route-example2-key2 - claim: name - destination: - name: "first-route-www.test.com-dest" - settings: - - endpoints: - - host: "1.2.3.4" - port: 50000 - - name: "second-route-www.test.com" - hostname: "*" - pathMatch: - exact: "foo/baz" - requestAuthentication: - jwt: - providers: - - name: example - issuer: https://www.example.com - audiences: - - foo.com - remoteJWKS: - uri: https://localhost/jwt/public-key/jwks.json - claimToHeaders: - - header: second-route-example-key1 - claim: claim.neteased.key - - name: example2 - issuer: https://www.two.example.com - audiences: - - one.foo.com - - two.foo.com - remoteJWKS: - uri: https://192.168.1.250:8080/jwt/public-key/jwks.json - destination: - name: "second-route-www.test.com-dest" - settings: - - endpoints: - - host: "5.6.7.8" - port: 50000 diff --git a/internal/xds/translator/testdata/in/xds-ir/authn-multi-route-single-provider.yaml b/internal/xds/translator/testdata/in/xds-ir/authn-multi-route-single-provider.yaml deleted file mode 100644 index fbd1b6784dd..00000000000 --- a/internal/xds/translator/testdata/in/xds-ir/authn-multi-route-single-provider.yaml +++ /dev/null @@ -1,51 +0,0 @@ -accesslog: - text: - - path: "/dev/stdout" -http: -- name: "first-listener" - address: "0.0.0.0" - port: 10080 - hostnames: - - "*" - routes: - - name: "first-route" - hostname: "*" - pathMatch: - exact: "foo/bar" - requestAuthentication: - jwt: - providers: - - name: example - issuer: https://www.example.com - audiences: - - foo.com - remoteJWKS: - uri: https://localhost/jwt/public-key/jwks.json - claimToHeaders: - - header: first-route-key - claim: claim.neteased.key - destination: - name: "first-route-dest" - settings: - - endpoints: - - host: "1.2.3.4" - port: 50000 - - name: "second-route" - hostname: "*" - pathMatch: - exact: "foo/baz" - requestAuthentication: - jwt: - providers: - - name: example - issuer: https://www.example.com - audiences: - - foo.com - remoteJWKS: - uri: https://localhost/jwt/public-key/jwks.json - destination: - name: "second-route-dest" - settings: - - endpoints: - - host: "5.6.7.8" - port: 50000 diff --git a/internal/xds/translator/testdata/in/xds-ir/authn-ratelimit.yaml b/internal/xds/translator/testdata/in/xds-ir/authn-ratelimit.yaml deleted file mode 100644 index 75b442cc9a3..00000000000 --- a/internal/xds/translator/testdata/in/xds-ir/authn-ratelimit.yaml +++ /dev/null @@ -1,70 +0,0 @@ -http: -- name: "first-listener" - address: "0.0.0.0" - port: 10080 - hostnames: - - "*" - routes: - - name: "first-route" - hostname: "*" - rateLimit: - global: - rules: - - headerMatches: - - name: "x-user-id" - exact: "one" - limit: - requests: 5 - unit: second - pathMatch: - exact: "foo/bar" - destination: - name: "first-route-dest" - settings: - - endpoints: - - host: "1.2.3.4" - port: 50000 - requestAuthentication: - jwt: - providers: - - name: example - issuer: https://www.example.com - audiences: - - foo.com - remoteJWKS: - uri: https://192.168.1.250/jwt/public-key/jwks.json - - name: "second-route" - hostname: "*" - rateLimit: - global: - rules: - - headerMatches: - - name: "x-user-id" - distinct: true - limit: - requests: 5 - unit: second - pathMatch: - exact: "example" - destination: - name: "second-route-dest" - settings: - - endpoints: - - host: "1.2.3.4" - port: 50000 - - name: "third-route" - hostname: "*" - rateLimit: - global: - rules: - - limit: - requests: 5 - unit: second - pathMatch: - exact: "test" - destination: - name: "third-route-dest" - settings: - - endpoints: - - host: "1.2.3.4" - port: 50000 diff --git a/internal/xds/translator/testdata/in/xds-ir/authn-single-route-single-match.yaml b/internal/xds/translator/testdata/in/xds-ir/authn-single-route-single-match.yaml deleted file mode 100644 index 03cbbb26528..00000000000 --- a/internal/xds/translator/testdata/in/xds-ir/authn-single-route-single-match.yaml +++ /dev/null @@ -1,26 +0,0 @@ -http: -- name: "first-listener" - address: "0.0.0.0" - port: 10080 - hostnames: - - "*" - routes: - - name: "first-route" - hostname: "*" - pathMatch: - exact: "foo/bar" - requestAuthentication: - jwt: - providers: - - name: example - issuer: https://www.example.com - audiences: - - foo.com - remoteJWKS: - uri: https://localhost/jwt/public-key/jwks.json - destination: - name: "first-route-dest" - settings: - - endpoints: - - host: "1.2.3.4" - port: 50000 diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-authn-multi-route-multi-provider.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-multi-provider.yaml similarity index 100% rename from internal/xds/translator/testdata/in/xds-ir/jwt-authn-multi-route-multi-provider.yaml rename to internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-multi-provider.yaml diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-authn-multi-route-single-provider.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-single-provider.yaml similarity index 100% rename from internal/xds/translator/testdata/in/xds-ir/jwt-authn-multi-route-single-provider.yaml rename to internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-single-provider.yaml diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-authn-ratelimit.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-ratelimit.yaml similarity index 100% rename from internal/xds/translator/testdata/in/xds-ir/jwt-authn-ratelimit.yaml rename to internal/xds/translator/testdata/in/xds-ir/jwt-ratelimit.yaml diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-authn-single-route-single-match.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-single-route-single-match.yaml similarity index 100% rename from internal/xds/translator/testdata/in/xds-ir/jwt-authn-single-route-single-match.yaml rename to internal/xds/translator/testdata/in/xds-ir/jwt-single-route-single-match.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.clusters.yaml deleted file mode 100755 index bf7f010954b..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.clusters.yaml +++ /dev/null @@ -1,81 +0,0 @@ -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: first-route-www.test.com-dest - lbPolicy: LEAST_REQUEST - name: first-route-www.test.com-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: second-route-www.test.com-dest - lbPolicy: LEAST_REQUEST - name: second-route-www.test.com-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - dnsRefreshRate: 30s - lbPolicy: LEAST_REQUEST - loadAssignment: - clusterName: localhost_443 - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: localhost - portValue: 443 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} - name: localhost_443 - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - respectDnsTtl: true - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - validationContext: - trustedCa: - filename: /etc/ssl/certs/ca-certificates.crt - type: STRICT_DNS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: "192_168_1_250_8080" - lbPolicy: LEAST_REQUEST - name: "192_168_1_250_8080" - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - validationContext: - trustedCa: - filename: /etc/ssl/certs/ca-certificates.crt - type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.endpoints.yaml deleted file mode 100755 index 7d394e5f496..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.endpoints.yaml +++ /dev/null @@ -1,33 +0,0 @@ -- clusterName: first-route-www.test.com-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 1.2.3.4 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} -- clusterName: second-route-www.test.com-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 5.6.7.8 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} -- clusterName: "192_168_1_250_8080" - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 192.168.1.250 - portValue: 8080 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.listeners.yaml deleted file mode 100755 index 1eec8005ef8..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.listeners.yaml +++ /dev/null @@ -1,113 +0,0 @@ -- address: - socketAddress: - address: 0.0.0.0 - portValue: 10080 - defaultFilterChain: - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - commonHttpProtocolOptions: - headersWithUnderscoresAction: REJECT_REQUEST - http2ProtocolOptions: - initialConnectionWindowSize: 1048576 - initialStreamWindowSize: 65536 - maxConcurrentStreams: 100 - httpFilters: - - name: envoy.filters.http.jwt_authn - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication - providers: - first-route-www.test.com/example: - audiences: - - foo.com - claimToHeaders: - - claimName: claim.neteased.key - headerName: one-route-example-key1 - issuer: https://www.example.com - payloadInMetadata: https://www.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: localhost_443 - timeout: 5s - uri: https://localhost/jwt/public-key/jwks.json - retryPolicy: {} - first-route-www.test.com/example2: - audiences: - - one.foo.com - - two.foo.com - claimToHeaders: - - claimName: claim.neteased.key - headerName: one-route-example2-key1 - - claimName: name - headerName: one-route-example2-key2 - issuer: https://www.two.example.com - payloadInMetadata: https://www.two.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: "192_168_1_250_8080" - timeout: 5s - uri: https://192.168.1.250:8080/jwt/public-key/jwks.json - retryPolicy: {} - second-route-www.test.com/example: - audiences: - - foo.com - claimToHeaders: - - claimName: claim.neteased.key - headerName: second-route-example-key1 - issuer: https://www.example.com - payloadInMetadata: https://www.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: localhost_443 - timeout: 5s - uri: https://localhost/jwt/public-key/jwks.json - retryPolicy: {} - second-route-www.test.com/example2: - audiences: - - one.foo.com - - two.foo.com - issuer: https://www.two.example.com - payloadInMetadata: https://www.two.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: "192_168_1_250_8080" - timeout: 5s - uri: https://192.168.1.250:8080/jwt/public-key/jwks.json - retryPolicy: {} - requirementMap: - first-route-www.test.com: - requiresAny: - requirements: - - providerName: first-route-www.test.com/example - - providerName: first-route-www.test.com/example2 - second-route-www.test.com: - requiresAny: - requirements: - - providerName: second-route-www.test.com/example - - providerName: second-route-www.test.com/example2 - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - mergeSlashes: true - normalizePath: true - pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT - rds: - configSource: - ads: {} - resourceApiVersion: V3 - routeConfigName: first-listener - statPrefix: http - upgradeConfigs: - - upgradeType: websocket - useRemoteAddress: true - name: first-listener - perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.routes.yaml deleted file mode 100755 index 630157c4b40..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-multi-provider.routes.yaml +++ /dev/null @@ -1,25 +0,0 @@ -- ignorePortInHostMatching: true - name: first-listener - virtualHosts: - - domains: - - '*' - name: first-listener/* - routes: - - match: - path: foo/bar - name: first-route-www.test.com - route: - cluster: first-route-www.test.com-dest - typedPerFilterConfig: - envoy.filters.http.jwt_authn: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig - requirementName: first-route-www.test.com - - match: - path: foo/baz - name: second-route-www.test.com - route: - cluster: second-route-www.test.com-dest - typedPerFilterConfig: - envoy.filters.http.jwt_authn: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig - requirementName: second-route-www.test.com diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.clusters.yaml deleted file mode 100644 index 35bc85eaf5b..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.clusters.yaml +++ /dev/null @@ -1,59 +0,0 @@ -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: first-route-dest - lbPolicy: LEAST_REQUEST - name: first-route-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: second-route-dest - lbPolicy: LEAST_REQUEST - name: second-route-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - dnsRefreshRate: 30s - lbPolicy: LEAST_REQUEST - loadAssignment: - clusterName: localhost_443 - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: localhost - portValue: 443 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} - name: localhost_443 - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - respectDnsTtl: true - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - validationContext: - trustedCa: - filename: /etc/ssl/certs/ca-certificates.crt - type: STRICT_DNS diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.endpoints.yaml deleted file mode 100644 index b321ca1f8e7..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.endpoints.yaml +++ /dev/null @@ -1,22 +0,0 @@ -- clusterName: first-route-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 1.2.3.4 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} -- clusterName: second-route-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 5.6.7.8 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.listeners.yaml deleted file mode 100644 index 133530ef79f..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.listeners.yaml +++ /dev/null @@ -1,93 +0,0 @@ -- accessLog: - - filter: - responseFlagFilter: - flags: - - NR - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - logFormat: - textFormatSource: - inlineString: | - {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} - path: /dev/stdout - address: - socketAddress: - address: 0.0.0.0 - portValue: 10080 - defaultFilterChain: - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - accessLog: - - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - logFormat: - textFormatSource: - inlineString: | - {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} - path: /dev/stdout - commonHttpProtocolOptions: - headersWithUnderscoresAction: REJECT_REQUEST - http2ProtocolOptions: - initialConnectionWindowSize: 1048576 - initialStreamWindowSize: 65536 - maxConcurrentStreams: 100 - httpFilters: - - name: envoy.filters.http.jwt_authn - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication - providers: - first-route/example: - audiences: - - foo.com - claimToHeaders: - - claimName: claim.neteased.key - headerName: first-route-key - issuer: https://www.example.com - payloadInMetadata: https://www.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: localhost_443 - timeout: 5s - uri: https://localhost/jwt/public-key/jwks.json - retryPolicy: {} - second-route/example: - audiences: - - foo.com - issuer: https://www.example.com - payloadInMetadata: https://www.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: localhost_443 - timeout: 5s - uri: https://localhost/jwt/public-key/jwks.json - retryPolicy: {} - requirementMap: - first-route: - providerName: first-route/example - second-route: - providerName: second-route/example - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - mergeSlashes: true - normalizePath: true - pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT - rds: - configSource: - ads: {} - resourceApiVersion: V3 - routeConfigName: first-listener - statPrefix: http - upgradeConfigs: - - upgradeType: websocket - useRemoteAddress: true - name: first-listener - perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.routes.yaml deleted file mode 100644 index 2078809a694..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-multi-route-single-provider.routes.yaml +++ /dev/null @@ -1,25 +0,0 @@ -- ignorePortInHostMatching: true - name: first-listener - virtualHosts: - - domains: - - '*' - name: first-listener/* - routes: - - match: - path: foo/bar - name: first-route - route: - cluster: first-route-dest - typedPerFilterConfig: - envoy.filters.http.jwt_authn: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig - requirementName: first-route - - match: - path: foo/baz - name: second-route - route: - cluster: second-route-dest - typedPerFilterConfig: - envoy.filters.http.jwt_authn: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig - requirementName: second-route diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.clusters.yaml deleted file mode 100644 index 868cdb1b6c2..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.clusters.yaml +++ /dev/null @@ -1,105 +0,0 @@ -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: first-route-dest - lbPolicy: LEAST_REQUEST - name: first-route-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: second-route-dest - lbPolicy: LEAST_REQUEST - name: second-route-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: third-route-dest - lbPolicy: LEAST_REQUEST - name: third-route-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - dnsRefreshRate: 30s - lbPolicy: LEAST_REQUEST - loadAssignment: - clusterName: ratelimit_cluster - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: envoy-ratelimit.envoy-gateway-system.svc.cluster.local - portValue: 8081 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} - name: ratelimit_cluster - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - respectDnsTtl: true - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - tlsCertificates: - - certificateChain: - filename: /certs/tls.crt - privateKey: - filename: /certs/tls.key - validationContext: - trustedCa: - filename: /certs/ca.crt - type: STRICT_DNS - typedExtensionProtocolOptions: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicitHttpConfig: - http2ProtocolOptions: {} -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: "192_168_1_250_443" - lbPolicy: LEAST_REQUEST - name: "192_168_1_250_443" - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - validationContext: - trustedCa: - filename: /etc/ssl/certs/ca-certificates.crt - type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.endpoints.yaml deleted file mode 100644 index d8d04b17185..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.endpoints.yaml +++ /dev/null @@ -1,44 +0,0 @@ -- clusterName: first-route-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 1.2.3.4 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} -- clusterName: second-route-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 1.2.3.4 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} -- clusterName: third-route-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 1.2.3.4 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} -- clusterName: "192_168_1_250_443" - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 192.168.1.250 - portValue: 443 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.listeners.yaml deleted file mode 100644 index 8ff2832d64b..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.listeners.yaml +++ /dev/null @@ -1,63 +0,0 @@ -- address: - socketAddress: - address: 0.0.0.0 - portValue: 10080 - defaultFilterChain: - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - commonHttpProtocolOptions: - headersWithUnderscoresAction: REJECT_REQUEST - http2ProtocolOptions: - initialConnectionWindowSize: 1048576 - initialStreamWindowSize: 65536 - maxConcurrentStreams: 100 - httpFilters: - - name: envoy.filters.http.jwt_authn - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication - providers: - first-route/example: - audiences: - - foo.com - issuer: https://www.example.com - payloadInMetadata: https://www.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: "192_168_1_250_443" - timeout: 5s - uri: https://192.168.1.250/jwt/public-key/jwks.json - retryPolicy: {} - requirementMap: - first-route: - providerName: first-route/example - - name: envoy.filters.http.ratelimit - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit - domain: first-listener - enableXRatelimitHeaders: DRAFT_VERSION_03 - rateLimitService: - grpcService: - envoyGrpc: - clusterName: ratelimit_cluster - transportApiVersion: V3 - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - mergeSlashes: true - normalizePath: true - pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT - rds: - configSource: - ads: {} - resourceApiVersion: V3 - routeConfigName: first-listener - statPrefix: http - upgradeConfigs: - - upgradeType: websocket - useRemoteAddress: true - name: first-listener - perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.routes.yaml deleted file mode 100644 index 0223e989d39..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-ratelimit.routes.yaml +++ /dev/null @@ -1,46 +0,0 @@ -- ignorePortInHostMatching: true - name: first-listener - virtualHosts: - - domains: - - '*' - name: first-listener/* - routes: - - match: - path: foo/bar - name: first-route - route: - cluster: first-route-dest - rateLimits: - - actions: - - headerValueMatch: - descriptorKey: first-route-key-rule-0-match-0 - descriptorValue: first-route-value-rule-0-match-0 - expectMatch: true - headers: - - name: x-user-id - stringMatch: - exact: one - typedPerFilterConfig: - envoy.filters.http.jwt_authn: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig - requirementName: first-route - - match: - path: example - name: second-route - route: - cluster: second-route-dest - rateLimits: - - actions: - - requestHeaders: - descriptorKey: second-route-key-rule-0-match-0 - headerName: x-user-id - - match: - path: test - name: third-route - route: - cluster: third-route-dest - rateLimits: - - actions: - - genericKey: - descriptorKey: third-route-key-rule-0-match--1 - descriptorValue: third-route-value-rule-0-match--1 diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.clusters.yaml deleted file mode 100644 index 7a0c933174e..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.clusters.yaml +++ /dev/null @@ -1,45 +0,0 @@ -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: first-route-dest - lbPolicy: LEAST_REQUEST - name: first-route-dest - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS -- commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - dnsRefreshRate: 30s - lbPolicy: LEAST_REQUEST - loadAssignment: - clusterName: localhost_443 - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: localhost - portValue: 443 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} - name: localhost_443 - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - respectDnsTtl: true - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - validationContext: - trustedCa: - filename: /etc/ssl/certs/ca-certificates.crt - type: STRICT_DNS diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.endpoints.yaml deleted file mode 100644 index 0d68b430c20..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.endpoints.yaml +++ /dev/null @@ -1,11 +0,0 @@ -- clusterName: first-route-dest - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 1.2.3.4 - portValue: 50000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.listeners.yaml deleted file mode 100644 index 9a095ee2e29..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.listeners.yaml +++ /dev/null @@ -1,53 +0,0 @@ -- address: - socketAddress: - address: 0.0.0.0 - portValue: 10080 - defaultFilterChain: - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - commonHttpProtocolOptions: - headersWithUnderscoresAction: REJECT_REQUEST - http2ProtocolOptions: - initialConnectionWindowSize: 1048576 - initialStreamWindowSize: 65536 - maxConcurrentStreams: 100 - httpFilters: - - name: envoy.filters.http.jwt_authn - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication - providers: - first-route/example: - audiences: - - foo.com - issuer: https://www.example.com - payloadInMetadata: https://www.example.com - remoteJwks: - asyncFetch: {} - cacheDuration: 300s - httpUri: - cluster: localhost_443 - timeout: 5s - uri: https://localhost/jwt/public-key/jwks.json - retryPolicy: {} - requirementMap: - first-route: - providerName: first-route/example - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - mergeSlashes: true - normalizePath: true - pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT - rds: - configSource: - ads: {} - resourceApiVersion: V3 - routeConfigName: first-listener - statPrefix: http - upgradeConfigs: - - upgradeType: websocket - useRemoteAddress: true - name: first-listener - perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.routes.yaml deleted file mode 100644 index c73bec09093..00000000000 --- a/internal/xds/translator/testdata/out/xds-ir/jwt-authn-single-route-single-match.routes.yaml +++ /dev/null @@ -1,16 +0,0 @@ -- ignorePortInHostMatching: true - name: first-listener - virtualHosts: - - domains: - - '*' - name: first-listener/* - routes: - - match: - path: foo/bar - name: first-route - route: - cluster: first-route-dest - typedPerFilterConfig: - envoy.filters.http.jwt_authn: - '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig - requirementName: first-route diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.clusters.yaml old mode 100644 new mode 100755 similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.clusters.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.clusters.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.endpoints.yaml old mode 100644 new mode 100755 similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.endpoints.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.endpoints.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.listeners.yaml old mode 100644 new mode 100755 similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.listeners.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.listeners.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.routes.yaml old mode 100644 new mode 100755 similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-multi-provider.routes.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-multi-provider.routes.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.clusters.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.clusters.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.clusters.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.endpoints.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.endpoints.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.endpoints.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.listeners.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.listeners.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.listeners.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.routes.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-multi-route-single-provider.routes.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-multi-route-single-provider.routes.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.clusters.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.clusters.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.clusters.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.endpoints.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.endpoints.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.endpoints.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.listeners.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.listeners.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.listeners.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.routes.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-ratelimit.routes.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.routes.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.clusters.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.clusters.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.clusters.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.endpoints.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.endpoints.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.endpoints.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.listeners.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.listeners.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.listeners.yaml diff --git a/internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.routes.yaml similarity index 100% rename from internal/xds/translator/testdata/out/xds-ir/authn-single-route-single-match.routes.yaml rename to internal/xds/translator/testdata/out/xds-ir/jwt-single-route-single-match.routes.yaml diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index e13f8f4cc93..82fd0937aef 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -254,11 +254,6 @@ func (t *Translator) processHTTPListenerXdsTranslation(tCtx *types.ResourceVersi return err } - // Create authn jwks clusters, if needed. // TODO zhaohuabing remove this after deprecating authentication filter - if err := createJwksClusters(tCtx, httpListener.Routes); err != nil { - return err - } - // Create authn jwks clusters, if needed. if err := createJWKSClusters(tCtx, httpListener.Routes); err != nil { return err diff --git a/internal/xds/translator/translator_test.go b/internal/xds/translator/translator_test.go index 6c6fd275397..15fac37f495 100644 --- a/internal/xds/translator/translator_test.go +++ b/internal/xds/translator/translator_test.go @@ -90,10 +90,6 @@ func TestTranslateXds(t *testing.T) { name: "simple-tls", requireSecrets: true, }, - { - name: "mixed-tls-jwt-authn", - requireSecrets: true, - }, { name: "tls-route-passthrough", }, @@ -151,18 +147,6 @@ func TestTranslateXds(t *testing.T) { { name: "ratelimit-sourceip", }, - { - name: "authn-single-route-single-match", - }, - { - name: "authn-multi-route-single-provider", - }, - { - name: "authn-multi-route-multi-provider", - }, - { - name: "authn-ratelimit", - }, { name: "accesslog", }, @@ -194,16 +178,16 @@ func TestTranslateXds(t *testing.T) { name: "cors", }, { - name: "jwt-authn-multi-route-multi-provider", + name: "jwt-multi-route-multi-provider", }, { - name: "jwt-authn-multi-route-single-provider", + name: "jwt-multi-route-single-provider", }, { - name: "jwt-authn-ratelimit", + name: "jwt-ratelimit", }, { - name: "jwt-authn-single-route-single-match", + name: "jwt-single-route-single-match", }, } diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 310aa30de47..a76e5d3d52d 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -14,7 +14,6 @@ API group. ### Resource Types -- [AuthenticationFilter](#authenticationfilter) - [BackendTrafficPolicy](#backendtrafficpolicy) - [BackendTrafficPolicyList](#backendtrafficpolicylist) - [ClientTrafficPolicy](#clienttrafficpolicy) @@ -28,48 +27,6 @@ API group. -#### AuthenticationFilter - - - - - - - -| Field | Description | -| --- | --- | -| `apiVersion` _string_ | `gateway.envoyproxy.io/v1alpha1` -| `kind` _string_ | `AuthenticationFilter` -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | -| `spec` _[AuthenticationFilterSpec](#authenticationfilterspec)_ | Spec defines the desired state of the AuthenticationFilter type. | - - -#### AuthenticationFilterSpec - - - -AuthenticationFilterSpec defines the desired state of the AuthenticationFilter type. - -_Appears in:_ -- [AuthenticationFilter](#authenticationfilter) - -| Field | Description | -| --- | --- | -| `type` _[AuthenticationFilterType](#authenticationfiltertype)_ | Type defines the type of authentication provider to use. Supported provider types are "JWT". | -| `jwtProviders` _[JwtAuthenticationFilterProvider](#jwtauthenticationfilterprovider) array_ | JWT defines the JSON Web Token (JWT) authentication provider type. When multiple jwtProviders are specified, the JWT is considered valid if any of the providers successfully validate the JWT. For additional details, see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter.html. | - - -#### AuthenticationFilterType - -_Underlying type:_ `string` - -AuthenticationFilterType is a type of authentication provider. - -_Appears in:_ -- [AuthenticationFilterSpec](#authenticationfilterspec) - - - #### BackendTrafficPolicy @@ -158,7 +115,6 @@ ClaimToHeader defines a configuration to convert JWT claims into HTTP headers _Appears in:_ - [JWTProvider](#jwtprovider) -- [JwtAuthenticationFilterProvider](#jwtauthenticationfilterprovider) | Field | Description | | --- | --- | @@ -939,24 +895,6 @@ _Appears in:_ | `claimToHeaders` _[ClaimToHeader](#claimtoheader) array_ | ClaimToHeaders is a list of JWT claims that must be extracted into HTTP request headers For examples, following config: The claim must be of type; string, int, double, bool. Array type claims are not supported | -#### JwtAuthenticationFilterProvider - - - -JwtAuthenticationFilterProvider defines the JSON Web Token (JWT) authentication provider type and how JWTs should be verified: - -_Appears in:_ -- [AuthenticationFilterSpec](#authenticationfilterspec) - -| Field | Description | -| --- | --- | -| `name` _string_ | Name defines a unique name for the JWT provider. A name can have a variety of forms, including RFC1123 subdomains, RFC 1123 labels, or RFC 1035 labels. | -| `issuer` _string_ | Issuer is the principal that issued the JWT and takes the form of a URL or email address. For additional details, see https://tools.ietf.org/html/rfc7519#section-4.1.1 for URL format and https://rfc-editor.org/rfc/rfc5322.html for email format. If not provided, the JWT issuer is not checked. | -| `audiences` _string array_ | Audiences is a list of JWT audiences allowed access. For additional details, see https://tools.ietf.org/html/rfc7519#section-4.1.3. If not provided, JWT audiences are not checked. | -| `remoteJWKS` _[RemoteJWKS](#remotejwks)_ | RemoteJWKS defines how to fetch and cache JSON Web Key Sets (JWKS) from a remote HTTP/HTTPS endpoint. | -| `claimToHeaders` _[ClaimToHeader](#claimtoheader) array_ | ClaimToHeaders is a list of JWT claims that must be extracted into HTTP request headers For examples, following config: The claim must be of type; string, int, double, bool. Array type claims are not supported | - - #### KubernetesContainerSpec @@ -1577,7 +1515,6 @@ RemoteJWKS defines how to fetch and cache JSON Web Key Sets (JWKS) from a remote _Appears in:_ - [JWTProvider](#jwtprovider) -- [JwtAuthenticationFilterProvider](#jwtauthenticationfilterprovider) | Field | Description | | --- | --- | diff --git a/site/content/en/latest/design/rate-limit.md b/site/content/en/latest/design/rate-limit.md index d7ee194e580..d2f68c7e78d 100644 --- a/site/content/en/latest/design/rate-limit.md +++ b/site/content/en/latest/design/rate-limit.md @@ -220,18 +220,22 @@ will be rate limited at 10 requests/hour. ```yaml apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter +kind: SecurityPolicy metadata: name: jwt-example spec: - type: JWT - jwtProviders: - - name: example - remoteJWKS: - uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json - claimToHeaders: - - claim: name - header: custom-request-header + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: eg + jwt: + providers: + - name: example + remoteJWKS: + uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json + claimToHeaders: + - claim: name + header: custom-request-header --- apiVersion: gateway.envoyproxy.io/v1alpha1 kind: RateLimitFilter @@ -266,11 +270,6 @@ spec: port: 3000 weight: 1 filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: jwt-example - type: ExtensionRef - type: ExtensionRef extensionRef: group: gateway.envoyproxy.io diff --git a/site/content/en/latest/design/request-authentication.md b/site/content/en/latest/design/request-authentication.md deleted file mode 100644 index 82682bf2a0b..00000000000 --- a/site/content/en/latest/design/request-authentication.md +++ /dev/null @@ -1,515 +0,0 @@ ---- -title: "Request Authentication Design" ---- - -## Overview - -[Issue 336][] specifies the need for exposing a user-facing API to configure request authentication. Request -authentication is defined as an authentication mechanism to be enforced by Envoy on a per-request basis. A connection -will be rejected if it contains invalid authentication information, based on the `AuthenticationFilter` API type -proposed in this design document. - -Envoy Gateway leverages [Gateway API][] for configuring managed Envoy proxies. Gateway API defines core, extended, and -implementation-specific API [support levels][] for implementers such as Envoy Gateway to expose features. Since -implementing request authentication is not covered by `Core` or `Extended` APIs, an `Implementation-specific` API will -be created for this purpose. - -## Goals - -* Define an API for configuring request authentication. -* Implement [JWT] as the first supported authentication type. -* Allow users that manage routes, e.g. [HTTPRoute][], to authenticate matching requests before forwarding to a backend - service. -* Support HTTPRoutes as an Authentication API referent. HTTPRoute provides multiple [extension points][]. The - [HTTPRouteFilter][] is the extension point supported by the Authentication API. - -## Non-Goals - -* Allow infrastructure administrators to override or establish default authentication policies. -* Support referents other than HTTPRoute. -* Support Gateway API extension points other than HTTPRouteFilter. - -## Use-Cases - -These use-cases are presented as an aid for how users may attempt to utilize the outputs of the design. They are not an -exhaustive list of features for authentication support in Envoy Gateway. - -As a Service Producer, I need the ability to: -* Authenticate a request before forwarding it to a backend service. -* Have different authentication mechanisms per route rule. -* Choose from different authentication mechanisms supported by Envoy, e.g. OIDC. - -### Authentication API Type - -The Authentication API type defines authentication configuration for authenticating requests through managed Envoy -proxies. - -```go -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -) - -type AuthenticationFilter struct { - metav1.TypeMeta - metav1.ObjectMeta - - // Spec defines the desired state of the Authentication type. - Spec AuthenticationFilterSpec - - // Note: The status sub-resource has been excluded but may be added in the future. -} - -// AuthenticationFilterSpec defines the desired state of the AuthenticationFilter type. -// +union -type AuthenticationFilterSpec struct { - // Type defines the type of authentication provider to use. Supported provider types are: - // - // * JWT: A provider that uses JSON Web Token (JWT) for authenticating requests. - // - // +unionDiscriminator - Type AuthenticationFilterType - - // JWT defines the JSON Web Token (JWT) authentication provider type. When multiple - // jwtProviders are specified, the JWT is considered valid if any of the providers - // successfully validate the JWT. - JwtProviders []JwtAuthenticationFilterProvider -} - -... -``` - -Refer to [PR 773][] for the detailed AuthenticationFilter API spec. - -The status subresource is not included in the AuthenticationFilter API. Status will be surfaced by an HTTPRoute that -references an AuthenticationFilter. For example, an HTTPRoute will surface the `ResolvedRefs=False` status condition if it -references an AuthenticationFilter that does not exist. It may be beneficial to add AuthenticationFilter status fields in the future -based on defined use-cases. For example, a remote [JWKS][] can be validated based on the specified URI and have an -appropriate status condition surfaced. - -#### AuthenticationFilter Example - -The following is an AuthenticationFilter example with one JWT authentication provider: - -```yaml -apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter -metadata: - name: example -spec: - type: JWT - jwtProviders: - - name: example - issuer: https://www.example.com - audiences: - - foo.com - remoteJwks: - uri: https://foo.com/jwt/public-key/jwks.json - -``` - -__Note:__ `type` is a union type, allowing only one of any supported provider type such as `jwtProviders` to be -specified. - -The following is an example HTTPRoute configured to use the above JWT authentication provider: - -```yaml -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: example -spec: - parentRefs: - - name: eg - hostnames: - - www.example.com - rules: - - matches: - - path: - type: PathPrefix - value: /foo - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: example - backendRefs: - - name: backend - port: 3000 -``` - -Requests for `www.example.com/foo` will be authenticated using the referenced JWT provider before being forwarded to the -backend service named "backend". - -## Implementation Details - -The JWT authentication type is translated to an Envoy [JWT authentication filter][] and a cluster is created for each -remote [JWKS][]. The following examples provide additional details on how Gateway API and AuthenticationFilter resources are -translated into Envoy configuration. - -### Example 1: One Route with One JWT Provider - -The following cluster is created from the above HTTPRoute and AuthenticationFilter: - -```yaml -dynamic_clusters: - - name: foo.com|443 - load_assignment: - cluster_name: foo.com|443 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: foo.com - port_value: 443 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - sni: foo.com - common_tls_context: - validation_context: - match_subject_alt_names: - - exact: "*.foo.com" - trusted_ca: - filename: /etc/ssl/certs/ca-certificates.crt -``` - -A JWT authentication HTTP filter is added to the HTTP Connection Manager. For example: - -```yaml -dynamic_resources: - dynamic_listeners: - - name: example_listener - address: - socket_address: - address: 1.2.3.4 - port_value: 80 - filter_chains: - - filters: - - name: envoy.http_connection_manager - http_filters: - - name: envoy.filters.http.jwt_authn - typed_config: - "@type": type.googleapis.com/envoy.config.filter.http.jwt_authn.v2alpha.JwtAuthentication -``` - -This JWT authentication HTTP filter contains two fields: -* The `providers` field specifies how a JWT should be verified, such as where to extract the token, where to fetch the - public key ([JWKS][]) and where to output its payload. This field is built from the source resource `namespace-name`, and - the JWT provider name of an AuthenticationFilter. -* The `rules` field specifies matching rules and their requirements. If a request matches a rule, its requirement - applies. The requirement specifies which JWT providers should be used. This field is built from a HTTPRoute - `matches` rule that references the AuthenticationFilter. When a referenced Authentication specifies multiple - `jwtProviders`, the JWT is considered valid if __any__ of the providers successfully validate the JWT. - -The following JWT authentication HTTP filter `providers` configuration is created from the above AuthenticationFilter. - -```yaml -providers: - example: - issuer: https://www.example.com - audiences: - - foo.com - remote_jwks: - http_uri: - uri: https://foo.com/jwt/public-key/jwks.json - cluster: example_jwks_cluster - timeout: 1s -``` - -The following JWT authentication HTTP filter `rules` configuration is created from the above HTTPRoute. - -```yaml -rules: - - match: - prefix: /foo - requires: - provider_name: default-example-example -``` - -### Example 2: Two HTTPRoutes with Different AuthenticationFilters - -The following example contains: -* Two HTTPRoutes with different hostnames. -* Each HTTPRoute references a different AuthenticationFilter. -* Each AuthenticationFilter contains a different JWT provider. - -```yaml -apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter -metadata: - name: example1 -spec: - type: JWT - jwtProviders: - - name: example1 - issuer: https://www.example1.com - audiences: - - foo.com - remoteJwks: - uri: https://foo.com/jwt/public-key/jwks.json ---- -apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter -metadata: - name: example2 -spec: - type: JWT - jwtProviders: - - name: example2 - issuer: https://www.example2.com - audiences: - - bar.com - remoteJwks: - uri: https://bar.com/jwt/public-key/jwks.json ---- -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: example1 -spec: - hostnames: - - www.example1.com - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: eg - rules: - - matches: - - path: - type: PathPrefix - value: /foo - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: example1 - backendRefs: - - name: backend - port: 3000 ---- -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: example2 -spec: - hostnames: - - www.example2.com - parentRefs: - - group: gateway.networking.k8s.io - kind: Gateway - name: eg - rules: - - matches: - - path: - type: PathPrefix - value: /bar - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: example2 - backendRefs: - - name: backend2 - port: 3000 -``` - -The following xDS configuration is created from the above example resources: - -```yaml -configs: -... -dynamic_listeners: - - name: default-eg-http - ... - default_filter_chain: - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - '@type': >- - type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: http - rds: - config_source: - ... - route_config_name: default-eg-http - http_filters: - - name: envoy.filters.http.jwt_authn - typed_config: - '@type': >- - type.googleapis.com/envoy.config.filter.http.jwt_authn.v2alpha.JwtAuthentication - providers: - default-example1-example1: - issuer: https://www.example1.com - audiences: - - foo.com - remote_jwks: - http_uri: - uri: https://foo.com/jwt/public-key/jwks.json - cluster: default-example1-example1-jwt - default-example2-example2: - issuer: https://www.example2.com - audiences: - - bar.com - remote_jwks: - http_uri: - uri: https://bar.com/jwt/public-key/jwks.json - cluster: default-example2-example2-jwt - rules: - - match: - exact: /foo - requires: - provider_name: default-example1-example1 - - match: - exact: /bar - requires: - provider_name: default-example2-example2 - - name: envoy.filters.http.router - typed_config: - '@type': >- - type.googleapis.com/envoy.extensions.filters.http.router.v3.Router -dynamic_route_configs: - - route_config: - '@type': type.googleapis.com/envoy.config.route.v3.RouteConfiguration - name: default-eg-http - virtual_hosts: - - name: default-eg-http - domains: - - '*' - routes: - - match: - prefix: /foo - headers: - - name: ':authority' - string_match: - exact: www.example1.com - route: - cluster: default-backend-rule-0-match-0-www.example1.com - - match: - prefix: /bar - headers: - - name: ':authority' - string_match: - exact: www.example2.com - route: - cluster: default-backend2-rule-0-match-0-www.example2.com -dynamic_active_clusters: - - cluster: - name: default-backend-rule-0-match-0-www.example.com - ... - endpoints: - - locality: {} - lb_endpoints: - - endpoint: - address: - socket_address: - address: $BACKEND_SERVICE1_IP - port_value: 3000 - - cluster: - '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster - name: default-backend-rule-1-match-0-www.example.com - ... - endpoints: - - locality: {} - lb_endpoints: - - endpoint: - address: - socket_address: - address: $BACKEND_SERVICE2_IP - port_value: 3000 -... -``` - -__Note:__ The JWT provider cluster and route is omitted from the above example for brevity. - -### Implementation Outline - -* Update the Kubernetes provider to get/watch AuthenticationFilter resources that are referenced by managed HTTPRoutes. - Add the referenced AuthenticationFilter object to the resource map and publish it. -* Update the resource translator to include the AuthenticationFilter API in HTTPRoute processing. -* Update the xDS translator to translate an AuthenticationFilter into xDS resources. The translator should perform the - following: - * Convert a list of JWT rules from the xds IR into an Envoy JWT filter config. - * Create a JWT authentication HTTP filter. - * Build the HTTP Connection Manager (HCM) HTTP filters. - * Build the HCM. - * When building the Listener, create an HCM for each filter-chain. - -## Adding Authentication Types - -Additional authentication types can be added in the future through the `AuthenticationFilterType` API. For -example, to add the `Foo` authentication type: - -Define the `Foo` authentication provider: - -```go -package v1alpha1 - -// FooAuthenticationFilterProvider defines the "Foo" authentication filter provider type. -type FooAuthenticationFilterProvider struct { - // TODO: Define fields of the Foo authentication filter provider type. -} -``` - -Add the `FooAuthenticationFilterProvider` type to `AuthenticationFilterSpec`: - -```go -package v1alpha1 - -type AuthenticationFilterSpec struct { - ... - - // Foo defines the Foo authentication type. For additional - // details, see: - // - // - // - // +optional - Foo *FooAuthenticationFilterProvider -} -``` - -Lastly, add the type to the `AuthenticationType` enum: - -```go -// AuthenticationType is a type of authentication provider. -// +kubebuilder:validation:Enum=JWT,FOO -type AuthenticationFilterType string - -const ( - // JwtAuthenticationProviderType is the JWT authentication provider type. - FooAuthenticationFilterProviderType AuthenticationFilterType = "FOO" -) -``` - -The AuthenticationFilter API should support additional authentication types in the future, for example: -- OAuth2 -- OIDC - -## Outstanding Questions - -- If Envoy Gateway owns the AuthenticationFilter API, is an xDS IR equivalent needed? -- Should local [JWKS][] be implemented before remote [JWKS][]? -- How should Envoy obtain the trusted CA for a remote [JWKS][]? -- Should HTTPS be the only supported scheme for remote [JWKS][]? -- Should OR'ing JWT providers be supported? -- Should Authentication provide status? -- Are the API field validation rules acceptable? - -[Issue 336]: https://github.com/envoyproxy/gateway/issues/336 -[Gateway API]: https://gateway-api.sigs.k8s.io/ -[support levels]: https://gateway-api.sigs.k8s.io/concepts/conformance/?h=extended#2-support-levels -[JWT]: https://jwt.io/ -[HTTPRoute]: https://gateway-api.sigs.k8s.io/api-types/httproute/ -[extension points]: https://gateway-api.sigs.k8s.io/concepts/api-overview/?h=extension#extension-points -[HTTPRouteFilter]: https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRouteFilter -[JWKS]: https://www.rfc-editor.org/rfc/rfc7517 -[JWT authentication filter]: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter#config-http-filters-jwt-authn -[PR 773]: https://github.com/envoyproxy/gateway/pull/733 diff --git a/site/content/en/latest/user/authn.md b/site/content/en/latest/user/jwt-authentication.md similarity index 67% rename from site/content/en/latest/user/authn.md rename to site/content/en/latest/user/jwt-authentication.md index 18409cb5dee..239bca9b88c 100644 --- a/site/content/en/latest/user/authn.md +++ b/site/content/en/latest/user/jwt-authentication.md @@ -1,12 +1,15 @@ --- -title: "Request Authentication" +title: "JWT Authentication" --- This guide provides instructions for configuring [JSON Web Token (JWT)][jwt] authentication. JWT authentication checks if an incoming request has a valid JWT before routing the request to a backend service. Currently, Envoy Gateway only supports validating a JWT from an HTTP header, e.g. `Authorization: Bearer `. -## Installation +Envoy Gateway introduces a new CRD called [SecurityPolicy][SecurityPolicy] that allows the user to configure JWT authentication. +This instantiated resource can be linked to a [Gateway][Gateway], [HTTPRoute][HTTPRoute] or [GRPCRoute][GRPCRoute] resource. + +## Prerequisites Follow the steps from the [Quickstart](quickstart.md) guide to install Envoy Gateway and the example manifest. For GRPC - follow the steps from the [GRPC Routing](grpc-routing.md) example. @@ -14,39 +17,42 @@ Before proceeding, you should be able to query the example backend using HTTP or ## Configuration -Allow requests with a valid JWT by creating an [AuthenticationFilter][] and referencing it from the example HTTPRoute or GRPCRoute. +Allow requests with a valid JWT by creating an [SecurityPolicy][SecurityPolicy] and attaching it to the example +HTTPRoute or GRPCRoute. ### HTTPRoute ```shell -kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/authn/jwt.yaml +kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/jwt/jwt.yaml ``` -The HTTPRoute is now updated to authenticate requests for `/foo` and allow unauthenticated requests to `/bar`. The -`/foo` route rule references an AuthenticationFilter that provides the JWT authentication configuration. +Two HTTPRoute has been created, one for `/foo` and another for `/bar`. A SecurityPolicy has been created and targeted +HTTPRoute foo to authenticate requests for `/foo`. The HTTPRoute bar is not targeted by the SecurityPolicy and will allow +unauthenticated requests to `/bar`. Verify the HTTPRoute configuration and status: ```shell -kubectl get httproute/backend -o yaml +kubectl get httproute/foo -o yaml +kubectl get httproute/bar -o yaml ``` -The AuthenticationFilter is configured for JWT authentication and uses a single [JSON Web Key Set (JWKS)][jwks] +The SecurityPolicy is configured for JWT authentication and uses a single [JSON Web Key Set (JWKS)][jwks] provider for authenticating the JWT. -Verify the AuthenticationFilter configuration: +Verify the SecurityPolicy configuration: ```shell -kubectl get authenticationfilter/jwt-example -o yaml +kubectl get securitypolicy/jwt-example -o yaml ``` ### GRPCRoute ```shell -kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/authn/grtpc-jwt.yaml +kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/jwt/grtpc-jwt.yaml ``` -The GRPCRoute is now updated to authenticate all requests to `yages` service, by referencing an AuthenticationFilter that provides the JWT authentication configuration. +A SecurityPolicy has been created and targeted GRPCRoute yages to authenticate all requests for `yages` service.. Verify the GRPCRoute configuration and status: @@ -54,13 +60,13 @@ Verify the GRPCRoute configuration and status: kubectl get grpcroute/yages -o yaml ``` -The AuthenticationFilter is configured for JWT authentication and uses a single [JSON Web Key Set (JWKS)][jwks] +The SecurityPolicy is configured for JWT authentication and uses a single [JSON Web Key Set (JWKS)][jwks] provider for authenticating the JWT. -Verify the AuthenticationFilter configuration: +Verify the SecurityPolicy configuration: ```shell -kubectl get authenticationfilter/jwt-example -o yaml +kubectl get securitypolicy/jwt-example -o yaml ``` ## Testing @@ -146,16 +152,19 @@ You should see the below response Follow the steps from the [Quickstart](quickstart.md) guide to uninstall Envoy Gateway and the example manifest. -Delete the AuthenticationFilter: +Delete the SecurityPolicy: ```shell -kubectl delete authenticationfilter/jwt-example +kubectl delete securitypolicy/jwt-example ``` ## Next Steps Checkout the [Developer Guide](../../contributions/develop/) to get involved in the project. +[SecurityPolicy]: https://gateway.envoyproxy.io/latest/design/security-policy [jwt]: https://tools.ietf.org/html/rfc7519 -[AuthenticationFilter]: https://gateway.envoyproxy.io/latest/api/extension_types.html#authenticationfilter [jwks]: https://tools.ietf.org/html/rfc7517 +[Gateway]: https://gateway-api.sigs.k8s.io/api-types/gateway +[HTTPRoute]: https://gateway-api.sigs.k8s.io/api-types/httproute +[GRPCRoute]: https://gateway-api.sigs.k8s.io/api-types/grpcroute diff --git a/test/e2e/testdata/ratelimit-based-jwt-claims.yaml b/test/e2e/testdata/ratelimit-based-jwt-claims.yaml index 9a2f1342120..edfcb8ad6aa 100644 --- a/test/e2e/testdata/ratelimit-based-jwt-claims.yaml +++ b/test/e2e/testdata/ratelimit-based-jwt-claims.yaml @@ -1,17 +1,22 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: AuthenticationFilter +kind: SecurityPolicy metadata: name: jwt-example namespace: gateway-conformance-infra spec: - type: JWT - jwtProviders: - - name: example - remoteJWKS: - uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json - claimToHeaders: - - claim: name - header: x-claim-name + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: http-ratelimit-based-jwt-claims + namespace: gateway-conformance-infra + jwt: + providers: + - name: example + remoteJWKS: + uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/authn/jwks.json + claimToHeaders: + - claim: name + header: x-claim-name --- apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy @@ -48,16 +53,20 @@ spec: - backendRefs: - name: infra-backend-v1 port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: AuthenticationFilter - name: jwt-example - type: ExtensionRef matches: - path: type: PathPrefix value: /foo +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-no-ratelimit + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: - backendRefs: - name: infra-backend-v1 port: 8080 diff --git a/tools/crd-ref-docs/config.yaml b/tools/crd-ref-docs/config.yaml index 89963f55d8f..cd95e3d8d4a 100644 --- a/tools/crd-ref-docs/config.yaml +++ b/tools/crd-ref-docs/config.yaml @@ -1,7 +1,7 @@ processor: # RE2 regular expressions describing types that should be excluded from the generated documentation. ignoreTypes: - - "(EnvoyProxy|AuthenticationFilter)List$" + - "(EnvoyProxy)List$" # RE2 regular expressions describing type fields that should be excluded from the generated documentation. ignoreFields: - "status$"