From 93a05614a65a513367b2f92e5c49454ad0e1fa39 Mon Sep 17 00:00:00 2001 From: zirain Date: Wed, 9 Oct 2024 13:17:33 +0800 Subject: [PATCH 01/39] bump google.golang.org/grpc v1.67 (#4390) * bump grpc Signed-off-by: zirain * 1.67.1 Signed-off-by: zirain --------- Signed-off-by: zirain --- go.mod | 2 +- go.sum | 4 ++-- internal/gatewayapi/runner/runner.go | 1 + internal/globalratelimit/runner/runner.go | 1 + internal/xds/server/runner/runner.go | 1 + internal/xds/server/runner/runner_test.go | 1 + 6 files changed, 7 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2dd4911a207..a07ab071892 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( require ( github.com/docker/docker v27.3.1+incompatible github.com/replicatedhq/troubleshoot v0.105.2 - google.golang.org/grpc v1.66.2 + google.golang.org/grpc v1.67.1 sigs.k8s.io/kubectl-validate v0.0.5-0.20240827210056-ce13d95db263 ) diff --git a/go.sum b/go.sum index 624b91ab533..6e355f58e24 100644 --- a/go.sum +++ b/go.sum @@ -1092,8 +1092,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= -google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/gatewayapi/runner/runner.go b/internal/gatewayapi/runner/runner.go index f9068b68dcf..f8f7b2a6965 100644 --- a/internal/gatewayapi/runner/runner.go +++ b/internal/gatewayapi/runner/runner.go @@ -564,6 +564,7 @@ func (r *Runner) tlsConfig() (*tls.Config, error) { // Configure the server to require client certificates return &tls.Config{ Certificates: []tls.Certificate{serverCert}, + NextProtos: []string{"h2"}, ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: caCertPool, MinVersion: tls.VersionTLS13, diff --git a/internal/globalratelimit/runner/runner.go b/internal/globalratelimit/runner/runner.go index ffccb1ab3a3..baaaaacd6b7 100644 --- a/internal/globalratelimit/runner/runner.go +++ b/internal/globalratelimit/runner/runner.go @@ -213,6 +213,7 @@ func (r *Runner) tlsConfig(cert, key, ca string) *tls.Config { return &tls.Config{ Certificates: []tls.Certificate{cert}, + NextProtos: []string{"h2"}, ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: certPool, MinVersion: tls.VersionTLS13, diff --git a/internal/xds/server/runner/runner.go b/internal/xds/server/runner/runner.go index d8acab8d951..19c4076d458 100644 --- a/internal/xds/server/runner/runner.go +++ b/internal/xds/server/runner/runner.go @@ -180,6 +180,7 @@ func (r *Runner) tlsConfig(cert, key, ca string) *tls.Config { return &tls.Config{ Certificates: []tls.Certificate{cert}, + NextProtos: []string{"h2"}, ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: certPool, MinVersion: tls.VersionTLS13, diff --git a/internal/xds/server/runner/runner_test.go b/internal/xds/server/runner/runner_test.go index 823d426864c..1a3e9322c68 100644 --- a/internal/xds/server/runner/runner_test.go +++ b/internal/xds/server/runner/runner_test.go @@ -157,6 +157,7 @@ func tryConnect(address string, clientCert tls.Certificate, caCertPool *x509.Cer ServerName: "localhost", MinVersion: tls.VersionTLS13, Certificates: []tls.Certificate{clientCert}, + NextProtos: []string{"h2"}, RootCAs: caCertPool, } conn, err := tls.Dial("tcp", address, clientConfig) From 87b841871d4cc44b7443187c318feeee493d01f6 Mon Sep 17 00:00:00 2001 From: zirain Date: Wed, 9 Oct 2024 13:18:41 +0800 Subject: [PATCH 02/39] chore: fix osv scanner (#4414) * chore: fix osv scanner Signed-off-by: zirain * remove comment Signed-off-by: zirain * nit Signed-off-by: zirain --------- Signed-off-by: zirain --- .github/workflows/license-scan.yml | 1 - .github/workflows/osv-scanner.yml | 1 - osv-scanner.toml | 7 +++++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/license-scan.yml b/.github/workflows/license-scan.yml index 2484d76340e..ff3f8d31a02 100644 --- a/.github/workflows/license-scan.yml +++ b/.github/workflows/license-scan.yml @@ -20,7 +20,6 @@ jobs: - name: Run scanner uses: google/osv-scanner-action/osv-scanner-action@19ec1116569a47416e11a45848722b1af31a857b # v1.9.0 with: - # TODO enable call analysis once https://github.com/google/osv-scanner/issues/1220 is resolved scan-args: |- --skip-git --experimental-licenses=Apache-2.0,BSD-2-Clause,BSD-2-Clause-FreeBSD,BSD-3-Clause,MIT,ISC,Python-2.0,PostgreSQL,X11,Zlib diff --git a/.github/workflows/osv-scanner.yml b/.github/workflows/osv-scanner.yml index 8263faac895..e43942d85c7 100644 --- a/.github/workflows/osv-scanner.yml +++ b/.github/workflows/osv-scanner.yml @@ -39,7 +39,6 @@ jobs: contents: read security-events: write with: - # TODO enable call analysis once https://github.com/google/osv-scanner/issues/1220 is resolved scan-args: |- --skip-git --recursive diff --git a/osv-scanner.toml b/osv-scanner.toml index 7125af4a3f7..02cdbc6af53 100644 --- a/osv-scanner.toml +++ b/osv-scanner.toml @@ -96,3 +96,10 @@ version = "1.2.0-rc2" ecosystem = "Go" license.override = ["Apache-2.0"] reason = "https://github.com/envoyproxy/gateway/actions/runs/11065210699/job/30744231458?pr=4270" + +[[PackageOverrides]] +name = "sigs.k8s.io/json" +version = "0.0.0-20221116044647-bc3834ca7abd" +ecosystem = "Go" +license.override = ["Apache-2.0"] +reason = "https://github.com/kubernetes-sigs/json/blob/main/LICENSE" From b9f594ca2cd3b189268e0ed44869ed24737fe9e7 Mon Sep 17 00:00:00 2001 From: zirain Date: Wed, 9 Oct 2024 20:45:03 +0800 Subject: [PATCH 03/39] chore: upgrade test should use VERSION by default (#4393) * chore: upgrade test should use VERSION by default Signed-off-by: zirain * update Signed-off-by: zirain --------- Signed-off-by: zirain --- test/e2e/tests/eg_upgrade.go | 96 +++++++++++++++++++++--------------- tools/make/kube.mk | 2 +- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/test/e2e/tests/eg_upgrade.go b/test/e2e/tests/eg_upgrade.go index 385952bd2a5..4ca4db15637 100644 --- a/test/e2e/tests/eg_upgrade.go +++ b/test/e2e/tests/eg_upgrade.go @@ -12,14 +12,17 @@ import ( "context" "fmt" "os" + "strings" "testing" "time" + "github.com/stretchr/testify/require" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/kube" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -50,11 +53,11 @@ var EGUpgradeTest = suite.ConformanceTest{ chartPath := "../../../charts/gateway-helm" relName := "eg" depNS := "envoy-gateway-system" - lastVersionTag := os.Getenv("last_version_tag") + lastVersionTag := os.Getenv("LAST_VERSION_TAG") if lastVersionTag == "" { - // Use v1.0.2 instead of v1.1.2 due to https://github.com/envoyproxy/gateway/issues/4336 - lastVersionTag = "v1.0.2" // Default version tag if not specified + lastVersionTag = "v1.1.2" // Default version tag if not specified } + t.Logf("Upgrading from version: %s", lastVersionTag) // Uninstall the current version of EG relNamespace := "envoy-gateway-system" @@ -105,18 +108,25 @@ var EGUpgradeTest = suite.ConformanceTest{ suite.Applier.GatewayClass = suite.GatewayClassName suite.Applier.MustApplyWithCleanup(t, suite.Client, suite.TimeoutConfig, suite.BaseManifests, suite.Cleanup) + // verify latestVersion is working + kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{depNS}) + + // let's make sure the gateway is up and running + ns := "gateway-upgrade-infra" + gwNN := types.NamespacedName{Name: "ha-gateway", Namespace: ns} + _, err = kubernetes.WaitForGatewayAddress(t, suite.Client, suite.TimeoutConfig, kubernetes.GatewayRef{ + NamespacedName: gwNN, + }) + require.NoErrorf(t, err, "timed out waiting for Gateway address to be assigned") + + // Apply the test manifests for _, manifestLocation := range []string{"testdata/eg-upgrade.yaml"} { tlog.Logf(t, "Applying %s", manifestLocation) suite.Applier.MustApplyWithCleanup(t, suite.Client, suite.TimeoutConfig, manifestLocation, true) } // wait for everything to startup - kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{depNS}) - - // verify latestVersion is working - ns := "gateway-upgrade-infra" routeNN := types.NamespacedName{Name: "http-backend-eg-upgrade", Namespace: ns} - gwNN := types.NamespacedName{Name: "ha-gateway", Namespace: ns} gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{depNS}) @@ -266,47 +276,53 @@ func updateChartCRDs(actionConfig *action.Configuration, gatewayChart *chart.Cha return err } -// TODO: proper migration framework required -func migrateChartCRDs(actionConfig *action.Configuration, gatewayChart *chart.Chart, timeout time.Duration) error { +func migrateChartCRDs(actionConfig *action.Configuration, gatewayChart *chart.Chart, _ time.Duration) error { crds, err := extractCRDs(actionConfig, gatewayChart) if err != nil { return err } + // https: //gateway-api.sigs.k8s.io/guides/?h=upgrade#v12-upgrade-notes + storedVersionsMap := map[string]string{ + "referencegrants.gateway.networking.k8s.io": "v1beta1", + "grpcroutes.gateway.networking.k8s.io": "v1", + } + + restCfg, err := actionConfig.RESTClientGetter.ToRESTConfig() + if err != nil { + return err + } + + cli, err := client.New(restCfg, client.Options{}) + if err != nil { + return err + } + for _, crd := range crds { - if crd.Name == "backendtlspolicies.gateway.networking.k8s.io" || - crd.Name == "grpcroutes.gateway.networking.k8s.io" { - newVersion, err := getGWAPIVersion(crd.Object) + storedVersion, ok := storedVersionsMap[crd.Name] + if !ok { + continue + } + + newVersion, err := getGWAPIVersion(crd.Object) + if err != nil { + return err + } + + if strings.HasPrefix(newVersion, "v1.2.0") { + existingCRD := &apiextensionsv1.CustomResourceDefinition{} + err := cli.Get(context.Background(), types.NamespacedName{Name: crd.Name}, existingCRD) + if kerrors.IsNotFound(err) { + continue + } if err != nil { - return err + return fmt.Errorf("failed to get CRD: %s", err.Error()) } - // https://gateway-api.sigs.k8s.io/guides/?h=upgrade#v11-upgrade-notes - if newVersion == "v1.2.0-rc2" { - helper := resource.NewHelper(crd.Client, crd.Mapping) - existingCRD, err := helper.Get(crd.Namespace, crd.Name) - if kerrors.IsNotFound(err) { - continue - } - // previous version exists - existingVersion, err := getGWAPIVersion(existingCRD) - if err != nil { - return err - } + existingCRD.Status.StoredVersions = []string{storedVersion} - if existingVersion == "v1.0.0" { - // Delete the existing instance of the BTLS and GRPCRoute CRDs - _, errs := actionConfig.KubeClient.Delete([]*resource.Info{crd}) - if errs != nil { - return fmt.Errorf("failed to delete backendtlspolicies: %s", util.MultipleErrors("", errs)) - } - - if kubeClient, ok := actionConfig.KubeClient.(kube.InterfaceExt); ok { - if err := kubeClient.WaitForDelete([]*resource.Info{crd}, timeout); err != nil { - return fmt.Errorf("failed to wait for backendtlspolicies deletion: %s", err.Error()) - } - } - } + if err := cli.Status().Patch(context.Background(), existingCRD, client.MergeFrom(existingCRD)); err != nil { + return fmt.Errorf("failed to patch CRD: %s", err.Error()) } } } @@ -354,7 +370,7 @@ func getGWAPIVersion(object runtime.Object) (string, error) { if ok { return newVersion, nil } - return "", fmt.Errorf("failed to determine Gateway API CRD version") + return "", fmt.Errorf("failed to determine Gateway API CRD version: %v", annotations) } // extractCRDs Extract the CRDs part of the chart diff --git a/tools/make/kube.mk b/tools/make/kube.mk index 2344a3b868d..c659e234787 100644 --- a/tools/make/kube.mk +++ b/tools/make/kube.mk @@ -158,7 +158,7 @@ ifeq ($(E2E_RUN_TEST),) go test $(E2E_TEST_ARGS) ./test/e2e --gateway-class=envoy-gateway --debug=true --cleanup-base-resources=false go test $(E2E_TEST_ARGS) ./test/e2e/merge_gateways --gateway-class=merge-gateways --debug=true --cleanup-base-resources=false go test $(E2E_TEST_ARGS) ./test/e2e/multiple_gc --debug=true --cleanup-base-resources=true - go test $(E2E_TEST_ARGS) ./test/e2e/upgrade --gateway-class=upgrade --debug=true --cleanup-base-resources=$(E2E_CLEANUP) + LAST_VERSION_TAG=$(shell cat VERSION) go test $(E2E_TEST_ARGS) ./test/e2e/upgrade --gateway-class=upgrade --debug=true --cleanup-base-resources=$(E2E_CLEANUP) else go test $(E2E_TEST_ARGS) ./test/e2e --gateway-class=envoy-gateway --debug=true --cleanup-base-resources=$(E2E_CLEANUP) \ --run-test $(E2E_RUN_TEST) From d1cc0ba4372fd7d3f8ede1a1278930e21c22b9f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:55:38 +0800 Subject: [PATCH 04/39] build(deps): bump fortio.org/fortio from 1.66.3 to 1.67.1 (#4405) Bumps [fortio.org/fortio](https://github.com/fortio/fortio) from 1.66.3 to 1.67.1. - [Release notes](https://github.com/fortio/fortio/releases) - [Commits](https://github.com/fortio/fortio/compare/v1.66.3...v1.67.1) --- updated-dependencies: - dependency-name: fortio.org/fortio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 11 ++++++----- go.sum | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index a07ab071892..a34be2541d4 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.23.1 replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16 require ( - fortio.org/fortio v1.66.3 - fortio.org/log v1.16.0 + fortio.org/fortio v1.67.1 + fortio.org/log v1.17.1 github.com/Masterminds/semver/v3 v3.3.0 github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc @@ -72,9 +72,10 @@ require ( cel.dev/expr v0.16.0 // indirect dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect - fortio.org/cli v1.9.0 // indirect - fortio.org/dflag v1.7.2 // indirect - fortio.org/scli v1.15.2 // indirect + fortio.org/cli v1.9.2 // indirect + fortio.org/dflag v1.7.3 // indirect + fortio.org/safecast v1.0.0 // indirect + fortio.org/scli v1.15.3 // indirect fortio.org/sets v1.2.0 // indirect fortio.org/struct2env v0.4.1 // indirect fortio.org/version v1.0.4 // indirect diff --git a/go.sum b/go.sum index 6e355f58e24..acca7a0b90d 100644 --- a/go.sum +++ b/go.sum @@ -9,16 +9,18 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= fortio.org/assert v1.2.1 h1:48I39urpeDj65RP1KguF7akCjILNeu6vICiYMEysR7Q= fortio.org/assert v1.2.1/go.mod h1:039mG+/iYDPO8Ibx8TrNuJCm2T2SuhwRI3uL9nHTTls= -fortio.org/cli v1.9.0 h1:cPgNHvrjxznmbmwuXSwPqQLKZ+RMW8i0iAOESLjt1aI= -fortio.org/cli v1.9.0/go.mod h1:pk/JBE8LcXtNuo5Yj2bLsVbwPaHo8NWdbstSN0cpbFk= -fortio.org/dflag v1.7.2 h1:lUhXFvDlw4CJj/q7hPv/TC+n/wVoQylzQO6bUg5GQa0= -fortio.org/dflag v1.7.2/go.mod h1:6yO/NIgrWfQH195WbHJ3Y45SCx11ffivQjfx2C/FS1U= -fortio.org/fortio v1.66.3 h1:N/Ic9W2tVoJ5LAcr8ZjcF3mNb2ftCw77ZtKF02jwf8Q= -fortio.org/fortio v1.66.3/go.mod h1:+W7ooyLn/Fp3h0UF9JclFEJN50EOvelO6c+VhCYGwnM= -fortio.org/log v1.16.0 h1:GhU8/9NkYZmEIzvTN/DTMedDAStLJraWUUVUA2EbNDc= -fortio.org/log v1.16.0/go.mod h1:t58Spg9njjymvRioh5F6qKGSupEsnMjXLGWIS1i3khE= -fortio.org/scli v1.15.2 h1:vWXt4QOViXNWy4Gdm7d2FDfptzWD00QiWzYAM/IUF7c= -fortio.org/scli v1.15.2/go.mod h1:XvY2JglgCeeZOIc5CrfBTtcsxkVV8xmGL5ykAcBjEHI= +fortio.org/cli v1.9.2 h1:17eJ8QZPjXHcLBpeCe0QMO/0fj5Bw0ZTxVgL7V9jOqc= +fortio.org/cli v1.9.2/go.mod h1:7r55OoTV8NXcTvJT4boWk8s3I2LP6TMZh/0LLMJEYw0= +fortio.org/dflag v1.7.3 h1:yws+v+/fJ67bYgrgcWpLtgdZPEWkYuwdfqz/WyQ8UXo= +fortio.org/dflag v1.7.3/go.mod h1:O1Pk4lKRolw9wwAGyjTo8IsNyqqNRQGKxPOfpOElMqM= +fortio.org/fortio v1.67.1 h1:KAYyeu6z/01d/QwJm2dCVIadAhd8jNsezJHhlkoOMwU= +fortio.org/fortio v1.67.1/go.mod h1:XfrXH/BJ/hhxBXHj9z8FaqvsBbnf46SLyoWtPgopDlU= +fortio.org/log v1.17.1 h1:YQoGyZBnXTVIs77/nZw7BppwSOIamP3I092PGBenBZs= +fortio.org/log v1.17.1/go.mod h1:t58Spg9njjymvRioh5F6qKGSupEsnMjXLGWIS1i3khE= +fortio.org/safecast v1.0.0 h1:dr3131WPX8iS1pTf76+39WeXbTrerDYLvi9s7Oi3wiY= +fortio.org/safecast v1.0.0/go.mod h1:xZmcPk3vi4kuUFf+tq4SvnlVdwViqf6ZSZl91Jr9Jdg= +fortio.org/scli v1.15.3 h1:XZYONPupGOd1Q68G4aq0vWg9obw0M57sC4snkyiab9w= +fortio.org/scli v1.15.3/go.mod h1:cWJJbXObkF+GsbtPqxE60GFctllOANYS+Yp9PJK0xK8= fortio.org/sets v1.2.0 h1:FBfC7R2xrOJtkcioUbY6WqEzdujuBoZRbSdp1fYF4Kk= fortio.org/sets v1.2.0/go.mod h1:J2BwIxNOLWsSU7IMZUg541kh3Au4JEKHrghVwXs68tE= fortio.org/struct2env v0.4.1 h1:rJludAMO5eBvpWplWEQNqoVDFZr4RWMQX7RUapgZyc0= From 3e0742122543d32d24e31b4295a8e74d6d953ce5 Mon Sep 17 00:00:00 2001 From: Guy Daich Date: Wed, 9 Oct 2024 21:10:38 -0500 Subject: [PATCH 05/39] api: host header rewrite (#4410) * api: host header rewrite Signed-off-by: Guy Daich * review fixes Signed-off-by: Guy Daich --------- Signed-off-by: Guy Daich --- api/v1alpha1/httproutefilter_types.go | 30 ++++++++++ api/v1alpha1/zz_generated.deepcopy.go | 25 +++++++++ ...ateway.envoyproxy.io_httproutefilters.yaml | 24 ++++++++ site/content/en/latest/api/extension_types.md | 30 ++++++++++ site/content/zh/latest/api/extension_types.md | 30 ++++++++++ test/cel-validation/httproutefilter_test.go | 55 +++++++++++++++++++ 6 files changed, 194 insertions(+) diff --git a/api/v1alpha1/httproutefilter_types.go b/api/v1alpha1/httproutefilter_types.go index e0e4755f214..7f56ca07d7c 100644 --- a/api/v1alpha1/httproutefilter_types.go +++ b/api/v1alpha1/httproutefilter_types.go @@ -37,6 +37,12 @@ type HTTPRouteFilterSpec struct { // HTTPURLRewriteFilter define rewrites of HTTP URL components such as path and host type HTTPURLRewriteFilter struct { + // Hostname is the value to be used to replace the Host header value during + // forwarding. + // + // +optional + // +notImplementedHide + Hostname *HTTPHostnameModifier `json:"hostname,omitempty"` // Path defines a path rewrite. // // +optional @@ -53,6 +59,18 @@ const ( RegexHTTPPathModifier HTTPPathModifierType = "ReplaceRegexMatch" ) +// HTTPPathModifierType defines the type of Hostname rewrite. +type HTTPHostnameModifierType string + +const ( + // HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in setFromHeader. + // https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header + HeaderHTTPHostnameModifier HTTPHostnameModifierType = "SetFromHeader" + // BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists. + // https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite + BackendHTTPHostnameModifier HTTPHostnameModifierType = "SetFromBackend" +) + type ReplaceRegexMatch struct { // Pattern matches a regular expression against the value of the HTTP Path.The regex string must // adhere to the syntax documented in https://github.com/google/re2/wiki/Syntax. @@ -91,6 +109,18 @@ type HTTPPathModifier struct { ReplaceRegexMatch *ReplaceRegexMatch `json:"replaceRegexMatch,omitempty"` } +// +kubebuilder:validation:XValidation:message="setFromHeader must be nil if the type is not SetFromHeader",rule="!(has(self.setFromHeader) && self.type != 'SetFromHeader')" +// +kubebuilder:validation:XValidation:message="setFromHeader must be specified for SetFromHeader type",rule="!(!has(self.setFromHeader) && self.type == 'SetFromHeader')" +type HTTPHostnameModifier struct { + // +kubebuilder:validation:Enum=SetFromHeader;SetFromBackend + // +kubebuilder:validation:Required + Type HTTPHostnameModifierType `json:"type"` + + // SetFromHeader is the name of the header whose value would be used to rewrite the Host header + // +optional + SetFromHeader *string `json:"setFromHeader,omitempty"` +} + //+kubebuilder:object:root=true // HTTPRouteFilterList contains a list of HTTPRouteFilter resources. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index b6b944b3a14..ed5df681ad2 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -2709,6 +2709,26 @@ func (in *HTTPExtAuthService) DeepCopy() *HTTPExtAuthService { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPHostnameModifier) DeepCopyInto(out *HTTPHostnameModifier) { + *out = *in + if in.SetFromHeader != nil { + in, out := &in.SetFromHeader, &out.SetFromHeader + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHostnameModifier. +func (in *HTTPHostnameModifier) DeepCopy() *HTTPHostnameModifier { + if in == nil { + return nil + } + out := new(HTTPHostnameModifier) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HTTPPathModifier) DeepCopyInto(out *HTTPPathModifier) { *out = *in @@ -2835,6 +2855,11 @@ func (in *HTTPTimeout) DeepCopy() *HTTPTimeout { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HTTPURLRewriteFilter) DeepCopyInto(out *HTTPURLRewriteFilter) { *out = *in + if in.Hostname != nil { + in, out := &in.Hostname, &out.Hostname + *out = new(HTTPHostnameModifier) + (*in).DeepCopyInto(*out) + } if in.Path != nil { in, out := &in.Path, &out.Path *out = new(HTTPPathModifier) diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml index 11447cc470e..7a55ec8871f 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml @@ -53,6 +53,30 @@ spec: description: HTTPURLRewriteFilter define rewrites of HTTP URL components such as path and host properties: + hostname: + description: |- + Hostname is the value to be used to replace the Host header value during + forwarding. + properties: + setFromHeader: + description: SetFromHeader is the name of the header whose + value would be used to rewrite the Host header + type: string + type: + description: HTTPPathModifierType defines the type of Hostname + rewrite. + enum: + - SetFromHeader + - SetFromBackend + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: setFromHeader must be nil if the type is not SetFromHeader + rule: '!(has(self.setFromHeader) && self.type != ''SetFromHeader'')' + - message: setFromHeader must be specified for SetFromHeader type + rule: '!(!has(self.setFromHeader) && self.type == ''SetFromHeader'')' path: description: Path defines a path rewrite. properties: diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 193e698722c..bc01189920d 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1938,6 +1938,36 @@ _Appears in:_ | `headersToBackend` | _string array_ | false | HeadersToBackend are the authorization response headers that will be added
to the original client request before sending it to the backend server.
Note that coexisting headers will be overridden.
If not specified, no authorization response headers will be added to the
original client request. | +#### HTTPHostnameModifier + + + + + +_Appears in:_ +- [HTTPURLRewriteFilter](#httpurlrewritefilter) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `type` | _[HTTPHostnameModifierType](#httphostnamemodifiertype)_ | true | | +| `setFromHeader` | _string_ | false | SetFromHeader is the name of the header whose value would be used to rewrite the Host header | + + +#### HTTPHostnameModifierType + +_Underlying type:_ _string_ + +HTTPPathModifierType defines the type of Hostname rewrite. + +_Appears in:_ +- [HTTPHostnameModifier](#httphostnamemodifier) + +| Value | Description | +| ----- | ----------- | +| `SetFromHeader` | HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in setFromHeader.
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header
| +| `SetFromBackend` | BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists.
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite
| + + #### HTTPPathModifier diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 193e698722c..bc01189920d 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -1938,6 +1938,36 @@ _Appears in:_ | `headersToBackend` | _string array_ | false | HeadersToBackend are the authorization response headers that will be added
to the original client request before sending it to the backend server.
Note that coexisting headers will be overridden.
If not specified, no authorization response headers will be added to the
original client request. | +#### HTTPHostnameModifier + + + + + +_Appears in:_ +- [HTTPURLRewriteFilter](#httpurlrewritefilter) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `type` | _[HTTPHostnameModifierType](#httphostnamemodifiertype)_ | true | | +| `setFromHeader` | _string_ | false | SetFromHeader is the name of the header whose value would be used to rewrite the Host header | + + +#### HTTPHostnameModifierType + +_Underlying type:_ _string_ + +HTTPPathModifierType defines the type of Hostname rewrite. + +_Appears in:_ +- [HTTPHostnameModifier](#httphostnamemodifier) + +| Value | Description | +| ----- | ----------- | +| `SetFromHeader` | HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in setFromHeader.
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header
| +| `SetFromBackend` | BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists.
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite
| + + #### HTTPPathModifier diff --git a/test/cel-validation/httproutefilter_test.go b/test/cel-validation/httproutefilter_test.go index 67a9e4455bb..7f84deb71e5 100644 --- a/test/cel-validation/httproutefilter_test.go +++ b/test/cel-validation/httproutefilter_test.go @@ -15,6 +15,7 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" ) @@ -84,6 +85,60 @@ func TestHTTPRouteFilter(t *testing.T) { "spec.urlRewrite.path.replaceRegexMatch.pattern: Invalid value: \"\": spec.urlRewrite.path.replaceRegexMatch.pattern in body should be at least 1 chars long", }, }, + { + desc: "Valid SetFromHeader", + mutate: func(httproutefilter *egv1a1.HTTPRouteFilter) { + httproutefilter.Spec = egv1a1.HTTPRouteFilterSpec{ + URLRewrite: &egv1a1.HTTPURLRewriteFilter{ + Hostname: &egv1a1.HTTPHostnameModifier{ + Type: egv1a1.HeaderHTTPHostnameModifier, + SetFromHeader: ptr.To("foo"), + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "Valid SetFromBackend", + mutate: func(httproutefilter *egv1a1.HTTPRouteFilter) { + httproutefilter.Spec = egv1a1.HTTPRouteFilterSpec{ + URLRewrite: &egv1a1.HTTPURLRewriteFilter{ + Hostname: &egv1a1.HTTPHostnameModifier{ + Type: egv1a1.BackendHTTPHostnameModifier, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "invalid SetFromHeader missing settings", + mutate: func(httproutefilter *egv1a1.HTTPRouteFilter) { + httproutefilter.Spec = egv1a1.HTTPRouteFilterSpec{ + URLRewrite: &egv1a1.HTTPURLRewriteFilter{ + Hostname: &egv1a1.HTTPHostnameModifier{ + Type: egv1a1.HeaderHTTPHostnameModifier, + }, + }, + } + }, + wantErrors: []string{"spec.urlRewrite.hostname: Invalid value: \"object\": setFromHeader must be specified for SetFromHeader type"}, + }, + { + desc: "invalid SetFromBackend type", + mutate: func(httproutefilter *egv1a1.HTTPRouteFilter) { + httproutefilter.Spec = egv1a1.HTTPRouteFilterSpec{ + URLRewrite: &egv1a1.HTTPURLRewriteFilter{ + Hostname: &egv1a1.HTTPHostnameModifier{ + Type: egv1a1.BackendHTTPHostnameModifier, + SetFromHeader: ptr.To("foo"), + }, + }, + } + }, + wantErrors: []string{"spec.urlRewrite.hostname: Invalid value: \"object\": setFromHeader must be nil if the type is not SetFromHeader"}, + }, } for _, tc := range cases { From ae6787e228677ce30274ea80e67d1265da99d1ca Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Thu, 10 Oct 2024 08:23:40 +0530 Subject: [PATCH 06/39] feat: support inverting header matches for rate limit (#4286) Signed-off-by: Rudrakh Panigrahi --- internal/gatewayapi/backendtrafficpolicy.go | 10 +- ...-ratelimit-invalid-distinct-invert.in.yaml | 53 ++++++ ...ratelimit-invalid-distinct-invert.out.yaml | 164 ++++++++++++++++++ ...ackendtrafficpolicy-with-ratelimit.in.yaml | 3 + ...ckendtrafficpolicy-with-ratelimit.out.yaml | 7 + internal/ir/xds.go | 6 + internal/ir/xds_test.go | 19 +- internal/ir/zz_generated.deepcopy.go | 5 + internal/xds/translator/local_ratelimit.go | 6 +- internal/xds/translator/ratelimit.go | 6 +- .../testdata/in/xds-ir/ratelimit.yaml | 21 +++ .../out/xds-ir/ratelimit.clusters.yaml | 17 ++ .../out/xds-ir/ratelimit.endpoints.yaml | 12 ++ .../testdata/out/xds-ir/ratelimit.routes.yaml | 20 +++ 14 files changed, 344 insertions(+), 5 deletions(-) create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.in.yaml create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.out.yaml diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index d71d49f32ca..12453ea1826 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -710,8 +710,9 @@ func buildRateLimitRule(rule egv1a1.RateLimitRule) (*ir.RateLimitRule, error) { fallthrough case *header.Type == egv1a1.HeaderMatchExact && header.Value != nil: m := &ir.StringMatch{ - Name: header.Name, - Exact: header.Value, + Name: header.Name, + Exact: header.Value, + Invert: header.Invert, } irRule.HeaderMatches = append(irRule.HeaderMatches, m) case *header.Type == egv1a1.HeaderMatchRegularExpression && header.Value != nil: @@ -721,9 +722,14 @@ func buildRateLimitRule(rule egv1a1.RateLimitRule) (*ir.RateLimitRule, error) { m := &ir.StringMatch{ Name: header.Name, SafeRegex: header.Value, + Invert: header.Invert, } irRule.HeaderMatches = append(irRule.HeaderMatches, m) case *header.Type == egv1a1.HeaderMatchDistinct && header.Value == nil: + if header.Invert != nil && *header.Invert { + return nil, fmt.Errorf("unable to translate rateLimit." + + "Invert is not applicable for distinct header match type") + } m := &ir.StringMatch{ Name: header.Name, Distinct: true, diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.in.yaml new file mode 100644 index 00000000000..a1ed0f512cc --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.in.yaml @@ -0,0 +1,53 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway + 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 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway + sectionName: http + rules: + - backendRefs: + - name: service + port: 8080 +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway + rateLimit: + type: Global + global: + rules: + - clientSelectors: + - headers: + - name: x-org-id + type: Distinct + invert: true + limit: + requests: 10 + unit: Hour diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.out.yaml new file mode 100644 index 00000000000..4ea1623c867 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit-invalid-distinct-invert.out.yaml @@ -0,0 +1,164 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: policy-for-gateway + namespace: envoy-gateway + spec: + rateLimit: + global: + rules: + - clientSelectors: + - headers: + - invert: true + name: x-org-id + type: Distinct + limit: + requests: 10 + unit: Hour + type: Global + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: 'RateLimit: unable to translate rateLimit.Invert is not applicable + for distinct header match type.' + reason: Invalid + status: "False" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway + 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 + namespace: default + spec: + parentRefs: + - name: gateway + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Service default/service not found + reason: BackendNotFound + status: "False" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway +xdsIR: + envoy-gateway/gateway: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: true + metadata: + kind: Gateway + name: gateway + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + name: grpcroute/default/grpcroute/rule/0 + settings: + - weight: 1 + directResponse: + statusCode: 500 + hostname: '*' + isHTTP2: true + metadata: + kind: GRPCRoute + name: grpcroute + namespace: default + name: grpcroute/default/grpcroute/rule/0/match/-1/* diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml index e4f1fc10c64..f536d9a20bc 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml @@ -83,6 +83,9 @@ backendTrafficPolicies: value: one - name: x-org-id type: Distinct + - name: x-org-id + value: admin + invert: true limit: requests: 10 unit: Hour diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml index 2f7a2d5e8f9..07fa997e109 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml @@ -52,6 +52,9 @@ backendTrafficPolicies: value: one - name: x-org-id type: Distinct + - invert: true + name: x-org-id + value: admin limit: requests: 10 unit: Hour @@ -306,6 +309,10 @@ xdsIR: name: x-user-id - distinct: true name: x-org-id + - distinct: false + exact: admin + invert: true + name: x-org-id limit: requests: 10 unit: Hour diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 9750680f387..40e7da917f3 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -47,6 +47,7 @@ var ( ErrDestEndpointUDSPortInvalid = errors.New("field Port must not be specified for Unix Domain Socket address") ErrDestEndpointUDSHostInvalid = errors.New("field Host must not be specified for Unix Domain Socket address") ErrStringMatchConditionInvalid = errors.New("only one of the Exact, Prefix, SafeRegex or Distinct fields must be set") + ErrStringMatchInvertDistinctInvalid = errors.New("only one of the Invert or Distinct fields can be set") ErrStringMatchNameIsEmpty = errors.New("field Name must be specified") ErrDirectResponseStatusInvalid = errors.New("only HTTP status codes 100 - 599 are supported for DirectResponse") ErrRedirectUnsupportedStatus = errors.New("only HTTP status codes 301 and 302 are supported for redirect filters") @@ -1443,6 +1444,8 @@ type StringMatch struct { // Distinct match condition. // Used to match any and all possible unique values encountered within the Name field. Distinct bool `json:"distinct" yaml:"distinct"` + // Invert inverts the final match decision + Invert *bool `json:"invert,omitempty" yaml:"invert,omitempty"` } // Validate the fields within the StringMatch structure @@ -1465,6 +1468,9 @@ func (s StringMatch) Validate() error { if s.Name == "" { errs = errors.Join(errs, ErrStringMatchNameIsEmpty) } + if s.Invert != nil && *s.Invert { + errs = errors.Join(errs, ErrStringMatchInvertDistinctInvalid) + } matchCount++ } diff --git a/internal/ir/xds_test.go b/internal/ir/xds_test.go index 14b624f22f3..5ff9a8736ef 100644 --- a/internal/ir/xds_test.go +++ b/internal/ir/xds_test.go @@ -1182,12 +1182,20 @@ func TestValidateStringMatch(t *testing.T) { want error }{ { - name: "happy", + name: "happy exact", input: StringMatch{ Exact: ptr.To("example"), }, want: nil, }, + { + name: "happy distinct", + input: StringMatch{ + Distinct: true, + Name: "example", + }, + want: nil, + }, { name: "no fields set", input: StringMatch{}, @@ -1202,6 +1210,15 @@ func TestValidateStringMatch(t *testing.T) { }, want: ErrStringMatchConditionInvalid, }, + { + name: "both invert and distinct fields are set", + input: StringMatch{ + Distinct: true, + Name: "example", + Invert: ptr.To(true), + }, + want: ErrStringMatchInvertDistinctInvalid, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 5afb29d12ce..4400b555dd7 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -2573,6 +2573,11 @@ func (in *StringMatch) DeepCopyInto(out *StringMatch) { *out = new(string) **out = **in } + if in.Invert != nil { + in, out := &in.Invert, &out.Invert + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StringMatch. diff --git a/internal/xds/translator/local_ratelimit.go b/internal/xds/translator/local_ratelimit.go index 1503758dfb4..ba330e22034 100644 --- a/internal/xds/translator/local_ratelimit.go +++ b/internal/xds/translator/local_ratelimit.go @@ -218,13 +218,17 @@ func buildRouteLocalRateLimits(local *ir.LocalRateLimit) ( StringMatch: buildXdsStringMatcher(match), }, } + expectMatch := true + if match.Invert != nil && *match.Invert { + expectMatch = false + } action := &routev3.RateLimit_Action{ ActionSpecifier: &routev3.RateLimit_Action_HeaderValueMatch_{ HeaderValueMatch: &routev3.RateLimit_Action_HeaderValueMatch{ DescriptorKey: descriptorKey, DescriptorValue: descriptorVal, ExpectMatch: &wrapperspb.BoolValue{ - Value: true, + Value: expectMatch, }, Headers: []*routev3.HeaderMatcher{headerMatcher}, }, diff --git a/internal/xds/translator/ratelimit.go b/internal/xds/translator/ratelimit.go index 8e3e661f9d7..660bc2a7dec 100644 --- a/internal/xds/translator/ratelimit.go +++ b/internal/xds/translator/ratelimit.go @@ -180,13 +180,17 @@ func buildRouteRateLimits(descriptorPrefix string, global *ir.GlobalRateLimit) [ StringMatch: buildXdsStringMatcher(match), }, } + expectMatch := true + if match.Invert != nil && *match.Invert { + expectMatch = false + } action := &routev3.RateLimit_Action{ ActionSpecifier: &routev3.RateLimit_Action_HeaderValueMatch_{ HeaderValueMatch: &routev3.RateLimit_Action_HeaderValueMatch{ DescriptorKey: descriptorKey, DescriptorValue: descriptorVal, ExpectMatch: &wrapperspb.BoolValue{ - Value: true, + Value: expectMatch, }, Headers: []*routev3.HeaderMatcher{headerMatcher}, }, diff --git a/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml b/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml index 271d39cfdcb..2279315caed 100644 --- a/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml @@ -65,3 +65,24 @@ http: - endpoints: - host: "1.2.3.4" port: 50000 + - name: "fourth-route" + hostname: "*" + traffic: + rateLimit: + global: + rules: + - headerMatches: + - name: "x-org-id" + exact: "admin" + invert: true + limit: + requests: 5 + unit: second + pathMatch: + exact: "foo/bar/login" + destination: + name: "fourth-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit.clusters.yaml index 0ba1749076a..427f6d15340 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ratelimit.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit.clusters.yaml @@ -49,6 +49,23 @@ outlierDetection: {} perConnectionBufferLimitBytes: 32768 type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: fourth-route-dest + lbPolicy: LEAST_REQUEST + name: fourth-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS - circuitBreakers: thresholds: - maxRetries: 1024 diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit.endpoints.yaml index 475b89a087c..f185af17da7 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ratelimit.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit.endpoints.yaml @@ -34,3 +34,15 @@ loadBalancingWeight: 1 locality: region: third-route-dest/backend/0 +- clusterName: fourth-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: fourth-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml index 479c2cd143c..e6e83bc2bfb 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml @@ -55,3 +55,23 @@ descriptorValue: rule-0-match--1 upgradeConfigs: - upgradeType: websocket + - match: + path: foo/bar/login + name: fourth-route + route: + cluster: fourth-route-dest + rateLimits: + - actions: + - genericKey: + descriptorKey: fourth-route + descriptorValue: fourth-route + - headerValueMatch: + descriptorKey: rule-0-match-0 + descriptorValue: rule-0-match-0 + expectMatch: false + headers: + - name: x-org-id + stringMatch: + exact: admin + upgradeConfigs: + - upgradeType: websocket From 956586369d6dc59bacf96e56ca214182c367a306 Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 10 Oct 2024 11:36:36 +0800 Subject: [PATCH 07/39] bump gwapi to 1.2.0 (#4384) * bump gwapi to 1.2.0 Signed-off-by: zirain * use v1.1.2 Signed-off-by: zirain * update Signed-off-by: zirain * fix Signed-off-by: zirain * lint Signed-off-by: zirain * update Signed-off-by: zirain * remove Signed-off-by: zirain --------- Signed-off-by: zirain --- charts/gateway-helm/crds/gatewayapi-crds.yaml | 40 +++++++++---------- go.mod | 2 +- go.sum | 4 +- osv-scanner.toml | 7 ---- 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/charts/gateway-helm/crds/gatewayapi-crds.yaml b/charts/gateway-helm/crds/gatewayapi-crds.yaml index f19c1adb3b4..57595956279 100644 --- a/charts/gateway-helm/crds/gatewayapi-crds.yaml +++ b/charts/gateway-helm/crds/gatewayapi-crds.yaml @@ -23,8 +23,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null labels: @@ -524,8 +524,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null labels: @@ -1153,8 +1153,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: gatewayclasses.gateway.networking.k8s.io @@ -1673,8 +1673,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: gateways.gateway.networking.k8s.io @@ -4089,8 +4089,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: grpcroutes.gateway.networking.k8s.io @@ -6327,8 +6327,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: httproutes.gateway.networking.k8s.io @@ -12489,8 +12489,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: referencegrants.gateway.networking.k8s.io @@ -12682,8 +12682,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: tcproutes.gateway.networking.k8s.io @@ -13427,8 +13427,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: tlsroutes.gateway.networking.k8s.io @@ -14235,8 +14235,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2997 - gateway.networking.k8s.io/bundle-version: v1.2.0-rc2 + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/3328 + gateway.networking.k8s.io/bundle-version: v1.2.0 gateway.networking.k8s.io/channel: experimental creationTimestamp: null name: udproutes.gateway.networking.k8s.io diff --git a/go.mod b/go.mod index a34be2541d4..e34c38bed54 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( k8s.io/kubectl v0.31.1 k8s.io/utils v0.0.0-20240821151609-f90d01438635 sigs.k8s.io/controller-runtime v0.19.0 - sigs.k8s.io/gateway-api v1.2.0-rc2 + sigs.k8s.io/gateway-api v1.2.0 sigs.k8s.io/mcs-api v0.1.0 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index acca7a0b90d..01eea5533e5 100644 --- a/go.sum +++ b/go.sum @@ -1212,8 +1212,8 @@ sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gE sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= -sigs.k8s.io/gateway-api v1.2.0-rc2 h1:v7V7JzaBuzwOLWWyyqlkqiqBi3ANBuZGV+uyyKzwmE8= -sigs.k8s.io/gateway-api v1.2.0-rc2/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0= +sigs.k8s.io/gateway-api v1.2.0 h1:LrToiFwtqKTKZcZtoQPTuo3FxhrrhTgzQG0Te+YGSo8= +sigs.k8s.io/gateway-api v1.2.0/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.8.1/go.mod h1:oNKTxUVPYkV9lWzY6CVMNluVq8cBsyq+UgPJdvA3uu4= diff --git a/osv-scanner.toml b/osv-scanner.toml index 02cdbc6af53..6144707a297 100644 --- a/osv-scanner.toml +++ b/osv-scanner.toml @@ -90,13 +90,6 @@ ecosystem = "Go" license.override = ["BSD-3-Clause"] reason = "Unidentified license, remove once https://github.com/google/deps.dev/issues/86 is resolved" -[[PackageOverrides]] -name = "sigs.k8s.io/gateway-api" -version = "1.2.0-rc2" -ecosystem = "Go" -license.override = ["Apache-2.0"] -reason = "https://github.com/envoyproxy/gateway/actions/runs/11065210699/job/30744231458?pr=4270" - [[PackageOverrides]] name = "sigs.k8s.io/json" version = "0.0.0-20221116044647-bc3834ca7abd" From 4313fd607ba6fad2499aa4e01908a06f9a7b3575 Mon Sep 17 00:00:00 2001 From: Guy Daich Date: Thu, 10 Oct 2024 06:33:26 -0500 Subject: [PATCH 08/39] feat(translator): implement access log types (#4341) * impl: access log types Signed-off-by: Guy Daich * clarify docs Signed-off-by: Guy Daich * add note on default settings override Signed-off-by: Guy Daich * support default log re-enablement Signed-off-by: Guy Daich * fix xds test to contain route Signed-off-by: Guy Daich --------- Signed-off-by: Guy Daich Co-authored-by: zirain --- api/v1alpha1/accesslogging_types.go | 1 - internal/gatewayapi/listener.go | 27 +- .../envoyproxy-accesslog-types.in.yaml | 236 +++++++++ .../envoyproxy-accesslog-types.out.yaml | 460 ++++++++++++++++++ internal/ir/xds.go | 37 +- internal/ir/zz_generated.deepcopy.go | 20 + internal/xds/translator/accesslog.go | 49 +- internal/xds/translator/listener.go | 12 +- .../testdata/in/xds-ir/accesslog-types.yaml | 184 +++++++ .../out/xds-ir/accesslog-types.clusters.yaml | 263 ++++++++++ .../out/xds-ir/accesslog-types.endpoints.yaml | 84 ++++ .../out/xds-ir/accesslog-types.listeners.yaml | 300 ++++++++++++ .../out/xds-ir/accesslog-types.routes.yaml | 20 + site/content/en/latest/api/extension_types.md | 1 + .../tasks/observability/proxy-accesslog.md | 59 +++ site/content/zh/latest/api/extension_types.md | 1 + test/config/gatewayclass.yaml | 9 + test/e2e/tests/accesslog.go | 32 ++ 18 files changed, 1764 insertions(+), 31 deletions(-) create mode 100644 internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml create mode 100644 internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml create mode 100644 internal/xds/translator/testdata/in/xds-ir/accesslog-types.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/accesslog-types.clusters.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/accesslog-types.endpoints.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/accesslog-types.listeners.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/accesslog-types.routes.yaml diff --git a/api/v1alpha1/accesslogging_types.go b/api/v1alpha1/accesslogging_types.go index edc19e97599..31eac69f122 100644 --- a/api/v1alpha1/accesslogging_types.go +++ b/api/v1alpha1/accesslogging_types.go @@ -37,7 +37,6 @@ type ProxyAccessLogSetting struct { // If type is defined, the accesslog settings would apply to the relevant component (as-is). // +kubebuilder:validation:Enum=Listener;Route // +optional - // +notImplementedHide Type *ProxyAccessLogType `json:"type,omitempty"` } diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 0c69d7b3097..5c85e561ea1 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -241,7 +241,6 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * }, }, nil } - if envoyproxy.Spec.Telemetry.AccessLog.Disable { return nil, nil } @@ -249,6 +248,16 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * irAccessLog := &ir.AccessLog{} // translate the access log configuration to the IR for i, accessLog := range envoyproxy.Spec.Telemetry.AccessLog.Settings { + var accessLogType *ir.ProxyAccessLogType + if accessLog.Type != nil { + switch *accessLog.Type { + case egv1a1.ProxyAccessLogTypeRoute: + accessLogType = ptr.To(ir.ProxyAccessLogTypeRoute) + case egv1a1.ProxyAccessLogTypeListener: + accessLogType = ptr.To(ir.ProxyAccessLogTypeListener) + } + } + var format egv1a1.ProxyAccessLogFormat if accessLog.Format != nil { format = *accessLog.Format @@ -274,6 +283,16 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * return nil, utilerrors.NewAggregate(errs) } + if len(accessLog.Sinks) == 0 { + al := &ir.TextAccessLog{ + Format: format.Text, + CELMatches: validExprs, + LogType: accessLogType, + Path: "/dev/stdout", + } + irAccessLog.Text = append(irAccessLog.Text, al) + } + for j, sink := range accessLog.Sinks { switch sink.Type { case egv1a1.ProxyAccessLogSinkTypeFile: @@ -287,6 +306,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * Format: format.Text, Path: sink.File.Path, CELMatches: validExprs, + LogType: accessLogType, } irAccessLog.Text = append(irAccessLog.Text, al) case egv1a1.ProxyAccessLogFormatTypeJSON: @@ -299,6 +319,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * JSON: format.JSON, Path: sink.File.Path, CELMatches: validExprs, + LogType: accessLogType, } irAccessLog.JSON = append(irAccessLog.JSON, al) } @@ -329,6 +350,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * Traffic: traffic, Type: sink.ALS.Type, CELMatches: validExprs, + LogType: accessLogType, } if al.Type == egv1a1.ALSEnvoyProxyAccessLogTypeHTTP && sink.ALS.HTTP != nil { @@ -339,7 +361,6 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * } al.HTTP = http } - switch format.Type { case egv1a1.ProxyAccessLogFormatTypeJSON: al.Attributes = format.JSON @@ -367,6 +388,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * Settings: ds, }, Traffic: traffic, + LogType: accessLogType, } if len(ds) == 0 { @@ -391,7 +413,6 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * } } } - return irAccessLog, nil } diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml new file mode 100644 index 00000000000..03977e33075 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml @@ -0,0 +1,236 @@ +envoyProxyForGatewayClass: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + telemetry: + accessLog: + settings: + - type: Route + - type: Listener + - type: Route + format: + type: Text + text: | + this is a route log + sinks: + - type: File + file: + path: /dev/stdout + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + - type: OpenTelemetry + openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: "cluster-1" + - type: Listener + format: + type: Text + text: | + this is a listener log + sinks: + - type: File + file: + path: /dev/stdout + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + - type: OpenTelemetry + openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: "cluster-1" + - format: + type: Text + text: | + this is a Global log + sinks: + - type: File + file: + path: /dev/stdout + - type: ALS + als: + logName: accesslog + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + type: HTTP + - type: ALS + als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + - type: OpenTelemetry + openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: "cluster-1" + provider: + type: Kubernetes + kubernetes: + envoyService: + type: LoadBalancer + envoyDeployment: + replicas: 2 + container: + env: + - name: env_a + value: env_a_value + - name: env_b + value: env_b_name + image: "envoyproxy/envoy:distroless-dev" + resources: + requests: + cpu: 100m + memory: 512Mi + securityContext: + runAsUser: 2000 + allowPrivilegeEscalation: false + pod: + annotations: + key1: val1 + key2: val2 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-nodepool + operator: In + values: + - router-node + tolerations: + - effect: NoSchedule + key: node-type + operator: Exists + value: "router" + securityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + fsGroupChangePolicy: "OnRootMismatch" + volumes: + - name: certs + secret: + secretName: envoy-cert +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: Same +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: envoy-gateway + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + rules: + - matches: + - path: + type: Exact + value: "/exact" + backendRefs: + - name: service-1 + port: 8080 +services: +- apiVersion: v1 + kind: Service + metadata: + name: envoy-als + namespace: monitoring + spec: + type: ClusterIP + ports: + - name: grpc + port: 9000 + appProtocol: grpc + protocol: TCP + targetPort: 9000 +endpointSlices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: endpointslice-envoy-als + namespace: monitoring + labels: + kubernetes.io/service-name: envoy-als + addressType: IPv4 + ports: + - name: grpc + protocol: TCP + appProtocol: grpc + port: 9090 + endpoints: + - addresses: + - "10.240.0.10" + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml new file mode 100644 index 00000000000..9c2c0d1cf82 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml @@ -0,0 +1,460 @@ +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: Same + 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: envoy-gateway + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + type: Exact + value: /exact + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Service envoy-gateway/service-1 not found + reason: BackendNotFound + status: "False" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway +infraIR: + envoy-gateway/gateway-1: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + creationTimestamp: null + name: test + namespace: envoy-gateway-system + spec: + logging: {} + provider: + kubernetes: + envoyDeployment: + container: + env: + - name: env_a + value: env_a_value + - name: env_b + value: env_b_name + image: envoyproxy/envoy:distroless-dev + resources: + requests: + cpu: 100m + memory: 512Mi + securityContext: + allowPrivilegeEscalation: false + runAsUser: 2000 + pod: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-nodepool + operator: In + values: + - router-node + annotations: + key1: val1 + key2: val2 + securityContext: + fsGroup: 2000 + fsGroupChangePolicy: OnRootMismatch + runAsGroup: 3000 + runAsUser: 1000 + tolerations: + - effect: NoSchedule + key: node-type + operator: Exists + value: router + volumes: + - name: certs + secret: + secretName: envoy-cert + replicas: 2 + envoyService: + type: LoadBalancer + type: Kubernetes + telemetry: + accessLog: + settings: + - sinks: null + type: Route + - sinks: null + type: Listener + - format: + text: | + this is a route log + type: Text + sinks: + - file: + path: /dev/stdout + type: File + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS + - openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: cluster-1 + type: OpenTelemetry + type: Route + - format: + text: | + this is a listener log + type: Text + sinks: + - file: + path: /dev/stdout + type: File + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS + - openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: cluster-1 + type: OpenTelemetry + type: Listener + - format: + text: | + this is a Global log + type: Text + sinks: + - file: + path: /dev/stdout + type: File + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logName: accesslog + type: HTTP + type: ALS + - als: + backendRefs: + - name: envoy-als + namespace: monitoring + port: 9000 + type: TCP + type: ALS + - openTelemetry: + host: otel-collector.monitoring.svc.cluster.local + port: 4317 + resources: + k8s.cluster.name: cluster-1 + type: OpenTelemetry + status: {} + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + 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: + als: + - destination: + name: accesslog_als_2_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Route + name: accesslog + text: | + this is a route log + type: HTTP + - destination: + name: accesslog_als_2_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Route + name: envoy-gateway-system/test + text: | + this is a route log + type: TCP + - destination: + name: accesslog_als_3_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Listener + name: accesslog + text: | + this is a listener log + type: HTTP + - destination: + name: accesslog_als_3_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Listener + name: envoy-gateway-system/test + text: | + this is a listener log + type: TCP + - destination: + name: accesslog_als_4_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + name: accesslog + text: | + this is a Global log + type: HTTP + - destination: + name: accesslog_als_4_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + name: envoy-gateway-system/test + text: | + this is a Global log + type: TCP + openTelemetry: + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_2_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Route + resources: + k8s.cluster.name: cluster-1 + text: | + this is a route log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_3_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Listener + resources: + k8s.cluster.name: cluster-1 + text: | + this is a listener log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_4_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + resources: + k8s.cluster.name: cluster-1 + text: | + this is a Global log + text: + - logType: Route + path: /dev/stdout + - logType: Listener + path: /dev/stdout + - format: | + this is a route log + logType: Route + path: /dev/stdout + - format: | + this is a listener log + logType: Listener + path: /dev/stdout + - format: | + this is a Global log + path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - weight: 1 + directResponse: + statusCode: 500 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: envoy-gateway + name: httproute/envoy-gateway/httproute-1/rule/0/match/0/* + pathMatch: + distinct: false + exact: /exact + name: "" diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 40e7da917f3..53eb34fa2a6 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1739,6 +1739,13 @@ type RateLimitValue struct { Unit RateLimitUnit `json:"unit" yaml:"unit"` } +type ProxyAccessLogType egv1a1.ProxyAccessLogType + +const ( + ProxyAccessLogTypeRoute = ProxyAccessLogType(egv1a1.ProxyAccessLogTypeRoute) + ProxyAccessLogTypeListener = ProxyAccessLogType(egv1a1.ProxyAccessLogTypeListener) +) + // AccessLog holds the access logging configuration. // +k8s:deepcopy-gen=true type AccessLog struct { @@ -1751,17 +1758,19 @@ type AccessLog struct { // TextAccessLog holds the configuration for text access logging. // +k8s:deepcopy-gen=true type TextAccessLog struct { - CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` - Format *string `json:"format,omitempty" yaml:"format,omitempty"` - Path string `json:"path" yaml:"path"` + CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` + Format *string `json:"format,omitempty" yaml:"format,omitempty"` + Path string `json:"path" yaml:"path"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // JSONAccessLog holds the configuration for JSON access logging. // +k8s:deepcopy-gen=true type JSONAccessLog struct { - CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` - JSON map[string]string `json:"json,omitempty" yaml:"json,omitempty"` - Path string `json:"path" yaml:"path"` + CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` + JSON map[string]string `json:"json,omitempty" yaml:"json,omitempty"` + Path string `json:"path" yaml:"path"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // ALSAccessLog holds the configuration for gRPC ALS access logging. @@ -1775,6 +1784,7 @@ type ALSAccessLog struct { Text *string `json:"text,omitempty" yaml:"text,omitempty"` Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` HTTP *ALSAccessLogHTTP `json:"http,omitempty" yaml:"http,omitempty"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // ALSAccessLogHTTP holds the configuration for HTTP ALS access logging. @@ -1788,13 +1798,14 @@ type ALSAccessLogHTTP struct { // OpenTelemetryAccessLog holds the configuration for OpenTelemetry access logging. // +k8s:deepcopy-gen=true type OpenTelemetryAccessLog struct { - CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` - Authority string `json:"authority,omitempty" yaml:"authority,omitempty"` - Text *string `json:"text,omitempty" yaml:"text,omitempty"` - Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` - Resources map[string]string `json:"resources,omitempty" yaml:"resources,omitempty"` - Destination RouteDestination `json:"destination,omitempty" yaml:"destination,omitempty"` - Traffic *TrafficFeatures `json:"traffic,omitempty" yaml:"traffic,omitempty"` + CELMatches []string `json:"celMatches,omitempty" yaml:"celMatches,omitempty"` + Authority string `json:"authority,omitempty" yaml:"authority,omitempty"` + Text *string `json:"text,omitempty" yaml:"text,omitempty"` + Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` + Resources map[string]string `json:"resources,omitempty" yaml:"resources,omitempty"` + Destination RouteDestination `json:"destination,omitempty" yaml:"destination,omitempty"` + Traffic *TrafficFeatures `json:"traffic,omitempty" yaml:"traffic,omitempty"` + LogType *ProxyAccessLogType `json:"logType,omitempty" yaml:"logType,omitempty"` } // EnvoyPatchPolicy defines the intermediate representation of the EnvoyPatchPolicy resource. diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 4400b555dd7..1a0185bbb9f 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -47,6 +47,11 @@ func (in *ALSAccessLog) DeepCopyInto(out *ALSAccessLog) { *out = new(ALSAccessLogHTTP) (*in).DeepCopyInto(*out) } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ALSAccessLog. @@ -1690,6 +1695,11 @@ func (in *JSONAccessLog) DeepCopyInto(out *JSONAccessLog) { (*out)[key] = val } } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONAccessLog. @@ -1976,6 +1986,11 @@ func (in *OpenTelemetryAccessLog) DeepCopyInto(out *OpenTelemetryAccessLog) { *out = new(TrafficFeatures) (*in).DeepCopyInto(*out) } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryAccessLog. @@ -2985,6 +3000,11 @@ func (in *TextAccessLog) DeepCopyInto(out *TextAccessLog) { *out = new(string) **out = **in } + if in.LogType != nil { + in, out := &in.LogType, &out.LogType + *out = new(ProxyAccessLogType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TextAccessLog. diff --git a/internal/xds/translator/accesslog.go b/internal/xds/translator/accesslog.go index 8acb6e4b005..6660ba8fab6 100644 --- a/internal/xds/translator/accesslog.go +++ b/internal/xds/translator/accesslog.go @@ -90,15 +90,24 @@ var ( } ) -func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLog { +func buildXdsAccessLog(al *ir.AccessLog, accessLogType ir.ProxyAccessLogType) []*accesslog.AccessLog { if al == nil { return nil } totalLen := len(al.Text) + len(al.JSON) + len(al.OpenTelemetry) accessLogs := make([]*accesslog.AccessLog, 0, totalLen) + // handle text file access logs for _, text := range al.Text { + // Filter out logs that are not Global or match the desired access log type + if !(text.LogType == nil || *text.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && text.LogType == nil + filelog := &fileaccesslog.FileAccessLog{ Path: text.Path, } @@ -131,11 +140,19 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(text.CELMatches, forListener), + Filter: buildAccessLogFilter(text.CELMatches, defaultLogTypeForListener), }) } // handle json file access logs for _, json := range al.JSON { + // Filter out logs that are not Global or match the desired access log type + if !(json.LogType == nil || *json.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && json.LogType == nil + jsonFormat := &structpb.Struct{ Fields: make(map[string]*structpb.Value, len(json.JSON)), } @@ -174,11 +191,19 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(json.CELMatches, forListener), + Filter: buildAccessLogFilter(json.CELMatches, defaultLogTypeForListener), }) } // handle ALS access logs for _, als := range al.ALS { + // Filter out logs that are not Global or match the desired access log type + if !(als.LogType == nil || *als.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && als.LogType == nil + cc := &grpcaccesslog.CommonGrpcAccessLogConfig{ LogName: als.LogName, GrpcService: &cfgcore.GrpcService{ @@ -209,7 +234,7 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(als.CELMatches, forListener), + Filter: buildAccessLogFilter(als.CELMatches, defaultLogTypeForListener), }) case egv1a1.ALSEnvoyProxyAccessLogTypeTCP: alCfg := &grpcaccesslog.TcpGrpcAccessLogConfig{ @@ -222,12 +247,20 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(als.CELMatches, forListener), + Filter: buildAccessLogFilter(als.CELMatches, defaultLogTypeForListener), }) } } // handle open telemetry access logs for _, otel := range al.OpenTelemetry { + // Filter out logs that are not Global or match the desired access log type + if !(otel.LogType == nil || *otel.LogType == accessLogType) { + continue + } + + // NR is only added to listener logs originating from a global log configuration + defaultLogTypeForListener := accessLogType == ir.ProxyAccessLogTypeListener && otel.LogType == nil + al := &otelaccesslog.OpenTelemetryAccessLogConfig{ CommonConfig: &grpcaccesslog.CommonGrpcAccessLogConfig{ LogName: otelLogName, @@ -270,7 +303,7 @@ func buildXdsAccessLog(al *ir.AccessLog, forListener bool) []*accesslog.AccessLo ConfigType: &accesslog.AccessLog_TypedConfig{ TypedConfig: accesslogAny, }, - Filter: buildAccessLogFilter(otel.CELMatches, forListener), + Filter: buildAccessLogFilter(otel.CELMatches, defaultLogTypeForListener), }) } @@ -292,13 +325,13 @@ func celAccessLogFilter(expr string) *accesslog.AccessLogFilter { } } -func buildAccessLogFilter(exprs []string, forListener bool) *accesslog.AccessLogFilter { +func buildAccessLogFilter(exprs []string, withNoRouteMatchFilter bool) *accesslog.AccessLogFilter { // add filter for access logs var filters []*accesslog.AccessLogFilter for _, expr := range exprs { filters = append(filters, celAccessLogFilter(expr)) } - if forListener { + if withNoRouteMatchFilter { filters = append(filters, listenerAccessLogFilter) } diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index 98f7c28e372..9cc8e61f6ed 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -151,7 +151,7 @@ func originalIPDetectionExtensions(clientIPDetection *ir.ClientIPDetectionSettin // TODO: Improve function parameters func buildXdsTCPListener(name, address string, port uint32, keepalive *ir.TCPKeepalive, connection *ir.ClientConnection, accesslog *ir.AccessLog) *listenerv3.Listener { socketOptions := buildTCPSocketOptions(keepalive) - al := buildXdsAccessLog(accesslog, true) + al := buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeListener) bufferLimitBytes := buildPerConnectionBufferLimitBytes(connection) return &listenerv3.Listener{ Name: name, @@ -183,7 +183,7 @@ func buildPerConnectionBufferLimitBytes(connection *ir.ClientConnection) *wrappe func buildXdsQuicListener(name, address string, port uint32, accesslog *ir.AccessLog) *listenerv3.Listener { xdsListener := &listenerv3.Listener{ Name: name + "-quic", - AccessLog: buildXdsAccessLog(accesslog, true), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeListener), Address: &corev3.Address{ Address: &corev3.Address_SocketAddress{ SocketAddress: &corev3.SocketAddress{ @@ -220,7 +220,7 @@ func buildXdsQuicListener(name, address string, port uint32, accesslog *ir.Acces func (t *Translator) addHCMToXDSListener(xdsListener *listenerv3.Listener, irListener *ir.HTTPListener, accesslog *ir.AccessLog, tracing *ir.Tracing, http3Listener bool, connection *ir.ClientConnection, ) error { - al := buildXdsAccessLog(accesslog, false) + al := buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeRoute) hcmTracing, err := buildHCMTracing(tracing) if err != nil { @@ -494,7 +494,7 @@ func addXdsTCPFilterChain(xdsListener *listenerv3.Listener, irRoute *ir.TCPRoute statPrefix = strings.Join([]string{statPrefix, strconv.Itoa(int(xdsListener.Address.GetSocketAddress().GetPortValue()))}, "-") mgr := &tcpv3.TcpProxy{ - AccessLog: buildXdsAccessLog(accesslog, false), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeRoute), StatPrefix: statPrefix, ClusterSpecifier: &tcpv3.TcpProxy_Cluster{ Cluster: clusterName, @@ -773,7 +773,7 @@ func buildXdsUDPListener(clusterName string, udpListener *ir.UDPListener, access udpProxy := &udpv3.UdpProxyConfig{ StatPrefix: statPrefix, - AccessLog: buildXdsAccessLog(accesslog, false), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeRoute), RouteSpecifier: &udpv3.UdpProxyConfig_Matcher{ Matcher: &matcher.Matcher{ OnNoMatch: &matcher.Matcher_OnMatch{ @@ -794,7 +794,7 @@ func buildXdsUDPListener(clusterName string, udpListener *ir.UDPListener, access xdsListener := &listenerv3.Listener{ Name: udpListener.Name, - AccessLog: buildXdsAccessLog(accesslog, true), + AccessLog: buildXdsAccessLog(accesslog, ir.ProxyAccessLogTypeListener), Address: &corev3.Address{ Address: &corev3.Address_SocketAddress{ SocketAddress: &corev3.SocketAddress{ diff --git a/internal/xds/translator/testdata/in/xds-ir/accesslog-types.yaml b/internal/xds/translator/testdata/in/xds-ir/accesslog-types.yaml new file mode 100644 index 00000000000..d2458abfce9 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/accesslog-types.yaml @@ -0,0 +1,184 @@ +accessLog: + als: + - destination: + name: accesslog_als_0_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Route + name: accesslog + text: | + this is a route log + type: HTTP + - destination: + name: accesslog_als_0_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Route + name: envoy-gateway-system/test + text: | + this is a route log + type: TCP + - destination: + name: accesslog_als_1_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + logType: Listener + name: accesslog + text: | + this is a listener log + type: HTTP + - destination: + name: accesslog_als_1_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + logType: Listener + name: envoy-gateway-system/test + text: | + this is a listener log + type: TCP + - destination: + name: accesslog_als_2_1 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + http: + requestHeaders: + - x-client-ip-address + responseHeaders: + - cache-control + responseTrailers: + - expires + name: accesslog + text: | + this is a Global log + type: HTTP + - destination: + name: accesslog_als_2_2 + settings: + - addressType: IP + endpoints: + - host: 10.240.0.10 + port: 9090 + protocol: GRPC + name: envoy-gateway-system/test + text: | + this is a Global log + type: TCP + openTelemetry: + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_0_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Route + resources: + k8s.cluster.name: cluster-1 + text: | + this is a route log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_1_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + logType: Listener + resources: + k8s.cluster.name: cluster-1 + text: | + this is a listener log + - authority: otel-collector.monitoring.svc.cluster.local + destination: + name: accesslog_otel_2_3 + settings: + - endpoints: + - host: otel-collector.monitoring.svc.cluster.local + port: 4317 + protocol: GRPC + weight: 1 + resources: + k8s.cluster.name: cluster-1 + text: | + this is a Global log + text: + - logType: Route + path: /dev/stdout + - logType: Listener + path: /dev/stdout + - format: | + this is a route log + logType: Route + path: /dev/stdout + - format: | + this is a listener log + logType: Listener + path: /dev/stdout + - format: | + this is a Global log + path: /dev/stdout +http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - name: "direct-route" + hostname: "*" + destination: + name: "direct-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + directResponse: + body: "Unknown custom filter type: UnsupportedType" + statusCode: 500 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-types.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.clusters.yaml new file mode 100644 index 00000000000..e0328b6e26c --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.clusters.yaml @@ -0,0 +1,263 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: direct-route-dest + lbPolicy: LEAST_REQUEST + name: direct-route-dest + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_0_1 + lbPolicy: LEAST_REQUEST + name: accesslog_als_0_1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_0_2 + lbPolicy: LEAST_REQUEST + name: accesslog_als_0_2 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_1_1 + lbPolicy: LEAST_REQUEST + name: accesslog_als_1_1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_1_2 + lbPolicy: LEAST_REQUEST + name: accesslog_als_1_2 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_2_1 + lbPolicy: LEAST_REQUEST + name: accesslog_als_2_1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: accesslog_als_2_2 + lbPolicy: LEAST_REQUEST + name: accesslog_als_2_2 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: accesslog_otel_0_3 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: otel-collector.monitoring.svc.cluster.local + portValue: 4317 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_otel_0_3/backend/0 + name: accesslog_otel_0_3 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: accesslog_otel_1_3 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: otel-collector.monitoring.svc.cluster.local + portValue: 4317 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_otel_1_3/backend/0 + name: accesslog_otel_1_3 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: accesslog_otel_2_3 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: otel-collector.monitoring.svc.cluster.local + portValue: 4317 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_otel_2_3/backend/0 + name: accesslog_otel_2_3 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-types.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.endpoints.yaml new file mode 100644 index 00000000000..e9526ab5d90 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.endpoints.yaml @@ -0,0 +1,84 @@ +- clusterName: direct-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: direct-route-dest/backend/0 +- clusterName: accesslog_als_0_1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_0_1/backend/0 +- clusterName: accesslog_als_0_2 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_0_2/backend/0 +- clusterName: accesslog_als_1_1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_1_1/backend/0 +- clusterName: accesslog_als_1_2 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_1_2/backend/0 +- clusterName: accesslog_als_2_1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_2_1/backend/0 +- clusterName: accesslog_als_2_2 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 10.240.0.10 + portValue: 9090 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: accesslog_als_2_2/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-types.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.listeners.yaml new file mode 100644 index 00000000000..dbb30726378 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.listeners.yaml @@ -0,0 +1,300 @@ +- 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 + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + this is a listener log + path: /dev/stdout + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + this is a Global log + path: /dev/stdout + - name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_1_1 + logName: accesslog + transportApiVersion: V3 + - name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_1_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_1 + logName: accesslog + transportApiVersion: V3 + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - name: envoy.access_loggers.open_telemetry + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.open_telemetry.v3.OpenTelemetryAccessLogConfig + attributes: + values: + - key: k8s.namespace.name + value: + stringValue: '%ENVIRONMENT(ENVOY_GATEWAY_NAMESPACE)%' + - key: k8s.pod.name + value: + stringValue: '%ENVIRONMENT(ENVOY_POD_NAME)%' + body: + stringValue: | + this is a listener log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_1_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + - filter: + responseFlagFilter: + flags: + - NR + name: envoy.access_loggers.open_telemetry + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.open_telemetry.v3.OpenTelemetryAccessLogConfig + attributes: + values: + - key: k8s.namespace.name + value: + stringValue: '%ENVIRONMENT(ENVOY_GATEWAY_NAMESPACE)%' + - key: k8s.pod.name + value: + stringValue: '%ENVIRONMENT(ENVOY_POD_NAME)%' + body: + stringValue: | + this is a Global log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_2_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + 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 + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + this is a route log + path: /dev/stdout + - name: envoy.access_loggers.file + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + logFormat: + textFormatSource: + inlineString: | + this is a Global log + path: /dev/stdout + - name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_0_1 + logName: accesslog + transportApiVersion: V3 + - name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_0_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - name: envoy.access_loggers.http_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig + additionalRequestHeadersToLog: + - x-client-ip-address + additionalResponseHeadersToLog: + - cache-control + additionalResponseTrailersToLog: + - expires + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_1 + logName: accesslog + transportApiVersion: V3 + - name: envoy.access_loggers.tcp_grpc + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.TcpGrpcAccessLogConfig + commonConfig: + grpcService: + envoyGrpc: + clusterName: accesslog_als_2_2 + logName: envoy-gateway-system/test + transportApiVersion: V3 + - name: envoy.access_loggers.open_telemetry + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.open_telemetry.v3.OpenTelemetryAccessLogConfig + attributes: + values: + - key: k8s.namespace.name + value: + stringValue: '%ENVIRONMENT(ENVOY_GATEWAY_NAMESPACE)%' + - key: k8s.pod.name + value: + stringValue: '%ENVIRONMENT(ENVOY_POD_NAME)%' + body: + stringValue: | + this is a route log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_0_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + - name: envoy.access_loggers.open_telemetry + typedConfig: + '@type': type.googleapis.com/envoy.extensions.access_loggers.open_telemetry.v3.OpenTelemetryAccessLogConfig + attributes: + values: + - key: k8s.namespace.name + value: + stringValue: '%ENVIRONMENT(ENVOY_GATEWAY_NAMESPACE)%' + - key: k8s.pod.name + value: + stringValue: '%ENVIRONMENT(ENVOY_POD_NAME)%' + body: + stringValue: | + this is a Global log + commonConfig: + grpcService: + envoyGrpc: + authority: otel-collector.monitoring.svc.cluster.local + clusterName: accesslog_otel_2_3 + logName: otel_envoy_accesslog + transportApiVersion: V3 + resourceAttributes: + values: + - key: k8s.cluster.name + value: + stringValue: cluster-1 + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http + name: envoy-gateway/gateway-1/http + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-types.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.routes.yaml new file mode 100644 index 00000000000..ff2210f8d50 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-types.routes.yaml @@ -0,0 +1,20 @@ +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http + virtualHosts: + - domains: + - '*' + metadata: + filterMetadata: + envoy-gateway: + resources: + - kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http/* + routes: + - directResponse: + status: 500 + match: + prefix: / + name: direct-route diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index bc01189920d..c26a8c713f8 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2995,6 +2995,7 @@ _Appears in:_ | `format` | _[ProxyAccessLogFormat](#proxyaccesslogformat)_ | false | Format defines the format of accesslog.
This will be ignored if sink type is ALS. | | `matches` | _string array_ | true | Matches defines the match conditions for accesslog in CEL expression.
An accesslog will be emitted only when one or more match conditions are evaluated to true.
Invalid [CEL](https://www.envoyproxy.io/docs/envoy/latest/xds/type/v3/cel.proto.html#common-expression-language-cel-proto) expressions will be ignored. | | `sinks` | _[ProxyAccessLogSink](#proxyaccesslogsink) array_ | true | Sinks defines the sinks of accesslog. | +| `type` | _[ProxyAccessLogType](#proxyaccesslogtype)_ | false | Type defines the component emitting the accesslog, such as Listener and Route.
If type not defined, the setting would apply to:
(1) All Routes.
(2) Listeners if and only if Envoy does not find a matching route for a request.
If type is defined, the accesslog settings would apply to the relevant component (as-is). | #### ProxyAccessLogSink diff --git a/site/content/en/latest/tasks/observability/proxy-accesslog.md b/site/content/en/latest/tasks/observability/proxy-accesslog.md index fb0200f1739..17d444b8636 100644 --- a/site/content/en/latest/tasks/observability/proxy-accesslog.md +++ b/site/content/en/latest/tasks/observability/proxy-accesslog.md @@ -249,3 +249,62 @@ Envoy Gateway provides additional metadata about the K8s resources that were tra For example, details about the `HTTPRoute` and `GRPCRoute` (kind, group, name, namespace and annotations) are available for access log formatter using the `METADATA` operator. To enrich logs, users can add log operator such as: `%METADATA(ROUTE:envoy-gateway:resources)%` to their access log format. + +## Access Log Types + +By default, Access Log settings would apply to: +- All Routes +- If traffic is not matched by any Route known to Envoy, the Listener would emit the access log instead + +Users may wish to customize this behavior: +- Emit Access Logs by all Listeners for all traffic with specific settings +- Do not emit Route-oriented access logs when a route is not matched. + +To achieve this, users can select if Access Log settings follow the default behavior or apply specifically to +Routes or Listeners by specifying the setting's type. + +**Note**: When users define their own Access Log settings (with or without a type), the default Envoy Gateway +file access log is no longer configured. It can be re-enabled explicitly by adding empty settings for the desired components. + +In the following example: +- Route Access logs would use the default Envoy Gateway format and sink +- Listener Access logs are customized to report transport-level failures and connection attributes + +```shell +kubectl apply -f - <This will be ignored if sink type is ALS. | | `matches` | _string array_ | true | Matches defines the match conditions for accesslog in CEL expression.
An accesslog will be emitted only when one or more match conditions are evaluated to true.
Invalid [CEL](https://www.envoyproxy.io/docs/envoy/latest/xds/type/v3/cel.proto.html#common-expression-language-cel-proto) expressions will be ignored. | | `sinks` | _[ProxyAccessLogSink](#proxyaccesslogsink) array_ | true | Sinks defines the sinks of accesslog. | +| `type` | _[ProxyAccessLogType](#proxyaccesslogtype)_ | false | Type defines the component emitting the accesslog, such as Listener and Route.
If type not defined, the setting would apply to:
(1) All Routes.
(2) Listeners if and only if Envoy does not find a matching route for a request.
If type is defined, the accesslog settings would apply to the relevant component (as-is). | #### ProxyAccessLogSink diff --git a/test/config/gatewayclass.yaml b/test/config/gatewayclass.yaml index fa07a159305..6e8acf3d0f8 100644 --- a/test/config/gatewayclass.yaml +++ b/test/config/gatewayclass.yaml @@ -68,6 +68,15 @@ spec: namespace: monitoring port: 8080 type: HTTP + - type: Listener + format: + type: Text + text: | + LISTENER ACCESS LOG %UPSTREAM_PROTOCOL% %RESPONSE_CODE% + sinks: + - type: File + file: + path: /dev/stdout tracing: provider: backendRefs: diff --git a/test/e2e/tests/accesslog.go b/test/e2e/tests/accesslog.go index 2019d92568c..b2c9a28ac94 100644 --- a/test/e2e/tests/accesslog.go +++ b/test/e2e/tests/accesslog.go @@ -81,6 +81,38 @@ var FileAccessLogTest = suite.ConformanceTest{ runLogTest(t, suite, gwAddr, expectedResponse, labels, match, 0) }) + + t.Run("Listener Logs", func(t *testing.T) { + // Ensure that Listener is emitting the log: protocol and response code should be + // empty in listener logs as they are upstream L7 attributes + expectedMatch := "LISTENER ACCESS LOG - 0" + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "accesslog-file", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + + expectedResponse := httputils.ExpectedResponse{ + Request: httputils.Request{ + Path: "/file", + Headers: map[string]string{ + "connection": "close", + }, + }, + ExpectedRequest: &httputils.ExpectedRequest{ + Request: httputils.Request{ + Path: "/file", + }, + }, + Response: httputils.Response{ + StatusCode: 200, + }, + Namespace: ns, + } + // make sure listener is ready + httputils.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) + + runLogTest(t, suite, gwAddr, expectedResponse, labels, expectedMatch, 0) + }) }, } From f1df0c95e0cffaec3f119d7dfb63607a78a4f808 Mon Sep 17 00:00:00 2001 From: shaoyue Date: Fri, 11 Oct 2024 00:19:59 +0800 Subject: [PATCH 09/39] fix dashboard typos (#4422) Signed-off-by: haorenfsa --- charts/gateway-addons-helm/dashboards/envoy-clusters.json | 4 ++-- .../gateway-addons-helm/dashboards/envoy-proxy-global.json | 2 +- test/helm/gateway-addons-helm/default.out.yaml | 6 +++--- test/helm/gateway-addons-helm/e2e.out.yaml | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/charts/gateway-addons-helm/dashboards/envoy-clusters.json b/charts/gateway-addons-helm/dashboards/envoy-clusters.json index 4505f188e7d..8ee91675d96 100644 --- a/charts/gateway-addons-helm/dashboards/envoy-clusters.json +++ b/charts/gateway-addons-helm/dashboards/envoy-clusters.json @@ -259,7 +259,7 @@ "uid": "$datasource" }, "editorMode": "builder", - "expr": "SUM(envoy_server_memory_allocated{})", + "expr": "sum(envoy_server_memory_allocated{})", "format": "time_series", "intervalFactor": 1, "legendFormat": "", @@ -339,7 +339,7 @@ "uid": "$datasource" }, "editorMode": "code", - "expr": "SUM(envoy_server_memory_heap_size)", + "expr": "sum(envoy_server_memory_heap_size)", "format": "time_series", "intervalFactor": 1, "legendFormat": "", diff --git a/charts/gateway-addons-helm/dashboards/envoy-proxy-global.json b/charts/gateway-addons-helm/dashboards/envoy-proxy-global.json index f2c0ae2b0d4..99522ae061e 100644 --- a/charts/gateway-addons-helm/dashboards/envoy-proxy-global.json +++ b/charts/gateway-addons-helm/dashboards/envoy-proxy-global.json @@ -1849,7 +1849,7 @@ "uid": "${datasource}" }, "editorMode": "builder", - "expr": "sum by(namespace) (rate(envoy_cluster_upstream_cx_rx_bytes_total{namespace=~\"$Namespace\"}[5m]))", + "expr": "sum by(namespace) (rate(envoy_cluster_upstream_cx_tx_bytes_total{namespace=~\"$Namespace\"}[5m]))", "instant": false, "legendFormat": "{{namespace}}", "range": true, diff --git a/test/helm/gateway-addons-helm/default.out.yaml b/test/helm/gateway-addons-helm/default.out.yaml index f2fac1dfe09..614a2d22454 100644 --- a/test/helm/gateway-addons-helm/default.out.yaml +++ b/test/helm/gateway-addons-helm/default.out.yaml @@ -941,7 +941,7 @@ data: "uid": "$datasource" }, "editorMode": "builder", - "expr": "SUM(envoy_server_memory_allocated{})", + "expr": "sum(envoy_server_memory_allocated{})", "format": "time_series", "intervalFactor": 1, "legendFormat": "", @@ -1021,7 +1021,7 @@ data: "uid": "$datasource" }, "editorMode": "code", - "expr": "SUM(envoy_server_memory_heap_size)", + "expr": "sum(envoy_server_memory_heap_size)", "format": "time_series", "intervalFactor": 1, "legendFormat": "", @@ -7247,7 +7247,7 @@ data: "uid": "${datasource}" }, "editorMode": "builder", - "expr": "sum by(namespace) (rate(envoy_cluster_upstream_cx_rx_bytes_total{namespace=~\"$Namespace\"}[5m]))", + "expr": "sum by(namespace) (rate(envoy_cluster_upstream_cx_tx_bytes_total{namespace=~\"$Namespace\"}[5m]))", "instant": false, "legendFormat": "{{namespace}}", "range": true, diff --git a/test/helm/gateway-addons-helm/e2e.out.yaml b/test/helm/gateway-addons-helm/e2e.out.yaml index 52ed8fcb97e..15445239f3d 100644 --- a/test/helm/gateway-addons-helm/e2e.out.yaml +++ b/test/helm/gateway-addons-helm/e2e.out.yaml @@ -973,7 +973,7 @@ data: "uid": "$datasource" }, "editorMode": "builder", - "expr": "SUM(envoy_server_memory_allocated{})", + "expr": "sum(envoy_server_memory_allocated{})", "format": "time_series", "intervalFactor": 1, "legendFormat": "", @@ -1053,7 +1053,7 @@ data: "uid": "$datasource" }, "editorMode": "code", - "expr": "SUM(envoy_server_memory_heap_size)", + "expr": "sum(envoy_server_memory_heap_size)", "format": "time_series", "intervalFactor": 1, "legendFormat": "", @@ -7279,7 +7279,7 @@ data: "uid": "${datasource}" }, "editorMode": "builder", - "expr": "sum by(namespace) (rate(envoy_cluster_upstream_cx_rx_bytes_total{namespace=~\"$Namespace\"}[5m]))", + "expr": "sum by(namespace) (rate(envoy_cluster_upstream_cx_tx_bytes_total{namespace=~\"$Namespace\"}[5m]))", "instant": false, "legendFormat": "{{namespace}}", "range": true, From c1f4837f4af7b47d19c829091eacc8e4d3340eb7 Mon Sep 17 00:00:00 2001 From: Isaac <10012479+jukie@users.noreply.github.com> Date: Sat, 12 Oct 2024 18:38:00 -0600 Subject: [PATCH 10/39] feat: add labels to envoyService config (#4427) --- api/v1alpha1/shared_types.go | 6 +++ api/v1alpha1/zz_generated.deepcopy.go | 7 ++++ .../gateway.envoyproxy.io_envoyproxies.yaml | 7 ++++ .../kubernetes/proxy/resource_provider.go | 22 ++++++++--- .../proxy/resource_provider_test.go | 28 ++++++++++++++ .../proxy/testdata/services/custom.yaml | 1 + .../testdata/services/override-labels.yaml | 37 +++++++++++++++++++ .../testdata/services/with-svc-labels.yaml | 32 ++++++++++++++++ site/content/en/latest/api/extension_types.md | 1 + site/content/zh/latest/api/extension_types.md | 1 + 10 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 internal/infrastructure/kubernetes/proxy/testdata/services/override-labels.yaml create mode 100644 internal/infrastructure/kubernetes/proxy/testdata/services/with-svc-labels.yaml diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index 48e3471c77d..3f165cc6c2d 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -262,6 +262,12 @@ type KubernetesServiceSpec struct { // +optional Annotations map[string]string `json:"annotations,omitempty"` + // Labels that should be appended to the service. + // By default, no labels are appended. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` + // Type determines how the Service is exposed. Defaults to LoadBalancer. // Valid options are ClusterIP, LoadBalancer and NodePort. // "LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it). diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ed5df681ad2..a72706c33bb 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3580,6 +3580,13 @@ func (in *KubernetesServiceSpec) DeepCopyInto(out *KubernetesServiceSpec) { (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.Type != nil { in, out := &in.Type, &out.Type *out = new(ServiceType) diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 1b18890cd27..487f436ab81 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -10134,6 +10134,13 @@ spec: - Local - Cluster type: string + labels: + additionalProperties: + type: string + description: |- + Labels that should be appended to the service. + By default, no labels are appended. + type: object loadBalancerClass: description: |- LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index 768ed7514ba..233afddce73 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -101,10 +101,10 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { } } - // Set the labels based on the owning gatewayclass name. - labels := envoyLabels(r.infra.GetProxyMetadata().Labels) - if OwningGatewayLabelsAbsent(labels) { - return nil, fmt.Errorf("missing owning gateway labels") + // Set the infraLabels based on the owning gatewayclass name. + infraLabels := envoyLabels(r.infra.GetProxyMetadata().Labels) + if OwningGatewayLabelsAbsent(infraLabels) { + return nil, fmt.Errorf("missing owning gateway infraLabels") } // Get annotations @@ -120,10 +120,20 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { annotations = nil } + // Get service-specific labels + svcLabels := map[string]string{} + maps.Copy(svcLabels, infraLabels) + if envoyServiceConfig.Labels != nil { + maps.Copy(svcLabels, envoyServiceConfig.Labels) + } + if len(svcLabels) == 0 { + svcLabels = nil + } + // Set the spec of gateway service serviceSpec := resource.ExpectedServiceSpec(envoyServiceConfig) serviceSpec.Ports = ports - serviceSpec.Selector = resource.GetSelector(labels).MatchLabels + serviceSpec.Selector = resource.GetSelector(infraLabels).MatchLabels if (*envoyServiceConfig.Type) == egv1a1.ServiceTypeClusterIP { if len(r.infra.Addresses) > 0 { @@ -144,7 +154,7 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { }, ObjectMeta: metav1.ObjectMeta{ Namespace: r.Namespace, - Labels: labels, + Labels: svcLabels, Annotations: annotations, }, Spec: serviceSpec, diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider_test.go b/internal/infrastructure/kubernetes/proxy/resource_provider_test.go index c92d94d4b42..8c4138a3825 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider_test.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider_test.go @@ -1051,6 +1051,9 @@ func TestService(t *testing.T) { caseName: "custom", infra: newTestInfra(), service: &egv1a1.KubernetesServiceSpec{ + Labels: map[string]string{ + "key1": "value1", + }, Annotations: map[string]string{ "key1": "value1", }, @@ -1079,6 +1082,31 @@ func TestService(t *testing.T) { }, }, }, + { + caseName: "with-svc-labels", + infra: newTestInfra(), + service: &egv1a1.KubernetesServiceSpec{ + Labels: map[string]string{ + "label1": "value1", + "label2": "value2", + }, + }, + }, + { + caseName: "override-labels", + infra: newTestInfraWithAnnotationsAndLabels(map[string]string{ + "anno1": "value1", + "anno2": "value2", + }, map[string]string{ + "label1": "value1", + "label2": "value2", + }), + service: &egv1a1.KubernetesServiceSpec{ + Labels: map[string]string{ + "label1": "value1-override", + }, + }, + }, { caseName: "clusterIP-custom-addresses", infra: newTestInfraWithAddresses([]string{ diff --git a/internal/infrastructure/kubernetes/proxy/testdata/services/custom.yaml b/internal/infrastructure/kubernetes/proxy/testdata/services/custom.yaml index e898ccb1aff..d087bf24bf6 100644 --- a/internal/infrastructure/kubernetes/proxy/testdata/services/custom.yaml +++ b/internal/infrastructure/kubernetes/proxy/testdata/services/custom.yaml @@ -4,6 +4,7 @@ metadata: annotations: key1: value1 labels: + key1: value1 app.kubernetes.io/name: envoy app.kubernetes.io/component: proxy app.kubernetes.io/managed-by: envoy-gateway diff --git a/internal/infrastructure/kubernetes/proxy/testdata/services/override-labels.yaml b/internal/infrastructure/kubernetes/proxy/testdata/services/override-labels.yaml new file mode 100644 index 00000000000..6f60f58176c --- /dev/null +++ b/internal/infrastructure/kubernetes/proxy/testdata/services/override-labels.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + anno1: value1 + anno2: value2 + labels: + app.kubernetes.io/name: envoy + app.kubernetes.io/component: proxy + app.kubernetes.io/managed-by: envoy-gateway + gateway.envoyproxy.io/owning-gateway-name: default + gateway.envoyproxy.io/owning-gateway-namespace: default + label1: value1-override + label2: value2 + name: envoy-default-37a8eec1 + namespace: envoy-gateway-system +spec: + externalTrafficPolicy: Local + ports: + - name: EnvoyHTTPPort + port: 0 + protocol: TCP + targetPort: 8080 + - name: EnvoyHTTPSPort + port: 0 + protocol: TCP + targetPort: 8443 + selector: + app.kubernetes.io/name: envoy + app.kubernetes.io/component: proxy + app.kubernetes.io/managed-by: envoy-gateway + gateway.envoyproxy.io/owning-gateway-name: default + gateway.envoyproxy.io/owning-gateway-namespace: default + label1: value1 + label2: value2 + sessionAffinity: None + type: LoadBalancer diff --git a/internal/infrastructure/kubernetes/proxy/testdata/services/with-svc-labels.yaml b/internal/infrastructure/kubernetes/proxy/testdata/services/with-svc-labels.yaml new file mode 100644 index 00000000000..8ff9e5bb319 --- /dev/null +++ b/internal/infrastructure/kubernetes/proxy/testdata/services/with-svc-labels.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + label1: value1 + label2: value2 + app.kubernetes.io/name: envoy + app.kubernetes.io/component: proxy + app.kubernetes.io/managed-by: envoy-gateway + gateway.envoyproxy.io/owning-gateway-name: default + gateway.envoyproxy.io/owning-gateway-namespace: default + name: envoy-default-37a8eec1 + namespace: envoy-gateway-system +spec: + externalTrafficPolicy: Local + ports: + - name: EnvoyHTTPPort + port: 0 + protocol: TCP + targetPort: 8080 + - name: EnvoyHTTPSPort + port: 0 + protocol: TCP + targetPort: 8443 + selector: + app.kubernetes.io/name: envoy + app.kubernetes.io/component: proxy + app.kubernetes.io/managed-by: envoy-gateway + gateway.envoyproxy.io/owning-gateway-name: default + gateway.envoyproxy.io/owning-gateway-namespace: default + sessionAffinity: None + type: LoadBalancer diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index c26a8c713f8..76adfb15735 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2564,6 +2564,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `annotations` | _object (keys:string, values:string)_ | false | Annotations that should be appended to the service.
By default, no annotations are appended. | +| `labels` | _object (keys:string, values:string)_ | false | Labels that should be appended to the service.
By default, no labels are appended. | | `type` | _[ServiceType](#servicetype)_ | false | Type determines how the Service is exposed. Defaults to LoadBalancer.
Valid options are ClusterIP, LoadBalancer and NodePort.
"LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it).
"ClusterIP" means a service will only be accessible inside the cluster, via the cluster IP.
"NodePort" means a service will be exposed on a static Port on all Nodes of the cluster. | | `loadBalancerClass` | _string_ | false | LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider
implementation if more than one are available or is otherwise expected to be specified | | `allocateLoadBalancerNodePorts` | _boolean_ | false | AllocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for
services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster
load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a
value), those requests will be respected, regardless of this field. This field may only be set for
services with type LoadBalancer and will be cleared if the type is changed to any other type. | diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index c26a8c713f8..76adfb15735 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -2564,6 +2564,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `annotations` | _object (keys:string, values:string)_ | false | Annotations that should be appended to the service.
By default, no annotations are appended. | +| `labels` | _object (keys:string, values:string)_ | false | Labels that should be appended to the service.
By default, no labels are appended. | | `type` | _[ServiceType](#servicetype)_ | false | Type determines how the Service is exposed. Defaults to LoadBalancer.
Valid options are ClusterIP, LoadBalancer and NodePort.
"LoadBalancer" means a service will be exposed via an external load balancer (if the cloud provider supports it).
"ClusterIP" means a service will only be accessible inside the cluster, via the cluster IP.
"NodePort" means a service will be exposed on a static Port on all Nodes of the cluster. | | `loadBalancerClass` | _string_ | false | LoadBalancerClass, when specified, allows for choosing the LoadBalancer provider
implementation if more than one are available or is otherwise expected to be specified | | `allocateLoadBalancerNodePorts` | _boolean_ | false | AllocateLoadBalancerNodePorts defines if NodePorts will be automatically allocated for
services with type LoadBalancer. Default is "true". It may be set to "false" if the cluster
load-balancer does not rely on NodePorts. If the caller requests specific NodePorts (by specifying a
value), those requests will be respected, regardless of this field. This field may only be set for
services with type LoadBalancer and will be cleared if the type is changed to any other type. | From e0455acdd6dc598a30a35cc90e481f9f81431bc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:42:46 +0800 Subject: [PATCH 11/39] build(deps): bump helm.sh/helm/v3 from 3.16.1 to 3.16.2 (#4436) Bumps [helm.sh/helm/v3](https://github.com/helm/helm) from 3.16.1 to 3.16.2. - [Release notes](https://github.com/helm/helm/releases) - [Commits](https://github.com/helm/helm/compare/v3.16.1...v3.16.2) --- updated-dependencies: - dependency-name: helm.sh/helm/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e34c38bed54..956bf2831c6 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( golang.org/x/sys v0.26.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.16.1 + helm.sh/helm/v3 v3.16.2 k8s.io/api v0.31.1 k8s.io/apiextensions-apiserver v0.31.1 k8s.io/apimachinery v0.31.1 diff --git a/go.sum b/go.sum index 01eea5533e5..d26d6608694 100644 --- a/go.sum +++ b/go.sum @@ -1146,8 +1146,8 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.16.1 h1:cER6tI/8PgUAsaJaQCVBUg3VI9KN4oVaZJgY60RIc0c= -helm.sh/helm/v3 v3.16.1/go.mod h1:r+xBHHP20qJeEqtvBXMf7W35QDJnzY/eiEBzt+TfHps= +helm.sh/helm/v3 v3.16.2 h1:Y9v7ry+ubQmi+cb5zw1Llx8OKHU9Hk9NQ/+P+LGBe2o= +helm.sh/helm/v3 v3.16.2/go.mod h1:SyTXgKBjNqi2NPsHCW5dDAsHqvGIu0kdNYNH9gQaw70= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 045a438c10ae3b3a60185065ab381ed178c0eed2 Mon Sep 17 00:00:00 2001 From: Puerco Date: Mon, 14 Oct 2024 22:30:11 -0600 Subject: [PATCH 12/39] docs: Fix capital D in ratelimit example (#4428) --- site/content/en/docs/tasks/traffic/global-rate-limit.md | 2 +- site/content/en/latest/tasks/traffic/global-rate-limit.md | 2 +- site/content/en/v1.1/tasks/traffic/global-rate-limit.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/site/content/en/docs/tasks/traffic/global-rate-limit.md b/site/content/en/docs/tasks/traffic/global-rate-limit.md index bb87c47de49..da00334b296 100644 --- a/site/content/en/docs/tasks/traffic/global-rate-limit.md +++ b/site/content/en/docs/tasks/traffic/global-rate-limit.md @@ -871,7 +871,7 @@ spec: - clientSelectors: - sourceCIDR: value: 0.0.0.0/0 - type: distinct + type: Distinct limit: requests: 3 unit: Hour diff --git a/site/content/en/latest/tasks/traffic/global-rate-limit.md b/site/content/en/latest/tasks/traffic/global-rate-limit.md index f105de880cd..6c96b12efe7 100644 --- a/site/content/en/latest/tasks/traffic/global-rate-limit.md +++ b/site/content/en/latest/tasks/traffic/global-rate-limit.md @@ -870,7 +870,7 @@ spec: - clientSelectors: - sourceCIDR: value: 0.0.0.0/0 - type: distinct + type: Distinct limit: requests: 3 unit: Hour diff --git a/site/content/en/v1.1/tasks/traffic/global-rate-limit.md b/site/content/en/v1.1/tasks/traffic/global-rate-limit.md index bb87c47de49..da00334b296 100644 --- a/site/content/en/v1.1/tasks/traffic/global-rate-limit.md +++ b/site/content/en/v1.1/tasks/traffic/global-rate-limit.md @@ -871,7 +871,7 @@ spec: - clientSelectors: - sourceCIDR: value: 0.0.0.0/0 - type: distinct + type: Distinct limit: requests: 3 unit: Hour From a6beeed0552ba7a5a4dcae29854bc20ced759433 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:37:57 +0800 Subject: [PATCH 13/39] build(deps): bump google.golang.org/protobuf from 1.34.2 to 1.35.1 in /examples/extension-server (#4439) build(deps): bump google.golang.org/protobuf Bumps google.golang.org/protobuf from 1.34.2 to 1.35.1. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Huabing Zhao --- examples/extension-server/go.mod | 2 +- examples/extension-server/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/extension-server/go.mod b/examples/extension-server/go.mod index d6f03677ed6..75d36f57857 100644 --- a/examples/extension-server/go.mod +++ b/examples/extension-server/go.mod @@ -7,7 +7,7 @@ require ( github.com/envoyproxy/go-control-plane v0.13.1-0.20240917224354-20d038a70568 github.com/urfave/cli/v2 v2.27.4 google.golang.org/grpc v1.67.1 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.35.1 k8s.io/apimachinery v0.31.1 sigs.k8s.io/controller-runtime v0.19.0 sigs.k8s.io/gateway-api v1.2.0 diff --git a/examples/extension-server/go.sum b/examples/extension-server/go.sum index fd1ecc8f322..e987ca82ce8 100644 --- a/examples/extension-server/go.sum +++ b/examples/extension-server/go.sum @@ -111,8 +111,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 14aadc7d4a23c7f0ed66d5f011ef1486b6a27b88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:04:52 +0800 Subject: [PATCH 14/39] build(deps): bump github.com/prometheus/common from 0.59.1 to 0.60.0 (#4438) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.59.1 to 0.60.0. - [Release notes](https://github.com/prometheus/common/releases) - [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md) - [Commits](https://github.com/prometheus/common/compare/v0.59.1...v0.60.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Huabing Zhao --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 956bf2831c6..416c6bc01b5 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/miekg/dns v1.1.62 github.com/ohler55/ojg v1.24.1 github.com/prometheus/client_golang v1.20.4 - github.com/prometheus/common v0.59.1 + github.com/prometheus/common v0.60.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 @@ -274,7 +274,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 - golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/term v0.25.0 // indirect golang.org/x/text v0.19.0 // indirect diff --git a/go.sum b/go.sum index d26d6608694..7f32941ab83 100644 --- a/go.sum +++ b/go.sum @@ -701,8 +701,8 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= -github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= +github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= +github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -981,8 +981,8 @@ golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 8f0131c50dcaaafae0c30a1f98eeb6a1ed7aee8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:49:50 +0800 Subject: [PATCH 15/39] build(deps): bump github.com/replicatedhq/troubleshoot from 0.105.2 to 0.107.0 (#4437) build(deps): bump github.com/replicatedhq/troubleshoot Bumps [github.com/replicatedhq/troubleshoot](https://github.com/replicatedhq/troubleshoot) from 0.105.2 to 0.107.0. - [Release notes](https://github.com/replicatedhq/troubleshoot/releases) - [Commits](https://github.com/replicatedhq/troubleshoot/compare/v0.105.2...v0.107.0) --- updated-dependencies: - dependency-name: github.com/replicatedhq/troubleshoot dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Huabing Zhao --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 416c6bc01b5..b9599f0714e 100644 --- a/go.mod +++ b/go.mod @@ -63,7 +63,7 @@ require ( require ( github.com/docker/docker v27.3.1+incompatible - github.com/replicatedhq/troubleshoot v0.105.2 + github.com/replicatedhq/troubleshoot v0.107.0 google.golang.org/grpc v1.67.1 sigs.k8s.io/kubectl-validate v0.0.5-0.20240827210056-ce13d95db263 ) diff --git a/go.sum b/go.sum index 7f32941ab83..8008b00e8e6 100644 --- a/go.sum +++ b/go.sum @@ -717,8 +717,8 @@ github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ= github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= -github.com/replicatedhq/troubleshoot v0.105.2 h1:Fm1kKdzhPw+J7UnpLByxYJ3XAVV4IkylUIDt0eaUTFE= -github.com/replicatedhq/troubleshoot v0.105.2/go.mod h1:WqquTbNHLnZiSWsu6Mzo3rwez5kZ/A+1Hq4K/yq0HBo= +github.com/replicatedhq/troubleshoot v0.107.0 h1:AzaKBxNKuIQpERyitjJ4EINZTz4vlUacW5QguZZkTww= +github.com/replicatedhq/troubleshoot v0.107.0/go.mod h1:AjaLpi9kidsFAuyAvBrvcG04w49WIDm7Iy6XyMVMv6U= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= From 838cd27771b1a0ba29e0a584ba9e68884109337b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:10:11 +0800 Subject: [PATCH 16/39] build(deps): bump github.com/bufbuild/buf from 1.44.0 to 1.45.0 in /tools/src/buf (#4440) build(deps): bump github.com/bufbuild/buf in /tools/src/buf Bumps [github.com/bufbuild/buf](https://github.com/bufbuild/buf) from 1.44.0 to 1.45.0. - [Release notes](https://github.com/bufbuild/buf/releases) - [Changelog](https://github.com/bufbuild/buf/blob/main/CHANGELOG.md) - [Commits](https://github.com/bufbuild/buf/compare/v1.44.0...v1.45.0) --- updated-dependencies: - dependency-name: github.com/bufbuild/buf dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Huabing Zhao --- tools/src/buf/go.mod | 29 +++++++++++----------- tools/src/buf/go.sum | 58 +++++++++++++++++++++++--------------------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/tools/src/buf/go.mod b/tools/src/buf/go.mod index 9154ce02a93..b2022d8afde 100644 --- a/tools/src/buf/go.mod +++ b/tools/src/buf/go.mod @@ -2,7 +2,7 @@ module local go 1.23.1 -require github.com/bufbuild/buf v1.44.0 +require github.com/bufbuild/buf v1.45.0 require ( buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.34.2-20240928190436-5e8abcfd7a7e.2 // indirect @@ -21,7 +21,7 @@ require ( github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/bufbuild/protocompile v0.14.1 // indirect github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a // indirect - github.com/bufbuild/protovalidate-go v0.7.1 // indirect + github.com/bufbuild/protovalidate-go v0.7.2 // indirect github.com/containerd/cgroups/v3 v3.0.3 // indirect github.com/containerd/containerd v1.7.22 // indirect github.com/containerd/continuity v0.4.3 // indirect @@ -50,7 +50,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/cel-go v0.21.0 // indirect github.com/google/go-containerregistry v0.20.2 // indirect - github.com/google/pprof v0.0.0-20240929191954-255acd752d31 // indirect + github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -87,7 +87,7 @@ require ( github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect - github.com/tetratelabs/wazero v1.8.0 // indirect + github.com/tetratelabs/wazero v1.8.1 // indirect github.com/vbatts/tar-split v0.11.6 // indirect go.lsp.dev/jsonrpc2 v0.10.0 // indirect go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 // indirect @@ -104,18 +104,19 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + go.uber.org/zap/exp v0.1.1-0.20240913022758-ede8e1888f83 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 // indirect golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.29.0 // indirect + golang.org/x/net v0.30.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/text v0.18.0 // indirect - golang.org/x/tools v0.25.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect - google.golang.org/grpc v1.67.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/tools v0.26.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f // indirect + google.golang.org/grpc v1.67.1 // indirect google.golang.org/protobuf v1.34.3-0.20240906163944-03df6c145d96 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect pluginrpc.com/pluginrpc v0.5.0 // indirect diff --git a/tools/src/buf/go.sum b/tools/src/buf/go.sum index 1c3d37804b5..6fb21576d0e 100644 --- a/tools/src/buf/go.sum +++ b/tools/src/buf/go.sum @@ -30,14 +30,14 @@ github.com/Microsoft/hcsshim v0.12.7 h1:MP6R1spmjxTE4EU4J3YsrTxn8CjvN9qwjTKJXldF github.com/Microsoft/hcsshim v0.12.7/go.mod h1:HPbAuJ9BvQYYZbB4yEQcyGIsTP5L4yHKeO9XO149AEM= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= -github.com/bufbuild/buf v1.44.0 h1:95vd2ZbgaDkKIJ557eZrx2z6jdMULEpVbNpLlw/9Y5w= -github.com/bufbuild/buf v1.44.0/go.mod h1:Ksh+C0pR3t1or0BGyzq7krkam3zhBv21QVs1zsqdOik= +github.com/bufbuild/buf v1.45.0 h1:WdaM5OCjqEURmzOiz3h9gVilFXqWpt6X+zbOVqKti1A= +github.com/bufbuild/buf v1.45.0/go.mod h1:j+GjGIKS+CvubKtPiC0KpEiHAd3wS9/5sn2/U5WlA20= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a h1:l3RhVoG0RtC61h6TVWnkniGj4TgBebuyPQRdleFAmTg= github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ= -github.com/bufbuild/protovalidate-go v0.7.1 h1:ac50NTO6+1+mKg5sP/GBPLlMkQFeI+OeaYGFdS1vu98= -github.com/bufbuild/protovalidate-go v0.7.1/go.mod h1:PHV5pFuWlRzdDW02/cmVyNzdiQ+RNNwo7idGxdzS7o4= +github.com/bufbuild/protovalidate-go v0.7.2 h1:UuvKyZHl5p7u3ztEjtRtqtDxOjRKX5VUOgKFq6p6ETk= +github.com/bufbuild/protovalidate-go v0.7.2/go.mod h1:PHV5pFuWlRzdDW02/cmVyNzdiQ+RNNwo7idGxdzS7o4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -147,8 +147,8 @@ github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/pprof v0.0.0-20240929191954-255acd752d31 h1:LcRdQWywSgfi5jPsYZ1r2avbbs5IQ5wtyhMBCcokyo4= -github.com/google/pprof v0.0.0-20240929191954-255acd752d31/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d h1:Jaz2JzpQaQXyET0AjLBXShrthbpqMkhGiEfkcQAiAUs= +github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -254,8 +254,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g= -github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= +github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550= +github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/vbatts/tar-split v0.11.6 h1:4SjTW5+PU11n6fZenf2IPoV8/tz3AaYHMWjf23envGs= github.com/vbatts/tar-split v0.11.6/go.mod h1:dqKNtesIOr2j2Qv3W/cHjnvk9I8+G7oAkFDFN6TCBEI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -298,14 +298,16 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.1.1-0.20240913022758-ede8e1888f83 h1:wpjRiPjppWaUIH+GC0bRvsdaH2K4Dw49dEJa7MX01Mk= +go.uber.org/zap/exp v0.1.1-0.20240913022758-ede8e1888f83/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw= +golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -322,8 +324,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -342,14 +344,14 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -360,8 +362,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= -golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -371,17 +373,17 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 h1:pAjq8XSSzXoP9ya73v/w+9QEAAJNluLrpmMq5qFJQNY= -google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:O6rP0uBq4k0mdi/b4ZEMAZjkhYWhS815kCvaMha4VN8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f h1:jTm13A2itBi3La6yTGqn8bVSrc3ZZ1r8ENHlIXBfnRA= +google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f/go.mod h1:CLGoBuH1VHxAUXVPP8FfPwPEVJB6lz3URE5mY2SuayE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From cec67a86ac7e690b853eaf479a9a1127850c0b3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:10:33 +0800 Subject: [PATCH 17/39] build(deps): bump the go-opentelemetry-io group across 1 directory with 8 updates (#4434) * build(deps): bump the go-opentelemetry-io group across 1 directory with 8 updates Bumps the go-opentelemetry-io group with 5 updates in the / directory: | Package | From | To | | --- | --- | --- | | [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) | `1.30.0` | `1.31.0` | | [go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc](https://github.com/open-telemetry/opentelemetry-go) | `1.30.0` | `1.31.0` | | [go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp](https://github.com/open-telemetry/opentelemetry-go) | `1.30.0` | `1.31.0` | | [go.opentelemetry.io/otel/exporters/prometheus](https://github.com/open-telemetry/opentelemetry-go) | `0.52.0` | `0.53.0` | | [go.opentelemetry.io/otel/exporters/stdout/stdoutmetric](https://github.com/open-telemetry/opentelemetry-go) | `1.30.0` | `1.31.0` | Updates `go.opentelemetry.io/otel` from 1.30.0 to 1.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.30.0...v1.31.0) Updates `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` from 1.30.0 to 1.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.30.0...v1.31.0) Updates `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` from 1.30.0 to 1.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.30.0...v1.31.0) Updates `go.opentelemetry.io/otel/exporters/prometheus` from 0.52.0 to 0.53.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/example/prometheus/v0.52.0...example/prometheus/v0.53.0) Updates `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` from 1.30.0 to 1.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.30.0...v1.31.0) Updates `go.opentelemetry.io/otel/metric` from 1.30.0 to 1.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.30.0...v1.31.0) Updates `go.opentelemetry.io/otel/sdk/metric` from 1.30.0 to 1.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.30.0...v1.31.0) Updates `go.opentelemetry.io/otel/sdk` from 1.30.0 to 1.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.30.0...v1.31.0) --- updated-dependencies: - dependency-name: go.opentelemetry.io/otel dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/exporters/prometheus dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/exporters/stdout/stdoutmetric dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/metric dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/sdk/metric dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/sdk dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io ... Signed-off-by: dependabot[bot] * update Signed-off-by: zirain --------- Signed-off-by: dependabot[bot] Signed-off-by: zirain Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: zirain Co-authored-by: Huabing Zhao --- examples/extension-server/go.mod | 4 +-- examples/extension-server/go.sum | 8 ++--- go.mod | 24 +++++++-------- go.sum | 52 ++++++++++++++++---------------- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/examples/extension-server/go.mod b/examples/extension-server/go.mod index 75d36f57857..c4a08fecafc 100644 --- a/examples/extension-server/go.mod +++ b/examples/extension-server/go.mod @@ -34,8 +34,8 @@ require ( golang.org/x/net v0.30.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect diff --git a/examples/extension-server/go.sum b/examples/extension-server/go.sum index e987ca82ce8..7d995a60424 100644 --- a/examples/extension-server/go.sum +++ b/examples/extension-server/go.sum @@ -105,10 +105,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 h1:pAjq8XSSzXoP9ya73v/w+9QEAAJNluLrpmMq5qFJQNY= -google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:O6rP0uBq4k0mdi/b4ZEMAZjkhYWhS815kCvaMha4VN8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= diff --git a/go.mod b/go.mod index b9599f0714e..1a235360cd7 100644 --- a/go.mod +++ b/go.mod @@ -34,18 +34,18 @@ require ( github.com/stretchr/testify v1.9.0 github.com/telepresenceio/watchable v0.0.0-20220726211108-9bb86f92afa7 github.com/tsaarni/certyaml v0.9.3 - go.opentelemetry.io/otel v1.30.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.30.0 - go.opentelemetry.io/otel/exporters/prometheus v0.52.0 - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.30.0 - go.opentelemetry.io/otel/metric v1.30.0 - go.opentelemetry.io/otel/sdk/metric v1.30.0 + go.opentelemetry.io/otel v1.31.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.31.0 + go.opentelemetry.io/otel/exporters/prometheus v0.53.0 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.31.0 + go.opentelemetry.io/otel/metric v1.31.0 + go.opentelemetry.io/otel/sdk/metric v1.31.0 go.opentelemetry.io/proto/otlp v1.3.1 go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e golang.org/x/sys v0.26.0 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.35.1 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.16.2 k8s.io/api v0.31.1 @@ -268,8 +268,8 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/tsaarni/x500dn v1.0.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect - go.opentelemetry.io/otel/sdk v1.30.0 - go.opentelemetry.io/otel/trace v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.31.0 + go.opentelemetry.io/otel/trace v1.31.0 // indirect go.starlark.net v0.0.0-20240520160348-046347dcd104 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/mod v0.21.0 // indirect @@ -281,8 +281,8 @@ require ( golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.24.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/component-base v0.31.1 // indirect diff --git a/go.sum b/go.sum index 8008b00e8e6..c5d453f9e0d 100644 --- a/go.sum +++ b/go.sum @@ -723,8 +723,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rubenv/sql-migrate v1.7.0 h1:HtQq1xyTN2ISmQDggnh0c9U3JlP8apWh8YO2jzlXpTI= github.com/rubenv/sql-migrate v1.7.0/go.mod h1:S4wtDEG1CKn+0ShpTtzWhFpHHI5PvCUtiGI+C+Z2THE= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -888,32 +888,32 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.5 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= -go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 h1:WypxHH02KX2poqqbaadmkMYalGyy/vil4HE4PM4nRJc= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0/go.mod h1:U79SV99vtvGSEBeeHnpgGJfTsnsdkWLpPN/CcHAzBSI= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.30.0 h1:VrMAbeJz4gnVDg2zEzjHG4dEH86j4jO6VYB+NgtGD8s= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.30.0/go.mod h1:qqN/uFdpeitTvm+JDqqnjm517pmQRYxTORbETHq5tOc= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0 h1:FZ6ei8GFW7kyPYdxJaV2rgI6M+4tvZzhYsQ2wgyVC08= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0/go.mod h1:MdEu/mC6j3D+tTEfvI15b5Ci2Fn7NneJ71YMoiS3tpI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.31.0 h1:ZsXq73BERAiNuuFXYqP4MR5hBrjXfMGSO+Cx7qoOZiM= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.31.0/go.mod h1:hg1zaDMpyZJuUzjFxFsRYBoccE86tM9Uf4IqNMUxvrY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= -go.opentelemetry.io/otel/exporters/prometheus v0.52.0 h1:kmU3H0b9ufFSi8IQCcxack+sWUblKkFbqWYs6YiACGQ= -go.opentelemetry.io/otel/exporters/prometheus v0.52.0/go.mod h1:+wsAp2+JhuGXX7YRkjlkx6hyWY3ogFPfNA4x3nyiAh0= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.30.0 h1:IyFlqNsi8VT/nwYlLJfdM0y1gavxGpEvnf6FtVfZ6X4= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.30.0/go.mod h1:bxiX8eUeKoAEQmbq/ecUT8UqZwCjZW52yJrXJUSozsk= +go.opentelemetry.io/otel/exporters/prometheus v0.53.0 h1:QXobPHrwiGLM4ufrY3EOmDPJpo2P90UuFau4CDPJA/I= +go.opentelemetry.io/otel/exporters/prometheus v0.53.0/go.mod h1:WOAXGr3D00CfzmFxtTV1eR0GpoHuPEu+HJT8UWW2SIU= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.31.0 h1:HZgBIps9wH0RDrwjrmNa3DVbNRW60HEhdzqZFyAp3fI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.31.0/go.mod h1:RDRhvt6TDG0eIXmonAx5bd9IcwpqCkziwkOClzWKwAQ= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E= -go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= -go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= -go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= -go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= -go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792jZO1bo4BXkM= -go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= -go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= -go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.starlark.net v0.0.0-20240520160348-046347dcd104 h1:3qhteRISupnJvaWshOmeqEUs2y9oc/+/ePPvDh3Eygg= @@ -1082,10 +1082,10 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -1105,8 +1105,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 1f29518dc2472d3f904d07eb93778675a4bb2ea3 Mon Sep 17 00:00:00 2001 From: Guy Daich Date: Tue, 15 Oct 2024 08:42:49 -0500 Subject: [PATCH 18/39] feat(translator): client tls session resumption (#4293) * api: client tls session resumption Signed-off-by: Guy Daich * change api Signed-off-by: Guy Daich * add cel Signed-off-by: Guy Daich * implement tls session Signed-off-by: Guy Daich * fix gen Signed-off-by: Guy Daich * fix e2e Signed-off-by: Guy Daich * review fixes Signed-off-by: Guy Daich * rm sessionTimeout, use session container and shorter names Signed-off-by: Guy Daich * fix review comments Signed-off-by: Guy Daich * fix comment Signed-off-by: Guy Daich * fix gen Signed-off-by: Guy Daich --------- Signed-off-by: Guy Daich Co-authored-by: zirain --- api/v1alpha1/tls_types.go | 41 ++ api/v1alpha1/zz_generated.deepcopy.go | 80 +++ ...y.envoyproxy.io_clienttrafficpolicies.yaml | 21 + internal/gatewayapi/clienttrafficpolicy.go | 9 + .../clienttrafficpolicy-tls-settings.in.yaml | 4 + .../clienttrafficpolicy-tls-settings.out.yaml | 6 + internal/ir/xds.go | 4 + internal/xds/translator/listener.go | 16 + .../tls-with-ciphers-versions-alpn.yaml | 2 + .../testdata/out/xds-ir/http3.listeners.yaml | 4 + .../jsonpatch-with-jsonpath.listeners.yaml | 2 + .../out/xds-ir/jsonpatch.listeners.yaml | 2 + .../listener-proxy-protocol.listeners.yaml | 2 + .../xds-ir/mixed-tls-jwt-authn.listeners.yaml | 2 + ...ultiple-listeners-same-port.listeners.yaml | 4 + ...ertificate-with-custom-data.listeners.yaml | 10 + ...-forward-client-certificate.listeners.yaml | 10 + ...client-certificate-disabled.listeners.yaml | 4 + .../out/xds-ir/mutual-tls.listeners.yaml | 4 + .../out/xds-ir/simple-tls.listeners.yaml | 2 + .../suppress-envoy-headers.listeners.yaml | 2 + .../tcp-route-tls-terminate.listeners.yaml | 4 + ...-with-ciphers-versions-alpn.listeners.yaml | 2 + site/content/en/latest/api/extension_types.md | 61 ++ .../latest/tasks/security/secure-gateways.md | 80 +++ site/content/zh/latest/api/extension_types.md | 61 ++ test/e2e/base/manifests.yaml | 546 +++++++++--------- test/e2e/testdata/client-mtls.yaml | 78 +++ test/e2e/tests/client_mtls.go | 170 ++++++ 29 files changed, 960 insertions(+), 273 deletions(-) diff --git a/api/v1alpha1/tls_types.go b/api/v1alpha1/tls_types.go index 38c52761125..b926558c525 100644 --- a/api/v1alpha1/tls_types.go +++ b/api/v1alpha1/tls_types.go @@ -15,6 +15,10 @@ type ClientTLSSettings struct { // +optional ClientValidation *ClientValidationContext `json:"clientValidation,omitempty"` TLSSettings `json:",inline"` + + // Session defines settings related to TLS session management. + // +optional + Session *Session `json:"session,omitempty"` } // +kubebuilder:validation:XValidation:rule="has(self.minVersion) && self.minVersion == '1.3' ? !has(self.ciphers) : true", message="setting ciphers has no effect if the minimum possible TLS version is 1.3" @@ -133,3 +137,40 @@ type ClientValidationContext struct { // +optional CACertificateRefs []gwapiv1.SecretObjectReference `json:"caCertificateRefs,omitempty"` } + +// Session defines settings related to TLS session management. +type Session struct { + // Resumption determines the proxy's supported TLS session resumption option. + // By default, Envoy Gateway does not enable session resumption. Use sessionResumption to + // enable stateful and stateless session resumption. Users should consider security impacts + // of different resumption methods. Performance gains from resumption are diminished when + // Envoy proxy is deployed with more than one replica. + // +optional + Resumption *SessionResumption `json:"resumption,omitempty"` +} + +// SessionResumption defines supported tls session resumption methods and their associated configuration. +type SessionResumption struct { + // Stateless defines setting for stateless (session-ticket based) session resumption + // +optional + Stateless *StatelessTLSSessionResumption `json:"stateless,omitempty"` + + // Stateful defines setting for stateful (session-id based) session resumption + // +optional + Stateful *StatefulTLSSessionResumption `json:"stateful,omitempty"` +} + +// StatefulTLSSessionResumption defines the stateful (session-id based) type of TLS session resumption. +// Note: When Envoy Proxy is deployed with more than one replica, session caches are not synchronized +// between instances, possibly leading to resumption failures. +// Envoy does not re-validate client certificates upon session resumption. +// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#config-route-v3-routematch-tlscontextmatchoptions +type StatefulTLSSessionResumption struct{} + +// StatelessTLSSessionResumption defines the stateless (session-ticket based) type of TLS session resumption. +// Note: When Envoy Proxy is deployed with more than one replica, session ticket encryption keys are not +// synchronized between instances, possibly leading to resumption failures. +// In-memory session ticket encryption keys are rotated every 48 hours. +// https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto#extensions-transport-sockets-tls-v3-tlssessionticketkeys +// https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Session-tickets +type StatelessTLSSessionResumption struct{} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index a72706c33bb..2ce5a5762ee 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -759,6 +759,11 @@ func (in *ClientTLSSettings) DeepCopyInto(out *ClientTLSSettings) { (*in).DeepCopyInto(*out) } in.TLSSettings.DeepCopyInto(&out.TLSSettings) + if in.Session != nil { + in, out := &in.Session, &out.Session + *out = new(Session) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientTLSSettings. @@ -4947,6 +4952,51 @@ func (in *SecurityPolicySpec) DeepCopy() *SecurityPolicySpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Session) DeepCopyInto(out *Session) { + *out = *in + if in.Resumption != nil { + in, out := &in.Resumption, &out.Resumption + *out = new(SessionResumption) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Session. +func (in *Session) DeepCopy() *Session { + if in == nil { + return nil + } + out := new(Session) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SessionResumption) DeepCopyInto(out *SessionResumption) { + *out = *in + if in.Stateless != nil { + in, out := &in.Stateless, &out.Stateless + *out = new(StatelessTLSSessionResumption) + **out = **in + } + if in.Stateful != nil { + in, out := &in.Stateful, &out.Stateful + *out = new(StatefulTLSSessionResumption) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionResumption. +func (in *SessionResumption) DeepCopy() *SessionResumption { + if in == nil { + return nil + } + out := new(SessionResumption) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ShutdownConfig) DeepCopyInto(out *ShutdownConfig) { *out = *in @@ -5037,6 +5087,36 @@ func (in *SourceMatch) DeepCopy() *SourceMatch { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatefulTLSSessionResumption) DeepCopyInto(out *StatefulTLSSessionResumption) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulTLSSessionResumption. +func (in *StatefulTLSSessionResumption) DeepCopy() *StatefulTLSSessionResumption { + if in == nil { + return nil + } + out := new(StatefulTLSSessionResumption) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatelessTLSSessionResumption) DeepCopyInto(out *StatelessTLSSessionResumption) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatelessTLSSessionResumption. +func (in *StatelessTLSSessionResumption) DeepCopy() *StatelessTLSSessionResumption { + if in == nil { + return nil + } + out := new(StatelessTLSSessionResumption) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StatusCodeMatch) DeepCopyInto(out *StatusCodeMatch) { *out = *in diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index 81f449b8860..582486e706f 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -808,6 +808,27 @@ spec: - "1.2" - "1.3" type: string + session: + description: Session defines settings related to TLS session management. + properties: + resumption: + description: |- + Resumption determines the proxy's supported TLS session resumption option. + By default, Envoy Gateway does not enable session resumption. Use sessionResumption to + enable stateful and stateless session resumption. Users should consider security impacts + of different resumption methods. Performance gains from resumption are diminished when + Envoy proxy is deployed with more than one replica. + properties: + stateful: + description: Stateful defines setting for stateful (session-id + based) session resumption + type: object + stateless: + description: Stateless defines setting for stateless (session-ticket + based) session resumption + type: object + type: object + type: object signatureAlgorithms: description: |- SignatureAlgorithms specifies which signature algorithms the listener should diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index 67cd60ad679..bded79d4cf9 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -864,6 +864,15 @@ func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPoli } } + if tlsParams.Session != nil && tlsParams.Session.Resumption != nil { + if tlsParams.Session.Resumption.Stateless != nil { + irTLSConfig.StatelessSessionResumption = true + } + if tlsParams.Session.Resumption.Stateful != nil { + irTLSConfig.StatefulSessionResumption = true + } + } + return irTLSConfig, nil } diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.in.yaml index 59dc2819c7c..bc5878a52f0 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.in.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.in.yaml @@ -22,6 +22,10 @@ clientTrafficPolicies: signatureAlgorithms: - sig1 - sig2 + session: + resumption: + stateless: {} + stateful: {} gateways: - apiVersion: gateway.networking.k8s.io/v1 kind: Gateway diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.out.yaml index f66ef90810d..ed684f328b4 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.out.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-tls-settings.out.yaml @@ -20,6 +20,10 @@ clientTrafficPolicies: - curve1 maxVersion: "1.3" minVersion: "1.0" + session: + resumption: + stateful: {} + stateless: {} signatureAlgorithms: - sig1 - sig2 @@ -174,6 +178,8 @@ xdsIR: signatureAlgorithms: - sig1 - sig2 + statefulSessionResumption: true + statelessSessionResumption: true - address: 0.0.0.0 hostnames: - '*' diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 53eb34fa2a6..49d6fdbf064 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -351,6 +351,10 @@ type TLSConfig struct { SignatureAlgorithms []string `json:"signatureAlgorithms,omitempty" yaml:"signatureAlgorithms,omitempty"` // ALPNProtocols exposed by this listener ALPNProtocols []string `json:"alpnProtocols,omitempty" yaml:"alpnProtocols,omitempty"` + // StatelessSessionResumption determines if stateless (session-ticket based) session resumption is enabled + StatelessSessionResumption bool `json:"statelessSessionResumption,omitempty" yaml:"statelessSessionResumption,omitempty"` + // StatefulSessionResumption determines if stateful (session-id based) session resumption is enabled + StatefulSessionResumption bool `json:"statefulSessionResumption,omitempty" yaml:"statefulSessionResumption,omitempty"` } // TLSCertificate holds a single certificate's details diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index 9cc8e61f6ed..dda639f9f2f 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -624,6 +624,8 @@ func buildDownstreamQUICTransportSocket(tlsConfig *ir.TLSConfig) (*corev3.Transp } } + setDownstreamTLSSessionSettings(tlsConfig, tlsCtx.DownstreamTlsContext) + tlsCtxAny, err := anypb.New(tlsCtx) if err != nil { return nil, err @@ -664,6 +666,8 @@ func buildXdsDownstreamTLSSocket(tlsConfig *ir.TLSConfig) (*corev3.TransportSock } } + setDownstreamTLSSessionSettings(tlsConfig, tlsCtx) + tlsCtxAny, err := anypb.New(tlsCtx) if err != nil { return nil, err @@ -677,6 +681,18 @@ func buildXdsDownstreamTLSSocket(tlsConfig *ir.TLSConfig) (*corev3.TransportSock }, nil } +func setDownstreamTLSSessionSettings(tlsConfig *ir.TLSConfig, tlsCtx *tlsv3.DownstreamTlsContext) { + if !tlsConfig.StatefulSessionResumption { + tlsCtx.DisableStatefulSessionResumption = true + } + + if !tlsConfig.StatelessSessionResumption { + tlsCtx.SessionTicketKeysType = &tlsv3.DownstreamTlsContext_DisableStatelessSessionResumption{ + DisableStatelessSessionResumption: true, + } + } +} + func buildTLSParams(tlsConfig *ir.TLSConfig) *tlsv3.TlsParameters { p := &tlsv3.TlsParameters{} isEmpty := true diff --git a/internal/xds/translator/testdata/in/xds-ir/tls-with-ciphers-versions-alpn.yaml b/internal/xds/translator/testdata/in/xds-ir/tls-with-ciphers-versions-alpn.yaml index 03e161599b7..afcf3322715 100644 --- a/internal/xds/translator/testdata/in/xds-ir/tls-with-ciphers-versions-alpn.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/tls-with-ciphers-versions-alpn.yaml @@ -30,6 +30,7 @@ http: minVersion: "1.0" alpnProtocols: - some-other-protocol + statefulSessionResumption: true certificates: - name: secret-1 # byte slice representation of "key-data" @@ -107,6 +108,7 @@ tcp: minVersion: "1.0" alpnProtocols: - some-other-protocol + statelessSessionResumption: true certificates: - name: secret-3 # byte slice representation of "key-data" diff --git a/internal/xds/translator/testdata/out/xds-ir/http3.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/http3.listeners.yaml index 56a11c58a99..49a651da85e 100644 --- a/internal/xds/translator/testdata/out/xds-ir/http3.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/http3.listeners.yaml @@ -47,6 +47,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true name: envoy-gateway/gateway-1/tls-quic udpListenerConfig: downstreamSocketConfig: {} @@ -96,5 +98,7 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true name: envoy-gateway/gateway-1/tls perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml index 6fe14b03f97..fb7bceafa22 100644 --- a/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml @@ -59,5 +59,7 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true name: first-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/jsonpatch.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jsonpatch.listeners.yaml index 6fe14b03f97..fb7bceafa22 100644 --- a/internal/xds/translator/testdata/out/xds-ir/jsonpatch.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/jsonpatch.listeners.yaml @@ -59,5 +59,7 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true name: first-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol.listeners.yaml index 89d57c725f0..210069d7019 100644 --- a/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol.listeners.yaml @@ -50,6 +50,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true listenerFilters: - name: envoy.filters.listener.proxy_protocol typedConfig: diff --git a/internal/xds/translator/testdata/out/xds-ir/mixed-tls-jwt-authn.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/mixed-tls-jwt-authn.listeners.yaml index b7967da1cc0..1426aeaa71f 100644 --- a/internal/xds/translator/testdata/out/xds-ir/mixed-tls-jwt-authn.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/mixed-tls-jwt-authn.listeners.yaml @@ -43,5 +43,7 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true name: first-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port.listeners.yaml index 1e62e5ca424..86002534182 100644 --- a/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port.listeners.yaml @@ -74,6 +74,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true - filterChainMatch: serverNames: - foo.net @@ -117,6 +119,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true - filterChainMatch: serverNames: - bar.com diff --git a/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate-with-custom-data.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate-with-custom-data.listeners.yaml index baaca0e4fb6..7d177b2e092 100644 --- a/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate-with-custom-data.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate-with-custom-data.listeners.yaml @@ -52,6 +52,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: first-listener perConnectionBufferLimitBytes: 32768 @@ -110,6 +112,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: second-listener perConnectionBufferLimitBytes: 32768 @@ -170,6 +174,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: third-listener perConnectionBufferLimitBytes: 32768 @@ -232,6 +238,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: fourth-listener perConnectionBufferLimitBytes: 32768 @@ -296,6 +304,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: fifth-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate.listeners.yaml index a99d3fd3906..33262561948 100644 --- a/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/mutual-tls-forward-client-certificate.listeners.yaml @@ -52,6 +52,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: first-listener perConnectionBufferLimitBytes: 32768 @@ -110,6 +112,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: second-listener perConnectionBufferLimitBytes: 32768 @@ -168,6 +172,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: third-listener perConnectionBufferLimitBytes: 32768 @@ -226,6 +232,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: fourth-listener perConnectionBufferLimitBytes: 32768 @@ -284,6 +292,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: fifth-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/mutual-tls-required-client-certificate-disabled.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/mutual-tls-required-client-certificate-disabled.listeners.yaml index 28836be314c..e945b5d9221 100644 --- a/internal/xds/translator/testdata/out/xds-ir/mutual-tls-required-client-certificate-disabled.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/mutual-tls-required-client-certificate-disabled.listeners.yaml @@ -52,6 +52,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: first-listener perConnectionBufferLimitBytes: 32768 @@ -85,6 +87,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: false name: second-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/mutual-tls.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/mutual-tls.listeners.yaml index 490cfa0f9d9..fc572910c06 100644 --- a/internal/xds/translator/testdata/out/xds-ir/mutual-tls.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/mutual-tls.listeners.yaml @@ -52,6 +52,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: true name: first-listener perConnectionBufferLimitBytes: 32768 @@ -85,6 +87,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true requireClientCertificate: true name: second-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/simple-tls.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/simple-tls.listeners.yaml index 54f30d4c445..3d65ed1a895 100644 --- a/internal/xds/translator/testdata/out/xds-ir/simple-tls.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/simple-tls.listeners.yaml @@ -47,5 +47,7 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true name: first-listener perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/suppress-envoy-headers.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/suppress-envoy-headers.listeners.yaml index bcc936863ca..4c624b8788f 100644 --- a/internal/xds/translator/testdata/out/xds-ir/suppress-envoy-headers.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/suppress-envoy-headers.listeners.yaml @@ -49,6 +49,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true listenerFilters: - name: envoy.filters.listener.tls_inspector typedConfig: diff --git a/internal/xds/translator/testdata/out/xds-ir/tcp-route-tls-terminate.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/tcp-route-tls-terminate.listeners.yaml index f27dc1b2123..10df3db202c 100644 --- a/internal/xds/translator/testdata/out/xds-ir/tcp-route-tls-terminate.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/tcp-route-tls-terminate.listeners.yaml @@ -23,6 +23,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true - filterChainMatch: serverNames: - '*.envoyproxy.io' @@ -47,6 +49,8 @@ sdsConfig: ads: {} resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true listenerFilters: - name: envoy.filters.listener.tls_inspector typedConfig: diff --git a/internal/xds/translator/testdata/out/xds-ir/tls-with-ciphers-versions-alpn.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/tls-with-ciphers-versions-alpn.listeners.yaml index dd12bc2b988..7eee7e167c0 100644 --- a/internal/xds/translator/testdata/out/xds-ir/tls-with-ciphers-versions-alpn.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/tls-with-ciphers-versions-alpn.listeners.yaml @@ -70,6 +70,7 @@ - rsa_pkcs1_sha1 tlsMaximumProtocolVersion: TLSv1_2 tlsMinimumProtocolVersion: TLSv1_0 + disableStatelessSessionResumption: true listenerFilters: - name: envoy.filters.listener.tls_inspector typedConfig: @@ -121,5 +122,6 @@ - rsa_pkcs1_sha1 tlsMaximumProtocolVersion: TLSv1_2 tlsMinimumProtocolVersion: TLSv1_0 + disableStatefulSessionResumption: true name: second-listener perConnectionBufferLimitBytes: 32768 diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 76adfb15735..956b3dbd228 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -610,6 +610,7 @@ _Appears in:_ | `ecdhCurves` | _string array_ | false | ECDHCurves specifies the set of supported ECDH curves.
In non-FIPS Envoy Proxy builds the default curves are:
- X25519
- P-256
In builds using BoringSSL FIPS the default curve is:
- P-256 | | `signatureAlgorithms` | _string array_ | false | SignatureAlgorithms specifies which signature algorithms the listener should
support. | | `alpnProtocols` | _[ALPNProtocol](#alpnprotocol) array_ | false | ALPNProtocols supplies the list of ALPN protocols that should be
exposed by the listener. By default h2 and http/1.1 are enabled.
Supported values are:
- http/1.0
- http/1.1
- h2 | +| `session` | _[Session](#session)_ | false | Session defines settings related to TLS session management. | #### ClientTimeout @@ -3676,6 +3677,35 @@ _Appears in:_ | `NodePort` | ServiceTypeNodePort means a service will be exposed on each Kubernetes Node
at a static Port, common across all Nodes.
| +#### Session + + + +Session defines settings related to TLS session management. + +_Appears in:_ +- [ClientTLSSettings](#clienttlssettings) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `resumption` | _[SessionResumption](#sessionresumption)_ | false | Resumption determines the proxy's supported TLS session resumption option.
By default, Envoy Gateway does not enable session resumption. Use sessionResumption to
enable stateful and stateless session resumption. Users should consider security impacts
of different resumption methods. Performance gains from resumption are diminished when
Envoy proxy is deployed with more than one replica. | + + +#### SessionResumption + + + +SessionResumption defines supported tls session resumption methods and their associated configuration. + +_Appears in:_ +- [Session](#session) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `stateless` | _[StatelessTLSSessionResumption](#statelesstlssessionresumption)_ | false | Stateless defines setting for stateless (session-ticket based) session resumption | +| `stateful` | _[StatefulTLSSessionResumption](#statefultlssessionresumption)_ | false | Stateful defines setting for stateful (session-id based) session resumption | + + #### ShutdownConfig @@ -3736,6 +3766,37 @@ _Appears in:_ | `Distinct` | SourceMatchDistinct Each IP Address within the specified Source IP CIDR is treated as a distinct client selector
and uses a separate rate limit bucket/counter.
Note: This is only supported for Global Rate Limits.
| +#### StatefulTLSSessionResumption + + + +StatefulTLSSessionResumption defines the stateful (session-id based) type of TLS session resumption. +Note: When Envoy Proxy is deployed with more than one replica, session caches are not synchronized +between instances, possibly leading to resumption failures. +Envoy does not re-validate client certificates upon session resumption. +https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#config-route-v3-routematch-tlscontextmatchoptions + +_Appears in:_ +- [SessionResumption](#sessionresumption) + + + +#### StatelessTLSSessionResumption + + + +StatelessTLSSessionResumption defines the stateless (session-ticket based) type of TLS session resumption. +Note: When Envoy Proxy is deployed with more than one replica, session ticket encryption keys are not +synchronized between instances, possibly leading to resumption failures. +In-memory session ticket encryption keys are rotated every 48 hours. +https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto#extensions-transport-sockets-tls-v3-tlssessionticketkeys +https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Session-tickets + +_Appears in:_ +- [SessionResumption](#sessionresumption) + + + #### StatusCodeMatch diff --git a/site/content/en/latest/tasks/security/secure-gateways.md b/site/content/en/latest/tasks/security/secure-gateways.md index f0e5c8c2697..2c8d5043812 100644 --- a/site/content/en/latest/tasks/security/secure-gateways.md +++ b/site/content/en/latest/tasks/security/secure-gateways.md @@ -512,8 +512,88 @@ Since the multiple certificates are configured on the same Gateway listener, Env {{% /tab %}} {{< /tabpane >}} +## Customize Gateway TLS Parameters + +In addition to enablement of TLS with Gateway-API, Envoy Gateway supports customizing TLS parameters. +To achieve this, the [ClientTrafficPolicy][] resource can be used to specify TLS parameters. +We will customize the minimum supported TLS version in this example to TLSv1.3. + +{{< tabpane text=true >}} +{{% tab header="Apply from stdin" %}} + +```shell +cat <}} + + +## Testing TLS Parameters + +Attempt to connecting using an unsupported TLS version: + +```shell +curl -v -HHost:www.sample.com --resolve "www.sample.com:8443:127.0.0.1" \ +--cacert sample.com.crt --tlsv1.2 --tls-max 1.2 https://www.sample.com:8443/get -I + +[...] + +* ALPN: curl offers h2,http/1.1 +* (304) (OUT), TLS handshake, Client hello (1): +* LibreSSL/3.3.6: error:1404B42E:SSL routines:ST_CONNECT:tlsv1 alert protocol version +* Closing connection +curl: (35) LibreSSL/3.3.6: error:1404B42E:SSL routines:ST_CONNECT:tlsv1 alert protocol version +``` + +The output shows that the connection fails due to an unsupported TLS protocol version used by the client. Now, connect +to the Gateway without specifying a client version, and note that the connection is established with TLSv1.3. + +```shell +curl -v -HHost:www.sample.com --resolve "www.sample.com:8443:127.0.0.1" \ +--cacert sample.com.crt https://www.sample.com:8443/get -I + +[...] + +* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 / [blank] / UNDEF +``` + ## Next Steps Checkout the [Developer Guide](../../../contributions/develop) to get involved in the project. [ReferenceGrant]: https://gateway-api.sigs.k8s.io/api-types/referencegrant/ +[ClientTrafficPolicy]: ../../api/extension_types#clienttrafficpolicy \ No newline at end of file diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 76adfb15735..956b3dbd228 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -610,6 +610,7 @@ _Appears in:_ | `ecdhCurves` | _string array_ | false | ECDHCurves specifies the set of supported ECDH curves.
In non-FIPS Envoy Proxy builds the default curves are:
- X25519
- P-256
In builds using BoringSSL FIPS the default curve is:
- P-256 | | `signatureAlgorithms` | _string array_ | false | SignatureAlgorithms specifies which signature algorithms the listener should
support. | | `alpnProtocols` | _[ALPNProtocol](#alpnprotocol) array_ | false | ALPNProtocols supplies the list of ALPN protocols that should be
exposed by the listener. By default h2 and http/1.1 are enabled.
Supported values are:
- http/1.0
- http/1.1
- h2 | +| `session` | _[Session](#session)_ | false | Session defines settings related to TLS session management. | #### ClientTimeout @@ -3676,6 +3677,35 @@ _Appears in:_ | `NodePort` | ServiceTypeNodePort means a service will be exposed on each Kubernetes Node
at a static Port, common across all Nodes.
| +#### Session + + + +Session defines settings related to TLS session management. + +_Appears in:_ +- [ClientTLSSettings](#clienttlssettings) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `resumption` | _[SessionResumption](#sessionresumption)_ | false | Resumption determines the proxy's supported TLS session resumption option.
By default, Envoy Gateway does not enable session resumption. Use sessionResumption to
enable stateful and stateless session resumption. Users should consider security impacts
of different resumption methods. Performance gains from resumption are diminished when
Envoy proxy is deployed with more than one replica. | + + +#### SessionResumption + + + +SessionResumption defines supported tls session resumption methods and their associated configuration. + +_Appears in:_ +- [Session](#session) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `stateless` | _[StatelessTLSSessionResumption](#statelesstlssessionresumption)_ | false | Stateless defines setting for stateless (session-ticket based) session resumption | +| `stateful` | _[StatefulTLSSessionResumption](#statefultlssessionresumption)_ | false | Stateful defines setting for stateful (session-id based) session resumption | + + #### ShutdownConfig @@ -3736,6 +3766,37 @@ _Appears in:_ | `Distinct` | SourceMatchDistinct Each IP Address within the specified Source IP CIDR is treated as a distinct client selector
and uses a separate rate limit bucket/counter.
Note: This is only supported for Global Rate Limits.
| +#### StatefulTLSSessionResumption + + + +StatefulTLSSessionResumption defines the stateful (session-id based) type of TLS session resumption. +Note: When Envoy Proxy is deployed with more than one replica, session caches are not synchronized +between instances, possibly leading to resumption failures. +Envoy does not re-validate client certificates upon session resumption. +https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#config-route-v3-routematch-tlscontextmatchoptions + +_Appears in:_ +- [SessionResumption](#sessionresumption) + + + +#### StatelessTLSSessionResumption + + + +StatelessTLSSessionResumption defines the stateless (session-ticket based) type of TLS session resumption. +Note: When Envoy Proxy is deployed with more than one replica, session ticket encryption keys are not +synchronized between instances, possibly leading to resumption failures. +In-memory session ticket encryption keys are rotated every 48 hours. +https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto#extensions-transport-sockets-tls-v3-tlssessionticketkeys +https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Session-tickets + +_Appears in:_ +- [SessionResumption](#sessionresumption) + + + #### StatusCodeMatch diff --git a/test/e2e/base/manifests.yaml b/test/e2e/base/manifests.yaml index 3bba21844a0..db9a265cba0 100644 --- a/test/e2e/base/manifests.yaml +++ b/test/e2e/base/manifests.yaml @@ -21,12 +21,12 @@ metadata: spec: gatewayClassName: "{GATEWAY_CLASS_NAME}" listeners: - - name: http - port: 80 - protocol: HTTP - allowedRoutes: - namespaces: - from: Same + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway @@ -36,12 +36,12 @@ metadata: spec: gatewayClassName: "{GATEWAY_CLASS_NAME}" listeners: - - name: http - port: 80 - protocol: HTTP - allowedRoutes: - namespaces: - from: All + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: All --- apiVersion: v1 kind: Service @@ -52,14 +52,14 @@ spec: selector: app: infra-backend-v1 ports: - - protocol: TCP - port: 8080 - name: http11 - targetPort: 3000 - - protocol: TCP - port: 8081 - name: http2 - targetPort: 3001 + - protocol: TCP + port: 8080 + name: http11 + targetPort: 3000 + - protocol: TCP + port: 8081 + name: http2 + targetPort: 3001 --- apiVersion: apps/v1 kind: Deployment @@ -79,23 +79,23 @@ spec: app: infra-backend-v1 spec: containers: - - name: infra-backend-v1 - # From https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/echo-basic/echo-basic.go - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: infra-backend-v1 - resources: - requests: - cpu: 10m + - name: infra-backend-v1 + # From https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/echo-basic/echo-basic.go + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: infra-backend-v1 + resources: + requests: + cpu: 10m --- apiVersion: v1 kind: Service @@ -106,9 +106,9 @@ spec: selector: app: infra-backend-v2 ports: - - protocol: TCP - port: 8080 - targetPort: 3000 + - protocol: TCP + port: 8080 + targetPort: 3000 --- apiVersion: apps/v1 kind: Deployment @@ -128,22 +128,22 @@ spec: app: infra-backend-v2 spec: containers: - - name: infra-backend-v2 - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: infra-backend-v2 - resources: - requests: - cpu: 10m + - name: infra-backend-v2 + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: infra-backend-v2 + resources: + requests: + cpu: 10m --- apiVersion: v1 kind: Service @@ -154,9 +154,9 @@ spec: selector: app: infra-backend-v3 ports: - - protocol: TCP - port: 8080 - targetPort: 3000 + - protocol: TCP + port: 8080 + targetPort: 3000 --- apiVersion: apps/v1 kind: Deployment @@ -176,22 +176,22 @@ spec: app: infra-backend-v3 spec: containers: - - name: infra-backend-v3 - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: infra-backend-v3 - resources: - requests: - cpu: 10m + - name: infra-backend-v3 + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: infra-backend-v3 + resources: + requests: + cpu: 10m --- apiVersion: v1 kind: Service @@ -202,9 +202,9 @@ spec: selector: app: tls-backend ports: - - protocol: TCP - port: 443 - targetPort: 8443 + - protocol: TCP + port: 443 + targetPort: 8443 --- apiVersion: apps/v1 kind: Deployment @@ -224,38 +224,38 @@ spec: app: tls-backend spec: containers: - - name: tls-backend - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - volumeMounts: - - name: secret-volume - mountPath: /etc/secret-volume - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: tls-backend - - name: TLS_SERVER_CERT - value: /etc/secret-volume/crt - - name: TLS_SERVER_PRIVKEY - value: /etc/secret-volume/key - resources: - requests: - cpu: 10m + - name: tls-backend + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + volumeMounts: + - name: secret-volume + mountPath: /etc/secret-volume + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: tls-backend + - name: TLS_SERVER_CERT + value: /etc/secret-volume/crt + - name: TLS_SERVER_PRIVKEY + value: /etc/secret-volume/key + resources: + requests: + cpu: 10m volumes: - - name: secret-volume - secret: - secretName: tls-passthrough-checks-certificate - items: - - key: tls.crt - path: crt - - key: tls.key - path: key + - name: secret-volume + secret: + secretName: tls-passthrough-checks-certificate + items: + - key: tls.crt + path: crt + - key: tls.key + path: key --- apiVersion: v1 kind: Namespace @@ -273,9 +273,9 @@ spec: selector: app: app-backend-v1 ports: - - protocol: TCP - port: 8080 - targetPort: 3000 + - protocol: TCP + port: 8080 + targetPort: 3000 --- apiVersion: apps/v1 kind: Deployment @@ -295,22 +295,22 @@ spec: app: app-backend-v1 spec: containers: - - name: app-backend-v1 - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: app-backend-v1 - resources: - requests: - cpu: 10m + - name: app-backend-v1 + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: app-backend-v1 + resources: + requests: + cpu: 10m --- apiVersion: v1 kind: Service @@ -321,9 +321,9 @@ spec: selector: app: app-backend-v2 ports: - - protocol: TCP - port: 8080 - targetPort: 3000 + - protocol: TCP + port: 8080 + targetPort: 3000 --- apiVersion: apps/v1 kind: Deployment @@ -343,22 +343,22 @@ spec: app: app-backend-v2 spec: containers: - - name: app-backend-v2 - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: app-backend-v2 - resources: - requests: - cpu: 10m + - name: app-backend-v2 + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: app-backend-v2 + resources: + requests: + cpu: 10m --- apiVersion: v1 kind: Namespace @@ -376,9 +376,9 @@ spec: selector: app: web-backend ports: - - protocol: TCP - port: 8080 - targetPort: 3000 + - protocol: TCP + port: 8080 + targetPort: 3000 --- apiVersion: apps/v1 kind: Deployment @@ -398,22 +398,22 @@ spec: app: web-backend spec: containers: - - name: web-backend - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: web-backend - resources: - requests: - cpu: 10m + - name: web-backend + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: web-backend + resources: + requests: + cpu: 10m --- apiVersion: v1 kind: Namespace @@ -427,55 +427,55 @@ metadata: namespace: gateway-preserve-case-backend data: go.mod: | - module srvr - go 1.22 - require ( - github.com/andybalholm/brotli v1.0.5 // indirect - github.com/klauspost/compress v1.17.0 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - ) + module srvr + go 1.22 + require ( + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/klauspost/compress v1.17.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + ) go.sum: | - github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= - github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= - github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= - github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= - github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= - github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= - github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= - github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= + github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= + github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= + github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= + github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= + github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= + github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= + github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= + github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= main.go: | - package main - import ( - "encoding/json" - "fmt" - "log" - "github.com/valyala/fasthttp" - ) - func HandleFastHTTP(ctx *fasthttp.RequestCtx) { - ctx.QueryArgs().VisitAll(func(key, value []byte) { - if string(key) == "headers" { - ctx.Response.Header.Add(string(value), "PrEsEnT") - } - }) - headers := map[string][]string{} - ctx.Request.Header.VisitAll(func(key, value []byte) { - headers[string(key)] = append(headers[string(key)], string(value)) - }) - if d, err := json.MarshalIndent(headers, "", " "); err != nil { - ctx.Error(fmt.Sprintf("%s", err), fasthttp.StatusBadRequest) - } else { - fmt.Fprintf(ctx, string(d)+"\n") - } - } - func main() { - s := fasthttp.Server{ - Handler: HandleFastHTTP, - DisableHeaderNamesNormalizing: true, - } - log.Printf("Starting on port 8000") - log.Fatal(s.ListenAndServe(":8000")) - } + package main + import ( + "encoding/json" + "fmt" + "log" + "github.com/valyala/fasthttp" + ) + func HandleFastHTTP(ctx *fasthttp.RequestCtx) { + ctx.QueryArgs().VisitAll(func(key, value []byte) { + if string(key) == "headers" { + ctx.Response.Header.Add(string(value), "PrEsEnT") + } + }) + headers := map[string][]string{} + ctx.Request.Header.VisitAll(func(key, value []byte) { + headers[string(key)] = append(headers[string(key)], string(value)) + }) + if d, err := json.MarshalIndent(headers, "", " "); err != nil { + ctx.Error(fmt.Sprintf("%s", err), fasthttp.StatusBadRequest) + } else { + fmt.Fprintf(ctx, string(d)+"\n") + } + } + func main() { + s := fasthttp.Server{ + Handler: HandleFastHTTP, + DisableHeaderNamesNormalizing: true, + } + log.Printf("Starting on port 8000") + log.Fatal(s.ListenAndServe(":8000")) + } --- apiVersion: apps/v1 kind: Deployment @@ -493,21 +493,21 @@ spec: app: golang-app spec: containers: - - name: golang-app-container - command: - - sh - - "-c" - - "cp -a /app /app-live && cd /app-live && go run . " - image: golang:1.22.3-alpine - ports: - - containerPort: 8000 - volumeMounts: - - name: go-server - mountPath: /app + - name: golang-app-container + command: + - sh + - "-c" + - "cp -a /app /app-live && cd /app-live && go run . " + image: golang:1.22.3-alpine + ports: + - containerPort: 8000 + volumeMounts: + - name: go-server + mountPath: /app volumes: - - name: go-server - configMap: - name: go-server + - name: go-server + configMap: + name: go-server --- apiVersion: v1 kind: Service @@ -518,9 +518,9 @@ spec: selector: app: golang-app ports: - - protocol: TCP - port: 8000 - targetPort: 8000 + - protocol: TCP + port: 8000 + targetPort: 8000 --- apiVersion: v1 data: @@ -579,9 +579,9 @@ spec: selector: app: tls-backend-2 ports: - - protocol: TCP - port: 443 - targetPort: 8443 + - protocol: TCP + port: 443 + targetPort: 8443 --- apiVersion: apps/v1 kind: Deployment @@ -601,38 +601,38 @@ spec: app: tls-backend-2 spec: containers: - - name: tls-backend - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e - volumeMounts: - - name: secret-volume - mountPath: /etc/secret-volume - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SERVICE_NAME - value: tls-backend-2 - - name: TLS_SERVER_CERT - value: /etc/secret-volume/crt - - name: TLS_SERVER_PRIVKEY - value: /etc/secret-volume/key - resources: - requests: - cpu: 10m + - name: tls-backend + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e + volumeMounts: + - name: secret-volume + mountPath: /etc/secret-volume + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_NAME + value: tls-backend-2 + - name: TLS_SERVER_CERT + value: /etc/secret-volume/crt + - name: TLS_SERVER_PRIVKEY + value: /etc/secret-volume/key + resources: + requests: + cpu: 10m volumes: - - name: secret-volume - secret: - secretName: backend-tls-checks-certificate - items: - - key: tls.crt - path: crt - - key: tls.key - path: key + - name: secret-volume + secret: + secretName: backend-tls-checks-certificate + items: + - key: tls.crt + path: crt + - key: tls.key + path: key --- apiVersion: v1 data: @@ -657,12 +657,12 @@ spec: app: envoy-als type: LoadBalancer ports: - - name: grpc-als - protocol: TCP - appProtocol: grpc - port: 8080 - targetPort: 8080 - - name: http-monitoring - protocol: TCP - port: 19001 - targetPort: 19001 + - name: grpc-als + protocol: TCP + appProtocol: grpc + port: 8080 + targetPort: 8080 + - name: http-monitoring + protocol: TCP + port: 19001 + targetPort: 19001 diff --git a/test/e2e/testdata/client-mtls.yaml b/test/e2e/testdata/client-mtls.yaml index fc1a62f1ca4..a34a00f71d1 100644 --- a/test/e2e/testdata/client-mtls.yaml +++ b/test/e2e/testdata/client-mtls.yaml @@ -17,6 +17,16 @@ metadata: spec: gatewayClassName: "{GATEWAY_CLASS_NAME}" listeners: + - name: tls-settings + port: 443 + protocol: HTTPS + hostname: tls-settings.example.com + tls: + certificateRefs: + - group: "" + kind: Secret + name: client-tls-settings-certificate + mode: Terminate - name: mtls port: 443 protocol: HTTPS @@ -69,3 +79,71 @@ spec: - kind: "Secret" group: "" name: "client-mtls-certificate" +--- +# openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout ca.key -out ca.crt +# cat > openssl.conf < Date: Tue, 15 Oct 2024 12:11:18 -0700 Subject: [PATCH 19/39] build(deps): bump actions/checkout from 4.2.0 to 4.2.1 (#4442) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/d632683dd7b4114ad314bca15554477dd762a938...eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_and_test.yaml | 18 +++++++++--------- .github/workflows/codeql.yml | 2 +- .github/workflows/docs.yaml | 4 ++-- .../workflows/experimental_conformance.yaml | 2 +- .github/workflows/latest_release.yaml | 4 ++-- .github/workflows/license-scan.yml | 2 +- .github/workflows/release.yaml | 4 ++-- .github/workflows/scorecard.yml | 2 +- .github/workflows/trivy.yml | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index dbbdbcd04ae..6870c1738d2 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -20,7 +20,7 @@ jobs: lint: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps # Generate the installation manifests first, so it can check # for errors while running `make -k lint` @@ -31,14 +31,14 @@ jobs: gen-check: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - run: make -k gen-check license-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - run: make -k licensecheck @@ -48,7 +48,7 @@ jobs: contents: read # for actions/checkout id-token: write # for fetching OIDC token steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps # test @@ -67,7 +67,7 @@ jobs: runs-on: ubuntu-latest needs: [lint, gen-check, license-check, coverage-test] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Build EG Multiarch Binaries @@ -87,7 +87,7 @@ jobs: matrix: version: [ v1.28.13, v1.29.8, v1.30.4, v1.31.0 ] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Download EG Binaries @@ -116,7 +116,7 @@ jobs: matrix: version: [ v1.28.13, v1.29.8, v1.30.4, v1.31.0 ] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Download EG Binaries @@ -143,7 +143,7 @@ jobs: if: ${{ ! startsWith(github.event_name, 'push') }} needs: [build] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Setup Graphviz @@ -170,7 +170,7 @@ jobs: runs-on: ubuntu-latest needs: [conformance-test, e2e-test] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Download EG Binaries diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 95262e597e5..7e911a0e584 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Initialize CodeQL diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 57a8868ff7a..687c824ea41 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Check out code - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} @@ -48,7 +48,7 @@ jobs: contents: write steps: - name: Git checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: submodules: true ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/experimental_conformance.yaml b/.github/workflows/experimental_conformance.yaml index 281bdbca9ae..4ca84797797 100644 --- a/.github/workflows/experimental_conformance.yaml +++ b/.github/workflows/experimental_conformance.yaml @@ -21,7 +21,7 @@ jobs: matrix: version: [ v1.28.13, v1.29.8, v1.30.4, v1.31.0 ] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps # gateway api experimental conformance diff --git a/.github/workflows/latest_release.yaml b/.github/workflows/latest_release.yaml index 875e0a508e5..b280daacadc 100644 --- a/.github/workflows/latest_release.yaml +++ b/.github/workflows/latest_release.yaml @@ -22,7 +22,7 @@ jobs: benchmark-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Setup Graphviz @@ -57,7 +57,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Generate Release Manifests diff --git a/.github/workflows/license-scan.yml b/.github/workflows/license-scan.yml index ff3f8d31a02..2bbb36ce830 100644 --- a/.github/workflows/license-scan.yml +++ b/.github/workflows/license-scan.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout code - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Run scanner uses: google/osv-scanner-action/osv-scanner-action@19ec1116569a47416e11a45848722b1af31a857b # v1.9.0 with: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 48de6eb9489..a794eb2a1f1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,7 +15,7 @@ jobs: benchmark-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: ./tools/github-actions/setup-deps - name: Setup Graphviz @@ -50,7 +50,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Extract Release Tag and Commit SHA id: vars diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 88324734fb7..44331f3a595 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -21,7 +21,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: persist-credentials: false diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 21c50d56902..5c598890a8f 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout code - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Build an image from Dockerfile run: | From 96f241df280bb897d79a9988e177d99a6d658aae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:22:47 -0700 Subject: [PATCH 20/39] build(deps): bump aquasecurity/trivy-action from 0.24.0 to 0.27.0 (#4443) Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.24.0 to 0.27.0. - [Release notes](https://github.com/aquasecurity/trivy-action/releases) - [Commits](https://github.com/aquasecurity/trivy-action/compare/6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8...5681af892cd0f4997658e2bacc62bd0a894cf564) --- updated-dependencies: - dependency-name: aquasecurity/trivy-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/trivy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 5c598890a8f..9e4a1460f8e 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -25,7 +25,7 @@ jobs: IMAGE=envoy-proxy/gateway-dev TAG=${{ github.sha }} make image - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # v0.24.0 + uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # v0.27.0 with: image-ref: envoy-proxy/gateway-dev:${{ github.sha }} exit-code: '1' From 3d7552a9e68ea494c2ee8f40f00dd4b188ac1316 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:23:14 -0700 Subject: [PATCH 21/39] build(deps): bump github/codeql-action from 3.26.11 to 3.26.12 (#4444) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.11 to 3.26.12. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea...c36620d31ac7c881962c3d9dd939c40ec9434f2b) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecard.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7e911a0e584..0f4771a3f5e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -36,14 +36,14 @@ jobs: - uses: ./tools/github-actions/setup-deps - name: Initialize CodeQL - uses: github/codeql-action/init@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/autobuild@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 44331f3a595..5750a0ce3c7 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -40,6 +40,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11 + uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: sarif_file: results.sarif From 172a73a1ebee1415715b51042757d9eef687b701 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:23:51 -0700 Subject: [PATCH 22/39] build(deps): bump actions/upload-artifact from 4.4.0 to 4.4.3 (#4441) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.4.0 to 4.4.3. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/50769540e7f4bd5e21e526ee35c689e35e0d6874...b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_and_test.yaml | 2 +- .github/workflows/experimental_conformance.yaml | 2 +- .github/workflows/latest_release.yaml | 2 +- .github/workflows/release.yaml | 2 +- .github/workflows/scorecard.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index 6870c1738d2..80992fc9d6d 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -74,7 +74,7 @@ jobs: run: make build-multiarch PLATFORMS="linux_amd64 linux_arm64" - name: Upload EG Binaries - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: envoy-gateway path: bin/ diff --git a/.github/workflows/experimental_conformance.yaml b/.github/workflows/experimental_conformance.yaml index 4ca84797797..931831b2bf1 100644 --- a/.github/workflows/experimental_conformance.yaml +++ b/.github/workflows/experimental_conformance.yaml @@ -33,7 +33,7 @@ jobs: run: make experimental-conformance - name: Upload Conformance Report - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: conformance-report-k8s-${{ matrix.version }} path: ./test/conformance/conformance-report-k8s-${{ matrix.version }}.yaml diff --git a/.github/workflows/latest_release.yaml b/.github/workflows/latest_release.yaml index b280daacadc..a0ceb53e08d 100644 --- a/.github/workflows/latest_release.yaml +++ b/.github/workflows/latest_release.yaml @@ -46,7 +46,7 @@ jobs: run: cd test/benchmark && zip -r benchmark_report.zip benchmark_report - name: Upload Benchmark Report - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: benchmark_report path: test/benchmark/benchmark_report.zip diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a794eb2a1f1..a95f411890d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -39,7 +39,7 @@ jobs: run: cd test/benchmark && zip -r benchmark_report.zip benchmark_report - name: Upload Benchmark Report - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: benchmark_report path: test/benchmark/benchmark_report.zip diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 5750a0ce3c7..987f7c2b62d 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,7 +33,7 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: SARIF file path: results.sarif From 8fc4ecba40b53a21a7854bd7e750c2ab48ef1e1b Mon Sep 17 00:00:00 2001 From: Isaac <10012479+jukie@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:59:07 -0600 Subject: [PATCH 23/39] feat: allow running EnvoyProxy as DaemonSet (#4429) * Update status when running in daemonset mode * Fix helm permissions and fully implement daemonset Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> --- charts/gateway-helm/templates/_rbac.tpl | 1 + internal/gatewayapi/status/gateway.go | 45 +++++++---- internal/provider/kubernetes/controller.go | 28 ++++++- internal/provider/kubernetes/kubernetes.go | 2 +- internal/provider/kubernetes/predicates.go | 63 +++++++++------ .../provider/kubernetes/predicates_test.go | 80 +++++++++++++------ internal/provider/kubernetes/status.go | 6 +- internal/provider/kubernetes/test/utils.go | 31 ++++++- .../certjen-custom-scheduling.out.yaml | 1 + .../control-plane-with-pdb.out.yaml | 1 + .../helm/gateway-helm/default-config.out.yaml | 1 + .../deployment-custom-topology.out.yaml | 1 + .../deployment-images-config.out.yaml | 1 + .../deployment-priorityclass.out.yaml | 1 + .../envoy-gateway-config.out.yaml | 1 + .../global-images-config.out.yaml | 1 + .../gateway-helm/service-annotations.out.yaml | 1 + 17 files changed, 189 insertions(+), 76 deletions(-) diff --git a/charts/gateway-helm/templates/_rbac.tpl b/charts/gateway-helm/templates/_rbac.tpl index 27e90061b0c..52a5648818c 100644 --- a/charts/gateway-helm/templates/_rbac.tpl +++ b/charts/gateway-helm/templates/_rbac.tpl @@ -43,6 +43,7 @@ apiGroups: - apps resources: - deployments +- daemonsets verbs: - get - list diff --git a/internal/gatewayapi/status/gateway.go b/internal/gatewayapi/status/gateway.go index f891f8c40af..8bf822479d0 100644 --- a/internal/gatewayapi/status/gateway.go +++ b/internal/gatewayapi/status/gateway.go @@ -13,6 +13,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) @@ -30,8 +31,8 @@ func UpdateGatewayStatusAcceptedCondition(gw *gwapiv1.Gateway, accepted bool) *g // UpdateGatewayStatusProgrammedCondition updates the status addresses for the provided gateway // based on the status IP/Hostname of svc and updates the Programmed condition based on the -// service and deployment state. -func UpdateGatewayStatusProgrammedCondition(gw *gwapiv1.Gateway, svc *corev1.Service, deployment *appsv1.Deployment, nodeAddresses ...string) { +// service and deployment or daemonset state. +func UpdateGatewayStatusProgrammedCondition(gw *gwapiv1.Gateway, svc *corev1.Service, envoyObj client.Object, nodeAddresses ...string) { var addresses, hostnames []string // Update the status addresses field. if svc != nil { @@ -98,7 +99,7 @@ func UpdateGatewayStatusProgrammedCondition(gw *gwapiv1.Gateway, svc *corev1.Ser } // Update the programmed condition. - updateGatewayProgrammedCondition(gw, deployment) + updateGatewayProgrammedCondition(gw, envoyObj) } func SetGatewayListenerStatusCondition(gateway *gwapiv1.Gateway, listenerStatusIdx int, @@ -132,13 +133,13 @@ func computeGatewayAcceptedCondition(gw *gwapiv1.Gateway, accepted bool) metav1. const ( messageAddressNotAssigned = "No addresses have been assigned to the Gateway" messageFmtTooManyAddresses = "Too many addresses (%d) have been assigned to the Gateway, the maximum number of addresses is 16" - messageNoResources = "Deployment replicas unavailable" - messageFmtProgrammed = "Address assigned to the Gateway, %d/%d envoy Deployment replicas available" + messageNoResources = "Envoy replicas unavailable" + messageFmtProgrammed = "Address assigned to the Gateway, %d/%d envoy replicas available" ) // updateGatewayProgrammedCondition computes the Gateway Programmed status condition. -// Programmed condition surfaces true when the Envoy Deployment status is ready. -func updateGatewayProgrammedCondition(gw *gwapiv1.Gateway, deployment *appsv1.Deployment) { +// Programmed condition surfaces true when the Envoy Deployment or DaemonSet status is ready. +func updateGatewayProgrammedCondition(gw *gwapiv1.Gateway, envoyObj client.Object) { if len(gw.Status.Addresses) == 0 { gw.Status.Conditions = MergeConditions(gw.Status.Conditions, newCondition(string(gwapiv1.GatewayConditionProgrammed), metav1.ConditionFalse, string(gwapiv1.GatewayReasonAddressNotAssigned), @@ -157,17 +158,27 @@ func updateGatewayProgrammedCondition(gw *gwapiv1.Gateway, deployment *appsv1.De return } - // If there are no available replicas for the Envoy Deployment, don't - // mark the Gateway as ready yet. - - if deployment == nil || deployment.Status.AvailableReplicas == 0 { - gw.Status.Conditions = MergeConditions(gw.Status.Conditions, - newCondition(string(gwapiv1.GatewayConditionProgrammed), metav1.ConditionFalse, string(gwapiv1.GatewayReasonNoResources), - messageNoResources, time.Now(), gw.Generation)) - return + // Check for available Envoy replicas and if found mark the gateway as ready. + switch obj := envoyObj.(type) { + case *appsv1.Deployment: + if obj != nil && obj.Status.AvailableReplicas > 0 { + gw.Status.Conditions = MergeConditions(gw.Status.Conditions, + newCondition(string(gwapiv1.GatewayConditionProgrammed), metav1.ConditionTrue, string(gwapiv1.GatewayConditionProgrammed), + fmt.Sprintf(messageFmtProgrammed, obj.Status.AvailableReplicas, obj.Status.Replicas), time.Now(), gw.Generation)) + return + } + case *appsv1.DaemonSet: + if obj != nil && obj.Status.NumberAvailable > 0 { + gw.Status.Conditions = MergeConditions(gw.Status.Conditions, + newCondition(string(gwapiv1.GatewayConditionProgrammed), metav1.ConditionTrue, string(gwapiv1.GatewayConditionProgrammed), + fmt.Sprintf(messageFmtProgrammed, obj.Status.NumberAvailable, obj.Status.CurrentNumberScheduled), time.Now(), gw.Generation)) + return + } } + // If there are no available replicas for the Envoy Deployment or + // Envoy DaemonSet, don't mark the Gateway as ready yet. gw.Status.Conditions = MergeConditions(gw.Status.Conditions, - newCondition(string(gwapiv1.GatewayConditionProgrammed), metav1.ConditionTrue, string(gwapiv1.GatewayConditionProgrammed), - fmt.Sprintf(messageFmtProgrammed, deployment.Status.AvailableReplicas, deployment.Status.Replicas), time.Now(), gw.Generation)) + newCondition(string(gwapiv1.GatewayConditionProgrammed), metav1.ConditionFalse, string(gwapiv1.GatewayReasonNoResources), + messageNoResources, time.Now(), gw.Generation)) } diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index dac8f1780a8..915e6e5acd8 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -1386,13 +1386,13 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M } // Watch Deployment CRUDs and process affected Gateways. - dPredicates := []predicate.TypedPredicate[*appsv1.Deployment]{ + deploymentPredicates := []predicate.TypedPredicate[*appsv1.Deployment]{ predicate.NewTypedPredicateFuncs[*appsv1.Deployment](func(deploy *appsv1.Deployment) bool { - return r.validateDeploymentForReconcile(deploy) + return r.validateObjectForReconcile(deploy) }), } if r.namespaceLabel != nil { - dPredicates = append(dPredicates, predicate.NewTypedPredicateFuncs[*appsv1.Deployment](func(deploy *appsv1.Deployment) bool { + deploymentPredicates = append(deploymentPredicates, predicate.NewTypedPredicateFuncs[*appsv1.Deployment](func(deploy *appsv1.Deployment) bool { return r.hasMatchingNamespaceLabels(deploy) })) } @@ -1401,7 +1401,27 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, deploy *appsv1.Deployment) []reconcile.Request { return r.enqueueClass(ctx, deploy) }), - dPredicates...)); err != nil { + deploymentPredicates...)); err != nil { + return err + } + + // Watch DaemonSet CRUDs and process affected Gateways. + daemonsetPredicates := []predicate.TypedPredicate[*appsv1.DaemonSet]{ + predicate.NewTypedPredicateFuncs[*appsv1.DaemonSet](func(daemonset *appsv1.DaemonSet) bool { + return r.validateObjectForReconcile(daemonset) + }), + } + if r.namespaceLabel != nil { + daemonsetPredicates = append(daemonsetPredicates, predicate.NewTypedPredicateFuncs[*appsv1.DaemonSet](func(daemonset *appsv1.DaemonSet) bool { + return r.hasMatchingNamespaceLabels(daemonset) + })) + } + if err := c.Watch( + source.Kind(mgr.GetCache(), &appsv1.DaemonSet{}, + handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, daemonset *appsv1.DaemonSet) []reconcile.Request { + return r.enqueueClass(ctx, daemonset) + }), + daemonsetPredicates...)); err != nil { return err } diff --git a/internal/provider/kubernetes/kubernetes.go b/internal/provider/kubernetes/kubernetes.go index b909eced608..ffef819ee07 100644 --- a/internal/provider/kubernetes/kubernetes.go +++ b/internal/provider/kubernetes/kubernetes.go @@ -107,7 +107,7 @@ func New(cfg *rest.Config, svr *ec.Server, resources *message.ProviderResources) return nil, fmt.Errorf("unable to set up ready check: %w", err) } - // Emit elected & continue with deployment of infra resources + // Emit elected & continue with envoyObjects of infra resources go func() { <-mgr.Elected() close(svr.Elected) diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 9fb3fe86fd1..9c4d582b58b 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -13,6 +13,7 @@ import ( corev1 "k8s.io/api/core/v1" discoveryv1 "k8s.io/api/discovery/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" @@ -439,21 +440,16 @@ func (r *gatewayAPIReconciler) validateEndpointSliceForReconcile(obj client.Obje return r.isEnvoyExtensionPolicyReferencingBackend(&nsName) } -// validateDeploymentForReconcile tries finding the owning Gateway of the Deployment +// validateObjectForReconcile tries finding the owning Gateway of the Deployment or DaemonSet // if it exists, finds the Gateway's Service, and further updates the Gateway -// status Ready condition. No Deployments are pushed for reconciliation. -func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) bool { +// status Ready condition. No Deployments or DaemonSets are pushed for reconciliation. +func (r *gatewayAPIReconciler) validateObjectForReconcile(obj client.Object) bool { ctx := context.Background() - deployment, ok := obj.(*appsv1.Deployment) - if !ok { - r.log.Info("unexpected object type, bypassing reconciliation", "object", obj) - return false - } - labels := deployment.GetLabels() + labels := obj.GetLabels() - // Only deployments in the configured namespace should be reconciled. - if deployment.Namespace == r.namespace { - // Check if the deployment belongs to a Gateway, if so, update the Gateway status. + // Only objects in the configured namespace should be reconciled. + if obj.GetNamespace() == r.namespace { + // Check if the obj belongs to a Gateway, if so, update the Gateway status. gtw := r.findOwningGateway(ctx, labels) if gtw != nil { r.updateStatusForGateway(ctx, gtw) @@ -471,27 +467,42 @@ func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) return false } - // There is no need to reconcile the Deployment any further. + // There is no need to reconcile the object any further. return false } -// 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) { - var deployments appsv1.DeploymentList - labelSelector := labels.SelectorFromSet(labels.Set(gatewayapi.OwnerLabels(gateway, r.mergeGateways.Has(string(gateway.Spec.GatewayClassName))))) - if err := r.client.List(ctx, &deployments, &client.ListOptions{ - LabelSelector: labelSelector, - Namespace: r.namespace, - }); err != nil { - if kerrors.IsNotFound(err) { +// envoyObjectForGateway returns the Envoy Deployment or DaemonSet, returning nil if neither exists. +func (r *gatewayAPIReconciler) envoyObjectForGateway(ctx context.Context, gateway *gwapiv1.Gateway) (client.Object, error) { + // Helper func to list and return the first object from results + listResource := func(list client.ObjectList) (client.Object, error) { + if err := r.client.List(ctx, list, &client.ListOptions{ + LabelSelector: labels.SelectorFromSet(gatewayapi.OwnerLabels(gateway, r.mergeGateways.Has(string(gateway.Spec.GatewayClassName)))), + Namespace: r.namespace, + }); err != nil { + if !kerrors.IsNotFound(err) { + return nil, err + } + } + items, err := meta.ExtractList(list) + if err != nil || len(items) == 0 { return nil, nil } - return nil, err + return items[0].(client.Object), nil } - if len(deployments.Items) == 0 { - return nil, nil + + // Check for Deployment + deployments := &appsv1.DeploymentList{} + if obj, err := listResource(deployments); obj != nil || err != nil { + return obj, err + } + + // Check for DaemonSet + daemonsets := &appsv1.DaemonSetList{} + if obj, err := listResource(daemonsets); obj != nil || err != nil { + return obj, err } - return &deployments.Items[0], nil + + return nil, nil } // envoyServiceForGateway returns the Envoy service, returning nil if the service doesn't exist. diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go index 61a09ffb8ae..ef8182ffdb9 100644 --- a/internal/provider/kubernetes/predicates_test.go +++ b/internal/provider/kubernetes/predicates_test.go @@ -525,7 +525,7 @@ func TestValidateServiceForReconcile(t *testing.T) { expect bool }{ { - name: "gateway service but deployment does not exist", + name: "gateway service but deployment or daemonset does not exist", configs: []client.Object{ test.GetGatewayClass("test-gc", egv1a1.GatewayControllerName, nil), sampleGateway, @@ -547,7 +547,22 @@ func TestValidateServiceForReconcile(t *testing.T) { gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", gatewayapi.OwningGatewayNamespaceLabel: "default", }, nil), - // Note that in case when a deployment exists, the Service is just processed for Gateway status + // Note that in case when a envoyObjects exists, the Service is just processed for Gateway status + // updates and not reconciled further. + expect: false, + }, + { + name: "gateway service daemonset also exist", + configs: []client.Object{ + test.GetGatewayClass("test-gc", egv1a1.GatewayControllerName, nil), + sampleGateway, + test.GetGatewayDaemonSet(types.NamespacedName{Name: proxy.ExpectedResourceHashedName("default/scheduled-status-test")}, nil), + }, + service: test.GetService(types.NamespacedName{Name: "service"}, map[string]string{ + gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", + gatewayapi.OwningGatewayNamespaceLabel: "default", + }, nil), + // Note that in case when a envoyObjects exists, the Service is just processed for Gateway status // updates and not reconciled further. expect: false, }, @@ -859,34 +874,39 @@ func TestValidateServiceForReconcile(t *testing.T) { } } -// TestValidateDeploymentForReconcile tests the validateDeploymentForReconcile +// TestValidateObjectForReconcile tests the validateObjectForReconcile // predicate function. -func TestValidateDeploymentForReconcile(t *testing.T) { +func TestValidateObjectForReconcile(t *testing.T) { sampleGateway := test.GetGateway(types.NamespacedName{Namespace: "default", Name: "scheduled-status-test"}, "test-gc", 8080) mergeGatewaysConfig := test.GetEnvoyProxy(types.NamespacedName{Namespace: "default", Name: "merge-gateways-config"}, true) testCases := []struct { - name string - configs []client.Object - deployment client.Object - expect bool + name string + configs []client.Object + envoyObjects []client.Object + expect bool }{ { - // No config should lead to a reconciliation of a Deployment object. The main - // purpose of the Deployment watcher is just for update Gateway object statuses. - name: "gateway deployment deployment also exist", + // No config should lead to a reconciliation of a Deployment or DaemonSet object. The main + // purpose of the watcher is just for updating Gateway object statuses. + name: "gateway deployment or daemonset also exist", configs: []client.Object{ test.GetGatewayClass("test-gc", egv1a1.GatewayControllerName, nil), sampleGateway, - test.GetService(types.NamespacedName{Name: "deployment"}, map[string]string{ + test.GetService(types.NamespacedName{Name: "envoyObjects"}, map[string]string{ gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", gatewayapi.OwningGatewayNamespaceLabel: "default", }, nil), }, - deployment: test.GetGatewayDeployment(types.NamespacedName{Name: "deployment"}, map[string]string{ - gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", - gatewayapi.OwningGatewayNamespaceLabel: "default", - }), + envoyObjects: []client.Object{ + test.GetGatewayDeployment(types.NamespacedName{Name: "deployment"}, map[string]string{ + gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", + gatewayapi.OwningGatewayNamespaceLabel: "default", + }), test.GetGatewayDaemonSet(types.NamespacedName{Name: "daemonset"}, map[string]string{ + gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", + gatewayapi.OwningGatewayNamespaceLabel: "default", + }), + }, expect: false, }, { @@ -900,9 +920,14 @@ func TestValidateDeploymentForReconcile(t *testing.T) { }), mergeGatewaysConfig, }, - deployment: test.GetGatewayDeployment(types.NamespacedName{Name: "deployment"}, map[string]string{ - gatewayapi.OwningGatewayClassLabel: "test-mg", - }), + envoyObjects: []client.Object{ + test.GetGatewayDeployment(types.NamespacedName{Name: "deployment"}, map[string]string{ + gatewayapi.OwningGatewayClassLabel: "test-mg", + }), + test.GetGatewayDaemonSet(types.NamespacedName{Name: "daemonset"}, map[string]string{ + gatewayapi.OwningGatewayClassLabel: "test-mg", + }), + }, expect: false, }, { @@ -919,9 +944,14 @@ func TestValidateDeploymentForReconcile(t *testing.T) { test.GetGateway(types.NamespacedName{Name: "merged-gateway-2", Namespace: "default"}, "test-mg", 8082), test.GetGateway(types.NamespacedName{Name: "merged-gateway-3", Namespace: "default"}, "test-mg", 8083), }, - deployment: test.GetGatewayDeployment(types.NamespacedName{Name: "deployment"}, map[string]string{ - gatewayapi.OwningGatewayClassLabel: "test-mg", - }), + envoyObjects: []client.Object{ + test.GetGatewayDeployment(types.NamespacedName{Name: "deployment"}, map[string]string{ + gatewayapi.OwningGatewayClassLabel: "test-mg", + }), + test.GetGatewayDaemonSet(types.NamespacedName{Name: "daemonset"}, map[string]string{ + gatewayapi.OwningGatewayClassLabel: "test-mg", + }), + }, expect: false, }, } @@ -938,8 +968,10 @@ func TestValidateDeploymentForReconcile(t *testing.T) { for _, tc := range testCases { r.client = fakeclient.NewClientBuilder().WithScheme(envoygateway.GetScheme()).WithObjects(tc.configs...).Build() t.Run(tc.name, func(t *testing.T) { - res := r.validateDeploymentForReconcile(tc.deployment) - require.Equal(t, tc.expect, res) + for _, obj := range tc.envoyObjects { + res := r.validateObjectForReconcile(obj) + require.Equal(t, tc.expect, res) + } }) } } diff --git a/internal/provider/kubernetes/status.go b/internal/provider/kubernetes/status.go index c94ad2bc556..c3d5553b0bf 100644 --- a/internal/provider/kubernetes/status.go +++ b/internal/provider/kubernetes/status.go @@ -475,8 +475,8 @@ func (r *gatewayAPIReconciler) updateStatusForGateway(ctx context.Context, gtw * return } - // Get deployment - deploy, err := r.envoyDeploymentForGateway(ctx, gtw) + // Get envoyObjects + envoyObj, err := r.envoyObjectForGateway(ctx, gtw) if err != nil { r.log.Info("failed to get Deployment for gateway", "namespace", gtw.Namespace, "name", gtw.Name) @@ -491,7 +491,7 @@ func (r *gatewayAPIReconciler) updateStatusForGateway(ctx context.Context, gtw * // update accepted condition status.UpdateGatewayStatusAcceptedCondition(gtw, true) // update address field and programmed condition - status.UpdateGatewayStatusProgrammedCondition(gtw, svc, deploy, r.store.listNodeAddresses()...) + status.UpdateGatewayStatusProgrammedCondition(gtw, svc, envoyObj, r.store.listNodeAddresses()...) key := utils.NamespacedName(gtw) diff --git a/internal/provider/kubernetes/test/utils.go b/internal/provider/kubernetes/test/utils.go index 6fe50fa75bd..77bc50c5e6f 100644 --- a/internal/provider/kubernetes/test/utils.go +++ b/internal/provider/kubernetes/test/utils.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" @@ -271,7 +272,7 @@ func GetUDPRoute(nsName types.NamespacedName, parent string, serviceName types.N } // GetGatewayDeployment returns a sample Deployment for a Gateway object. -func GetGatewayDeployment(nsName types.NamespacedName, labels map[string]string) *appsv1.Deployment { +func GetGatewayDeployment(nsName types.NamespacedName, labels map[string]string) client.Object { return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: nsName.Namespace, @@ -298,6 +299,34 @@ func GetGatewayDeployment(nsName types.NamespacedName, labels map[string]string) } } +// GetGatewayDaemonSet returns a sample DaemonSet for a Gateway object. +func GetGatewayDaemonSet(nsName types.NamespacedName, labels map[string]string) client.Object { + return &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: nsName.Namespace, + Name: nsName.Name, + Labels: labels, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: labels}, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "dummy", + Image: "dummy", + Ports: []corev1.ContainerPort{{ + ContainerPort: 8080, + }}, + }}, + }, + }, + }, + } +} + // GetService returns a sample Service with labels and ports. func GetService(nsName types.NamespacedName, labels map[string]string, ports map[string]int32) *corev1.Service { service := &corev1.Service{ diff --git a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml index 096e1eb5561..8a1513469de 100644 --- a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml +++ b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml @@ -105,6 +105,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml index 4c9a3d6cfdf..a71e46fe7bd 100644 --- a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml +++ b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml @@ -120,6 +120,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/default-config.out.yaml b/test/helm/gateway-helm/default-config.out.yaml index c830348f012..140d271c6e7 100644 --- a/test/helm/gateway-helm/default-config.out.yaml +++ b/test/helm/gateway-helm/default-config.out.yaml @@ -105,6 +105,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/deployment-custom-topology.out.yaml b/test/helm/gateway-helm/deployment-custom-topology.out.yaml index fd468b505f0..586b64b5584 100644 --- a/test/helm/gateway-helm/deployment-custom-topology.out.yaml +++ b/test/helm/gateway-helm/deployment-custom-topology.out.yaml @@ -105,6 +105,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/deployment-images-config.out.yaml b/test/helm/gateway-helm/deployment-images-config.out.yaml index aa5a36ff23d..10f849e1d77 100644 --- a/test/helm/gateway-helm/deployment-images-config.out.yaml +++ b/test/helm/gateway-helm/deployment-images-config.out.yaml @@ -105,6 +105,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/deployment-priorityclass.out.yaml b/test/helm/gateway-helm/deployment-priorityclass.out.yaml index d3648d443d9..4f735c42095 100644 --- a/test/helm/gateway-helm/deployment-priorityclass.out.yaml +++ b/test/helm/gateway-helm/deployment-priorityclass.out.yaml @@ -105,6 +105,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/envoy-gateway-config.out.yaml b/test/helm/gateway-helm/envoy-gateway-config.out.yaml index aa91dacecc8..04159958265 100644 --- a/test/helm/gateway-helm/envoy-gateway-config.out.yaml +++ b/test/helm/gateway-helm/envoy-gateway-config.out.yaml @@ -107,6 +107,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/global-images-config.out.yaml b/test/helm/gateway-helm/global-images-config.out.yaml index e18eecd7bc7..f280fc9f218 100644 --- a/test/helm/gateway-helm/global-images-config.out.yaml +++ b/test/helm/gateway-helm/global-images-config.out.yaml @@ -109,6 +109,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list diff --git a/test/helm/gateway-helm/service-annotations.out.yaml b/test/helm/gateway-helm/service-annotations.out.yaml index 97f39cd0bea..ec50a16e30d 100644 --- a/test/helm/gateway-helm/service-annotations.out.yaml +++ b/test/helm/gateway-helm/service-annotations.out.yaml @@ -105,6 +105,7 @@ rules: - apps resources: - deployments + - daemonsets verbs: - get - list From 5880d6bc0ae65c923142605e87516bb4e46bc6a8 Mon Sep 17 00:00:00 2001 From: Kensei Nakada Date: Wed, 16 Oct 2024 10:46:01 +1100 Subject: [PATCH 24/39] feat: implement RequestTimeout in BackendTrafficPolicy (#4329) * feat: implement RequestTimeout in BackendTrafficPolicy Signed-off-by: Kensei Nakada * fix: the timeout on HTTPRoute overwrites the timeout on BTP Signed-off-by: Kensei Nakada * fix: regenerate from the latest api spec Signed-off-by: Kensei Nakada --------- Signed-off-by: Kensei Nakada --- api/v1alpha1/timeout_types.go | 5 ++++ api/v1alpha1/zz_generated.deepcopy.go | 5 ++++ ....envoyproxy.io_backendtrafficpolicies.yaml | 5 ++++ ....envoyproxy.io_envoyextensionpolicies.yaml | 5 ++++ .../gateway.envoyproxy.io_envoyproxies.yaml | 26 ++++++++++++++++++ ...ateway.envoyproxy.io_securitypolicies.yaml | 15 +++++++++++ internal/gatewayapi/clustersettings.go | 27 ++++++++++++------- .../backendtrafficpolicy-with-timeout.in.yaml | 4 +++ ...backendtrafficpolicy-with-timeout.out.yaml | 6 +++++ site/content/en/latest/api/extension_types.md | 1 + site/content/zh/latest/api/extension_types.md | 1 + 11 files changed, 91 insertions(+), 9 deletions(-) diff --git a/api/v1alpha1/timeout_types.go b/api/v1alpha1/timeout_types.go index 36c0c320ed2..008582578d1 100644 --- a/api/v1alpha1/timeout_types.go +++ b/api/v1alpha1/timeout_types.go @@ -40,6 +40,11 @@ type HTTPTimeout struct { // // +optional MaxConnectionDuration *gwapiv1.Duration `json:"maxConnectionDuration,omitempty"` + + // RequestTimeout is the time until which entire response is received from the upstream. + // + // +optional + RequestTimeout *gwapiv1.Duration `json:"requestTimeout,omitempty" yaml:"requestTimeout,omitempty"` } type ClientTimeout struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 2ce5a5762ee..a5e8dc183ff 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -2845,6 +2845,11 @@ func (in *HTTPTimeout) DeepCopyInto(out *HTTPTimeout) { *out = new(apisv1.Duration) **out = **in } + if in.RequestTimeout != nil { + in, out := &in.RequestTimeout, &out.RequestTimeout + *out = new(apisv1.Duration) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPTimeout. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 7b13e2a123f..c0dce593804 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -1316,6 +1316,11 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is the time until which entire + response is received from the upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for TCP. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index 867b8933c0c..6baa2842c0c 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -878,6 +878,11 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is the time until which + entire response is received from the upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for TCP. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 487f436ab81..5b0130f2736 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -11220,6 +11220,13 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is + the time until which entire + response is received from the + upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for @@ -12190,6 +12197,13 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is + the time until which entire + response is received from the + upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for @@ -13220,6 +13234,12 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is the time + until which entire response is received + from the upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for TCP. @@ -14195,6 +14215,12 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is the time until + which entire response is received from the + upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for TCP. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 8c4debcef0a..ad2c81818c2 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -1182,6 +1182,11 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is the time until + which entire response is received from the upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for TCP. @@ -2060,6 +2065,11 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is the time until + which entire response is received from the upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for TCP. @@ -3214,6 +3224,11 @@ spec: Default: unlimited. pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ type: string + requestTimeout: + description: RequestTimeout is the time until + which entire response is received from the upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string type: object tcp: description: Timeout settings for TCP. diff --git a/internal/gatewayapi/clustersettings.go b/internal/gatewayapi/clustersettings.go index cf8221d277d..742b026249e 100644 --- a/internal/gatewayapi/clustersettings.go +++ b/internal/gatewayapi/clustersettings.go @@ -81,11 +81,11 @@ func translateTrafficFeatures(policy *egv1a1.ClusterSettings) (*ir.TrafficFeatur return ret, nil } -func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, traffic *ir.TrafficFeatures) (*ir.Timeout, error) { +func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, routeTrafficFeatures *ir.TrafficFeatures) (*ir.Timeout, error) { if policy.Timeout == nil { - if traffic != nil { + if routeTrafficFeatures != nil { // Don't lose any existing timeout definitions. - return mergeTimeoutSettings(nil, traffic.Timeout), nil + return mergeTimeoutSettings(nil, routeTrafficFeatures.Timeout), nil } return nil, nil } @@ -109,6 +109,7 @@ func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, traffic *ir.Traf if pto.HTTP != nil { var cit *metav1.Duration var mcd *metav1.Duration + var rt *metav1.Duration if pto.HTTP.ConnectionIdleTimeout != nil { d, err := time.ParseDuration(string(*pto.HTTP.ConnectionIdleTimeout)) @@ -128,19 +129,27 @@ func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, traffic *ir.Traf } } + if pto.HTTP.RequestTimeout != nil { + d, err := time.ParseDuration(string(*pto.HTTP.RequestTimeout)) + if err != nil { + errs = errors.Join(errs, fmt.Errorf("invalid RequestTimeout value %s", *pto.HTTP.RequestTimeout)) + } else { + rt = ptr.To(metav1.Duration{Duration: d}) + } + } + to.HTTP = &ir.HTTPTimeout{ ConnectionIdleTimeout: cit, MaxConnectionDuration: mcd, + RequestTimeout: rt, } } - // http request timeout is translated during the gateway-api route resource translation - // merge route timeout setting with backendtrafficpolicy timeout settings. - // Merging is done after the clustersettings definitions are translated so that - // clustersettings will override previous settings. - if traffic != nil { - to = mergeTimeoutSettings(to, traffic.Timeout) + // The timeout from route's TrafficFeatures takes precedence over the timeout in BTP + if routeTrafficFeatures != nil { + to = mergeTimeoutSettings(routeTrafficFeatures.Timeout, to) } + return to, errs } diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml index ef8843f70c4..30a9a3133ab 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml @@ -62,6 +62,8 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 + timeouts: + request: 1s backendTrafficPolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy @@ -79,6 +81,7 @@ backendTrafficPolicies: http: connectionIdleTimeout: 16s maxConnectionDuration: 17s + requestTimeout: 18s - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy metadata: @@ -95,3 +98,4 @@ backendTrafficPolicies: http: connectionIdleTimeout: 21s maxConnectionDuration: 22s + requestTimeout: 23s diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml index 5213fc9d6a2..0fad514c5e8 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml @@ -14,6 +14,7 @@ backendTrafficPolicies: http: connectionIdleTimeout: 21s maxConnectionDuration: 22s + requestTimeout: 23s tcp: connectTimeout: 20s status: @@ -46,6 +47,7 @@ backendTrafficPolicies: http: connectionIdleTimeout: 16s maxConnectionDuration: 17s + requestTimeout: 18s tcp: connectTimeout: 15s status: @@ -198,6 +200,8 @@ httpRoutes: matches: - path: value: / + timeouts: + request: 1s status: parents: - conditions: @@ -289,6 +293,7 @@ xdsIR: http: connectionIdleTimeout: 16s maxConnectionDuration: 17s + requestTimeout: 18s tcp: connectTimeout: 15s envoy-gateway/gateway-2: @@ -336,5 +341,6 @@ xdsIR: http: connectionIdleTimeout: 21s maxConnectionDuration: 22s + requestTimeout: 1s tcp: connectTimeout: 20s diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 956b3dbd228..60e92c2e019 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2071,6 +2071,7 @@ _Appears in:_ | --- | --- | --- | --- | | `connectionIdleTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The idle timeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
Default: 1 hour. | | `maxConnectionDuration` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The maximum duration of an HTTP connection.
Default: unlimited. | +| `requestTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | RequestTimeout is the time until which entire response is received from the upstream. | #### HTTPURLRewriteFilter diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 956b3dbd228..60e92c2e019 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -2071,6 +2071,7 @@ _Appears in:_ | --- | --- | --- | --- | | `connectionIdleTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The idle timeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
Default: 1 hour. | | `maxConnectionDuration` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The maximum duration of an HTTP connection.
Default: unlimited. | +| `requestTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | RequestTimeout is the time until which entire response is received from the upstream. | #### HTTPURLRewriteFilter From 958df4899d826c03ecd3aafaea379289bba85f3a Mon Sep 17 00:00:00 2001 From: zirain Date: Wed, 16 Oct 2024 14:03:37 +0800 Subject: [PATCH 25/39] infra: use labels when deleting infra (#4430) --- api/v1alpha1/shared_types.go | 2 +- internal/infrastructure/kubernetes/infra.go | 2 + .../kubernetes/infra_resource.go | 43 ++++++++++++++++--- .../kubernetes/proxy/resource_provider.go | 5 +++ .../kubernetes/ratelimit/resource_provider.go | 5 +++ .../kubernetes/ratelimit_infra.go | 4 -- site/content/en/latest/api/extension_types.md | 2 +- site/content/zh/latest/api/extension_types.md | 2 +- 8 files changed, 51 insertions(+), 14 deletions(-) diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index 3f165cc6c2d..8e98b904e35 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -98,7 +98,7 @@ type KubernetesDeploymentSpec struct { // TODO: Expose config as use cases are better understood, e.g. labels. } -// KubernetesDaemonsetSpec defines the desired state of the Kubernetes daemonset resource. +// KubernetesDaemonSetSpec defines the desired state of the Kubernetes daemonset resource. type KubernetesDaemonSetSpec struct { // Patch defines how to perform the patch operation to daemonset // diff --git a/internal/infrastructure/kubernetes/infra.go b/internal/infrastructure/kubernetes/infra.go index fed1f17cbe7..3d9c3e7b14f 100644 --- a/internal/infrastructure/kubernetes/infra.go +++ b/internal/infrastructure/kubernetes/infra.go @@ -13,6 +13,7 @@ import ( autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" + "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/controller-runtime/pkg/client" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" @@ -29,6 +30,7 @@ var _ ResourceRender = &ratelimit.ResourceRender{} // based on Infra IR resources. type ResourceRender interface { Name() string + LabelSelector() labels.Selector ServiceAccount() (*corev1.ServiceAccount, error) Service() (*corev1.Service, error) ConfigMap() (*corev1.ConfigMap, error) diff --git a/internal/infrastructure/kubernetes/infra_resource.go b/internal/infrastructure/kubernetes/infra_resource.go index 9966f5ebdd4..04d0a2e0c1f 100644 --- a/internal/infrastructure/kubernetes/infra_resource.go +++ b/internal/infrastructure/kubernetes/infra_resource.go @@ -19,6 +19,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/envoyproxy/gateway/internal/metrics" ) @@ -395,7 +396,11 @@ func (i *Infra) deleteServiceAccount(ctx context.Context, r ResourceRender) (err } }() - return i.Client.Delete(ctx, sa) + return i.Client.DeleteAllOf(ctx, sa, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + LabelSelector: r.LabelSelector(), + }, + }) } // deleteDeployment deletes the Envoy Deployment in the kube api server, if it exists. @@ -430,7 +435,11 @@ func (i *Infra) deleteDeployment(ctx context.Context, r ResourceRender) (err err } }() - return i.Client.Delete(ctx, deployment) + return i.Client.DeleteAllOf(ctx, deployment, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + LabelSelector: r.LabelSelector(), + }, + }) } // deleteDaemonSet deletes the Envoy DaemonSet in the kube api server, if it exists. @@ -465,7 +474,11 @@ func (i *Infra) deleteDaemonSet(ctx context.Context, r ResourceRender) (err erro } }() - return i.Client.Delete(ctx, daemonSet) + return i.Client.DeleteAllOf(ctx, daemonSet, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + LabelSelector: r.LabelSelector(), + }, + }) } // deleteConfigMap deletes the ConfigMap in the kube api server, if it exists. @@ -495,7 +508,11 @@ func (i *Infra) deleteConfigMap(ctx context.Context, r ResourceRender) (err erro } }() - return i.Client.Delete(ctx, cm) + return i.Client.DeleteAllOf(ctx, cm, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + LabelSelector: r.LabelSelector(), + }, + }) } // deleteService deletes the Service in the kube api server, if it exists. @@ -525,7 +542,11 @@ func (i *Infra) deleteService(ctx context.Context, r ResourceRender) (err error) } }() - return i.Client.Delete(ctx, svc) + return i.Client.DeleteAllOf(ctx, svc, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + LabelSelector: r.LabelSelector(), + }, + }) } // deleteHpa deletes the Horizontal Pod Autoscaler associated to its renderer, if it exists. @@ -560,7 +581,11 @@ func (i *Infra) deleteHPA(ctx context.Context, r ResourceRender) (err error) { } }() - return i.Client.Delete(ctx, hpa) + return i.Client.DeleteAllOf(ctx, hpa, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + LabelSelector: r.LabelSelector(), + }, + }) } // deletePDB deletes the PodDistribution budget associated to its renderer, if it exists. @@ -595,5 +620,9 @@ func (i *Infra) deletePDB(ctx context.Context, r ResourceRender) (err error) { } }() - return i.Client.Delete(ctx, pdb) + return i.Client.DeleteAllOf(ctx, pdb, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + LabelSelector: r.LabelSelector(), + }, + }) } diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index 233afddce73..5411c29e1c6 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -15,6 +15,7 @@ import ( corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" @@ -46,6 +47,10 @@ func (r *ResourceRender) Name() string { return ExpectedResourceHashedName(r.infra.Name) } +func (r *ResourceRender) LabelSelector() labels.Selector { + return labels.SelectorFromSet(r.stableSelector().MatchLabels) +} + // ServiceAccount returns the expected proxy serviceAccount. func (r *ResourceRender) ServiceAccount() (*corev1.ServiceAccount, error) { // Set the labels based on the owning gateway name. diff --git a/internal/infrastructure/kubernetes/ratelimit/resource_provider.go b/internal/infrastructure/kubernetes/ratelimit/resource_provider.go index 50c5c8bf7f2..3336d41eec2 100644 --- a/internal/infrastructure/kubernetes/ratelimit/resource_provider.go +++ b/internal/infrastructure/kubernetes/ratelimit/resource_provider.go @@ -15,6 +15,7 @@ import ( corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" @@ -60,6 +61,10 @@ func (r *ResourceRender) Name() string { return InfraName } +func (r *ResourceRender) LabelSelector() labels.Selector { + return labels.SelectorFromSet(rateLimitLabels()) +} + func enablePrometheus(rl *egv1a1.RateLimit) bool { if rl != nil && rl.Telemetry != nil && diff --git a/internal/infrastructure/kubernetes/ratelimit_infra.go b/internal/infrastructure/kubernetes/ratelimit_infra.go index 514f86a1d9d..d4f5707538c 100644 --- a/internal/infrastructure/kubernetes/ratelimit_infra.go +++ b/internal/infrastructure/kubernetes/ratelimit_infra.go @@ -52,10 +52,6 @@ func (i *Infra) CreateOrUpdateRateLimitInfra(ctx context.Context) error { // DeleteRateLimitInfra removes the managed kube infra, if it doesn't exist. func (i *Infra) DeleteRateLimitInfra(ctx context.Context) error { - if err := ratelimit.Validate(ctx, i.Client.Client, i.EnvoyGateway, i.Namespace); err != nil { - return err - } - // Delete ratelimit infra do not require the uid of owner reference. r := ratelimit.NewResourceRender(i.Namespace, i.EnvoyGateway, nil) return i.delete(ctx, r) diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 60e92c2e019..ddc32a2021e 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2431,7 +2431,7 @@ _Appears in:_ -KubernetesDaemonsetSpec defines the desired state of the Kubernetes daemonset resource. +KubernetesDaemonSetSpec defines the desired state of the Kubernetes daemonset resource. _Appears in:_ - [EnvoyProxyKubernetesProvider](#envoyproxykubernetesprovider) diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 60e92c2e019..ddc32a2021e 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -2431,7 +2431,7 @@ _Appears in:_ -KubernetesDaemonsetSpec defines the desired state of the Kubernetes daemonset resource. +KubernetesDaemonSetSpec defines the desired state of the Kubernetes daemonset resource. _Appears in:_ - [EnvoyProxyKubernetesProvider](#envoyproxykubernetesprovider) From 70c7c34d34a3746f3fc6ab224361f6515480bf4a Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 17 Oct 2024 01:50:21 +0800 Subject: [PATCH 26/39] chore: set klog (#4455) * chore: set klog Signed-off-by: zirain * lint Signed-off-by: zirain --------- Signed-off-by: zirain --- go.mod | 2 +- internal/provider/kubernetes/kubernetes.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1a235360cd7..482af942a9a 100644 --- a/go.mod +++ b/go.mod @@ -286,7 +286,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/component-base v0.31.1 // indirect - k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.17.2 // indirect diff --git a/internal/provider/kubernetes/kubernetes.go b/internal/provider/kubernetes/kubernetes.go index ffef819ee07..cca90a24a17 100644 --- a/internal/provider/kubernetes/kubernetes.go +++ b/internal/provider/kubernetes/kubernetes.go @@ -11,6 +11,7 @@ import ( "time" "k8s.io/client-go/rest" + "k8s.io/klog/v2" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" @@ -47,6 +48,7 @@ func New(cfg *rest.Config, svr *ec.Server, resources *message.ProviderResources) } log.SetLogger(mgrOpts.Logger) + klog.SetLogger(mgrOpts.Logger) if !ptr.Deref(svr.EnvoyGateway.Provider.Kubernetes.LeaderElection.Disable, false) { mgrOpts.LeaderElection = true From aab669dd99f0337afaaa7c22f7826d9ebd37cfeb Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 17 Oct 2024 10:46:42 +0800 Subject: [PATCH 27/39] infra: fix DeleteAllOf rbac (#4459) * infra: fix DeleteAllOf rbac Signed-off-by: zirain * fix more Signed-off-by: zirain --------- Signed-off-by: zirain --- charts/gateway-helm/templates/infra-manager-rbac.yaml | 4 ++++ internal/infrastructure/kubernetes/infra_resource.go | 7 +++++++ test/helm/gateway-helm/certjen-custom-scheduling.out.yaml | 4 ++++ test/helm/gateway-helm/control-plane-with-pdb.out.yaml | 4 ++++ test/helm/gateway-helm/default-config.out.yaml | 4 ++++ test/helm/gateway-helm/deployment-custom-topology.out.yaml | 4 ++++ test/helm/gateway-helm/deployment-images-config.out.yaml | 4 ++++ test/helm/gateway-helm/deployment-priorityclass.out.yaml | 4 ++++ test/helm/gateway-helm/envoy-gateway-config.out.yaml | 4 ++++ test/helm/gateway-helm/global-images-config.out.yaml | 4 ++++ test/helm/gateway-helm/service-annotations.out.yaml | 4 ++++ 11 files changed, 47 insertions(+) diff --git a/charts/gateway-helm/templates/infra-manager-rbac.yaml b/charts/gateway-helm/templates/infra-manager-rbac.yaml index 02382bc271c..74c0ec6282e 100644 --- a/charts/gateway-helm/templates/infra-manager-rbac.yaml +++ b/charts/gateway-helm/templates/infra-manager-rbac.yaml @@ -11,10 +11,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -25,6 +27,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -36,6 +39,7 @@ rules: - create - get - delete + - deletecollection - patch --- apiVersion: rbac.authorization.k8s.io/v1 diff --git a/internal/infrastructure/kubernetes/infra_resource.go b/internal/infrastructure/kubernetes/infra_resource.go index 04d0a2e0c1f..16cd72b9545 100644 --- a/internal/infrastructure/kubernetes/infra_resource.go +++ b/internal/infrastructure/kubernetes/infra_resource.go @@ -398,6 +398,7 @@ func (i *Infra) deleteServiceAccount(ctx context.Context, r ResourceRender) (err return i.Client.DeleteAllOf(ctx, sa, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ + Namespace: ns, LabelSelector: r.LabelSelector(), }, }) @@ -437,6 +438,7 @@ func (i *Infra) deleteDeployment(ctx context.Context, r ResourceRender) (err err return i.Client.DeleteAllOf(ctx, deployment, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ + Namespace: ns, LabelSelector: r.LabelSelector(), }, }) @@ -476,6 +478,7 @@ func (i *Infra) deleteDaemonSet(ctx context.Context, r ResourceRender) (err erro return i.Client.DeleteAllOf(ctx, daemonSet, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ + Namespace: ns, LabelSelector: r.LabelSelector(), }, }) @@ -510,6 +513,7 @@ func (i *Infra) deleteConfigMap(ctx context.Context, r ResourceRender) (err erro return i.Client.DeleteAllOf(ctx, cm, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ + Namespace: ns, LabelSelector: r.LabelSelector(), }, }) @@ -544,6 +548,7 @@ func (i *Infra) deleteService(ctx context.Context, r ResourceRender) (err error) return i.Client.DeleteAllOf(ctx, svc, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ + Namespace: ns, LabelSelector: r.LabelSelector(), }, }) @@ -583,6 +588,7 @@ func (i *Infra) deleteHPA(ctx context.Context, r ResourceRender) (err error) { return i.Client.DeleteAllOf(ctx, hpa, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ + Namespace: ns, LabelSelector: r.LabelSelector(), }, }) @@ -622,6 +628,7 @@ func (i *Infra) deletePDB(ctx context.Context, r ResourceRender) (err error) { return i.Client.DeleteAllOf(ctx, pdb, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ + Namespace: ns, LabelSelector: r.LabelSelector(), }, }) diff --git a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml index 8a1513469de..3746f12a18d 100644 --- a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml +++ b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml @@ -204,10 +204,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -218,6 +220,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -229,6 +232,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml index a71e46fe7bd..582fab0e8b9 100644 --- a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml +++ b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml @@ -219,10 +219,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -233,6 +235,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -244,6 +247,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/default-config.out.yaml b/test/helm/gateway-helm/default-config.out.yaml index 140d271c6e7..b4aac21b12c 100644 --- a/test/helm/gateway-helm/default-config.out.yaml +++ b/test/helm/gateway-helm/default-config.out.yaml @@ -204,10 +204,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -218,6 +220,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -229,6 +232,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/deployment-custom-topology.out.yaml b/test/helm/gateway-helm/deployment-custom-topology.out.yaml index 586b64b5584..37f58022beb 100644 --- a/test/helm/gateway-helm/deployment-custom-topology.out.yaml +++ b/test/helm/gateway-helm/deployment-custom-topology.out.yaml @@ -204,10 +204,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -218,6 +220,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -229,6 +232,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/deployment-images-config.out.yaml b/test/helm/gateway-helm/deployment-images-config.out.yaml index 10f849e1d77..8506b87b0ee 100644 --- a/test/helm/gateway-helm/deployment-images-config.out.yaml +++ b/test/helm/gateway-helm/deployment-images-config.out.yaml @@ -204,10 +204,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -218,6 +220,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -229,6 +232,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/deployment-priorityclass.out.yaml b/test/helm/gateway-helm/deployment-priorityclass.out.yaml index 4f735c42095..3f82746416b 100644 --- a/test/helm/gateway-helm/deployment-priorityclass.out.yaml +++ b/test/helm/gateway-helm/deployment-priorityclass.out.yaml @@ -204,10 +204,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -218,6 +220,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -229,6 +232,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/envoy-gateway-config.out.yaml b/test/helm/gateway-helm/envoy-gateway-config.out.yaml index 04159958265..9a3f5b4846b 100644 --- a/test/helm/gateway-helm/envoy-gateway-config.out.yaml +++ b/test/helm/gateway-helm/envoy-gateway-config.out.yaml @@ -206,10 +206,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -220,6 +222,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -231,6 +234,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/global-images-config.out.yaml b/test/helm/gateway-helm/global-images-config.out.yaml index f280fc9f218..38be258c7a3 100644 --- a/test/helm/gateway-helm/global-images-config.out.yaml +++ b/test/helm/gateway-helm/global-images-config.out.yaml @@ -208,10 +208,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -222,6 +224,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -233,6 +236,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml diff --git a/test/helm/gateway-helm/service-annotations.out.yaml b/test/helm/gateway-helm/service-annotations.out.yaml index ec50a16e30d..532988e919e 100644 --- a/test/helm/gateway-helm/service-annotations.out.yaml +++ b/test/helm/gateway-helm/service-annotations.out.yaml @@ -204,10 +204,12 @@ rules: resources: - serviceaccounts - services + - configmaps verbs: - create - get - delete + - deletecollection - patch - apiGroups: - apps @@ -218,6 +220,7 @@ rules: - create - get - delete + - deletecollection - patch - apiGroups: - autoscaling @@ -229,6 +232,7 @@ rules: - create - get - delete + - deletecollection - patch --- # Source: gateway-helm/templates/leader-election-rbac.yaml From 29d7020b5628545b307335e40fc4464ac94df880 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Thu, 17 Oct 2024 17:19:09 -0700 Subject: [PATCH 28/39] feat: implement fallback for the Backend API (#4461) * feat: implement fallback for the Backend API Relates to https://github.com/envoyproxy/gateway/issues/3055 Signed-off-by: Arko Dasgupta * fix lint Signed-off-by: Arko Dasgupta --------- Signed-off-by: Arko Dasgupta --- api/v1alpha1/backend_types.go | 1 - internal/gatewayapi/route.go | 12 +- .../testdata/backend-with-fallback.in.yaml | 58 ++++++ .../testdata/backend-with-fallback.out.yaml | 180 ++++++++++++++++++ site/content/en/latest/api/extension_types.md | 1 + site/content/zh/latest/api/extension_types.md | 1 + 6 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 internal/gatewayapi/testdata/backend-with-fallback.in.yaml create mode 100644 internal/gatewayapi/testdata/backend-with-fallback.out.yaml diff --git a/api/v1alpha1/backend_types.go b/api/v1alpha1/backend_types.go index a2022c2c5ef..bb407981af8 100644 --- a/api/v1alpha1/backend_types.go +++ b/api/v1alpha1/backend_types.go @@ -131,7 +131,6 @@ type BackendSpec struct { // the health of the active backends falls below 72%. // // +optional - // +notImplementedHide Fallback *bool `json:"fallback,omitempty"` } diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 1239caadc91..f82158715a5 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -1291,6 +1291,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext, resources, envoyProxy, ) + ds.Filters = t.processDestinationFilters(routeType, backendRefContext, parentRef, route, resources) } @@ -1672,9 +1673,18 @@ func (t *Translator) processBackendDestinationSetting(backendRef gwapiv1.Backend } } - return &ir.DestinationSetting{ + ds := &ir.DestinationSetting{ Protocol: dstProtocol, Endpoints: dstEndpoints, AddressType: dstAddrType, } + + if backend.Spec.Fallback != nil { + // set only the secondary priority, the backend defaults to a primary priority if unset. + if ptr.Deref(backend.Spec.Fallback, false) { + ds.Priority = ptr.To(uint32(1)) + } + } + + return ds } diff --git a/internal/gatewayapi/testdata/backend-with-fallback.in.yaml b/internal/gatewayapi/testdata/backend-with-fallback.in.yaml new file mode 100644 index 00000000000..667a75a6557 --- /dev/null +++ b/internal/gatewayapi/testdata/backend-with-fallback.in.yaml @@ -0,0 +1,58 @@ +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 +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + rules: + - matches: + - path: + value: "/" + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-1 + - group: gateway.envoyproxy.io + kind: Backend + name: backend-2 +backends: + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-1 + namespace: default + spec: + endpoints: + - ip: + address: 1.1.1.1 + port: 3001 + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-2 + namespace: default + spec: + fallback: true + endpoints: + - ip: + address: 2.2.2.2 + port: 3001 diff --git a/internal/gatewayapi/testdata/backend-with-fallback.out.yaml b/internal/gatewayapi/testdata/backend-with-fallback.out.yaml new file mode 100644 index 00000000000..74bd61795fe --- /dev/null +++ b/internal/gatewayapi/testdata/backend-with-fallback.out.yaml @@ -0,0 +1,180 @@ +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + creationTimestamp: null + name: backend-1 + namespace: default + spec: + endpoints: + - ip: + address: 1.1.1.1 + port: 3001 + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + creationTimestamp: null + name: backend-2 + namespace: default + spec: + endpoints: + - ip: + address: 2.2.2.2 + port: 3001 + fallback: true + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +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 +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-1 + - group: gateway.envoyproxy.io + kind: Backend + name: backend-2 + 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 +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + 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: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 1.1.1.1 + port: 3001 + weight: 1 + - addressType: IP + endpoints: + - host: 2.2.2.2 + port: 3001 + priority: 1 + weight: 1 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/* + pathMatch: + distinct: false + name: "" + prefix: / diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index ddc32a2021e..8a54fb2d6c6 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -384,6 +384,7 @@ _Appears in:_ | --- | --- | --- | --- | | `endpoints` | _[BackendEndpoint](#backendendpoint) array_ | true | Endpoints defines the endpoints to be used when connecting to the backend. | | `appProtocols` | _[AppProtocolType](#appprotocoltype) array_ | false | AppProtocols defines the application protocols to be supported when connecting to the backend. | +| `fallback` | _boolean_ | false | Fallback indicates whether the backend is designated as a fallback.
It is highly recommended to configure active or passive health checks to ensure that failover can be detected
when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again.
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%. | #### BackendStatus diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index ddc32a2021e..8a54fb2d6c6 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -384,6 +384,7 @@ _Appears in:_ | --- | --- | --- | --- | | `endpoints` | _[BackendEndpoint](#backendendpoint) array_ | true | Endpoints defines the endpoints to be used when connecting to the backend. | | `appProtocols` | _[AppProtocolType](#appprotocoltype) array_ | false | AppProtocols defines the application protocols to be supported when connecting to the backend. | +| `fallback` | _boolean_ | false | Fallback indicates whether the backend is designated as a fallback.
It is highly recommended to configure active or passive health checks to ensure that failover can be detected
when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again.
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%. | #### BackendStatus From d371d0b4ae1a74917f0a59574b14656be981a0b9 Mon Sep 17 00:00:00 2001 From: Huabing Zhao Date: Fri, 18 Oct 2024 08:24:25 +0800 Subject: [PATCH 29/39] chore: bump go control plane to 0.13.1 (#4465) * bump go control plane to 0.13.1 Signed-off-by: Huabing Zhao * bump go control plane to 0.13.1 Signed-off-by: Huabing Zhao --------- Signed-off-by: Huabing Zhao --- examples/extension-server/go.mod | 2 +- examples/extension-server/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/extension-server/go.mod b/examples/extension-server/go.mod index c4a08fecafc..92af0438105 100644 --- a/examples/extension-server/go.mod +++ b/examples/extension-server/go.mod @@ -4,7 +4,7 @@ go 1.23.1 require ( github.com/envoyproxy/gateway v1.0.2 - github.com/envoyproxy/go-control-plane v0.13.1-0.20240917224354-20d038a70568 + github.com/envoyproxy/go-control-plane v0.13.1 github.com/urfave/cli/v2 v2.27.4 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 diff --git a/examples/extension-server/go.sum b/examples/extension-server/go.sum index 7d995a60424..1df719e00af 100644 --- a/examples/extension-server/go.sum +++ b/examples/extension-server/go.sum @@ -11,8 +11,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.13.1-0.20240917224354-20d038a70568 h1:bUMUmkPtm/z62/8WiVbxtqTK8I7AzXGYn+qB8JAzAXw= -github.com/envoyproxy/go-control-plane v0.13.1-0.20240917224354-20d038a70568/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= +github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= diff --git a/go.mod b/go.mod index 482af942a9a..ee7928f0a0a 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/docker/cli v27.3.1+incompatible github.com/dominikbraun/graph v0.23.0 - github.com/envoyproxy/go-control-plane v0.13.1-0.20240917224354-20d038a70568 + github.com/envoyproxy/go-control-plane v0.13.1 github.com/envoyproxy/ratelimit v1.4.1-0.20230427142404-e2a87f41d3a7 github.com/evanphx/json-patch/v5 v5.9.0 github.com/fatih/color v1.17.0 diff --git a/go.sum b/go.sum index c5d453f9e0d..93ade68d710 100644 --- a/go.sum +++ b/go.sum @@ -222,8 +222,8 @@ github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRr github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.13.1-0.20240917224354-20d038a70568 h1:bUMUmkPtm/z62/8WiVbxtqTK8I7AzXGYn+qB8JAzAXw= -github.com/envoyproxy/go-control-plane v0.13.1-0.20240917224354-20d038a70568/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= +github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= From 7293b6c7f1f90906b55ead3b58e1a1a4222977e6 Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Fri, 18 Oct 2024 06:11:00 +0530 Subject: [PATCH 30/39] api: fix HeaderMatch list type to allow invert matches on same header (#4464) fix HeaderMatch list type to allow invert matches on same header Signed-off-by: Rudrakh Panigrahi --- api/v1alpha1/ratelimit_types.go | 9 --------- api/v1alpha1/zz_generated.deepcopy.go | 5 ----- ...way.envoyproxy.io_backendtrafficpolicies.yaml | 16 ---------------- 3 files changed, 30 deletions(-) diff --git a/api/v1alpha1/ratelimit_types.go b/api/v1alpha1/ratelimit_types.go index deb859400f8..d7a43751077 100644 --- a/api/v1alpha1/ratelimit_types.go +++ b/api/v1alpha1/ratelimit_types.go @@ -101,8 +101,6 @@ type RateLimitSelectCondition struct { // meaning, a request MUST match all the specified headers. // At least one of headers or sourceCIDR condition must be specified. // - // +listType=map - // +listMapKey=name // +optional // +kubebuilder:validation:MaxItems=16 Headers []HeaderMatch `json:"headers,omitempty"` @@ -138,13 +136,6 @@ type SourceMatch struct { // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=256 Value string `json:"value"` - - // Invert specifies whether the value match result will be inverted. - // - // +optional - // +kubebuilder:default=false - // +notImplementedHide - Invert *bool `json:"invert,omitempty"` } // HeaderMatch defines the match attributes within the HTTP Headers of the request. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index a5e8dc183ff..d6a4f9daf2f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -5075,11 +5075,6 @@ func (in *SourceMatch) DeepCopyInto(out *SourceMatch) { *out = new(SourceMatchType) **out = **in } - if in.Invert != nil { - in, out := &in.Invert, &out.Invert - *out = new(bool) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceMatch. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index c0dce593804..521ee8bcf46 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -727,19 +727,11 @@ spec: type: object maxItems: 16 type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map sourceCIDR: description: |- SourceCIDR is the client IP Address range to match on. At least one of headers or sourceCIDR condition must be specified. properties: - invert: - default: false - description: Invert specifies whether the - value match result will be inverted. - type: boolean type: default: Exact enum: @@ -870,19 +862,11 @@ spec: type: object maxItems: 16 type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map sourceCIDR: description: |- SourceCIDR is the client IP Address range to match on. At least one of headers or sourceCIDR condition must be specified. properties: - invert: - default: false - description: Invert specifies whether the - value match result will be inverted. - type: boolean type: default: Exact enum: From 5375cf0e045c12ec3f9205db0c81f76b2e678695 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Thu, 17 Oct 2024 18:39:40 -0700 Subject: [PATCH 31/39] api: direct response (#4334) * api: direct response Relates to https://github.com/envoyproxy/gateway/issues/2714 Signed-off-by: Arko Dasgupta --- api/v1alpha1/httproutefilter_types.go | 20 +++++++ api/v1alpha1/shared_types.go | 4 +- api/v1alpha1/zz_generated.deepcopy.go | 41 ++++++++++++- ....envoyproxy.io_backendtrafficpolicies.yaml | 2 - ...ateway.envoyproxy.io_httproutefilters.yaml | 60 +++++++++++++++++++ site/content/en/latest/api/extension_types.md | 20 ++++++- site/content/zh/latest/api/extension_types.md | 20 ++++++- 7 files changed, 161 insertions(+), 6 deletions(-) diff --git a/api/v1alpha1/httproutefilter_types.go b/api/v1alpha1/httproutefilter_types.go index 7f56ca07d7c..9ae8be59842 100644 --- a/api/v1alpha1/httproutefilter_types.go +++ b/api/v1alpha1/httproutefilter_types.go @@ -33,6 +33,8 @@ type HTTPRouteFilter struct { type HTTPRouteFilterSpec struct { // +optional URLRewrite *HTTPURLRewriteFilter `json:"urlRewrite,omitempty"` + // +optional + DirectResponse *HTTPDirectResponseFilter `json:"directResponse,omitempty"` } // HTTPURLRewriteFilter define rewrites of HTTP URL components such as path and host @@ -49,6 +51,24 @@ type HTTPURLRewriteFilter struct { Path *HTTPPathModifier `json:"path,omitempty"` } +// HTTPDirectResponseFilter defines the configuration to return a fixed response. +type HTTPDirectResponseFilter struct { + // Content Type of the response. This will be set in the Content-Type header. + // + // +optional + ContentType *string `json:"contentType,omitempty"` + + // Body of the Response + // + // +optional + Body *CustomResponseBody `json:"body,omitempty"` + + // Status Code of the HTTP response + // If unset, defaults to 200. + // +optional + StatusCode *int `json:"statusCode,omitempty"` +} + // HTTPPathModifierType defines the type of path redirect or rewrite. type HTTPPathModifierType string diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index 8e98b904e35..fe795c833db 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -669,7 +669,9 @@ type CustomResponse struct { ContentType *string `json:"contentType,omitempty"` // Body of the Custom Response - Body CustomResponseBody `json:"body"` + // + // +optional + Body *CustomResponseBody `json:"body,omitempty"` } // ResponseValueType defines the types of values for the response body supported by Envoy Gateway. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index d6a4f9daf2f..696c99259fb 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1148,7 +1148,11 @@ func (in *CustomResponse) DeepCopyInto(out *CustomResponse) { *out = new(string) **out = **in } - in.Body.DeepCopyInto(&out.Body) + if in.Body != nil { + in, out := &in.Body, &out.Body + *out = new(CustomResponseBody) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResponse. @@ -2688,6 +2692,36 @@ func (in *HTTPClientTimeout) DeepCopy() *HTTPClientTimeout { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPDirectResponseFilter) DeepCopyInto(out *HTTPDirectResponseFilter) { + *out = *in + if in.ContentType != nil { + in, out := &in.ContentType, &out.ContentType + *out = new(string) + **out = **in + } + if in.Body != nil { + in, out := &in.Body, &out.Body + *out = new(CustomResponseBody) + (*in).DeepCopyInto(*out) + } + if in.StatusCode != nil { + in, out := &in.StatusCode, &out.StatusCode + *out = new(int) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPDirectResponseFilter. +func (in *HTTPDirectResponseFilter) DeepCopy() *HTTPDirectResponseFilter { + if in == nil { + return nil + } + out := new(HTTPDirectResponseFilter) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HTTPExtAuthService) DeepCopyInto(out *HTTPExtAuthService) { *out = *in @@ -2820,6 +2854,11 @@ func (in *HTTPRouteFilterSpec) DeepCopyInto(out *HTTPRouteFilterSpec) { *out = new(HTTPURLRewriteFilter) (*in).DeepCopyInto(*out) } + if in.DirectResponse != nil { + in, out := &in.DirectResponse, &out.DirectResponse + *out = new(HTTPDirectResponseFilter) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteFilterSpec. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 521ee8bcf46..7b2e937312d 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -1035,8 +1035,6 @@ spec: description: Content Type of the response. This will be set in the Content-Type header. type: string - required: - - body type: object required: - match diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml index 7a55ec8871f..8a75fec4211 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml @@ -49,6 +49,66 @@ spec: spec: description: Spec defines the desired state of HTTPRouteFilter. properties: + directResponse: + description: HTTPDirectResponseFilter defines the configuration to + return a fixed response. + properties: + body: + description: Body of the Response + properties: + inline: + description: Inline contains the value as an inline string. + type: string + type: + description: Type is the type of method to use to read the + body value. + enum: + - Inline + - ValueRef + type: string + valueRef: + description: |- + ValueRef contains the contents of the body + specified as a local object reference. + Only a reference to ConfigMap is supported. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + required: + - type + type: object + contentType: + description: Content Type of the response. This will be set in + the Content-Type header. + type: string + statusCode: + description: |- + Status Code of the HTTP response + If unset, defaults to 200. + type: integer + type: object urlRewrite: description: HTTPURLRewriteFilter define rewrites of HTTP URL components such as path and host diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 8a54fb2d6c6..fe361099a84 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -866,7 +866,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `contentType` | _string_ | false | Content Type of the response. This will be set in the Content-Type header. | -| `body` | _[CustomResponseBody](#customresponsebody)_ | true | Body of the Custom Response | +| `body` | _[CustomResponseBody](#customresponsebody)_ | false | Body of the Custom Response | #### CustomResponseBody @@ -877,6 +877,7 @@ CustomResponseBody _Appears in:_ - [CustomResponse](#customresponse) +- [HTTPDirectResponseFilter](#httpdirectresponsefilter) | Field | Type | Required | Description | | --- | --- | --- | --- | @@ -1922,6 +1923,22 @@ _Appears in:_ | `idleTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | IdleTimeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
Default: 1 hour. | +#### HTTPDirectResponseFilter + + + +HTTPDirectResponseFilter defines the configuration to return a fixed response. + +_Appears in:_ +- [HTTPRouteFilterSpec](#httproutefilterspec) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `contentType` | _string_ | false | Content Type of the response. This will be set in the Content-Type header. | +| `body` | _[CustomResponseBody](#customresponsebody)_ | false | Body of the Response | +| `statusCode` | _integer_ | false | Status Code of the HTTP response
If unset, defaults to 200. | + + #### HTTPExtAuthService @@ -2045,6 +2062,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `urlRewrite` | _[HTTPURLRewriteFilter](#httpurlrewritefilter)_ | false | | +| `directResponse` | _[HTTPDirectResponseFilter](#httpdirectresponsefilter)_ | false | | #### HTTPStatus diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 8a54fb2d6c6..fe361099a84 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -866,7 +866,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `contentType` | _string_ | false | Content Type of the response. This will be set in the Content-Type header. | -| `body` | _[CustomResponseBody](#customresponsebody)_ | true | Body of the Custom Response | +| `body` | _[CustomResponseBody](#customresponsebody)_ | false | Body of the Custom Response | #### CustomResponseBody @@ -877,6 +877,7 @@ CustomResponseBody _Appears in:_ - [CustomResponse](#customresponse) +- [HTTPDirectResponseFilter](#httpdirectresponsefilter) | Field | Type | Required | Description | | --- | --- | --- | --- | @@ -1922,6 +1923,22 @@ _Appears in:_ | `idleTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | IdleTimeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
Default: 1 hour. | +#### HTTPDirectResponseFilter + + + +HTTPDirectResponseFilter defines the configuration to return a fixed response. + +_Appears in:_ +- [HTTPRouteFilterSpec](#httproutefilterspec) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `contentType` | _string_ | false | Content Type of the response. This will be set in the Content-Type header. | +| `body` | _[CustomResponseBody](#customresponsebody)_ | false | Body of the Response | +| `statusCode` | _integer_ | false | Status Code of the HTTP response
If unset, defaults to 200. | + + #### HTTPExtAuthService @@ -2045,6 +2062,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `urlRewrite` | _[HTTPURLRewriteFilter](#httpurlrewritefilter)_ | false | | +| `directResponse` | _[HTTPDirectResponseFilter](#httpdirectresponsefilter)_ | false | | #### HTTPStatus From a351c4bb457dba62e4c5d39d76d2f3a6d135a0ae Mon Sep 17 00:00:00 2001 From: Huabing Zhao Date: Fri, 18 Oct 2024 10:41:10 +0800 Subject: [PATCH 32/39] Use BackendCluster to represent OIDCProvider (#4227) * gateway api translation Signed-off-by: Huabing Zhao * gateway api translation Signed-off-by: Huabing Zhao * xds translation Signed-off-by: Huabing Zhao * add cel validation Signed-off-by: Huabing Zhao * add cel validation Signed-off-by: Huabing Zhao * CEL validation Signed-off-by: Huabing Zhao * add CEL validation Signed-off-by: Huabing Zhao * add retry trigger Signed-off-by: Huabing Zhao * refactory Signed-off-by: Huabing Zhao * fix gen Signed-off-by: Huabing Zhao * add e2e test for OIDC provider with BackendCluster Signed-off-by: Huabing Zhao * add dump Signed-off-by: Huabing Zhao * fix lint Signed-off-by: Huabing Zhao * fix test Signed-off-by: Huabing Zhao * fix test Signed-off-by: Huabing Zhao * fix test Signed-off-by: Huabing Zhao * fix test Signed-off-by: Huabing Zhao * Update internal/gatewayapi/ext_service.go Co-authored-by: Arko Dasgupta Signed-off-by: Huabing Zhao * address comment Signed-off-by: Huabing Zhao * address comment Signed-off-by: Huabing Zhao * address comment Signed-off-by: Huabing Zhao * address comment Signed-off-by: Huabing Zhao * address comment Signed-off-by: Huabing Zhao * address comment Signed-off-by: Huabing Zhao --------- Signed-off-by: Huabing Zhao --- api/v1alpha1/oidc_types.go | 3 +- ...ateway.envoyproxy.io_securitypolicies.yaml | 9 +- go.mod | 2 +- go.sum | 4 +- internal/gatewayapi/backendtrafficpolicy.go | 66 +---- internal/gatewayapi/clustersettings.go | 63 +++++ internal/gatewayapi/envoyextensionpolicy.go | 42 +-- internal/gatewayapi/ext_service.go | 53 +++- internal/gatewayapi/securitypolicy.go | 170 ++++++------ ...itypolicy-with-oidc-backendcluster.in.yaml | 101 +++++++ ...typolicy-with-oidc-backendcluster.out.yaml | 256 ++++++++++++++++++ internal/ir/xds.go | 9 + internal/ir/zz_generated.deepcopy.go | 27 +- internal/xds/translator/oidc.go | 188 +++++++++---- .../xds-ir/oidc-backend-cluster-provider.yaml | 60 ++++ .../oidc-backencluster-provider.clusters.yaml | 44 +++ ...oidc-backencluster-provider.endpoints.yaml | 12 + ...oidc-backencluster-provider.listeners.yaml | 83 ++++++ .../oidc-backencluster-provider.routes.yaml | 18 ++ .../oidc-backencluster-provider.secrets.yaml | 8 + ...idc-backend-cluster-provider.clusters.yaml | 44 +++ ...dc-backend-cluster-provider.endpoints.yaml | 12 + ...dc-backend-cluster-provider.listeners.yaml | 83 ++++++ .../oidc-backend-cluster-provider.routes.yaml | 18 ++ ...oidc-backend-cluster-provider.secrets.yaml | 8 + test/cel-validation/securitypolicy_test.go | 98 +++++++ .../oidc-securitypolicy-backendcluster.yaml | 86 ++++++ test/e2e/tests/oidc-backendcluster.go | 37 +++ test/e2e/tests/oidc.go | 192 ++++++------- 29 files changed, 1464 insertions(+), 332 deletions(-) create mode 100644 internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.in.yaml create mode 100644 internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.out.yaml create mode 100644 internal/xds/translator/testdata/in/xds-ir/oidc-backend-cluster-provider.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.clusters.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.endpoints.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.listeners.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.routes.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.secrets.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.clusters.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.endpoints.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.routes.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.secrets.yaml create mode 100644 test/e2e/testdata/oidc-securitypolicy-backendcluster.yaml create mode 100644 test/e2e/tests/oidc-backendcluster.go diff --git a/api/v1alpha1/oidc_types.go b/api/v1alpha1/oidc_types.go index 73e1dea8c6e..78c32287cde 100644 --- a/api/v1alpha1/oidc_types.go +++ b/api/v1alpha1/oidc_types.go @@ -107,7 +107,8 @@ type OIDC struct { // OIDCProvider defines the OIDC Provider configuration. // +kubebuilder:validation:XValidation:rule="!has(self.backendRef)",message="BackendRefs must be used, backendRef is not supported." -// +kubebuilder:validation:XValidation:rule="has(self.backendRefs)? self.backendRefs.size() > 1 : true",message="Only one backendRefs is allowed." +// +kubebuilder:validation:XValidation:rule="has(self.backendSettings)? (has(self.backendSettings.retry)?(has(self.backendSettings.retry.perRetry)? !has(self.backendSettings.retry.perRetry.timeout):true):true):true",message="Retry timeout is not supported." +// +kubebuilder:validation:XValidation:rule="has(self.backendSettings)? (has(self.backendSettings.retry)?(has(self.backendSettings.retry.retryOn)? !has(self.backendSettings.retry.retryOn.httpStatusCodes):true):true):true",message="HTTPStatusCodes is not supported." type OIDCProvider struct { // BackendRefs is used to specify the address of the OIDC Provider. // If the BackendRefs is not specified, The host and port of the OIDC Provider's token endpoint diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index ad2c81818c2..b6a040f8c42 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -3261,9 +3261,12 @@ spec: x-kubernetes-validations: - message: BackendRefs must be used, backendRef is not supported. rule: '!has(self.backendRef)' - - message: Only one backendRefs is allowed. - rule: 'has(self.backendRefs)? self.backendRefs.size() > 1 : - true' + - message: Retry timeout is not supported. + rule: has(self.backendSettings)? (has(self.backendSettings.retry)?(has(self.backendSettings.retry.perRetry)? + !has(self.backendSettings.retry.perRetry.timeout):true):true):true + - message: HTTPStatusCodes is not supported. + rule: has(self.backendSettings)? (has(self.backendSettings.retry)?(has(self.backendSettings.retry.retryOn)? + !has(self.backendSettings.retry.retryOn.httpStatusCodes):true):true):true redirectURL: description: |- The redirect URL to be used in the OIDC diff --git a/go.mod b/go.mod index ee7928f0a0a..0b7c29eb542 100644 --- a/go.mod +++ b/go.mod @@ -159,7 +159,7 @@ require ( github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/sys/user v0.2.0 // indirect + github.com/moby/sys/user v0.3.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect diff --git a/go.sum b/go.sum index 93ade68d710..5aa804824a4 100644 --- a/go.sum +++ b/go.sum @@ -601,8 +601,8 @@ github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9Kou github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/sys/user v0.2.0 h1:OnpapJsRp25vkhw8TFG6OLJODNh/3rEwRWtJ3kakwRM= -github.com/moby/sys/user v0.2.0/go.mod h1:RYstrcWOJpVh+6qzUqp2bU3eaRpdiQeKGlKitaH0PM8= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index 12453ea1826..b8f289a9df0 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -16,7 +16,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/utils/ptr" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" @@ -324,7 +323,7 @@ func (t *Translator) translateBackendTrafficPolicyForRoute(policy *egv1a1.Backen errs = errors.Join(errs, err) } if policy.Spec.Retry != nil { - rt = t.buildRetry(policy) + rt = buildRetry(policy.Spec.Retry) } if to, err = buildClusterSettingsTimeout(policy.Spec.ClusterSettings, nil); err != nil { err = perr.WithMessage(err, "Timeout") @@ -460,7 +459,7 @@ func (t *Translator) translateBackendTrafficPolicyForGateway(policy *egv1a1.Back errs = errors.Join(errs, err) } if policy.Spec.Retry != nil { - rt = t.buildRetry(policy) + rt = buildRetry(policy.Spec.Retry) } if ct, err = buildClusterSettingsTimeout(policy.Spec.ClusterSettings, nil); err != nil { err = perr.WithMessage(err, "Timeout") @@ -812,67 +811,6 @@ func (t *Translator) buildFaultInjection(policy *egv1a1.BackendTrafficPolicy) *i return fi } -func (t *Translator) buildRetry(policy *egv1a1.BackendTrafficPolicy) *ir.Retry { - var rt *ir.Retry - if policy.Spec.Retry != nil { - prt := policy.Spec.Retry - rt = &ir.Retry{} - - if prt.NumRetries != nil { - rt.NumRetries = ptr.To(uint32(*prt.NumRetries)) - } - - if prt.RetryOn != nil { - ro := &ir.RetryOn{} - bro := false - if prt.RetryOn.HTTPStatusCodes != nil { - ro.HTTPStatusCodes = makeIrStatusSet(prt.RetryOn.HTTPStatusCodes) - bro = true - } - - if prt.RetryOn.Triggers != nil { - ro.Triggers = makeIrTriggerSet(prt.RetryOn.Triggers) - bro = true - } - - if bro { - rt.RetryOn = ro - } - } - - if prt.PerRetry != nil { - pr := &ir.PerRetryPolicy{} - bpr := false - - if prt.PerRetry.Timeout != nil { - pr.Timeout = prt.PerRetry.Timeout - bpr = true - } - - if prt.PerRetry.BackOff != nil { - if prt.PerRetry.BackOff.MaxInterval != nil || prt.PerRetry.BackOff.BaseInterval != nil { - bop := &ir.BackOffPolicy{} - if prt.PerRetry.BackOff.MaxInterval != nil { - bop.MaxInterval = prt.PerRetry.BackOff.MaxInterval - } - - if prt.PerRetry.BackOff.BaseInterval != nil { - bop.BaseInterval = prt.PerRetry.BackOff.BaseInterval - } - pr.BackOff = bop - bpr = true - } - } - - if bpr { - rt.PerRetry = pr - } - } - } - - return rt -} - func makeIrStatusSet(in []egv1a1.HTTPStatus) []ir.HTTPStatus { statusSet := sets.NewInt() for _, r := range in { diff --git a/internal/gatewayapi/clustersettings.go b/internal/gatewayapi/clustersettings.go index 742b026249e..260c1db84d3 100644 --- a/internal/gatewayapi/clustersettings.go +++ b/internal/gatewayapi/clustersettings.go @@ -71,6 +71,8 @@ func translateTrafficFeatures(policy *egv1a1.ClusterSettings) (*ir.TrafficFeatur ret.HTTP2 = h2 } + ret.Retry = buildRetry(policy.Retry) + // If nothing was set in any of the above calls, return nil instead of an empty // container var empty ir.TrafficFeatures @@ -507,3 +509,64 @@ func translateDNS(policy egv1a1.ClusterSettings) *ir.DNS { DNSRefreshRate: policy.DNS.DNSRefreshRate, } } + +func buildRetry(r *egv1a1.Retry) *ir.Retry { + if r == nil { + return nil + } + + rt := &ir.Retry{} + + if r.NumRetries != nil { + rt.NumRetries = ptr.To(uint32(*r.NumRetries)) + } + + if r.RetryOn != nil { + ro := &ir.RetryOn{} + bro := false + if r.RetryOn.HTTPStatusCodes != nil { + ro.HTTPStatusCodes = makeIrStatusSet(r.RetryOn.HTTPStatusCodes) + bro = true + } + + if r.RetryOn.Triggers != nil { + ro.Triggers = makeIrTriggerSet(r.RetryOn.Triggers) + bro = true + } + + if bro { + rt.RetryOn = ro + } + } + + if r.PerRetry != nil { + pr := &ir.PerRetryPolicy{} + bpr := false + + if r.PerRetry.Timeout != nil { + pr.Timeout = r.PerRetry.Timeout + bpr = true + } + + if r.PerRetry.BackOff != nil { + if r.PerRetry.BackOff.MaxInterval != nil || r.PerRetry.BackOff.BaseInterval != nil { + bop := &ir.BackOffPolicy{} + if r.PerRetry.BackOff.MaxInterval != nil { + bop.MaxInterval = r.PerRetry.BackOff.MaxInterval + } + + if r.PerRetry.BackOff.BaseInterval != nil { + bop.BaseInterval = r.PerRetry.BackOff.BaseInterval + } + pr.BackOff = bop + bpr = true + } + } + + if bpr { + rt.PerRetry = pr + } + } + + return rt +} diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index 47394587529..5e61f2eb3aa 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -411,7 +411,7 @@ func (t *Translator) buildExtProcs(policy *egv1a1.EnvoyExtensionPolicy, resource for idx, ep := range policy.Spec.ExtProc { name := irConfigNameForExtProc(policy, idx) - extProcIR, err := t.buildExtProc(name, utils.NamespacedName(policy), ep, idx, resources, envoyProxy) + extProcIR, err := t.buildExtProc(name, policy, ep, idx, resources, envoyProxy) if err != nil { return nil, err } @@ -422,59 +422,33 @@ func (t *Translator) buildExtProcs(policy *egv1a1.EnvoyExtensionPolicy, resource func (t *Translator) buildExtProc( name string, - policyNamespacedName types.NamespacedName, + policy *egv1a1.EnvoyExtensionPolicy, extProc egv1a1.ExtProc, extProcIdx int, resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy, ) (*ir.ExtProc, error) { var ( - ds *ir.DestinationSetting + rd *ir.RouteDestination authority string err error ) - var dsl []*ir.DestinationSetting - for i := range extProc.BackendRefs { - if err = t.validateExtServiceBackendReference( - &extProc.BackendRefs[i].BackendObjectReference, - policyNamespacedName.Namespace, - egv1a1.KindEnvoyExtensionPolicy, - resources); err != nil { - return nil, err - } - - ds, err = t.processExtServiceDestination( - &extProc.BackendRefs[i], - policyNamespacedName, - egv1a1.KindEnvoyExtensionPolicy, - ir.GRPC, - resources, - envoyProxy, - ) - if err != nil { - return nil, err - } - - dsl = append(dsl, ds) - } - - rd := ir.RouteDestination{ - Name: irIndexedExtServiceDestinationName(policyNamespacedName, egv1a1.KindEnvoyExtensionPolicy, extProcIdx), - Settings: dsl, + if rd, err = t.translateExtServiceBackendRefs(policy, extProc.BackendRefs, ir.GRPC, resources, envoyProxy, extProcIdx); err != nil { + return nil, err } if extProc.BackendRefs[0].Port != nil { authority = fmt.Sprintf( "%s.%s:%d", extProc.BackendRefs[0].Name, - NamespaceDerefOr(extProc.BackendRefs[0].Namespace, policyNamespacedName.Namespace), + NamespaceDerefOr(extProc.BackendRefs[0].Namespace, policy.Namespace), *extProc.BackendRefs[0].Port) } else { authority = fmt.Sprintf( "%s.%s", extProc.BackendRefs[0].Name, - NamespaceDerefOr(extProc.BackendRefs[0].Namespace, policyNamespacedName.Namespace)) + NamespaceDerefOr(extProc.BackendRefs[0].Namespace, policy.Namespace)) } traffic, err := translateTrafficFeatures(extProc.BackendCluster.BackendSettings) @@ -484,7 +458,7 @@ func (t *Translator) buildExtProc( extProcIR := &ir.ExtProc{ Name: name, - Destination: rd, + Destination: *rd, Traffic: traffic, Authority: authority, } diff --git a/internal/gatewayapi/ext_service.go b/internal/gatewayapi/ext_service.go index 7e13b101011..e7ab19036ee 100644 --- a/internal/gatewayapi/ext_service.go +++ b/internal/gatewayapi/ext_service.go @@ -12,15 +12,66 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" 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/resource" "github.com/envoyproxy/gateway/internal/ir" + "github.com/envoyproxy/gateway/internal/utils" ) -// TODO: zhaohuabing combine this function with the one in the route translator +// translateExtServiceBackendRefs translates external service backend references to route destinations. +func (t *Translator) translateExtServiceBackendRefs( + policy client.Object, + backendRefs []egv1a1.BackendRef, + protocol ir.AppProtocol, + resources *resource.Resources, + envoyProxy *egv1a1.EnvoyProxy, + index int, // index is used to differentiate between multiple external services in the same policy +) (*ir.RouteDestination, error) { + var ( + rs *ir.RouteDestination + ds []*ir.DestinationSetting + err error + ) + + if len(backendRefs) == 0 { + return nil, errors.New("no backendRefs found for external service") + } + + pnn := utils.NamespacedName(policy) + for _, backendRef := range backendRefs { + if err = t.validateExtServiceBackendReference( + &backendRef.BackendObjectReference, + policy.GetNamespace(), + policy.GetObjectKind().GroupVersionKind().Kind, + resources); err != nil { + return nil, err + } + + var extServiceDest *ir.DestinationSetting + if extServiceDest, err = t.processExtServiceDestination( + &backendRef, + pnn, + policy.GetObjectKind().GroupVersionKind().Kind, + protocol, + resources, + envoyProxy, + ); err != nil { + return nil, err + } + ds = append(ds, extServiceDest) + } + + rs = &ir.RouteDestination{ + Name: irIndexedExtServiceDestinationName(pnn, policy.GetObjectKind().GroupVersionKind().Kind, index), + Settings: ds, + } + return rs, nil +} + func (t *Translator) processExtServiceDestination( backendRef *egv1a1.BackendRef, policyNamespacedName types.NamespacedName, diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index 2ab9670d501..c9289bbcfb3 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -329,7 +329,6 @@ func (t *Translator) translateSecurityPolicyForRoute( var ( cors *ir.CORS jwt *ir.JWT - oidc *ir.OIDC basicAuth *ir.BasicAuth authorization *ir.Authorization err, errs error @@ -343,15 +342,6 @@ func (t *Translator) translateSecurityPolicyForRoute( jwt = t.buildJWT(policy.Spec.JWT) } - if policy.Spec.OIDC != nil { - if oidc, err = t.buildOIDC( - policy, - resources); err != nil { - err = perr.WithMessage(err, "OIDC") - errs = errors.Join(errs, err) - } - } - if policy.Spec.BasicAuth != nil { if basicAuth, err = t.buildBasicAuth( policy, @@ -388,6 +378,18 @@ func (t *Translator) translateSecurityPolicyForRoute( errs = errors.Join(errs, err) } } + + var oidc *ir.OIDC + if policy.Spec.OIDC != nil { + if oidc, err = t.buildOIDC( + policy, + resources, + gtwCtx.envoyProxy); err != nil { + err = perr.WithMessage(err, "OIDC") + errs = errors.Join(errs, err) + } + } + irKey := t.getIRKey(gtwCtx.Gateway) for _, listener := range parentRefCtx.listeners { irListener := xdsIR[irKey].GetHTTPListener(irListenerName(listener)) @@ -445,7 +447,8 @@ func (t *Translator) translateSecurityPolicyForGateway( if policy.Spec.OIDC != nil { if oidc, err = t.buildOIDC( policy, - resources); err != nil { + resources, + gateway.envoyProxy); err != nil { err = perr.WithMessage(err, "OIDC") errs = errors.Join(errs, err) } @@ -566,19 +569,30 @@ func (t *Translator) buildJWT(jwt *egv1a1.JWT) *ir.JWT { func (t *Translator) buildOIDC( policy *egv1a1.SecurityPolicy, resources *resource.Resources, + envoyProxy *egv1a1.EnvoyProxy, ) (*ir.OIDC, error) { var ( - oidc = policy.Spec.OIDC - clientSecret *corev1.Secret - provider *ir.OIDCProvider - err error + oidc = policy.Spec.OIDC + provider *ir.OIDCProvider + clientSecret *corev1.Secret + redirectURL = defaultRedirectURL + redirectPath = defaultRedirectPath + logoutPath = defaultLogoutPath + forwardAccessToken = defaultForwardAccessToken + refreshToken = defaultRefreshToken + err error ) + if provider, err = t.buildOIDCProvider(policy, resources, envoyProxy); err != nil { + return nil, err + } + from := crossNamespaceFrom{ group: egv1a1.GroupName, kind: resource.KindSecurityPolicy, namespace: policy.Namespace, } + if clientSecret, err = t.validateSecretRef( false, from, oidc.ClientSecret, resources); err != nil { return nil, err @@ -591,25 +605,8 @@ func (t *Translator) buildOIDC( clientSecret.Namespace, clientSecret.Name) } - // Discover the token and authorization endpoints from the issuer's - // well-known url if not explicitly specified - if provider, err = discoverEndpointsFromIssuer(&oidc.Provider); err != nil { - return nil, err - } - - if err = validateTokenEndpoint(provider.TokenEndpoint); err != nil { - return nil, err - } scopes := appendOpenidScopeIfNotExist(oidc.Scopes) - var ( - redirectURL = defaultRedirectURL - redirectPath = defaultRedirectPath - logoutPath = defaultLogoutPath - forwardAccessToken = defaultForwardAccessToken - refreshToken = defaultRefreshToken - ) - if oidc.RedirectURL != nil { path, err := extractRedirectPath(*oidc.RedirectURL) if err != nil { @@ -668,6 +665,62 @@ func (t *Translator) buildOIDC( }, nil } +func (t *Translator) buildOIDCProvider(policy *egv1a1.SecurityPolicy, resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy) (*ir.OIDCProvider, error) { + var ( + provider = policy.Spec.OIDC.Provider + tokenEndpoint string + authorizationEndpoint string + protocol ir.AppProtocol + rd *ir.RouteDestination + traffic *ir.TrafficFeatures + err error + ) + + // Discover the token and authorization endpoints from the issuer's + // well-known url if not explicitly specified + if provider.TokenEndpoint == nil || provider.AuthorizationEndpoint == nil { + tokenEndpoint, authorizationEndpoint, err = fetchEndpointsFromIssuer(provider.Issuer) + if err != nil { + return nil, fmt.Errorf("error fetching endpoints from issuer: %w", err) + } + } else { + tokenEndpoint = *provider.TokenEndpoint + authorizationEndpoint = *provider.AuthorizationEndpoint + } + + if err = validateTokenEndpoint(tokenEndpoint); err != nil { + return nil, err + } + + u, err := url.Parse(tokenEndpoint) + if err != nil { + return nil, err + } + + if u.Scheme == "https" { + protocol = ir.HTTPS + } else { + protocol = ir.HTTP + } + + if len(provider.BackendRefs) > 0 { + if rd, err = t.translateExtServiceBackendRefs(policy, provider.BackendRefs, protocol, resources, envoyProxy, 0); err != nil { + return nil, err + } + } + + if traffic, err = translateTrafficFeatures(provider.BackendSettings); err != nil { + return nil, err + } + + return &ir.OIDCProvider{ + Destination: rd, + Traffic: traffic, + AuthorizationEndpoint: authorizationEndpoint, + TokenEndpoint: tokenEndpoint, + }, nil +} + func extractRedirectPath(redirectURL string) (string, error) { schemeDelimiter := strings.Index(redirectURL, "://") if schemeDelimiter <= 0 { @@ -712,26 +765,6 @@ type OpenIDConfig struct { AuthorizationEndpoint string `json:"authorization_endpoint"` } -// discoverEndpointsFromIssuer discovers the token and authorization endpoints from the issuer's well-known url -// return error if failed to fetch the well-known configuration -func discoverEndpointsFromIssuer(provider *egv1a1.OIDCProvider) (*ir.OIDCProvider, error) { - if provider.TokenEndpoint == nil || provider.AuthorizationEndpoint == nil { - tokenEndpoint, authorizationEndpoint, err := fetchEndpointsFromIssuer(provider.Issuer) - if err != nil { - return nil, fmt.Errorf("error fetching endpoints from issuer: %w", err) - } - return &ir.OIDCProvider{ - TokenEndpoint: tokenEndpoint, - AuthorizationEndpoint: authorizationEndpoint, - }, nil - } - - return &ir.OIDCProvider{ - TokenEndpoint: *provider.TokenEndpoint, - AuthorizationEndpoint: *provider.AuthorizationEndpoint, - }, nil -} - func fetchEndpointsFromIssuer(issuerURL string) (string, string, error) { // Fetch the OpenID configuration from the issuer URL resp, err := http.Get(fmt.Sprintf("%s/.well-known/openid-configuration", issuerURL)) @@ -811,7 +844,7 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *reso grpc = policy.Spec.ExtAuth.GRPC backends *egv1a1.BackendCluster protocol ir.AppProtocol - ds []*ir.DestinationSetting + rd *ir.RouteDestination authority string err error traffic *ir.TrafficFeatures @@ -833,12 +866,12 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *reso backends = &grpc.BackendCluster protocol = ir.GRPC } - pnn := utils.NamespacedName(policy) - for _, backendRef := range backends.BackendRefs { - if err = t.validateExtServiceBackendReference(&backendRef.BackendObjectReference, policy.Namespace, policy.Kind, resources); err != nil { - return nil, err - } + if rd, err = t.translateExtServiceBackendRefs(policy, backends.BackendRefs, protocol, resources, envoyProxy, 0); err != nil { + return nil, err + } + + for _, backendRef := range backends.BackendRefs { // Authority is the calculated hostname that will be used as the Authority header. // If there are multiple backend referenced, simply use the first one - there are no good answers here. // When translated to XDS, the authority is used on the filter level not on the cluster level. @@ -846,23 +879,6 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *reso if authority == "" { authority = backendRefAuthority(resources, &backendRef.BackendObjectReference, policy) } - - extServiceDest, err := t.processExtServiceDestination( - &backendRef, - pnn, - resource.KindSecurityPolicy, - protocol, - resources, - envoyProxy, - ) - if err != nil { - return nil, err - } - ds = append(ds, extServiceDest) - } - rd := ir.RouteDestination{ - Name: irIndexedExtServiceDestinationName(pnn, resource.KindSecurityPolicy, 0), - Settings: ds, } if traffic, err = translateTrafficFeatures(backends.BackendSettings); err != nil { @@ -878,14 +894,14 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *reso if http != nil { extAuth.HTTP = &ir.HTTPExtAuthService{ - Destination: rd, + Destination: *rd, Authority: authority, Path: ptr.Deref(http.Path, ""), HeadersToBackend: http.HeadersToBackend, } } else { extAuth.GRPC = &ir.GRPCExtAuthService{ - Destination: rd, + Destination: *rd, Authority: authority, } } diff --git a/internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.in.yaml b/internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.in.yaml new file mode 100644 index 00000000000..67b051e4b31 --- /dev/null +++ b/internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.in.yaml @@ -0,0 +1,101 @@ +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: client1-secret + data: + client-secret: Y2xpZW50MTpzZWNyZXQK +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway-system + name: envoy-oidc-hmac + data: + hmac-secret: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= +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 +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - www.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/foo" + backendRefs: + - name: service-1 + port: 8080 +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-fqdn + namespace: envoy-gateway + spec: + endpoints: + - fqdn: + hostname: 'oauth.foo.com' + port: 443 +securityPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway + uid: b8284d0f-de82-4c65-b204-96a0d3f258a1 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + oidc: + provider: + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-fqdn + port: 443 + backendSettings: + retry: + numRetries: 3 + perRetry: + backOff: + baseInterval: 1s + maxInterval: 5s + retryOn: + triggers: ["5xx", "gateway-error", "reset"] + issuer: "https://oauth.foo.com" + authorizationEndpoint: "https://oauth.foo.com/oauth2/v2/auth" + tokenEndpoint: "https://oauth.foo.com/token" + clientID: "client1.apps.googleusercontent.com" + clientSecret: + name: "client1-secret" + redirectURL: "https://www.example.com/bar/oauth2/callback" + logoutPath: "/bar/logout" + forwardAccessToken: true + defaultTokenTTL: 30m + refreshToken: true + defaultRefreshTokenTTL: 24h diff --git a/internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.out.yaml new file mode 100644 index 00000000000..d6f0c4dbc47 --- /dev/null +++ b/internal/gatewayapi/testdata/securitypolicy-with-oidc-backendcluster.out.yaml @@ -0,0 +1,256 @@ +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + creationTimestamp: null + name: backend-fqdn + namespace: envoy-gateway + spec: + endpoints: + - fqdn: + hostname: oauth.foo.com + port: 443 + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +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 +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + hostnames: + - www.example.com + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: /foo + 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: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + 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 +securityPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + creationTimestamp: null + name: policy-for-gateway + namespace: envoy-gateway + uid: b8284d0f-de82-4c65-b204-96a0d3f258a1 + spec: + oidc: + clientID: client1.apps.googleusercontent.com + clientSecret: + group: null + kind: null + name: client1-secret + defaultRefreshTokenTTL: 24h0m0s + defaultTokenTTL: 30m0s + forwardAccessToken: true + logoutPath: /bar/logout + provider: + authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-fqdn + port: 443 + backendSettings: + retry: + numRetries: 3 + perRetry: + backOff: + baseInterval: 1s + maxInterval: 5s + retryOn: + triggers: + - 5xx + - gateway-error + - reset + issuer: https://oauth.foo.com + tokenEndpoint: https://oauth.foo.com/token + redirectURL: https://www.example.com/bar/oauth2/callback + refreshToken: true + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +xdsIR: + envoy-gateway/gateway-1: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + hostname: www.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /foo + security: + oidc: + clientID: client1.apps.googleusercontent.com + clientSecret: Y2xpZW50MTpzZWNyZXQK + cookieSuffix: b0a1b740 + defaultRefreshTokenTTL: 24h0m0s + defaultTokenTTL: 30m0s + forwardAccessToken: true + hmacSecret: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= + logoutPath: /bar/logout + name: securitypolicy/envoy-gateway/policy-for-gateway + provider: + authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth + destination: + name: securitypolicy/envoy-gateway/policy-for-gateway/0 + settings: + - addressType: FQDN + endpoints: + - host: oauth.foo.com + port: 443 + protocol: HTTPS + weight: 1 + tokenEndpoint: https://oauth.foo.com/token + traffic: + retry: + numRetries: 3 + perRetry: + backOff: + baseInterval: 1s + maxInterval: 5s + retryOn: + triggers: + - 5xx + - gateway-error + - reset + redirectPath: /bar/oauth2/callback + redirectURL: https://www.example.com/bar/oauth2/callback + refreshToken: true + scopes: + - openid diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 49d6fdbf064..fdcace324f5 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -848,7 +848,16 @@ type OIDC struct { CookieDomain *string `json:"cookieDomain,omitempty"` } +// OIDCProvider defines the schema for the OIDC Provider. +// +// +k8s:deepcopy-gen=true type OIDCProvider struct { + // Destination defines the destination for the OIDC Provider. + Destination *RouteDestination `json:"destination,omitempty"` + + // Traffic contains configuration for traffic features for the OIDC Provider + Traffic *TrafficFeatures `json:"traffic,omitempty"` + // The OIDC Provider's [authorization endpoint](https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint). AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"` diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 1a0185bbb9f..3c0c1135f44 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -1900,7 +1900,7 @@ func (in *Metrics) DeepCopy() *Metrics { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OIDC) DeepCopyInto(out *OIDC) { *out = *in - out.Provider = in.Provider + in.Provider.DeepCopyInto(&out.Provider) if in.ClientSecret != nil { in, out := &in.ClientSecret, &out.ClientSecret *out = make([]byte, len(*in)) @@ -1953,6 +1953,31 @@ func (in *OIDC) DeepCopy() *OIDC { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OIDCProvider) DeepCopyInto(out *OIDCProvider) { + *out = *in + if in.Destination != nil { + in, out := &in.Destination, &out.Destination + *out = new(RouteDestination) + (*in).DeepCopyInto(*out) + } + if in.Traffic != nil { + in, out := &in.Traffic, &out.Traffic + *out = new(TrafficFeatures) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProvider. +func (in *OIDCProvider) DeepCopy() *OIDCProvider { + if in == nil { + return nil + } + out := new(OIDCProvider) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenTelemetryAccessLog) DeepCopyInto(out *OpenTelemetryAccessLog) { *out = *in diff --git a/internal/xds/translator/oidc.go b/internal/xds/translator/oidc.go index 41228a1d209..963b7c8046d 100644 --- a/internal/xds/translator/oidc.go +++ b/internal/xds/translator/oidc.go @@ -102,14 +102,24 @@ func oauth2FilterName(oidc *ir.OIDC) string { } func oauth2Config(oidc *ir.OIDC) (*oauth2v3.OAuth2, error) { - cluster, err := url2Cluster(oidc.Provider.TokenEndpoint) - if err != nil { - return nil, err - } - if cluster.endpointType == EndpointTypeStatic { - return nil, fmt.Errorf( - "static IP cluster is not allowed: %s", - oidc.Provider.TokenEndpoint) + var ( + tokenEndpointCluster string + err error + ) + + if oidc.Provider.Destination != nil && len(oidc.Provider.Destination.Settings) > 0 { + tokenEndpointCluster = oidc.Provider.Destination.Name + } else { + var cluster *urlCluster + if cluster, err = url2Cluster(oidc.Provider.TokenEndpoint); err != nil { + return nil, err + } + if cluster.endpointType == EndpointTypeStatic { + return nil, fmt.Errorf( + "static IP cluster is not allowed: %s", + oidc.Provider.TokenEndpoint) + } + tokenEndpointCluster = cluster.name } // Envoy OAuth2 filter deletes the HTTP authorization header by default, which surprises users. @@ -126,7 +136,7 @@ func oauth2Config(oidc *ir.OIDC) (*oauth2v3.OAuth2, error) { TokenEndpoint: &corev3.HttpUri{ Uri: oidc.Provider.TokenEndpoint, HttpUpstreamType: &corev3.HttpUri_Cluster{ - Cluster: cluster.name, + Cluster: tokenEndpointCluster, }, Timeout: &durationpb.Duration{ Seconds: defaultExtServiceRequestTimeout, @@ -210,9 +220,55 @@ func oauth2Config(oidc *ir.OIDC) (*oauth2v3.OAuth2, error) { oauth2.Config.Credentials.CookieDomain = *oidc.CookieDomain } + // Set the retry policy if it exists. + if oidc.Provider.Traffic != nil && oidc.Provider.Traffic.Retry != nil { + var rp *corev3.RetryPolicy + if rp, err = buildNonRouteRetryPolicy(oidc.Provider.Traffic.Retry); err != nil { + return nil, err + } + oauth2.Config.RetryPolicy = rp + } return oauth2, nil } +func buildNonRouteRetryPolicy(rr *ir.Retry) (*corev3.RetryPolicy, error) { + rp := &corev3.RetryPolicy{ + RetryOn: retryDefaultRetryOn, + } + + // These two fields in the RetryPolicy are just for route-level retries, they are not used for non-route retries. + // retry.PerRetry.Timeout + // retry.RetryOn.HTTPStatusCodes + + if rr.PerRetry != nil && rr.PerRetry.BackOff != nil { + rp.RetryBackOff = &corev3.BackoffStrategy{ + BaseInterval: &durationpb.Duration{ + Seconds: int64(rr.PerRetry.BackOff.BaseInterval.Seconds()), + }, + MaxInterval: &durationpb.Duration{ + Seconds: int64(rr.PerRetry.BackOff.MaxInterval.Seconds()), + }, + } + } + + if rr.NumRetries != nil { + rp.NumRetries = &wrappers.UInt32Value{ + Value: *rr.NumRetries, + } + } + + if rr.RetryOn != nil { + if len(rr.RetryOn.Triggers) > 0 { + if ro, err := buildRetryOn(rr.RetryOn.Triggers); err == nil { + rp.RetryOn = ro + } else { + return nil, err + } + } + } + return rp, nil +} + // routeContainsOIDC returns true if OIDC exists for the provided route. func routeContainsOIDC(irRoute *ir.HTTPRoute) bool { if irRoute != nil && @@ -226,7 +282,7 @@ func routeContainsOIDC(irRoute *ir.HTTPRoute) bool { func (*oidc) patchResources(tCtx *types.ResourceVersionTable, routes []*ir.HTTPRoute, ) error { - if err := createOAuth2TokenEndpointClusters(tCtx, routes); err != nil { + if err := createOAuthServerClusters(tCtx, routes); err != nil { return err } if err := createOAuth2Secrets(tCtx, routes); err != nil { @@ -235,9 +291,8 @@ func (*oidc) patchResources(tCtx *types.ResourceVersionTable, return nil } -// createOAuth2TokenEndpointClusters creates token endpoint clusters from the -// provided routes, if needed. -func createOAuth2TokenEndpointClusters(tCtx *types.ResourceVersionTable, +// createOAuthServerClusters creates clusters for the OAuth2 server. +func createOAuthServerClusters(tCtx *types.ResourceVersionTable, routes []*ir.HTTPRoute, ) error { if tCtx == nil || tCtx.XdsResources == nil { @@ -250,59 +305,78 @@ func createOAuth2TokenEndpointClusters(tCtx *types.ResourceVersionTable, continue } - var ( - cluster *urlCluster - ds *ir.DestinationSetting - tSocket *corev3.TransportSocket - err error - ) + oidc := route.Security.OIDC - cluster, err = url2Cluster(route.Security.OIDC.Provider.TokenEndpoint) - if err != nil { - errs = errors.Join(errs, err) - continue + // If the OIDC provider has a destination, use it. + if oidc.Provider.Destination != nil && len(oidc.Provider.Destination.Settings) > 0 { + if err := createExtServiceXDSCluster( + oidc.Provider.Destination, oidc.Provider.Traffic, tCtx); err != nil && !errors.Is( + err, ErrXdsClusterExists) { + errs = errors.Join(errs, err) + } + } else { + // Create a cluster with the token endpoint url. + if err := createOAuth2TokenEndpointCluster(tCtx, oidc.Provider.TokenEndpoint); err != nil { + errs = errors.Join(errs, err) + } } + } - // EG does not support static IP clusters for token endpoint clusters. - // This validation could be removed since it's already validated in the - // Gateway API translator. - if cluster.endpointType == EndpointTypeStatic { - errs = errors.Join(errs, fmt.Errorf( - "static IP cluster is not allowed: %s", - route.Security.OIDC.Provider.TokenEndpoint)) - continue - } + return errs +} - ds = &ir.DestinationSetting{ - Weight: ptr.To[uint32](1), - Endpoints: []*ir.DestinationEndpoint{ - ir.NewDestEndpoint( - cluster.hostname, - cluster.port), - }, - } +// createOAuth2TokenEndpointClusters creates token endpoint clusters from the +// provided routes, if needed. +func createOAuth2TokenEndpointCluster(tCtx *types.ResourceVersionTable, + tokenEndpoint string, +) error { + var ( + cluster *urlCluster + ds *ir.DestinationSetting + tSocket *corev3.TransportSocket + err error + ) + + if cluster, err = url2Cluster(tokenEndpoint); err != nil { + return err + } - clusterArgs := &xdsClusterArgs{ - name: cluster.name, - settings: []*ir.DestinationSetting{ds}, - tSocket: tSocket, - endpointType: cluster.endpointType, - } - if cluster.tls { - tSocket, err = buildXdsUpstreamTLSSocket(cluster.hostname) - if err != nil { - errs = errors.Join(errs, err) - continue - } - clusterArgs.tSocket = tSocket - } + // EG does not support static IP clusters for token endpoint clusters. + // This validation could be removed since it's already validated in the + // Gateway API translator. + if cluster.endpointType == EndpointTypeStatic { + return fmt.Errorf( + "static IP cluster is not allowed: %s", + tokenEndpoint) + } - if err = addXdsCluster(tCtx, clusterArgs); err != nil && !errors.Is(err, ErrXdsClusterExists) { - errs = errors.Join(errs, err) + ds = &ir.DestinationSetting{ + Weight: ptr.To[uint32](1), + Endpoints: []*ir.DestinationEndpoint{ + ir.NewDestEndpoint( + cluster.hostname, + cluster.port), + }, + } + + clusterArgs := &xdsClusterArgs{ + name: cluster.name, + settings: []*ir.DestinationSetting{ds}, + tSocket: tSocket, + endpointType: cluster.endpointType, + } + if cluster.tls { + if tSocket, err = buildXdsUpstreamTLSSocket(cluster.hostname); err != nil { + return err } + clusterArgs.tSocket = tSocket } - return errs + if err = addXdsCluster(tCtx, clusterArgs); err != nil && !errors.Is(err, ErrXdsClusterExists) { + return err + } + + return err } // createOAuth2Secrets creates OAuth2 client and HMAC secrets from the provided diff --git a/internal/xds/translator/testdata/in/xds-ir/oidc-backend-cluster-provider.yaml b/internal/xds/translator/testdata/in/xds-ir/oidc-backend-cluster-provider.yaml new file mode 100644 index 00000000000..6fc9a045bca --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/oidc-backend-cluster-provider.yaml @@ -0,0 +1,60 @@ +http: +- name: "first-listener" + address: "0.0.0.0" + port: 10080 + hostnames: + - "*" + path: + mergeSlashes: true + escapedSlashesAction: UnescapeAndRedirect + routes: + - name: "first-route" + hostname: "*" + pathMatch: + exact: "baz" + destination: + name: "third-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + security: + oidc: + name: securitypolicy/envoy-gateway/policy-for-gateway + clientID: client1.apps.googleusercontent.com + clientSecret: Y2xpZW50MTpzZWNyZXQK + cookieSuffix: b0a1b740 + defaultRefreshTokenTTL: 24h0m0s + defaultTokenTTL: 30m0s + forwardAccessToken: true + hmacSecret: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= + logoutPath: /bar/logout + provider: + authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth + destination: + name: securitypolicy/envoy-gateway/policy-for-gateway/0 + settings: + - addressType: FQDN + endpoints: + - host: oauth.foo.com + port: 443 + protocol: HTTPS + weight: 1 + tokenEndpoint: https://oauth.foo.com/token + traffic: + retry: + numRetries: 3 + perRetry: + backOff: + baseInterval: 1s + maxInterval: 5s + retryOn: + triggers: + - "5xx" + - gateway-error + - reset + redirectPath: /bar/oauth2/callback + redirectURL: https://www.example.com/bar/oauth2/callback + refreshToken: true + scopes: + - openid diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.clusters.yaml new file mode 100644 index 00000000000..863e761bf9a --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.clusters.yaml @@ -0,0 +1,44 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + 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 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: securitypolicy/envoy-gateway/policy-for-gateway/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: oauth.foo.com + portValue: 443 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: securitypolicy/envoy-gateway/policy-for-gateway/0/backend/0 + name: securitypolicy/envoy-gateway/policy-for-gateway/0 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.endpoints.yaml new file mode 100644 index 00000000000..6c69841c2ad --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.endpoints.yaml @@ -0,0 +1,12 @@ +- clusterName: third-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: third-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.listeners.yaml new file mode 100644 index 00000000000..3addb294484 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.listeners.yaml @@ -0,0 +1,83 @@ +- 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: + - disabled: true + name: envoy.filters.http.oauth2/securitypolicy/envoy-gateway/policy-for-gateway + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.oauth2.v3.OAuth2 + config: + authScopes: + - openid + authType: BASIC_AUTH + authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth + credentials: + clientId: client1.apps.googleusercontent.com + cookieNames: + bearerToken: AccessToken-b0a1b740 + idToken: IdToken-b0a1b740 + oauthExpires: OauthExpires-b0a1b740 + oauthHmac: OauthHMAC-b0a1b740 + oauthNonce: OauthNonce-b0a1b740 + refreshToken: RefreshToken-b0a1b740 + hmacSecret: + name: oauth2/hmac_secret/securitypolicy/envoy-gateway/policy-for-gateway + sdsConfig: + ads: {} + resourceApiVersion: V3 + tokenSecret: + name: oauth2/client_secret/securitypolicy/envoy-gateway/policy-for-gateway + sdsConfig: + ads: {} + resourceApiVersion: V3 + defaultExpiresIn: 1800s + defaultRefreshTokenExpiresIn: 86400s + forwardBearerToken: true + redirectPathMatcher: + path: + exact: /bar/oauth2/callback + redirectUri: https://www.example.com/bar/oauth2/callback + retryPolicy: + numRetries: 3 + retryBackOff: + baseInterval: 1s + maxInterval: 5s + retryOn: 5xx,gateway-error,reset + signoutPath: + path: + exact: /bar/logout + tokenEndpoint: + cluster: securitypolicy/envoy-gateway/policy-for-gateway/0 + timeout: 10s + uri: https://oauth.foo.com/token + useRefreshToken: true + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: first-listener + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: first-listener + name: first-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.routes.yaml new file mode 100644 index 00000000000..b17df86476d --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.routes.yaml @@ -0,0 +1,18 @@ +- ignorePortInHostMatching: true + name: first-listener + virtualHosts: + - domains: + - '*' + name: first-listener/* + routes: + - match: + path: baz + name: first-route + route: + cluster: third-route-dest + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.oauth2/securitypolicy/envoy-gateway/policy-for-gateway: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + config: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.secrets.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.secrets.yaml new file mode 100644 index 00000000000..398ab6cef7b --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backencluster-provider.secrets.yaml @@ -0,0 +1,8 @@ +- genericSecret: + secret: + inlineBytes: Y2xpZW50MTpzZWNyZXQK + name: oauth2/client_secret/securitypolicy/envoy-gateway/policy-for-gateway +- genericSecret: + secret: + inlineBytes: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= + name: oauth2/hmac_secret/securitypolicy/envoy-gateway/policy-for-gateway diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.clusters.yaml new file mode 100644 index 00000000000..863e761bf9a --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.clusters.yaml @@ -0,0 +1,44 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + 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 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_ONLY + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: securitypolicy/envoy-gateway/policy-for-gateway/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: oauth.foo.com + portValue: 443 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: securitypolicy/envoy-gateway/policy-for-gateway/0/backend/0 + name: securitypolicy/envoy-gateway/policy-for-gateway/0 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.endpoints.yaml new file mode 100644 index 00000000000..6c69841c2ad --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.endpoints.yaml @@ -0,0 +1,12 @@ +- clusterName: third-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: third-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml new file mode 100644 index 00000000000..3addb294484 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml @@ -0,0 +1,83 @@ +- 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: + - disabled: true + name: envoy.filters.http.oauth2/securitypolicy/envoy-gateway/policy-for-gateway + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.oauth2.v3.OAuth2 + config: + authScopes: + - openid + authType: BASIC_AUTH + authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth + credentials: + clientId: client1.apps.googleusercontent.com + cookieNames: + bearerToken: AccessToken-b0a1b740 + idToken: IdToken-b0a1b740 + oauthExpires: OauthExpires-b0a1b740 + oauthHmac: OauthHMAC-b0a1b740 + oauthNonce: OauthNonce-b0a1b740 + refreshToken: RefreshToken-b0a1b740 + hmacSecret: + name: oauth2/hmac_secret/securitypolicy/envoy-gateway/policy-for-gateway + sdsConfig: + ads: {} + resourceApiVersion: V3 + tokenSecret: + name: oauth2/client_secret/securitypolicy/envoy-gateway/policy-for-gateway + sdsConfig: + ads: {} + resourceApiVersion: V3 + defaultExpiresIn: 1800s + defaultRefreshTokenExpiresIn: 86400s + forwardBearerToken: true + redirectPathMatcher: + path: + exact: /bar/oauth2/callback + redirectUri: https://www.example.com/bar/oauth2/callback + retryPolicy: + numRetries: 3 + retryBackOff: + baseInterval: 1s + maxInterval: 5s + retryOn: 5xx,gateway-error,reset + signoutPath: + path: + exact: /bar/logout + tokenEndpoint: + cluster: securitypolicy/envoy-gateway/policy-for-gateway/0 + timeout: 10s + uri: https://oauth.foo.com/token + useRefreshToken: true + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: first-listener + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: first-listener + name: first-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.routes.yaml new file mode 100644 index 00000000000..b17df86476d --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.routes.yaml @@ -0,0 +1,18 @@ +- ignorePortInHostMatching: true + name: first-listener + virtualHosts: + - domains: + - '*' + name: first-listener/* + routes: + - match: + path: baz + name: first-route + route: + cluster: third-route-dest + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.oauth2/securitypolicy/envoy-gateway/policy-for-gateway: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + config: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.secrets.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.secrets.yaml new file mode 100644 index 00000000000..398ab6cef7b --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.secrets.yaml @@ -0,0 +1,8 @@ +- genericSecret: + secret: + inlineBytes: Y2xpZW50MTpzZWNyZXQK + name: oauth2/client_secret/securitypolicy/envoy-gateway/policy-for-gateway +- genericSecret: + secret: + inlineBytes: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= + name: oauth2/hmac_secret/securitypolicy/envoy-gateway/policy-for-gateway diff --git a/test/cel-validation/securitypolicy_test.go b/test/cel-validation/securitypolicy_test.go index c4efa812d58..f00ee84260c 100644 --- a/test/cel-validation/securitypolicy_test.go +++ b/test/cel-validation/securitypolicy_test.go @@ -18,6 +18,7 @@ import ( "k8s.io/utils/ptr" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" ) @@ -1121,6 +1122,103 @@ func TestSecurityPolicyTarget(t *testing.T) { }, wantErrors: []string{"at least one of claims or scopes must be specified"}, }, + { + desc: "oidc-retry", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{ + PolicyTargetReferences: egv1a1.PolicyTargetReferences{ + TargetSelectors: []egv1a1.TargetSelector{ + { + Group: ptr.To(gwapiv1a2.Group("gateway.networking.k8s.io")), + Kind: "HTTPRoute", + MatchLabels: map[string]string{ + "eg/namespace": "reference-apps", + }, + }, + }, + }, + OIDC: &egv1a1.OIDC{ + Provider: egv1a1.OIDCProvider{ + BackendCluster: egv1a1.BackendCluster{ + BackendSettings: &egv1a1.ClusterSettings{ + Retry: &egv1a1.Retry{ + NumRetries: ptr.To(int32(3)), + PerRetry: &egv1a1.PerRetryPolicy{ + BackOff: &egv1a1.BackOffPolicy{ + BaseInterval: &metav1.Duration{ + Duration: time.Second * 1, + }, + MaxInterval: &metav1.Duration{ + Duration: time.Second * 10, + }, + }, + }, + RetryOn: &egv1a1.RetryOn{ + Triggers: []egv1a1.TriggerEnum{ + egv1a1.Error5XX, egv1a1.GatewayError, egv1a1.Reset, + }, + }, + }, + }, + }, + Issuer: "https://accounts.google.com", + AuthorizationEndpoint: ptr.To("https://accounts.google.com/o/oauth2/v2/auth"), + TokenEndpoint: ptr.To("https://oauth2.googleapis.com/token"), + }, + ClientID: "client-id", + ClientSecret: gwapiv1b1.SecretObjectReference{ + Name: "secret", + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "oidc-retry-unsupported-parameters", + mutate: func(sp *egv1a1.SecurityPolicy) { + sp.Spec = egv1a1.SecurityPolicySpec{ + PolicyTargetReferences: egv1a1.PolicyTargetReferences{ + TargetSelectors: []egv1a1.TargetSelector{ + { + Group: ptr.To(gwapiv1a2.Group("gateway.networking.k8s.io")), + Kind: "HTTPRoute", + MatchLabels: map[string]string{ + "eg/namespace": "reference-apps", + }, + }, + }, + }, + OIDC: &egv1a1.OIDC{ + Provider: egv1a1.OIDCProvider{ + BackendCluster: egv1a1.BackendCluster{ + BackendSettings: &egv1a1.ClusterSettings{ + Retry: &egv1a1.Retry{ + NumRetries: ptr.To(int32(3)), + PerRetry: &egv1a1.PerRetryPolicy{ + Timeout: &metav1.Duration{ + Duration: time.Second * 10, + }, + }, + RetryOn: &egv1a1.RetryOn{ + HTTPStatusCodes: []egv1a1.HTTPStatus{500}, + }, + }, + }, + }, + Issuer: "https://accounts.google.com", + AuthorizationEndpoint: ptr.To("https://accounts.google.com/o/oauth2/v2/auth"), + TokenEndpoint: ptr.To("https://oauth2.googleapis.com/token"), + }, + ClientID: "client-id", + ClientSecret: gwapiv1b1.SecretObjectReference{ + Name: "secret", + }, + }, + } + }, + wantErrors: []string{"Retry timeout is not supported", "HTTPStatusCodes is not supported"}, + }, } for _, tc := range cases { diff --git a/test/e2e/testdata/oidc-securitypolicy-backendcluster.yaml b/test/e2e/testdata/oidc-securitypolicy-backendcluster.yaml new file mode 100644 index 00000000000..2e1a86791ec --- /dev/null +++ b/test/e2e/testdata/oidc-securitypolicy-backendcluster.yaml @@ -0,0 +1,86 @@ +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-with-oidc + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + hostnames: ["www.example.com"] + rules: + - matches: + - path: + type: PathPrefix + value: /myapp # This is the path that will be protected by OIDC + backendRefs: + - name: infra-backend-v1 + port: 8080 +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-keycloak + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + hostnames: ["keycloak.gateway-conformance-infra"] + rules: + - backendRefs: + - name: keycloak + port: 80 +--- +apiVersion: v1 +kind: Secret +metadata: + namespace: gateway-conformance-infra + name: oidctest-secret +data: + client-secret: b2lkY3Rlc3QtY2xpZW50LXNlY3JldA== # base64 encoding of "oidctest-client-secret" +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: oidc-test # Test OIDC Provider represented by a backend cluster + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: http-with-oidc + oidc: + provider: + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-keycloak + port: 80 + backendSettings: + retry: + numRetries: 3 + perRetry: + backOff: + baseInterval: 1s + maxInterval: 5s + retryOn: + triggers: ["5xx", "gateway-error", "reset"] + issuer: "http://keycloak.gateway-conformance-infra/realms/master" + authorizationEndpoint: "http://keycloak.gateway-conformance-infra/realms/master/protocol/openid-connect/auth" + tokenEndpoint: "http://keycloak.gateway-conformance-infra/realms/master/protocol/openid-connect/token" + clientID: "oidctest" + clientSecret: + name: "oidctest-secret" + redirectURL: "http://www.example.com/myapp/oauth2/callback" + logoutPath: "/myapp/logout" +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: Backend +metadata: + name: backend-keycloak + namespace: gateway-conformance-infra +spec: + endpoints: + - fqdn: + hostname: 'keycloak.gateway-conformance-infra' + port: 80 diff --git a/test/e2e/tests/oidc-backendcluster.go b/test/e2e/tests/oidc-backendcluster.go new file mode 100644 index 00000000000..b2bcc93cecb --- /dev/null +++ b/test/e2e/tests/oidc-backendcluster.go @@ -0,0 +1,37 @@ +// 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. + +//go:build e2e +// +build e2e + +package tests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/suite" +) + +func init() { + ConformanceTests = append(ConformanceTests, OIDCBackendClusterTest) +} + +// OIDCTest tests OIDC authentication for an http route with OIDC configured. +// The http route points to an application to verify that OIDC authentication works on application/http path level. +var OIDCBackendClusterTest = suite.ConformanceTest{ + ShortName: "OIDC with BackendCluster", + Description: "Test OIDC authentication", + Manifests: []string{"testdata/oidc-keycloak.yaml", "testdata/oidc-securitypolicy-backendcluster.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("oidc provider represented by a BackendCluster", func(t *testing.T) { + // Add a function to dump current cluster status + t.Cleanup(func() { + CollectAndDump(t, suite.RestConfig) + }) + + testOIDC(t, suite) + }) + }, +} diff --git a/test/e2e/tests/oidc.go b/test/e2e/tests/oidc.go index 27fb79be9b3..f03512c1e27 100644 --- a/test/e2e/tests/oidc.go +++ b/test/e2e/tests/oidc.go @@ -31,8 +31,6 @@ import ( ) const ( - testURL = "http://www.example.com/myapp" - logoutURL = "http://www.example.com/myapp/logout" keyCloakLoginFormID = "kc-form-login" username = "oidcuser" password = "oidcpassword" @@ -49,100 +47,13 @@ var OIDCTest = suite.ConformanceTest{ Description: "Test OIDC authentication", Manifests: []string{"testdata/oidc-keycloak.yaml", "testdata/oidc-securitypolicy.yaml"}, Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { - t.Run("http route with oidc authentication", func(t *testing.T) { + t.Run("oidc provider represented by a URL", func(t *testing.T) { // Add a function to dump current cluster status t.Cleanup(func() { CollectAndDump(t, suite.RestConfig) }) - ns := "gateway-conformance-infra" - routeNN := types.NamespacedName{Name: "http-with-oidc", Namespace: ns} - gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} - gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) - - ancestorRef := gwapiv1a2.ParentReference{ - Group: gatewayapi.GroupPtr(gwapiv1.GroupName), - Kind: gatewayapi.KindPtr(resource.KindGateway), - Namespace: gatewayapi.NamespacePtr(gwNN.Namespace), - Name: gwapiv1.ObjectName(gwNN.Name), - } - SecurityPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "oidc-test", Namespace: ns}, suite.ControllerName, ancestorRef) - podInitialized := corev1.PodCondition{Type: corev1.PodInitialized, Status: corev1.ConditionTrue} - - // Wait for the keycloak pod to be configured with the test user and client - WaitForPods(t, suite.Client, ns, map[string]string{"job-name": "setup-keycloak"}, corev1.PodSucceeded, podInitialized) - - // Initialize the test OIDC client that will keep track of the state of the OIDC login process - client, err := NewOIDCTestClient( - WithLoggingOptions(t.Log, true), - // Map the application and keycloak cluster DNS name to the gateway address - WithCustomAddressMappings(map[string]string{ - "www.example.com:80": gwAddr, - "keycloak.gateway-conformance-infra:80": gwAddr, - }), - ) - require.NoError(t, err) - - if err := wait.PollUntilContextTimeout(context.TODO(), time.Second, 5*time.Minute, true, - func(_ context.Context) (done bool, err error) { - tlog.Logf(t, "sending request to %s", testURL) - - // Send a request to the http route with OIDC configured. - // It will be redirected to the keycloak login page - res, err := client.Get(testURL, true) - require.NoError(t, err, "Failed to get the login page") - require.Equal(t, 200, res.StatusCode, "Expected 200 OK") - - // Parse the response body to get the URL where the login page would post the user-entered credentials - if err := client.ParseLoginForm(res.Body, keyCloakLoginFormID); err != nil { - tlog.Logf(t, "failed to parse login form: %v", err) - return false, nil - } - - t.Log("successfully parsed login form") - return true, nil - }); err != nil { - t.Errorf("failed to parse login form: %v", err) - } - - // Submit the login form to the IdP. - // This will authenticate and redirect back to the application - res, err := client.Login(map[string]string{"username": username, "password": password, "credentialId": ""}) - require.NoError(t, err, "Failed to login to the IdP") - - // Verify that we get the expected response from the application - body, err := io.ReadAll(res.Body) - require.NoError(t, err) - require.Equal(t, http.StatusOK, res.StatusCode) - require.Contains(t, string(body), "infra-backend-v1", "Expected response from the application") - - // Verify that we can access the application without logging in again - res, err = client.Get(testURL, false) - require.NoError(t, err) - require.Equal(t, http.StatusOK, res.StatusCode) - require.Contains(t, string(body), "infra-backend-v1", "Expected response from the application") - - // Verify that we can logout - // Note: OAuth2 filter just clears its cookies and does not log out from the IdP. - res, err = client.Get(logoutURL, false) - require.NoError(t, err) - require.Equal(t, http.StatusFound, res.StatusCode) - - // After logout, OAuth2 filter will redirect back to the root of the host, e.g, "www.example.com". - // Ideally, this should redirect to the application's root, e.g, "www.example.com/myapp", - // but Envoy OAuth2 filter does not support this yet. - require.Equal(t, "http://www.example.com/", res.Header.Get("Location"), "Expected redirect to the root of the host") - - // Verify that the oauth2 cookies have been deleted - var cookieDeleted bool - deletedCookies := res.Header.Values("Set-Cookie") - regx := regexp.MustCompile("^IdToken-.+=deleted.+") - for _, cookie := range deletedCookies { - if regx.Match([]byte(cookie)) { - cookieDeleted = true - } - } - require.True(t, cookieDeleted, "IdToken cookie not deleted") + testOIDC(t, suite) }) t.Run("http route without oidc authentication", func(t *testing.T) { @@ -185,3 +96,102 @@ var OIDCTest = suite.ConformanceTest{ }) }, } + +func testOIDC(t *testing.T, suite *suite.ConformanceTestSuite) { + var ( + testURL = "http://www.example.com/myapp" + logoutURL = "http://www.example.com/myapp/logout" + route = "http-with-oidc" + sp = "oidc-test" + ns = "gateway-conformance-infra" + ) + + routeNN := types.NamespacedName{Name: route, Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + + ancestorRef := gwapiv1a2.ParentReference{ + Group: gatewayapi.GroupPtr(gwapiv1.GroupName), + Kind: gatewayapi.KindPtr(resource.KindGateway), + Namespace: gatewayapi.NamespacePtr(gwNN.Namespace), + Name: gwapiv1.ObjectName(gwNN.Name), + } + SecurityPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: sp, Namespace: ns}, suite.ControllerName, ancestorRef) + + podInitialized := corev1.PodCondition{Type: corev1.PodInitialized, Status: corev1.ConditionTrue} + + // Wait for the keycloak pod to be configured with the test user and client + WaitForPods(t, suite.Client, ns, map[string]string{"job-name": "setup-keycloak"}, corev1.PodSucceeded, podInitialized) + + // Initialize the test OIDC client that will keep track of the state of the OIDC login process + client, err := NewOIDCTestClient( + WithLoggingOptions(t.Log, true), + // Map the application and keycloak cluster DNS name to the gateway address + WithCustomAddressMappings(map[string]string{ + "www.example.com:80": gwAddr, + "keycloak.gateway-conformance-infra:80": gwAddr, + }), + ) + require.NoError(t, err) + + if err := wait.PollUntilContextTimeout(context.TODO(), time.Second, 5*time.Minute, true, + func(_ context.Context) (done bool, err error) { + tlog.Logf(t, "sending request to %s", testURL) + + // Send a request to the http route with OIDC configured. + // It will be redirected to the keycloak login page + res, err := client.Get(testURL, true) + require.NoError(t, err, "Failed to get the login page") + require.Equal(t, 200, res.StatusCode, "Expected 200 OK") + + // Parse the response body to get the URL where the login page would post the user-entered credentials + if err := client.ParseLoginForm(res.Body, keyCloakLoginFormID); err != nil { + tlog.Logf(t, "failed to parse login form: %v", err) + return false, nil + } + + t.Log("successfully parsed login form") + return true, nil + }); err != nil { + t.Errorf("failed to parse login form: %v", err) + } + + // Submit the login form to the IdP. + // This will authenticate and redirect back to the application + res, err := client.Login(map[string]string{"username": username, "password": password, "credentialId": ""}) + require.NoError(t, err, "Failed to login to the IdP") + + // Verify that we get the expected response from the application + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + require.Equal(t, http.StatusOK, res.StatusCode) + require.Contains(t, string(body), "infra-backend-v1", "Expected response from the application") + + // Verify that we can access the application without logging in again + res, err = client.Get(testURL, false) + require.NoError(t, err) + require.Equal(t, http.StatusOK, res.StatusCode) + require.Contains(t, string(body), "infra-backend-v1", "Expected response from the application") + + // Verify that we can logout + // Note: OAuth2 filter just clears its cookies and does not log out from the IdP. + res, err = client.Get(logoutURL, false) + require.NoError(t, err) + require.Equal(t, http.StatusFound, res.StatusCode) + + // After logout, OAuth2 filter will redirect back to the root of the host, e.g, "www.example.com". + // Ideally, this should redirect to the application's root, e.g, "www.example.com/myapp", + // but Envoy OAuth2 filter does not support this yet. + require.Equal(t, "http://www.example.com/", res.Header.Get("Location"), "Expected redirect to the root of the host") + + // Verify that the oauth2 cookies have been deleted + var cookieDeleted bool + deletedCookies := res.Header.Values("Set-Cookie") + regx := regexp.MustCompile("^IdToken-.+=deleted.+") + for _, cookie := range deletedCookies { + if regx.Match([]byte(cookie)) { + cookieDeleted = true + } + } + require.True(t, cookieDeleted, "IdToken cookie not deleted") +} From 5a1c065e3ddbc12b6a232b92eaf3417cd3146a09 Mon Sep 17 00:00:00 2001 From: zirain Date: Fri, 18 Oct 2024 11:59:03 +0800 Subject: [PATCH 33/39] support reloadable EnvoyGateway configuration (#4451) * support reloadable EnvoyGateway configuration Signed-off-by: zirain * lint Signed-off-by: zirain * shutdown wasm http server Signed-off-by: zirain --------- Signed-off-by: zirain --- internal/cmd/server.go | 33 +- .../config/loader/configloader.go | 113 ++++++ .../config/loader/configloader_test.go | 59 ++++ .../config/loader/testdata/default.yaml | 24 ++ .../config/loader/testdata/enable-redis.yaml | 14 + internal/filewatcher/filewatcher.go | 179 ++++++++++ internal/filewatcher/filewatcher_test.go | 321 ++++++++++++++++++ internal/filewatcher/worker.go | 256 ++++++++++++++ internal/infrastructure/runner/runner.go | 7 + internal/provider/kubernetes/controller.go | 6 +- internal/provider/kubernetes/kubernetes.go | 3 +- internal/wasm/httpserver.go | 6 + tools/hack/deployment-exists.sh | 3 +- tools/make/kube.mk | 3 - 14 files changed, 1010 insertions(+), 17 deletions(-) create mode 100644 internal/envoygateway/config/loader/configloader.go create mode 100644 internal/envoygateway/config/loader/configloader_test.go create mode 100644 internal/envoygateway/config/loader/testdata/default.yaml create mode 100644 internal/envoygateway/config/loader/testdata/enable-redis.yaml create mode 100644 internal/filewatcher/filewatcher.go create mode 100644 internal/filewatcher/filewatcher_test.go create mode 100644 internal/filewatcher/worker.go diff --git a/internal/cmd/server.go b/internal/cmd/server.go index 25add4c8541..a4c9d3e9713 100644 --- a/internal/cmd/server.go +++ b/internal/cmd/server.go @@ -6,12 +6,15 @@ package cmd import ( + "context" + "github.com/spf13/cobra" ctrl "sigs.k8s.io/controller-runtime" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/admin" "github.com/envoyproxy/gateway/internal/envoygateway/config" + "github.com/envoyproxy/gateway/internal/envoygateway/config/loader" extensionregistry "github.com/envoyproxy/gateway/internal/extension/registry" "github.com/envoyproxy/gateway/internal/extension/types" gatewayapirunner "github.com/envoyproxy/gateway/internal/gatewayapi/runner" @@ -51,6 +54,20 @@ func server() error { return err } + ctx := ctrl.SetupSignalHandler() + hook := func(c context.Context, cfg *config.Server) error { + cfg.Logger.Info("Setup runners") + if err := setupRunners(c, cfg); err != nil { + cfg.Logger.Error(err, "failed to setup runners") + return err + } + return nil + } + l := loader.New(cfgPath, cfg, hook) + if err := l.Start(ctx); err != nil { + return err + } + // Init eg admin servers. if err := admin.Init(cfg); err != nil { return err @@ -60,10 +77,10 @@ func server() error { return err } - // init eg runners. - if err := setupRunners(cfg); err != nil { - return err - } + // Wait exit signal + <-ctx.Done() + + cfg.Logger.Info("shutting down") return nil } @@ -110,11 +127,7 @@ func getConfigByPath(cfgPath string) (*config.Server, error) { // setupRunners starts all the runners required for the Envoy Gateway to // fulfill its tasks. -func setupRunners(cfg *config.Server) (err error) { - // TODO - Setup a Config Manager - // https://github.com/envoyproxy/gateway/issues/43 - ctx := ctrl.SetupSignalHandler() - +func setupRunners(ctx context.Context, cfg *config.Server) (err error) { // Setup the Extension Manager var extMgr types.Manager if cfg.EnvoyGateway.Provider.Type == egv1a1.ProviderTypeKubernetes { @@ -212,7 +225,7 @@ func setupRunners(cfg *config.Server) (err error) { infraIR.Close() xds.Close() - cfg.Logger.Info("shutting down") + cfg.Logger.Info("runners are shutting down") if extMgr != nil { // Close connections to extension services diff --git a/internal/envoygateway/config/loader/configloader.go b/internal/envoygateway/config/loader/configloader.go new file mode 100644 index 00000000000..9523c7a432e --- /dev/null +++ b/internal/envoygateway/config/loader/configloader.go @@ -0,0 +1,113 @@ +// 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 loader + +import ( + "context" + "time" + + "github.com/envoyproxy/gateway/internal/envoygateway/config" + "github.com/envoyproxy/gateway/internal/filewatcher" + "github.com/envoyproxy/gateway/internal/logging" +) + +type HookFunc func(c context.Context, cfg *config.Server) error + +type Loader struct { + cfgPath string + cfg *config.Server + logger logging.Logger + cancel context.CancelFunc + hook HookFunc + + w filewatcher.FileWatcher +} + +func New(cfgPath string, cfg *config.Server, f HookFunc) *Loader { + return &Loader{ + cfgPath: cfgPath, + cfg: cfg, + logger: cfg.Logger.WithName("config-loader"), + hook: f, + w: filewatcher.NewWatcher(), + } +} + +func (r *Loader) Start(ctx context.Context) error { + r.runHook() + + if r.cfgPath == "" { + r.logger.Info("no config file provided, skipping config watcher") + return nil + } + + r.logger.Info("watching for changes to the EnvoyGateway configuration", "path", r.cfgPath) + if err := r.w.Add(r.cfgPath); err != nil { + r.logger.Error(err, "failed to add config file to watcher") + return err + } + + go func() { + defer func() { + _ = r.w.Close() + }() + for { + select { + case e := <-r.w.Events(r.cfgPath): + r.logger.Info("received fsnotify events", "name", e.Name, "op", e.Op.String()) + + // Load the config file. + eg, err := config.Decode(r.cfgPath) + if err != nil { + r.logger.Info("failed to decode config file", "name", r.cfgPath, "error", err) + // TODO: add a metric for this? + continue + } + // Set defaults for unset fields + eg.SetEnvoyGatewayDefaults() + r.cfg.EnvoyGateway = eg + // update cfg logger + eg.Logging.SetEnvoyGatewayLoggingDefaults() + r.cfg.Logger = logging.NewLogger(eg.Logging) + + // cancel last + if r.cancel != nil { + r.cancel() + } + + // TODO: we need to make sure that all runners are stopped, before we start the new ones + // Otherwise we might end up with error listening on:8081 + time.Sleep(3 * time.Second) + + r.runHook() + case err := <-r.w.Errors(r.cfgPath): + r.logger.Error(err, "watcher error") + case <-ctx.Done(): + if r.cancel != nil { + r.cancel() + } + return + } + } + }() + + return nil +} + +func (r *Loader) runHook() { + if r.hook == nil { + return + } + + r.logger.Info("running hook") + c, cancel := context.WithCancel(context.TODO()) + r.cancel = cancel + go func(ctx context.Context) { + if err := r.hook(ctx, r.cfg); err != nil { + r.logger.Error(err, "hook error") + } + }(c) +} diff --git a/internal/envoygateway/config/loader/configloader_test.go b/internal/envoygateway/config/loader/configloader_test.go new file mode 100644 index 00000000000..d0420df0f5f --- /dev/null +++ b/internal/envoygateway/config/loader/configloader_test.go @@ -0,0 +1,59 @@ +// 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 loader + +import ( + "context" + _ "embed" + "os" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/envoyproxy/gateway/internal/envoygateway/config" +) + +var ( + //go:embed testdata/default.yaml + defaultConfig string + //go:embed testdata/enable-redis.yaml + redisConfig string +) + +func TestConfigLoader(t *testing.T) { + tmpDir, err := os.MkdirTemp("", "envoy-gateway-configloader-test") + require.NoError(t, err) + defer func(path string) { + _ = os.RemoveAll(path) + }(tmpDir) + + cfgPath := tmpDir + "/config.yaml" + require.NoError(t, os.WriteFile(cfgPath, []byte(defaultConfig), 0o600)) + s, err := config.New() + require.NoError(t, err) + + ctx, cancel := context.WithCancel(context.TODO()) + defer func() { + cancel() + }() + + changed := 0 + loader := New(cfgPath, s, func(_ context.Context, cfg *config.Server) error { + changed++ + t.Logf("config changed %d times", changed) + if changed > 1 { + cancel() + } + return nil + }) + + require.NoError(t, loader.Start(ctx)) + go func() { + _ = os.WriteFile(cfgPath, []byte(redisConfig), 0o600) + }() + + <-ctx.Done() +} diff --git a/internal/envoygateway/config/loader/testdata/default.yaml b/internal/envoygateway/config/loader/testdata/default.yaml new file mode 100644 index 00000000000..20463f848e1 --- /dev/null +++ b/internal/envoygateway/config/loader/testdata/default.yaml @@ -0,0 +1,24 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyGateway +gateway: + controllerName: gateway.envoyproxy.io/gatewayclass-controller +logging: + level: + default: info +provider: + kubernetes: + rateLimitDeployment: + container: + image: docker.io/envoyproxy/ratelimit:master + patch: + type: StrategicMerge + value: + spec: + template: + spec: + containers: + - imagePullPolicy: IfNotPresent + name: envoy-ratelimit + shutdownManager: + image: docker.io/envoyproxy/gateway-dev:latest + type: Kubernetes diff --git a/internal/envoygateway/config/loader/testdata/enable-redis.yaml b/internal/envoygateway/config/loader/testdata/enable-redis.yaml new file mode 100644 index 00000000000..ed2218ab5ab --- /dev/null +++ b/internal/envoygateway/config/loader/testdata/enable-redis.yaml @@ -0,0 +1,14 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyGateway +provider: + type: Kubernetes +gateway: + controllerName: gateway.envoyproxy.io/gatewayclass-controller +extensionApis: + enableEnvoyPatchPolicy: true + enableBackend: true +rateLimit: + backend: + type: Redis + redis: + url: redis.redis-system.svc.cluster.local:6379 diff --git a/internal/filewatcher/filewatcher.go b/internal/filewatcher/filewatcher.go new file mode 100644 index 00000000000..4fce5e9aba4 --- /dev/null +++ b/internal/filewatcher/filewatcher.go @@ -0,0 +1,179 @@ +// 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 filewatcher + +import ( + "errors" + "fmt" + "path/filepath" + "sync" + + "github.com/fsnotify/fsnotify" +) + +// FileWatcher is an interface that watches a set of files, +// delivering events to related channel. +type FileWatcher interface { + Add(path string) error + Remove(path string) error + Close() error + Events(path string) chan fsnotify.Event + Errors(path string) chan error +} + +type fileWatcher struct { + mu sync.RWMutex + + // The watcher maintain a map of workers, + // keyed by watched dir (parent dir of watched files). + workers map[string]*workerState + + funcs *patchTable +} + +type workerState struct { + worker *worker + count int +} + +// functions that can be replaced in a test setting +type patchTable struct { + newWatcher func() (*fsnotify.Watcher, error) + addWatcherPath func(*fsnotify.Watcher, string) error +} + +// NewWatcher return with a FileWatcher instance that implemented with fsnotify. +func NewWatcher() FileWatcher { + return &fileWatcher{ + workers: map[string]*workerState{}, + + // replaceable functions for tests + funcs: &patchTable{ + newWatcher: fsnotify.NewWatcher, + addWatcherPath: func(watcher *fsnotify.Watcher, path string) error { + return watcher.Add(path) + }, + }, + } +} + +// Close releases all resources associated with the watcher +func (fw *fileWatcher) Close() error { + fw.mu.Lock() + defer fw.mu.Unlock() + + for _, ws := range fw.workers { + ws.worker.terminate() + } + fw.workers = nil + + return nil +} + +// Add a path to watch +func (fw *fileWatcher) Add(path string) error { + fw.mu.Lock() + defer fw.mu.Unlock() + + ws, cleanedPath, _, err := fw.getWorker(path) + if err != nil { + return err + } + + if err = ws.worker.addPath(cleanedPath); err == nil { + ws.count++ + } + + return err +} + +// Stop watching a path +func (fw *fileWatcher) Remove(path string) error { + fw.mu.Lock() + defer fw.mu.Unlock() + + ws, cleanedPath, parentPath, err := fw.getWorker(path) + if err != nil { + return err + } + + if err = ws.worker.removePath(cleanedPath); err == nil { + ws.count-- + if ws.count == 0 { + ws.worker.terminate() + delete(fw.workers, parentPath) + } + } + + return err +} + +// Events returns an event notification channel for a path +func (fw *fileWatcher) Events(path string) chan fsnotify.Event { + fw.mu.RLock() + defer fw.mu.RUnlock() + + ws, cleanedPath, err := fw.findWorker(path) + if err != nil { + return nil + } + + return ws.worker.eventChannel(cleanedPath) +} + +// Errors returns an error notification channel for a path +func (fw *fileWatcher) Errors(path string) chan error { + fw.mu.RLock() + defer fw.mu.RUnlock() + + ws, cleanedPath, err := fw.findWorker(path) + if err != nil { + return nil + } + + return ws.worker.errorChannel(cleanedPath) +} + +func (fw *fileWatcher) getWorker(path string) (*workerState, string, string, error) { + if fw.workers == nil { + return nil, "", "", errors.New("using a closed watcher") + } + + cleanedPath := filepath.Clean(path) + parentPath, _ := filepath.Split(cleanedPath) + + ws, workerExists := fw.workers[parentPath] + if !workerExists { + wk, err := newWorker(parentPath, fw.funcs) + if err != nil { + return nil, "", "", err + } + + ws = &workerState{ + worker: wk, + } + + fw.workers[parentPath] = ws + } + + return ws, cleanedPath, parentPath, nil +} + +func (fw *fileWatcher) findWorker(path string) (*workerState, string, error) { + if fw.workers == nil { + return nil, "", errors.New("using a closed watcher") + } + + cleanedPath := filepath.Clean(path) + parentPath, _ := filepath.Split(cleanedPath) + + ws, workerExists := fw.workers[parentPath] + if !workerExists { + return nil, "", fmt.Errorf("no path registered for %s", path) + } + + return ws, cleanedPath, nil +} diff --git a/internal/filewatcher/filewatcher_test.go b/internal/filewatcher/filewatcher_test.go new file mode 100644 index 00000000000..5230d7c05ad --- /dev/null +++ b/internal/filewatcher/filewatcher_test.go @@ -0,0 +1,321 @@ +// 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 filewatcher + +import ( + "errors" + "fmt" + "os" + "os/exec" + "path" + "runtime" + "sync" + "testing" + + "github.com/fsnotify/fsnotify" + "github.com/stretchr/testify/require" +) + +func newWatchFile(t *testing.T) string { + watchDir := t.TempDir() + watchFile := path.Join(watchDir, "test.conf") + err := os.WriteFile(watchFile, []byte("foo: bar\n"), 0o600) + require.NoError(t, err) + + return watchFile +} + +func newWatchFileThatDoesNotExist(t *testing.T) string { + watchDir := t.TempDir() + + watchFile := path.Join(watchDir, "test.conf") + + return watchFile +} + +// newTwoWatchFile returns with two watch files that exist in the same base dir. +func newTwoWatchFile(t *testing.T) (string, string) { + watchDir := t.TempDir() + + watchFile1 := path.Join(watchDir, "test1.conf") + err := os.WriteFile(watchFile1, []byte("foo: bar\n"), 0o600) + require.NoError(t, err) + + watchFile2 := path.Join(watchDir, "test2.conf") + err = os.WriteFile(watchFile2, []byte("foo: baz\n"), 0o600) + require.NoError(t, err) + + return watchFile1, watchFile2 +} + +// newSymlinkedWatchFile simulates the behavior of k8s configmap/secret. +// Path structure looks like: +// +// /test.conf +// ^ +// | +// +// /data/test.conf +// +// ^ +// | +// +// /data1/test.conf +func newSymlinkedWatchFile(t *testing.T) (string, string) { + watchDir := t.TempDir() + + dataDir1 := path.Join(watchDir, "data1") + err := os.Mkdir(dataDir1, 0o777) + require.NoError(t, err) + + realTestFile := path.Join(dataDir1, "test.conf") + t.Logf("Real test file location: %s\n", realTestFile) + err = os.WriteFile(realTestFile, []byte("foo: bar\n"), 0o600) + require.NoError(t, err) + + // Now, symlink the tmp `data1` dir to `data` in the baseDir + require.NoError(t, os.Symlink(dataDir1, path.Join(watchDir, "data"))) + // And link the `/datadir/test.conf` to `/test.conf` + watchFile := path.Join(watchDir, "test.conf") + require.NoError(t, os.Symlink(path.Join(watchDir, "data", "test.conf"), watchFile)) + t.Logf("Watch file location: %s\n", path.Join(watchDir, "test.conf")) + return watchDir, watchFile +} + +func TestWatchFile(t *testing.T) { + t.Run("file content changed", func(t *testing.T) { + // Given a file being watched + watchFile := newWatchFile(t) + _, err := os.Stat(watchFile) + require.NoError(t, err) + + w := NewWatcher() + require.NoError(t, w.Add(watchFile)) + events := w.Events(watchFile) + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + <-events + wg.Done() + }() + + // Overwriting the file and waiting its event to be received. + err = os.WriteFile(watchFile, []byte("foo: baz\n"), 0o600) + require.NoError(t, err) + wg.Wait() + + _ = w.Close() + }) + + t.Run("link to real file changed (for k8s configmap/secret path)", func(t *testing.T) { + // skip if not executed on Linux + if runtime.GOOS != "linux" { + t.Skip("Skipping test as symlink replacements don't work on non-linux environment...") + } + + watchDir, watchFile := newSymlinkedWatchFile(t) + + w := NewWatcher() + require.NoError(t, w.Add(watchFile)) + events := w.Events(watchFile) + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + <-events + wg.Done() + }() + + // Link to another `test.conf` file + dataDir2 := path.Join(watchDir, "data2") + err := os.Mkdir(dataDir2, 0o777) + require.NoError(t, err) + + watchFile2 := path.Join(dataDir2, "test.conf") + err = os.WriteFile(watchFile2, []byte("foo: baz\n"), 0o600) + require.NoError(t, err) + + // change the symlink using the `ln -sfn` command + err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run() + require.NoError(t, err) + + // Wait its event to be received. + wg.Wait() + + _ = w.Close() + }) + + t.Run("file added later", func(t *testing.T) { + // Given a file being watched + watchFile := newWatchFileThatDoesNotExist(t) + + w := NewWatcher() + require.NoError(t, w.Add(watchFile)) + events := w.Events(watchFile) + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + <-events + wg.Done() + }() + + // Overwriting the file and waiting its event to be received. + err := os.WriteFile(watchFile, []byte("foo: baz\n"), 0o600) + require.NoError(t, err) + wg.Wait() + + _ = w.Close() + }) +} + +func TestWatcherLifecycle(t *testing.T) { + watchFile1, watchFile2 := newTwoWatchFile(t) + + w := NewWatcher() + + // Validate Add behavior + err := w.Add(watchFile1) + require.NoError(t, err) + err = w.Add(watchFile2) + require.NoError(t, err) + + // Validate events and errors channel are fulfilled. + events1 := w.Events(watchFile1) + require.NotNil(t, events1) + events2 := w.Events(watchFile2) + require.NotNil(t, events2) + + errors1 := w.Errors(watchFile1) + require.NotNil(t, errors1) + errors2 := w.Errors(watchFile2) + require.NotNil(t, errors2) + + // Validate Remove behavior + err = w.Remove(watchFile1) + require.NoError(t, err) + events1 = w.Events(watchFile1) + require.Nil(t, events1) + errors1 = w.Errors(watchFile1) + require.Nil(t, errors1) + events2 = w.Events(watchFile2) + require.NotNil(t, events2) + errors2 = w.Errors(watchFile2) + require.NotNil(t, errors2) + + fmt.Printf("2\n") + // Validate Close behavior + err = w.Close() + require.NoError(t, err) + events1 = w.Events(watchFile1) + require.Nil(t, events1) + errors1 = w.Errors(watchFile1) + require.Nil(t, errors1) + events2 = w.Events(watchFile2) + require.Nil(t, events2) + errors2 = w.Errors(watchFile2) + require.Nil(t, errors2) +} + +func TestErrors(t *testing.T) { + w := NewWatcher() + + if ch := w.Errors("XYZ"); ch != nil { + t.Error("Expected no channel") + } + + if ch := w.Events("XYZ"); ch != nil { + t.Error("Expected no channel") + } + + name := newWatchFile(t) + _ = w.Add(name) + _ = w.Remove(name) + + if ch := w.Errors("XYZ"); ch != nil { + t.Error("Expected no channel") + } + + if ch := w.Events(name); ch != nil { + t.Error("Expected no channel") + } + + _ = w.Close() + + if err := w.Add(name); err == nil { + t.Error("Expecting error") + } + + if err := w.Remove(name); err == nil { + t.Error("Expecting error") + } + + if ch := w.Errors(name); ch != nil { + t.Error("Expecting nil") + } + + if ch := w.Events(name); ch != nil { + t.Error("Expecting nil") + } +} + +func TestBadWatcher(t *testing.T) { + w := NewWatcher() + w.(*fileWatcher).funcs.newWatcher = func() (*fsnotify.Watcher, error) { + return nil, errors.New("FOOBAR") + } + + name := newWatchFile(t) + if err := w.Add(name); err == nil { + t.Errorf("Expecting error, got nil") + } + if err := w.Close(); err != nil { + t.Errorf("Expecting nil, got %v", err) + } +} + +func TestBadAddWatcher(t *testing.T) { + w := NewWatcher() + w.(*fileWatcher).funcs.addWatcherPath = func(*fsnotify.Watcher, string) error { + return errors.New("FOOBAR") + } + + name := newWatchFile(t) + if err := w.Add(name); err == nil { + t.Errorf("Expecting error, got nil") + } + if err := w.Close(); err != nil { + t.Errorf("Expecting nil, got %v", err) + } +} + +func TestDuplicateAdd(t *testing.T) { + w := NewWatcher() + + name := newWatchFile(t) + + if err := w.Add(name); err != nil { + t.Errorf("Expecting nil, got %v", err) + } + + if err := w.Add(name); err == nil { + t.Errorf("Expecting error, got nil") + } + + _ = w.Close() +} + +func TestBogusRemove(t *testing.T) { + w := NewWatcher() + + name := newWatchFile(t) + if err := w.Remove(name); err == nil { + t.Errorf("Expecting error, got nil") + } + + _ = w.Close() +} diff --git a/internal/filewatcher/worker.go b/internal/filewatcher/worker.go new file mode 100644 index 00000000000..6ae9c9f77ba --- /dev/null +++ b/internal/filewatcher/worker.go @@ -0,0 +1,256 @@ +// 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 filewatcher + +import ( + "bufio" + "bytes" + "crypto/sha256" + "fmt" + "io" + "os" + "sync" + + "github.com/fsnotify/fsnotify" +) + +type worker struct { + mu sync.RWMutex + + // watcher is an fsnotify watcher that watches the parent + // dir of watchedFiles. + dirWatcher *fsnotify.Watcher + + // The worker maintains a map of channels keyed by watched file path. + // The worker watches parent path of given path, + // and filters out events of given path, then redirect + // to the result channel. + // Note that for symlink files, the content in received events + // do not have to be related to the file itself. + watchedFiles map[string]*fileTracker + + // tracker lifecycle + retireTrackerCh chan *fileTracker + + // tells the worker to exit + terminateCh chan bool +} + +type fileTracker struct { + events chan fsnotify.Event + errors chan error + + // Hash sum to indicate if a file has been updated. + hash []byte +} + +func newWorker(path string, funcs *patchTable) (*worker, error) { + dirWatcher, err := funcs.newWatcher() + if err != nil { + return nil, err + } + + if err = funcs.addWatcherPath(dirWatcher, path); err != nil { + _ = dirWatcher.Close() + return nil, err + } + + wk := &worker{ + dirWatcher: dirWatcher, + watchedFiles: make(map[string]*fileTracker), + retireTrackerCh: make(chan *fileTracker), + terminateCh: make(chan bool), + } + + go wk.listen() + + return wk, nil +} + +func (wk *worker) listen() { + wk.loop() + + _ = wk.dirWatcher.Close() + + // drain any retiring trackers that may be pending + wk.drainRetiringTrackers() + + // clean up the rest + for _, ft := range wk.watchedFiles { + retireTracker(ft) + } +} + +func (wk *worker) loop() { + for { + select { + case event := <-wk.dirWatcher.Events: + // work on a copy of the watchedFiles map, so that we don't interfere + // with the caller's use of the map + for path, ft := range wk.getTrackers() { + if ft.events == nil { + // tracker has been retired, skip it + continue + } + + sum := getHashSum(path) + if !bytes.Equal(sum, ft.hash) { + ft.hash = sum + + select { + case ft.events <- event: + // nothing to do + + case ft := <-wk.retireTrackerCh: + retireTracker(ft) + + case <-wk.terminateCh: + return + } + } + } + + case err := <-wk.dirWatcher.Errors: + for _, ft := range wk.getTrackers() { + if ft.errors == nil { + // tracker has been retired, skip it + continue + } + + select { + case ft.errors <- err: + // nothing to do + + case ft := <-wk.retireTrackerCh: + retireTracker(ft) + + case <-wk.terminateCh: + return + } + } + + case ft := <-wk.retireTrackerCh: + retireTracker(ft) + + case <-wk.terminateCh: + return + } + } +} + +// used only by the worker goroutine +func (wk *worker) drainRetiringTrackers() { + // cleanup any trackers that were in the process + // of being retired, but didn't get processed due + // to termination + for { + select { + case ft := <-wk.retireTrackerCh: + retireTracker(ft) + default: + return + } + } +} + +// make a local copy of the set of trackers to avoid contention with callers +// used only by the worker goroutine +func (wk *worker) getTrackers() map[string]*fileTracker { + wk.mu.RLock() + + result := make(map[string]*fileTracker, len(wk.watchedFiles)) + for k, v := range wk.watchedFiles { + result[k] = v + } + + wk.mu.RUnlock() + return result +} + +// used only by the worker goroutine +func retireTracker(ft *fileTracker) { + close(ft.events) + close(ft.errors) + ft.events = nil + ft.errors = nil +} + +func (wk *worker) terminate() { + wk.terminateCh <- true +} + +func (wk *worker) addPath(path string) error { + wk.mu.Lock() + + ft := wk.watchedFiles[path] + if ft != nil { + wk.mu.Unlock() + return fmt.Errorf("path %s is already being watched", path) + } + + ft = &fileTracker{ + events: make(chan fsnotify.Event), + errors: make(chan error), + hash: getHashSum(path), + } + + wk.watchedFiles[path] = ft + wk.mu.Unlock() + + return nil +} + +func (wk *worker) removePath(path string) error { + wk.mu.Lock() + + ft := wk.watchedFiles[path] + if ft == nil { + wk.mu.Unlock() + return fmt.Errorf("path %s not found", path) + } + + delete(wk.watchedFiles, path) + wk.mu.Unlock() + + wk.retireTrackerCh <- ft + return nil +} + +func (wk *worker) eventChannel(path string) chan fsnotify.Event { + wk.mu.RLock() + defer wk.mu.RUnlock() + + if ft := wk.watchedFiles[path]; ft != nil { + return ft.events + } + + return nil +} + +func (wk *worker) errorChannel(path string) chan error { + wk.mu.RLock() + defer wk.mu.RUnlock() + + if ft := wk.watchedFiles[path]; ft != nil { + return ft.errors + } + + return nil +} + +// gets the hash of the given file, or nil if there's a problem +func getHashSum(file string) []byte { + f, err := os.Open(file) + if err != nil { + return nil + } + defer f.Close() + r := bufio.NewReader(f) + + h := sha256.New() + _, _ = io.Copy(h, r) + return h.Sum(nil) +} diff --git a/internal/infrastructure/runner/runner.go b/internal/infrastructure/runner/runner.go index 6c261aff3f3..300314d92e0 100644 --- a/internal/infrastructure/runner/runner.go +++ b/internal/infrastructure/runner/runner.go @@ -56,6 +56,13 @@ func (r *Runner) Start(ctx context.Context) (err error) { // Enable global ratelimit if it has been configured. if r.EnvoyGateway.RateLimit != nil { go r.enableRateLimitInfra(ctx) + } else { + // Delete the ratelimit infra if it exists. + go func() { + if err := r.mgr.DeleteRateLimitInfra(ctx); err != nil { + r.Logger.Error(err, "failed to delete ratelimit infra") + } + }() } r.Logger.Info("started") } diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 915e6e5acd8..167e70746ec 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -8,6 +8,7 @@ package kubernetes import ( "context" "fmt" + "time" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -111,7 +112,10 @@ func newGatewayAPIController(mgr manager.Manager, cfg *config.Server, su Updater r.namespaceLabel = cfg.EnvoyGateway.Provider.Kubernetes.Watch.NamespaceSelector } - c, err := controller.New("gatewayapi", mgr, controller.Options{Reconciler: r, SkipNameValidation: skipNameValidation()}) + // controller-runtime doesn't allow run controller with same name for more than once + // see https://github.com/kubernetes-sigs/controller-runtime/blob/2b941650bce159006c88bd3ca0d132c7bc40e947/pkg/controller/name.go#L29 + name := fmt.Sprintf("gatewayapi-%d", time.Now().Unix()) + c, err := controller.New(name, mgr, controller.Options{Reconciler: r, SkipNameValidation: skipNameValidation()}) if err != nil { return fmt.Errorf("error creating controller: %w", err) } diff --git a/internal/provider/kubernetes/kubernetes.go b/internal/provider/kubernetes/kubernetes.go index cca90a24a17..4fdbc329dd0 100644 --- a/internal/provider/kubernetes/kubernetes.go +++ b/internal/provider/kubernetes/kubernetes.go @@ -112,7 +112,8 @@ func New(cfg *rest.Config, svr *ec.Server, resources *message.ProviderResources) // Emit elected & continue with envoyObjects of infra resources go func() { <-mgr.Elected() - close(svr.Elected) + // WARN: DO NOT CLOSE IT + svr.Elected <- struct{}{} }() return &Provider{ diff --git a/internal/wasm/httpserver.go b/internal/wasm/httpserver.go index 9b1d0b32c90..14e70a8c6dc 100644 --- a/internal/wasm/httpserver.go +++ b/internal/wasm/httpserver.go @@ -131,6 +131,12 @@ func (s *HTTPServer) Start(ctx context.Context) { return } }() + + go func() { + // waiting for shutdown + <-ctx.Done() + _ = s.server.Shutdown(context.Background()) + }() s.cache.Start(ctx) go s.resetFailedAttempts(ctx) } diff --git a/tools/hack/deployment-exists.sh b/tools/hack/deployment-exists.sh index cc50e1c2638..d5081b424bc 100755 --- a/tools/hack/deployment-exists.sh +++ b/tools/hack/deployment-exists.sh @@ -3,9 +3,8 @@ DEPLOYMENT_LABEL_SELECTOR=$1 DEPLOYMENT_NAMESPACE=$2 - # Timeout for deployment to exist (in seconds) -exist_timeout=25 +exist_timeout=300 end=$((SECONDS+exist_timeout)) while true; do diff --git a/tools/make/kube.mk b/tools/make/kube.mk index c659e234787..91c1580ab2d 100644 --- a/tools/make/kube.mk +++ b/tools/make/kube.mk @@ -138,9 +138,6 @@ e2e: create-cluster kube-install-image kube-deploy install-ratelimit install-e2e install-ratelimit: @$(LOG_TARGET) kubectl apply -f examples/redis/redis.yaml - kubectl rollout restart deployment envoy-gateway -n envoy-gateway-system - kubectl rollout status --watch --timeout=5m -n envoy-gateway-system deployment/envoy-gateway - kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available tools/hack/deployment-exists.sh "app.kubernetes.io/name=envoy-ratelimit" "envoy-gateway-system" kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-ratelimit --for=condition=Available From 272da6dae0a558c52a3a974ca6cb90cc3e8fe84a Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Sat, 19 Oct 2024 05:08:22 +0530 Subject: [PATCH 34/39] e2e: add tests for ratelimit invert matching headers (#4452) add tests for ratelimit invert matching headers Signed-off-by: Rudrakh Panigrahi --- .../ratelimit-header-invert-match.yaml | 42 +++++++++ test/e2e/tests/ratelimit.go | 88 +++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 test/e2e/testdata/ratelimit-header-invert-match.yaml diff --git a/test/e2e/testdata/ratelimit-header-invert-match.yaml b/test/e2e/testdata/ratelimit-header-invert-match.yaml new file mode 100644 index 00000000000..7261ef30e35 --- /dev/null +++ b/test/e2e/testdata/ratelimit-header-invert-match.yaml @@ -0,0 +1,42 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: ratelimit-anded-headers-with-invert + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: header-ratelimit + rateLimit: + type: Global + global: + rules: + - clientSelectors: + - headers: + - name: x-user-name + type: Distinct + - name: x-user-name + type: Exact + value: admin + invert: true + limit: + requests: 3 + unit: Hour +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: header-ratelimit + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: /get + backendRefs: + - name: infra-backend-v1 + port: 8080 diff --git a/test/e2e/tests/ratelimit.go b/test/e2e/tests/ratelimit.go index 80064e6d906..b87576b60aa 100644 --- a/test/e2e/tests/ratelimit.go +++ b/test/e2e/tests/ratelimit.go @@ -26,6 +26,7 @@ import ( func init() { ConformanceTests = append(ConformanceTests, RateLimitCIDRMatchTest) ConformanceTests = append(ConformanceTests, RateLimitHeaderMatchTest) + ConformanceTests = append(ConformanceTests, RateLimitHeaderInvertMatchTest) ConformanceTests = append(ConformanceTests, RateLimitHeadersDisabled) ConformanceTests = append(ConformanceTests, RateLimitBasedJwtClaimsTest) ConformanceTests = append(ConformanceTests, RateLimitMultipleListenersTest) @@ -170,6 +171,93 @@ var RateLimitHeaderMatchTest = suite.ConformanceTest{ }, } +var RateLimitHeaderInvertMatchTest = suite.ConformanceTest{ + ShortName: "RateLimitHeaderInvertMatch", + Description: "Limit all requests that match distinct headers except for which invert is set to true", + Manifests: []string{"testdata/ratelimit-header-invert-match.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "header-ratelimit", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + + t.Run("all matched headers got limited", func(t *testing.T) { + requestHeaders := map[string]string{ + "x-user-name": "username", + } + + ratelimitHeader := make(map[string]string) + expectOkResp := http.ExpectedResponse{ + Request: http.Request{ + Path: "/get", + Headers: requestHeaders, + }, + Response: http.Response{ + StatusCode: 200, + Headers: ratelimitHeader, + }, + Namespace: ns, + } + expectOkResp.Response.Headers["X-Ratelimit-Limit"] = "3, 3;w=3600" + expectOkReq := http.MakeRequest(t, &expectOkResp, gwAddr, "HTTP", "http") + + expectLimitResp := http.ExpectedResponse{ + Request: http.Request{ + Path: "/get", + Headers: requestHeaders, + }, + Response: http.Response{ + StatusCode: 429, + }, + Namespace: ns, + } + expectLimitReq := http.MakeRequest(t, &expectLimitResp, gwAddr, "HTTP", "http") + + // should just send exactly 4 requests, and expect 429 + + // keep sending requests till get 200 first, that will cost one 200 + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectOkResp) + + // fire the rest of the requests + if err := GotExactExpectedResponse(t, 2, suite.RoundTripper, expectOkReq, expectOkResp); err != nil { + t.Errorf("failed to get expected response for the first three requests: %v", err) + } + if err := GotExactExpectedResponse(t, 1, suite.RoundTripper, expectLimitReq, expectLimitResp); err != nil { + t.Errorf("failed to get expected response for the last (fourth) request: %v", err) + } + }) + + t.Run("if header matched with invert will not get limited", func(t *testing.T) { + requestHeaders := map[string]string{ + "x-user-name": "admin", + } + + // it does not require any rate limit header, since this request never be rate limited. + expectOkResp := http.ExpectedResponse{ + Request: http.Request{ + Path: "/get", + Headers: requestHeaders, + }, + Response: http.Response{ + StatusCode: 200, + }, + Namespace: ns, + } + expectOkReq := http.MakeRequest(t, &expectOkResp, gwAddr, "HTTP", "http") + + // send exactly 4 requests, and still expect 200 + + // keep sending requests till get 200 first, that will cost one 200 + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectOkResp) + + // fire the rest of the requests + if err := GotExactExpectedResponse(t, 3, suite.RoundTripper, expectOkReq, expectOkResp); err != nil { + t.Errorf("failed to get expected responses for the request: %v", err) + } + }) + }, +} + var RateLimitHeadersDisabled = suite.ConformanceTest{ ShortName: "RateLimitHeadersDisabled", Description: "Disable rate limit headers", From 8c748d385cd185e40d7c39e00135476a1f0c9bd2 Mon Sep 17 00:00:00 2001 From: zirain Date: Sat, 19 Oct 2024 13:24:24 +0800 Subject: [PATCH 35/39] chore: update logo (#4469) * chore: update logo Signed-off-by: zirain * update Signed-off-by: zirain --------- Signed-off-by: zirain --- site/assets/icons/logo.svg | 219 +++++++++---------------------------- 1 file changed, 51 insertions(+), 168 deletions(-) diff --git a/site/assets/icons/logo.svg b/site/assets/icons/logo.svg index b0e579bd9d4..77ac7ed5386 100644 --- a/site/assets/icons/logo.svg +++ b/site/assets/icons/logo.svg @@ -1,170 +1,53 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From d996c29dc559e3f6c412a3f120834e1a2daee753 Mon Sep 17 00:00:00 2001 From: zirain Date: Sat, 19 Oct 2024 13:25:26 +0800 Subject: [PATCH 36/39] docs: correct the curl command (#4467) Signed-off-by: zirain --- .../content/en/docs/tasks/extensibility/envoy-patch-policy.md | 4 ++-- .../en/latest/tasks/extensibility/envoy-patch-policy.md | 4 ++-- .../content/en/v1.1/tasks/extensibility/envoy-patch-policy.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/site/content/en/docs/tasks/extensibility/envoy-patch-policy.md b/site/content/en/docs/tasks/extensibility/envoy-patch-policy.md index 7fe84762189..3c4c0a4d068 100644 --- a/site/content/en/docs/tasks/extensibility/envoy-patch-policy.md +++ b/site/content/en/docs/tasks/extensibility/envoy-patch-policy.md @@ -269,8 +269,8 @@ kubectl patch httproute backend --type=json --patch ' * Test it out by specifying a path apart from `/get` -``` -$ curl --header "Host: www.example.com" http://localhost:8888/find +```shell +$ curl --header "Host: www.example.com" http://$GATEWAY_HOST/find Handling connection for 8888 could not find what you are looking for ``` diff --git a/site/content/en/latest/tasks/extensibility/envoy-patch-policy.md b/site/content/en/latest/tasks/extensibility/envoy-patch-policy.md index e503244c503..e9709cc7651 100644 --- a/site/content/en/latest/tasks/extensibility/envoy-patch-policy.md +++ b/site/content/en/latest/tasks/extensibility/envoy-patch-policy.md @@ -268,8 +268,8 @@ kubectl patch httproute backend --type=json --patch ' * Test it out by specifying a path apart from `/get` -``` -$ curl --header "Host: www.example.com" http://localhost:8888/find +```shell +$ curl --header "Host: www.example.com" http://$GATEWAY_HOST/find Handling connection for 8888 could not find what you are looking for ``` diff --git a/site/content/en/v1.1/tasks/extensibility/envoy-patch-policy.md b/site/content/en/v1.1/tasks/extensibility/envoy-patch-policy.md index 7fe84762189..3c4c0a4d068 100644 --- a/site/content/en/v1.1/tasks/extensibility/envoy-patch-policy.md +++ b/site/content/en/v1.1/tasks/extensibility/envoy-patch-policy.md @@ -269,8 +269,8 @@ kubectl patch httproute backend --type=json --patch ' * Test it out by specifying a path apart from `/get` -``` -$ curl --header "Host: www.example.com" http://localhost:8888/find +```shell +$ curl --header "Host: www.example.com" http://$GATEWAY_HOST/find Handling connection for 8888 could not find what you are looking for ``` From 3e39606f3fc74a8f2e6d8fb5091d2289bd918a5a Mon Sep 17 00:00:00 2001 From: zirain Date: Sat, 19 Oct 2024 13:28:39 +0800 Subject: [PATCH 37/39] chore: use ptr.Deref to simply code (#4477) Signed-off-by: zirain --- internal/gatewayapi/listener.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 5c85e561ea1..51fd1f74da2 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -344,7 +344,8 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * al := &ir.ALSAccessLog{ LogName: logName, Destination: ir.RouteDestination{ - Name: fmt.Sprintf("accesslog_als_%d_%d", i, j), // TODO: rename this, so that we can share backend with tracing? + // TODO: rename this, so that we can share backend with tracing? + Name: fmt.Sprintf("accesslog_als_%d_%d", i, j), Settings: ds, }, Traffic: traffic, @@ -384,7 +385,8 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * CELMatches: validExprs, Resources: sink.OpenTelemetry.Resources, Destination: ir.RouteDestination{ - Name: fmt.Sprintf("accesslog_otel_%d_%d", i, j), // TODO: rename this, so that we can share backend with tracing? + // TODO: rename this, so that we can share backend with tracing? + Name: fmt.Sprintf("accesslog_otel_%d_%d", i, j), Settings: ds, }, Traffic: traffic, @@ -416,7 +418,9 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources * return irAccessLog, nil } -func (t *Translator) processTracing(gw *gwapiv1.Gateway, envoyproxy *egv1a1.EnvoyProxy, mergeGateways bool, resources *resource.Resources) (*ir.Tracing, error) { +func (t *Translator) processTracing(gw *gwapiv1.Gateway, envoyproxy *egv1a1.EnvoyProxy, + mergeGateways bool, resources *resource.Resources, +) (*ir.Tracing, error) { if envoyproxy == nil || envoyproxy.Spec.Telemetry == nil || envoyproxy.Spec.Telemetry.Tracing == nil { @@ -460,7 +464,8 @@ func (t *Translator) processTracing(gw *gwapiv1.Gateway, envoyproxy *egv1a1.Envo SamplingRate: samplingRate, CustomTags: tracing.CustomTags, Destination: ir.RouteDestination{ - Name: "tracing", // TODO: rename this, so that we can share backend with accesslog? + // TODO: rename this, so that we can share backend with accesslog? + Name: "tracing", Settings: ds, }, Provider: tracing.Provider, @@ -487,13 +492,15 @@ func (t *Translator) processMetrics(envoyproxy *egv1a1.EnvoyProxy, resources *re } return &ir.Metrics{ - EnableVirtualHostStats: envoyproxy.Spec.Telemetry.Metrics.EnableVirtualHostStats != nil && *envoyproxy.Spec.Telemetry.Metrics.EnableVirtualHostStats, - EnablePerEndpointStats: envoyproxy.Spec.Telemetry.Metrics.EnablePerEndpointStats != nil && *envoyproxy.Spec.Telemetry.Metrics.EnablePerEndpointStats, - EnableRequestResponseSizesStats: envoyproxy.Spec.Telemetry.Metrics.EnableRequestResponseSizesStats != nil && *envoyproxy.Spec.Telemetry.Metrics.EnableRequestResponseSizesStats, + EnableVirtualHostStats: ptr.Deref(envoyproxy.Spec.Telemetry.Metrics.EnableVirtualHostStats, false), + EnablePerEndpointStats: ptr.Deref(envoyproxy.Spec.Telemetry.Metrics.EnablePerEndpointStats, false), + EnableRequestResponseSizesStats: ptr.Deref(envoyproxy.Spec.Telemetry.Metrics.EnableRequestResponseSizesStats, false), }, nil } -func (t *Translator) processBackendRefs(backendCluster egv1a1.BackendCluster, namespace string, resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy) ([]*ir.DestinationSetting, *ir.TrafficFeatures, error) { +func (t *Translator) processBackendRefs(backendCluster egv1a1.BackendCluster, namespace string, + resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy, +) ([]*ir.DestinationSetting, *ir.TrafficFeatures, error) { traffic, err := translateTrafficFeatures(backendCluster.BackendSettings) if err != nil { return nil, nil, err From 8854d2db3e454e9e908f469f274c83b0f7923248 Mon Sep 17 00:00:00 2001 From: zirain Date: Sat, 19 Oct 2024 13:32:14 +0800 Subject: [PATCH 38/39] chore: bump crd-ref-docs (#4474) * bump crd-ref-docs Signed-off-by: zirain * use go 1.23.1 Signed-off-by: zirain * lint Signed-off-by: zirain --------- Signed-off-by: zirain --- api/v1alpha1/basic_auth_types.go | 6 ++++-- api/v1alpha1/oidc_types.go | 4 ++-- api/v1alpha1/wasm_types.go | 4 ++-- internal/gatewayapi/validate.go | 6 +++--- internal/provider/kubernetes/controller.go | 6 +++--- internal/provider/kubernetes/indexers.go | 2 +- internal/provider/kubernetes/predicates_test.go | 7 +++---- test/e2e/tests/wasm_oci.go | 3 +-- tools/src/crd-ref-docs/go.mod | 4 ++-- tools/src/crd-ref-docs/go.sum | 6 ++---- 10 files changed, 23 insertions(+), 25 deletions(-) diff --git a/api/v1alpha1/basic_auth_types.go b/api/v1alpha1/basic_auth_types.go index 97fa66d5e76..f7bec283780 100644 --- a/api/v1alpha1/basic_auth_types.go +++ b/api/v1alpha1/basic_auth_types.go @@ -5,7 +5,9 @@ package v1alpha1 -import gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" +import ( + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" +) const BasicAuthUsersSecretKey = ".htpasswd" @@ -23,5 +25,5 @@ type BasicAuth struct { // for more details. // // Note: The secret must be in the same namespace as the SecurityPolicy. - Users gwapiv1b1.SecretObjectReference `json:"users"` + Users gwapiv1.SecretObjectReference `json:"users"` } diff --git a/api/v1alpha1/oidc_types.go b/api/v1alpha1/oidc_types.go index 78c32287cde..dcc03615772 100644 --- a/api/v1alpha1/oidc_types.go +++ b/api/v1alpha1/oidc_types.go @@ -7,7 +7,7 @@ package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) const OIDCClientSecretKey = "client-secret" @@ -29,7 +29,7 @@ type OIDC struct { // This is an Opaque secret. The client secret should be stored in the key // "client-secret". // +kubebuilder:validation:Required - ClientSecret gwapiv1b1.SecretObjectReference `json:"clientSecret"` + ClientSecret gwapiv1.SecretObjectReference `json:"clientSecret"` // The optional cookie name overrides to be used for Bearer and IdToken cookies in the // [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). diff --git a/api/v1alpha1/wasm_types.go b/api/v1alpha1/wasm_types.go index 1c41513f941..66c0e1fc84f 100644 --- a/api/v1alpha1/wasm_types.go +++ b/api/v1alpha1/wasm_types.go @@ -7,7 +7,7 @@ package v1alpha1 import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) // Wasm defines a Wasm extension. @@ -136,7 +136,7 @@ type ImageWasmCodeSource struct { // Only support Kubernetes Secret resource from the same namespace. // +kubebuilder:validation:XValidation:message="only support Secret kind.",rule="self.kind == 'Secret'" // +optional - PullSecretRef *gwapiv1b1.SecretObjectReference `json:"pullSecretRef,omitempty"` + PullSecretRef *gwapiv1.SecretObjectReference `json:"pullSecretRef,omitempty"` } // ImagePullPolicy defines the policy to use when pulling an OIC image. diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index 87020d7f6ec..6b9a488b86b 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -914,7 +914,7 @@ func (t *Translator) validateHostname(hostname string) error { func (t *Translator) validateSecretRef( allowCrossNamespace bool, from crossNamespaceFrom, - secretObjRef gwapiv1b1.SecretObjectReference, + secretObjRef gwapiv1.SecretObjectReference, resources *resource.Resources, ) (*corev1.Secret, error) { if err := t.validateSecretObjectRef(allowCrossNamespace, from, secretObjRef, resources); err != nil { @@ -938,7 +938,7 @@ func (t *Translator) validateSecretRef( func (t *Translator) validateConfigMapRef( allowCrossNamespace bool, from crossNamespaceFrom, - secretObjRef gwapiv1b1.SecretObjectReference, + secretObjRef gwapiv1.SecretObjectReference, resources *resource.Resources, ) (*corev1.ConfigMap, error) { if err := t.validateSecretObjectRef(allowCrossNamespace, from, secretObjRef, resources); err != nil { @@ -962,7 +962,7 @@ func (t *Translator) validateConfigMapRef( func (t *Translator) validateSecretObjectRef( allowCrossNamespace bool, from crossNamespaceFrom, - secretRef gwapiv1b1.SecretObjectReference, + secretRef gwapiv1.SecretObjectReference, resources *resource.Resources, ) error { var kind string diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 167e70746ec..7fe3c3d32ff 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -602,7 +602,7 @@ func (r *gatewayAPIReconciler) processSecretRef( ownerKind string, ownerNS string, ownerName string, - secretRef gwapiv1b1.SecretObjectReference, + secretRef gwapiv1.SecretObjectReference, ) error { secret := new(corev1.Secret) secretNS := gatewayapi.NamespaceDerefOr(secretRef.Namespace, ownerNS) @@ -704,7 +704,7 @@ func (r *gatewayAPIReconciler) processConfigMapRef( ownerKind string, ownerNS string, ownerName string, - configMapRef gwapiv1b1.SecretObjectReference, + configMapRef gwapiv1.SecretObjectReference, ) error { configMap := new(corev1.ConfigMap) configMapNS := gatewayapi.NamespaceDerefOr(configMapRef.Namespace, ownerNS) @@ -1794,7 +1794,7 @@ func (r *gatewayAPIReconciler) processBackendTLSPolicyRefs( string(caCertRef.Kind) == resource.KindSecret { var err error - caRefNew := gwapiv1b1.SecretObjectReference{ + caRefNew := gwapiv1.SecretObjectReference{ Group: gatewayapi.GroupPtr(string(caCertRef.Group)), Kind: gatewayapi.KindPtr(string(caCertRef.Kind)), Name: caCertRef.Name, diff --git a/internal/provider/kubernetes/indexers.go b/internal/provider/kubernetes/indexers.go index 68a58dd872d..462a70542f3 100644 --- a/internal/provider/kubernetes/indexers.go +++ b/internal/provider/kubernetes/indexers.go @@ -531,7 +531,7 @@ func secretSecurityPolicyIndexFunc(rawObj client.Object) []string { securityPolicy := rawObj.(*egv1a1.SecurityPolicy) var ( - secretReferences []gwapiv1b1.SecretObjectReference + secretReferences []gwapiv1.SecretObjectReference values []string ) diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go index ef8182ffdb9..5954e94675e 100644 --- a/internal/provider/kubernetes/predicates_test.go +++ b/internal/provider/kubernetes/predicates_test.go @@ -19,7 +19,6 @@ import ( fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/envoygateway" @@ -261,7 +260,7 @@ func TestValidateSecretForReconcile(t *testing.T) { TokenEndpoint: ptr.To("https://oauth2.googleapis.com/token"), }, ClientID: "client-id", - ClientSecret: gwapiv1b1.SecretObjectReference{ + ClientSecret: gwapiv1.SecretObjectReference{ Name: "secret", }, }, @@ -290,7 +289,7 @@ func TestValidateSecretForReconcile(t *testing.T) { }, }, BasicAuth: &egv1a1.BasicAuth{ - Users: gwapiv1b1.SecretObjectReference{ + Users: gwapiv1.SecretObjectReference{ Name: "secret", }, }, @@ -336,7 +335,7 @@ func TestValidateSecretForReconcile(t *testing.T) { Type: egv1a1.ImageWasmCodeSourceType, Image: &egv1a1.ImageWasmCodeSource{ URL: "https://example.com/testwasm:v1.0.0", - PullSecretRef: &gwapiv1b1.SecretObjectReference{ + PullSecretRef: &gwapiv1.SecretObjectReference{ Name: "secret", }, }, diff --git a/test/e2e/tests/wasm_oci.go b/test/e2e/tests/wasm_oci.go index 1a0a43a33c5..4a6a53f6603 100644 --- a/test/e2e/tests/wasm_oci.go +++ b/test/e2e/tests/wasm_oci.go @@ -32,7 +32,6 @@ import ( "k8s.io/utils/ptr" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1" "sigs.k8s.io/gateway-api/conformance/utils/http" "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" "sigs.k8s.io/gateway-api/conformance/utils/suite" @@ -416,7 +415,7 @@ func createEEPForWasmTest( }, } if withPullSecret { - eep.Spec.Wasm[0].Code.Image.PullSecretRef = &gwapiv1b1.SecretObjectReference{ + eep.Spec.Wasm[0].Code.Image.PullSecretRef = &gwapiv1.SecretObjectReference{ Name: gwapiv1.ObjectName(pullSecret), } } diff --git a/tools/src/crd-ref-docs/go.mod b/tools/src/crd-ref-docs/go.mod index 23b3153de03..017b54837b8 100644 --- a/tools/src/crd-ref-docs/go.mod +++ b/tools/src/crd-ref-docs/go.mod @@ -1,8 +1,8 @@ module local -go 1.22.7 +go 1.23.1 -require github.com/elastic/crd-ref-docs v0.0.13-0.20240723135120-56876bccac3a +require github.com/elastic/crd-ref-docs v0.1.0 require ( github.com/Masterminds/goutils v1.1.1 // indirect diff --git a/tools/src/crd-ref-docs/go.sum b/tools/src/crd-ref-docs/go.sum index 2c129e265b6..8bfb30cec1a 100644 --- a/tools/src/crd-ref-docs/go.sum +++ b/tools/src/crd-ref-docs/go.sum @@ -8,10 +8,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/elastic/crd-ref-docs v0.0.13-0.20240413123740-ea9fcaa0230f h1:cE1CF4Bfi+9gvaNz35jOsp3tFJVm/mFr88szZ41FG8Q= -github.com/elastic/crd-ref-docs v0.0.13-0.20240413123740-ea9fcaa0230f/go.mod h1:X83mMBdJt05heJUYiS3T0yJ/JkCuliuhSUNav5Gjo/U= -github.com/elastic/crd-ref-docs v0.0.13-0.20240723135120-56876bccac3a h1:+sHMdth53bKHbct/BqfYIhYXGKhIZJDv2PhS9Gfw8xg= -github.com/elastic/crd-ref-docs v0.0.13-0.20240723135120-56876bccac3a/go.mod h1:X83mMBdJt05heJUYiS3T0yJ/JkCuliuhSUNav5Gjo/U= +github.com/elastic/crd-ref-docs v0.1.0 h1:Cr5kz89QB3Iuuj7dhAfLMApCrChEGAaIBTxGk/xuRKw= +github.com/elastic/crd-ref-docs v0.1.0/go.mod h1:X83mMBdJt05heJUYiS3T0yJ/JkCuliuhSUNav5Gjo/U= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= From 70c568beae352160cebc138576dccd75239da0e4 Mon Sep 17 00:00:00 2001 From: zirain Date: Sat, 19 Oct 2024 13:40:11 +0800 Subject: [PATCH 39/39] docs: improve a little bit visual (#4468) * docs: improve a little bit visual Signed-off-by: zirain * sidebar Signed-off-by: zirain --------- Signed-off-by: zirain --- site/assets/scss/_variables_project.scss | 9 +++++++++ .../en/docs/tasks/extensibility/extension-server.md | 1 + .../en/latest/tasks/extensibility/extension-server.md | 1 + .../en/v1.1/tasks/extensibility/extension-server.md | 1 + 4 files changed, 12 insertions(+) diff --git a/site/assets/scss/_variables_project.scss b/site/assets/scss/_variables_project.scss index 8c3ce90a2cf..e799cef8e90 100644 --- a/site/assets/scss/_variables_project.scss +++ b/site/assets/scss/_variables_project.scss @@ -11,4 +11,13 @@ $dark: #280C53; // better style when pre inside tab pane .td-content .highlight pre{ margin-bottom: 1rem !important; +} + +nav.foldable-nav .with-child, nav.foldable-nav .without-child { + position: relative; + padding-left: 1.0em !important; +} + +nav.foldable-nav .ul-1 .with-child > label:before { + padding-left: 0 !important; } \ No newline at end of file diff --git a/site/content/en/docs/tasks/extensibility/extension-server.md b/site/content/en/docs/tasks/extensibility/extension-server.md index 7d67c23f6da..323ce5642ea 100644 --- a/site/content/en/docs/tasks/extensibility/extension-server.md +++ b/site/content/en/docs/tasks/extensibility/extension-server.md @@ -1,5 +1,6 @@ --- title: "Envoy Gateway Extension Server" +linkTitle: "Extension Server" --- This task explains how to extend Envoy Gateway using an Extension Server. Envoy Gateway diff --git a/site/content/en/latest/tasks/extensibility/extension-server.md b/site/content/en/latest/tasks/extensibility/extension-server.md index 922f0de7c8e..6d16013d410 100644 --- a/site/content/en/latest/tasks/extensibility/extension-server.md +++ b/site/content/en/latest/tasks/extensibility/extension-server.md @@ -1,5 +1,6 @@ --- title: "Envoy Gateway Extension Server" +linkTitle: "Extension Server" --- This task explains how to extend Envoy Gateway using an Extension Server. Envoy Gateway diff --git a/site/content/en/v1.1/tasks/extensibility/extension-server.md b/site/content/en/v1.1/tasks/extensibility/extension-server.md index 7d67c23f6da..323ce5642ea 100644 --- a/site/content/en/v1.1/tasks/extensibility/extension-server.md +++ b/site/content/en/v1.1/tasks/extensibility/extension-server.md @@ -1,5 +1,6 @@ --- title: "Envoy Gateway Extension Server" +linkTitle: "Extension Server" --- This task explains how to extend Envoy Gateway using an Extension Server. Envoy Gateway