From 42ee2b4e88b95d58304b753249e6a4bd7ae34616 Mon Sep 17 00:00:00 2001 From: izturn <44051386+izturn@users.noreply.github.com> Date: Thu, 16 Nov 2023 00:12:47 +0800 Subject: [PATCH] httpproxy: fix the order for filter: AuthZ & AuthN (#5840) Signed-off-by: gang.liu --- changelogs/unreleased/5840-izturn-minor.md | 3 + internal/envoy/v3/listener.go | 4 +- internal/envoy/v3/listener_test.go | 451 +++----- internal/xdscache/v3/listener.go | 8 +- internal/xdscache/v3/listener_test.go | 1193 ++++---------------- internal/xdscache/v3/secret_test.go | 1 + 6 files changed, 390 insertions(+), 1270 deletions(-) create mode 100644 changelogs/unreleased/5840-izturn-minor.md diff --git a/changelogs/unreleased/5840-izturn-minor.md b/changelogs/unreleased/5840-izturn-minor.md new file mode 100644 index 00000000000..e7ef76d5755 --- /dev/null +++ b/changelogs/unreleased/5840-izturn-minor.md @@ -0,0 +1,3 @@ +## JWT Authentication happens before External Authorization + +Fixes a bug where when the external authorization filter and JWT authentication filter were both configured, the external authorization filter was executed _before_ the JWT authentication filter. Now, JWT authentication happens before external authorization when they are both configured. \ No newline at end of file diff --git a/internal/envoy/v3/listener.go b/internal/envoy/v3/listener.go index 6e644c5042c..efd18cef12e 100644 --- a/internal/envoy/v3/listener.go +++ b/internal/envoy/v3/listener.go @@ -815,9 +815,9 @@ func FilterExternalAuthz(externalAuthorization *dag.ExternalAuthorization) *http } } -// FilterJWTAuth returns a `jwt_authn` filter configured with the +// FilterJWTAuthN returns a `jwt_authn` filter configured with the // requested parameters. -func FilterJWTAuth(jwtProviders []dag.JWTProvider) *http.HttpFilter { +func FilterJWTAuthN(jwtProviders []dag.JWTProvider) *http.HttpFilter { if len(jwtProviders) == 0 { return nil } diff --git a/internal/envoy/v3/listener_test.go b/internal/envoy/v3/listener_test.go index aa2164284a2..023ef43f149 100644 --- a/internal/envoy/v3/listener_test.go +++ b/internal/envoy/v3/listener_test.go @@ -17,13 +17,19 @@ import ( "testing" "time" + "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" + "github.com/projectcontour/contour/internal/dag" + "github.com/projectcontour/contour/internal/envoy" + "github.com/projectcontour/contour/internal/protobuf" + "github.com/projectcontour/contour/internal/ref" + "github.com/projectcontour/contour/internal/timeout" + envoy_accesslog_v3 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3" envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" envoy_gzip_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/compression/gzip/compressor/v3" envoy_compressor_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/compressor/v3" envoy_cors_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/cors/v3" - envoy_config_filter_http_ext_authz_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3" envoy_config_filter_http_grpc_stats_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/grpc_stats/v3" envoy_grpc_web_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/grpc_web/v3" envoy_config_filter_http_local_ratelimit_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/local_ratelimit/v3" @@ -33,14 +39,7 @@ import ( http "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" envoy_tcp_proxy_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3" envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" - envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3" "github.com/envoyproxy/go-control-plane/pkg/wellknown" - "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" - "github.com/projectcontour/contour/internal/dag" - "github.com/projectcontour/contour/internal/envoy" - "github.com/projectcontour/contour/internal/protobuf" - "github.com/projectcontour/contour/internal/ref" - "github.com/projectcontour/contour/internal/timeout" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/anypb" @@ -1740,6 +1739,84 @@ func TestBuilderValidation(t *testing.T) { } func TestAddFilter(t *testing.T) { + routerFilter := &http.HttpFilter{ + Name: "router", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), + }, + } + grpcWebFilter := &http.HttpFilter{ + Name: "grpcweb", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), + }, + } + corsFilter := &http.HttpFilter{ + Name: "cors", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_cors_v3.Cors{}), + }, + } + + grpcStatsFilter := &http.HttpFilter{ + Name: "grpc_stats", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny( + &envoy_config_filter_http_grpc_stats_v3.FilterConfig{ + EmitFilterState: true, + EnableUpstreamStats: true, + }, + ), + }, + } + luaFilter := &http.HttpFilter{ + Name: "envoy.filters.http.lua", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&lua.Lua{ + DefaultSourceCode: &envoy_core_v3.DataSource{ + Specifier: &envoy_core_v3.DataSource_InlineString{ + InlineString: "-- Placeholder for per-Route or per-Cluster overrides.", + }, + }, + }), + }, + } + rbacFilter := &http.HttpFilter{ + Name: "envoy.filters.http.rbac", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_rbac_v3.RBAC{}), + }, + } + + localRateLimitFilter := &http.HttpFilter{ + Name: "local_ratelimit", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny( + &envoy_config_filter_http_local_ratelimit_v3.LocalRateLimit{ + StatPrefix: "http", + }, + ), + }, + } + + compressFilter := &http.HttpFilter{ + Name: "compressor", + ConfigType: &http.HttpFilter_TypedConfig{ + TypedConfig: protobuf.MustMarshalAny(&envoy_compressor_v3.Compressor{ + CompressorLibrary: &envoy_core_v3.TypedExtensionConfig{ + Name: "gzip", + TypedConfig: protobuf.MustMarshalAny( + &envoy_gzip_v3.Gzip{}, + ), + }, + ResponseDirectionConfig: &envoy_compressor_v3.Compressor_ResponseDirectionConfig{ + CommonConfig: &envoy_compressor_v3.Compressor_CommonDirectionConfig{ + ContentType: compressorContentTypes, + }, + }, + }), + }, + } tests := map[string]struct { builder *httpConnectionManagerBuilder @@ -1753,318 +1830,61 @@ func TestAddFilter(t *testing.T) { }, "Add a single router filter to empty builder": { builder: HTTPConnectionManagerBuilder(), - add: &http.HttpFilter{ - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }, - want: []*http.HttpFilter{ - { - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }, - }, + add: routerFilter, + want: []*http.HttpFilter{routerFilter}, }, "Add a single non-router filter to empty builder": { builder: HTTPConnectionManagerBuilder(), - add: &http.HttpFilter{ - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }, - want: []*http.HttpFilter{ - { - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }, - }, + add: grpcWebFilter, + want: []*http.HttpFilter{grpcWebFilter}, }, "Add a single router filter to non-empty builder": { - builder: HTTPConnectionManagerBuilder().AddFilter(&http.HttpFilter{ - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }), - add: &http.HttpFilter{ - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }, - want: []*http.HttpFilter{ - { - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }, - { - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }, - }, + builder: HTTPConnectionManagerBuilder().AddFilter(grpcWebFilter), + add: routerFilter, + want: []*http.HttpFilter{grpcWebFilter, routerFilter}, }, "Add a filter to a builder with a router": { - builder: HTTPConnectionManagerBuilder().AddFilter(&http.HttpFilter{ - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }), - add: &http.HttpFilter{ - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }, - want: []*http.HttpFilter{ - { - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }, - { - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }, - }, + builder: HTTPConnectionManagerBuilder().AddFilter(routerFilter), + add: grpcWebFilter, + want: []*http.HttpFilter{grpcWebFilter, routerFilter}, }, "Add to the default filters": { builder: HTTPConnectionManagerBuilder().DefaultFilters(), - add: FilterExternalAuthz(&dag.ExternalAuthorization{ - AuthorizationService: &dag.ExtensionCluster{ - Name: "test", - SNI: "", - }, - AuthorizationFailOpen: false, - AuthorizationResponseTimeout: timeout.Setting{}, - AuthorizationServerWithRequestBody: nil, - }), + add: authzFilter(), want: []*http.HttpFilter{ - { - Name: "compressor", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_compressor_v3.Compressor{ - CompressorLibrary: &envoy_core_v3.TypedExtensionConfig{ - Name: "gzip", - TypedConfig: protobuf.MustMarshalAny( - &envoy_gzip_v3.Gzip{}, - ), - }, - ResponseDirectionConfig: &envoy_compressor_v3.Compressor_ResponseDirectionConfig{ - CommonConfig: &envoy_compressor_v3.Compressor_CommonDirectionConfig{ - ContentType: compressorContentTypes, - }, - }, - }), - }, - }, - { - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }, - { - Name: "grpc_stats", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny( - &envoy_config_filter_http_grpc_stats_v3.FilterConfig{ - EmitFilterState: true, - EnableUpstreamStats: true, - }, - ), - }, - }, - { - Name: "cors", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_cors_v3.Cors{}), - }, - }, - { - Name: "local_ratelimit", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny( - &envoy_config_filter_http_local_ratelimit_v3.LocalRateLimit{ - StatPrefix: "http", - }, - ), - }, - }, - { - Name: "envoy.filters.http.lua", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&lua.Lua{ - DefaultSourceCode: &envoy_core_v3.DataSource{ - Specifier: &envoy_core_v3.DataSource_InlineString{ - InlineString: "-- Placeholder for per-Route or per-Cluster overrides.", - }, - }, - }), - }, - }, - { - Name: "envoy.filters.http.rbac", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_rbac_v3.RBAC{}), - }, - }, - FilterExternalAuthz(&dag.ExternalAuthorization{ - AuthorizationService: &dag.ExtensionCluster{ - Name: "test", - SNI: "", - }, - AuthorizationFailOpen: false, - AuthorizationResponseTimeout: timeout.Setting{}, - AuthorizationServerWithRequestBody: nil, - }), - { - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }, + compressFilter, + grpcWebFilter, + grpcStatsFilter, + corsFilter, + localRateLimitFilter, + luaFilter, + rbacFilter, + authzFilter(), + routerFilter, }, }, "Add to the default filters with AuthorizationServerBufferSettings": { builder: HTTPConnectionManagerBuilder().DefaultFilters(), - add: FilterExternalAuthz(&dag.ExternalAuthorization{ - AuthorizationService: &dag.ExtensionCluster{ - Name: "test", - SNI: "ext-auth-server.com", - }, - AuthorizationFailOpen: false, - AuthorizationResponseTimeout: timeout.Setting{}, - AuthorizationServerWithRequestBody: &dag.AuthorizationServerBufferSettings{ + add: authzFilter("ext-auth-server.com", &dag.AuthorizationServerBufferSettings{ + MaxRequestBytes: 10, + AllowPartialMessage: true, + PackAsBytes: true, + }), + want: []*http.HttpFilter{ + compressFilter, + grpcWebFilter, + grpcStatsFilter, + corsFilter, + localRateLimitFilter, + luaFilter, + rbacFilter, + authzFilter("ext-auth-server.com", &dag.AuthorizationServerBufferSettings{ MaxRequestBytes: 10, AllowPartialMessage: true, PackAsBytes: true, - }, - }), - want: []*http.HttpFilter{ - { - Name: "compressor", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_compressor_v3.Compressor{ - CompressorLibrary: &envoy_core_v3.TypedExtensionConfig{ - Name: "gzip", - TypedConfig: protobuf.MustMarshalAny( - &envoy_gzip_v3.Gzip{}, - ), - }, - ResponseDirectionConfig: &envoy_compressor_v3.Compressor_ResponseDirectionConfig{ - CommonConfig: &envoy_compressor_v3.Compressor_CommonDirectionConfig{ - ContentType: compressorContentTypes, - }, - }, - }), - }, - }, - { - Name: "grpcweb", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_grpc_web_v3.GrpcWeb{}), - }, - }, - { - Name: "grpc_stats", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny( - &envoy_config_filter_http_grpc_stats_v3.FilterConfig{ - EmitFilterState: true, - EnableUpstreamStats: true, - }, - ), - }, - }, - { - Name: "cors", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_cors_v3.Cors{}), - }, - }, - { - Name: "local_ratelimit", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny( - &envoy_config_filter_http_local_ratelimit_v3.LocalRateLimit{ - StatPrefix: "http", - }, - ), - }, - }, - { - Name: "envoy.filters.http.lua", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&lua.Lua{ - DefaultSourceCode: &envoy_core_v3.DataSource{ - Specifier: &envoy_core_v3.DataSource_InlineString{ - InlineString: "-- Placeholder for per-Route or per-Cluster overrides.", - }, - }, - }), - }, - }, - { - Name: "envoy.filters.http.rbac", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_rbac_v3.RBAC{}), - }, - }, - { - Name: "envoy.filters.http.ext_authz", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny( - &envoy_config_filter_http_ext_authz_v3.ExtAuthz{ - Services: &envoy_config_filter_http_ext_authz_v3.ExtAuthz_GrpcService{ - GrpcService: &envoy_core_v3.GrpcService{ - TargetSpecifier: &envoy_core_v3.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &envoy_core_v3.GrpcService_EnvoyGrpc{ - ClusterName: "test", - Authority: "ext-auth-server.com", - }, - }, - Timeout: envoy.Timeout(timeout.Setting{}), - InitialMetadata: []*envoy_core_v3.HeaderValue{}, - }, - }, - ClearRouteCache: true, - FailureModeAllow: false, - StatusOnError: &envoy_type_v3.HttpStatus{ - Code: envoy_type_v3.StatusCode_Forbidden, - }, - MetadataContextNamespaces: []string{}, - IncludePeerCertificate: true, - TransportApiVersion: envoy_core_v3.ApiVersion_V3, - WithRequestBody: &envoy_config_filter_http_ext_authz_v3.BufferSettings{ - MaxRequestBytes: 10, - AllowPartialMessage: true, - PackAsBytes: true, - }, - }, - ), - }, - }, - { - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }, + }), + routerFilter, }, }, } @@ -2077,11 +1897,28 @@ func TestAddFilter(t *testing.T) { } assert.Panics(t, func() { - HTTPConnectionManagerBuilder().DefaultFilters().AddFilter(&http.HttpFilter{ - Name: "router", - ConfigType: &http.HttpFilter_TypedConfig{ - TypedConfig: protobuf.MustMarshalAny(&envoy_router_v3.Router{}), - }, - }) + HTTPConnectionManagerBuilder().DefaultFilters().AddFilter(routerFilter) + }) +} + +func authzFilter(extras ...any) *http.HttpFilter { + sni := "" + if len(extras) > 0 { + sni = extras[0].(string) + } + + var body *dag.AuthorizationServerBufferSettings + if len(extras) > 1 { + body = extras[1].(*dag.AuthorizationServerBufferSettings) + } + + return FilterExternalAuthz(&dag.ExternalAuthorization{ + AuthorizationService: &dag.ExtensionCluster{ + Name: "test", + SNI: sni, + }, + AuthorizationFailOpen: false, + AuthorizationResponseTimeout: timeout.Setting{}, + AuthorizationServerWithRequestBody: body, }) } diff --git a/internal/xdscache/v3/listener.go b/internal/xdscache/v3/listener.go index 01e99745689..85070cd2253 100644 --- a/internal/xdscache/v3/listener.go +++ b/internal/xdscache/v3/listener.go @@ -464,10 +464,10 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { } if vh.TCPProxy == nil { - var authFilter *http.HttpFilter + var authzFilter *http.HttpFilter if vh.ExternalAuthorization != nil { - authFilter = envoy_v3.FilterExternalAuthz(vh.ExternalAuthorization) + authzFilter = envoy_v3.FilterExternalAuthz(vh.ExternalAuthorization) } // Create a uniquely named HTTP connection manager for @@ -481,8 +481,8 @@ func (c *ListenerCache) OnChange(root *dag.DAG) { Codec(envoy_v3.CodecForVersions(cfg.DefaultHTTPVersions...)). AddFilter(envoy_v3.FilterMisdirectedRequests(vh.VirtualHost.Name)). DefaultFilters(). - AddFilter(authFilter). - AddFilter(envoy_v3.FilterJWTAuth(vh.JWTProviders)). + AddFilter(envoy_v3.FilterJWTAuthN(vh.JWTProviders)). + AddFilter(authzFilter). RouteConfigName(httpsRouteConfigName(listener, vh.VirtualHost.Name)). MetricsPrefix(listener.Name). AccessLoggers(cfg.newSecureAccessLog()). diff --git a/internal/xdscache/v3/listener_test.go b/internal/xdscache/v3/listener_test.go index 0c64fc3030f..c50baa84f52 100644 --- a/internal/xdscache/v3/listener_test.go +++ b/internal/xdscache/v3/listener_test.go @@ -14,21 +14,14 @@ package v3 import ( + "net/url" "path" "testing" "time" - "google.golang.org/protobuf/types/known/wrapperspb" - - envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" - envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" - ratelimit_config_v3 "github.com/envoyproxy/go-control-plane/envoy/config/ratelimit/v3" - ratelimit_filter_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ratelimit/v3" - http "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" - envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" - "github.com/envoyproxy/go-control-plane/pkg/wellknown" contour_api_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" + contour_api_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" "github.com/projectcontour/contour/internal/contourconfig" "github.com/projectcontour/contour/internal/dag" envoy_v3 "github.com/projectcontour/contour/internal/envoy/v3" @@ -36,8 +29,17 @@ import ( "github.com/projectcontour/contour/internal/protobuf" "github.com/projectcontour/contour/internal/ref" "github.com/projectcontour/contour/internal/timeout" + + envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" + ratelimit_config_v3 "github.com/envoyproxy/go-control-plane/envoy/config/ratelimit/v3" + ratelimit_filter_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ratelimit/v3" + http "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" + envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" + "github.com/envoyproxy/go-control-plane/pkg/wellknown" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/wrapperspb" v1 "k8s.io/api/core/v1" networking_v1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -161,6 +163,49 @@ func TestListenerVisit(t *testing.T) { AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, v1alpha1.LogLevelInfo)). Get() + jwksTimeout := "10s" + jwksTimeoutDuration, _ := time.ParseDuration(jwksTimeout) + jwtProvider := contour_api_v1.JWTProvider{ + Name: "provider-1", + Issuer: "issuer.jwt.example.com", + RemoteJWKS: contour_api_v1.RemoteJWKS{ + URI: "https://jwt.example.com/jwks.json", + Timeout: jwksTimeout, + }, + } + jwksURL, _ := url.Parse(jwtProvider.RemoteJWKS.URI) + + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "secret", + Namespace: "default", + }, + Type: "kubernetes.io/tls", + Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), + } + + fallbackSecret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fallbacksecret", + Namespace: "default", + }, + Type: "kubernetes.io/tls", + Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), + } + + service := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kuard", + Namespace: "default", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Name: "http", + Protocol: "TCP", + Port: 8080, + }}, + }, + } tests := map[string]struct { ListenerConfig fallbackCertificate *types.NamespacedName @@ -183,19 +228,7 @@ func TestListenerVisit(t *testing.T) { DefaultBackend: backend("kuard", 8080), }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -226,19 +259,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -272,27 +293,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -362,27 +364,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -436,27 +419,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -487,27 +451,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -575,27 +520,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTPS_LISTENER, @@ -640,27 +566,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -716,27 +623,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -794,27 +682,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -870,27 +739,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kuard", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 8080, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -942,27 +792,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1013,27 +844,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1084,27 +896,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1164,35 +957,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1281,35 +1048,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1398,35 +1139,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1515,35 +1230,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1632,35 +1321,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1749,35 +1412,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1860,35 +1497,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -1974,35 +1585,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2065,34 +1650,15 @@ func TestListenerVisit(t *testing.T) { Services: []contour_api_v1.Service{ { Name: "backend", - Port: 80, - }, - }, - }, - }, - }, - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, + Port: 80, + }, + }, + }, + }, }, }, + secret, + service, }, want: listenermap(), }, @@ -2128,27 +1694,8 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2198,19 +1745,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2254,19 +1789,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2310,19 +1833,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2366,19 +1877,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2422,19 +1921,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2479,27 +1966,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2561,19 +2029,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2615,19 +2071,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ @@ -2670,19 +2114,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ @@ -2725,19 +2157,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2781,27 +2201,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2866,27 +2267,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -2950,27 +2332,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3034,27 +2397,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3125,19 +2469,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3209,27 +2541,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3353,35 +2666,9 @@ func TestListenerVisit(t *testing.T) { }, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fallbacksecret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + fallbackSecret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3527,19 +2814,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3573,19 +2848,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3627,27 +2890,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3709,19 +2953,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3763,27 +2995,8 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", - }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), - }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3845,19 +3058,7 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "backend", - Namespace: "default", - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, - }}, - }, - }, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3899,27 +3100,85 @@ func TestListenerVisit(t *testing.T) { }}, }, }, - &v1.Secret{ + secret, + service, + }, + want: listenermap(&envoy_listener_v3.Listener{ + Name: ENVOY_HTTP_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8080), + PerConnectionBufferLimitBytes: wrapperspb.UInt32(32768), + FilterChains: envoy_v3.FilterChains(envoy_v3.HTTPConnectionManagerBuilder(). + RouteConfigName(ENVOY_HTTP_LISTENER). + MetricsPrefix(ENVOY_HTTP_LISTENER). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, v1alpha1.LogLevelInfo)). + DefaultFilters(). + Get(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }, &envoy_listener_v3.Listener{ + Name: ENVOY_HTTPS_LISTENER, + Address: envoy_v3.SocketAddress("0.0.0.0", 8443), + PerConnectionBufferLimitBytes: wrapperspb.UInt32(32768), + FilterChains: []*envoy_listener_v3.FilterChain{{ + FilterChainMatch: &envoy_listener_v3.FilterChainMatch{ + ServerNames: []string{"www.example.com"}, + }, + TransportSocket: transportSocket("secret", envoy_tls_v3.TlsParameters_TLSv1_2, envoy_tls_v3.TlsParameters_TLSv1_3, nil, "h2", "http/1.1"), + Filters: envoy_v3.Filters(envoy_v3.HTTPConnectionManagerBuilder(). + AddFilter(envoy_v3.FilterMisdirectedRequests("www.example.com")). + DefaultFilters(). + MetricsPrefix(ENVOY_HTTPS_LISTENER). + RouteConfigName(path.Join("https", "www.example.com")). + AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, v1alpha1.LogLevelInfo)). + Get()), + }}, + ListenerFilters: envoy_v3.ListenerFilters( + envoy_v3.TLSInspector(), + ), + SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(), + }), + }, + + "httpproxy with authZ the authN": { + ListenerConfig: ListenerConfig{ + PerConnectionBufferLimitBytes: ref.To(uint32(32768)), + }, + objs: []any{ + &contour_api_v1alpha1.ExtensionService{ ObjectMeta: metav1.ObjectMeta{ - Name: "secret", - Namespace: "default", + Name: "auth", + Namespace: "extension", }, - Type: "kubernetes.io/tls", - Data: secretdata(CERTIFICATE, RSA_PRIVATE_KEY), }, - &v1.Service{ + &contour_api_v1.HTTPProxy{ ObjectMeta: metav1.ObjectMeta{ - Name: "backend", + Name: "simple", Namespace: "default", }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{{ - Name: "http", - Protocol: "TCP", - Port: 80, + Spec: contour_api_v1.HTTPProxySpec{ + VirtualHost: &contour_api_v1.VirtualHost{ + Fqdn: "www.example.com", + TLS: &contour_api_v1.TLS{ + SecretName: "secret", + }, + Authorization: &contour_api_v1.AuthorizationServer{ + ExtensionServiceRef: contour_api_v1.ExtensionServiceReference{ + Namespace: "extension", + Name: "auth", + }, + }, + JWTProviders: []contour_api_v1.JWTProvider{jwtProvider}, + }, + Routes: []contour_api_v1.Route{{ + Services: []contour_api_v1.Service{{ + Name: "backend", + Port: 80, + }}, }}, }, }, + secret, + service, }, want: listenermap(&envoy_listener_v3.Listener{ Name: ENVOY_HTTP_LISTENER, @@ -3945,6 +3204,24 @@ func TestListenerVisit(t *testing.T) { Filters: envoy_v3.Filters(envoy_v3.HTTPConnectionManagerBuilder(). AddFilter(envoy_v3.FilterMisdirectedRequests("www.example.com")). DefaultFilters(). + AddFilter(envoy_v3.FilterJWTAuthN([]dag.JWTProvider{{ + Name: jwtProvider.Name, + Issuer: jwtProvider.Issuer, + RemoteJWKS: dag.RemoteJWKS{ + URI: jwtProvider.RemoteJWKS.URI, + Cluster: dag.DNSNameCluster{ + Address: jwksURL.Hostname(), + Scheme: jwksURL.Scheme, + Port: 443, + }, + Timeout: jwksTimeoutDuration, + }, + }})). + AddFilter(envoy_v3.FilterExternalAuthz(&dag.ExternalAuthorization{ + AuthorizationService: &dag.ExtensionCluster{ + Name: "extension/extension/auth", + }, + })). MetricsPrefix(ENVOY_HTTPS_LISTENER). RouteConfigName(path.Join("https", "www.example.com")). AccessLoggers(envoy_v3.FileAccessLogEnvoy(DEFAULT_HTTP_ACCESS_LOG, "", nil, v1alpha1.LogLevelInfo)). @@ -3960,9 +3237,11 @@ func TestListenerVisit(t *testing.T) { for name, tc := range tests { t.Run(name, func(t *testing.T) { + lc := ListenerCache{ Config: tc.ListenerConfig, } + lc.OnChange(buildDAGFallback(t, tc.fallbackCertificate, tc.objs...)) protobuf.ExpectEqual(t, tc.want, lc.values) }) diff --git a/internal/xdscache/v3/secret_test.go b/internal/xdscache/v3/secret_test.go index 1559b879ccf..989d50c744e 100644 --- a/internal/xdscache/v3/secret_test.go +++ b/internal/xdscache/v3/secret_test.go @@ -504,6 +504,7 @@ func buildDAGFallback(t *testing.T, fallbackCertificate *types.NamespacedName, o FieldLogger: fixture.NewTestLogger(t), }, Processors: []dag.Processor{ + &dag.ExtensionServiceProcessor{}, &dag.ListenerProcessor{ HTTPAddress: "0.0.0.0", HTTPPort: 8080,