From 798966742dc1cb214b2eef549ca5c918af9dcd2d Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 14 Nov 2024 23:02:55 +0800 Subject: [PATCH 1/3] chore: bump golang to 1.23.3 (#4716) Signed-off-by: zirain --- examples/envoy-als/Dockerfile | 2 +- examples/envoy-als/go.mod | 2 +- examples/extension-server/go.mod | 2 +- examples/grpc-ext-auth/Dockerfile | 2 +- examples/grpc-ext-auth/go.mod | 2 +- examples/grpc-ext-proc/Dockerfile | 2 +- examples/grpc-ext-proc/go.mod | 2 +- examples/preserve-case-backend/Dockerfile | 2 +- examples/preserve-case-backend/go.mod | 2 +- go.mod | 2 +- tools/make/examples.mk | 9 +++++++++ tools/make/golang.mk | 2 +- tools/src/buf/go.mod | 2 +- tools/src/crd-ref-docs/go.mod | 2 +- tools/src/gci/go.mod | 2 +- tools/src/golangci-lint/go.mod | 2 +- tools/src/helm-docs/go.mod | 2 +- tools/src/jb/go.mod | 2 +- tools/src/jsonnet/go.mod | 2 +- tools/src/kind/go.mod | 2 +- tools/src/protoc-gen-go-grpc/go.mod | 2 +- tools/src/protoc-gen-go/go.mod | 2 +- tools/src/setup-envtest/go.mod | 2 +- 23 files changed, 31 insertions(+), 22 deletions(-) diff --git a/examples/envoy-als/Dockerfile b/examples/envoy-als/Dockerfile index 0ad9437f993..835a8200716 100644 --- a/examples/envoy-als/Dockerfile +++ b/examples/envoy-als/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23.1 AS builder +FROM golang:1.23.3 AS builder ARG GO_LDFLAGS="" diff --git a/examples/envoy-als/go.mod b/examples/envoy-als/go.mod index 610090483ad..df62679506a 100644 --- a/examples/envoy-als/go.mod +++ b/examples/envoy-als/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-envoy-als -go 1.23.1 +go 1.23.3 require ( github.com/envoyproxy/go-control-plane v0.13.1 diff --git a/examples/extension-server/go.mod b/examples/extension-server/go.mod index 13edb3f3877..24e910c1ddf 100644 --- a/examples/extension-server/go.mod +++ b/examples/extension-server/go.mod @@ -1,6 +1,6 @@ module github.com/exampleorg/envoygateway-extension -go 1.23.1 +go 1.23.3 require ( github.com/envoyproxy/gateway v1.0.2 diff --git a/examples/grpc-ext-auth/Dockerfile b/examples/grpc-ext-auth/Dockerfile index 4f6ea6ff545..f90bb04d8cb 100644 --- a/examples/grpc-ext-auth/Dockerfile +++ b/examples/grpc-ext-auth/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23.1 AS builder +FROM golang:1.23.3 AS builder ARG GO_LDFLAGS="" diff --git a/examples/grpc-ext-auth/go.mod b/examples/grpc-ext-auth/go.mod index 8e3fcb7e061..fe656cdc112 100644 --- a/examples/grpc-ext-auth/go.mod +++ b/examples/grpc-ext-auth/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-grcp-ext-auth -go 1.23.1 +go 1.23.3 require ( github.com/envoyproxy/go-control-plane v0.13.1 diff --git a/examples/grpc-ext-proc/Dockerfile b/examples/grpc-ext-proc/Dockerfile index a07ab13f48b..cd0f7db820b 100644 --- a/examples/grpc-ext-proc/Dockerfile +++ b/examples/grpc-ext-proc/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23.1 AS builder +FROM golang:1.23.3 AS builder ARG GO_LDFLAGS="" diff --git a/examples/grpc-ext-proc/go.mod b/examples/grpc-ext-proc/go.mod index bb18254c721..5c7b98ee08e 100644 --- a/examples/grpc-ext-proc/go.mod +++ b/examples/grpc-ext-proc/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-grpc-ext-proc -go 1.23.1 +go 1.23.3 require ( github.com/envoyproxy/go-control-plane v0.13.1 diff --git a/examples/preserve-case-backend/Dockerfile b/examples/preserve-case-backend/Dockerfile index 4616d465cb6..46d71ff22b5 100644 --- a/examples/preserve-case-backend/Dockerfile +++ b/examples/preserve-case-backend/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23.1 AS builder +FROM golang:1.23.3 AS builder ARG GO_LDFLAGS="" diff --git a/examples/preserve-case-backend/go.mod b/examples/preserve-case-backend/go.mod index 7a9712aa341..22c616a7ba3 100644 --- a/examples/preserve-case-backend/go.mod +++ b/examples/preserve-case-backend/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-preserve-case-backend -go 1.23.1 +go 1.23.3 require github.com/valyala/fasthttp v1.51.0 diff --git a/go.mod b/go.mod index 74bb7f24aca..59d3ffde5fb 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway -go 1.23.1 +go 1.23.3 replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16 diff --git a/tools/make/examples.mk b/tools/make/examples.mk index 5caf9846e63..e0e01e190d6 100644 --- a/tools/make/examples.mk +++ b/tools/make/examples.mk @@ -17,4 +17,13 @@ kube-install-examples-image: kube-build-examples-image @$(LOG_TARGET) @for app in $(EXAMPLE_APPS); do \ tools/hack/kind-load-image.sh $(EXAMPLE_IMAGE_PREFIX)$$app $(EXAMPLE_TAG); \ + done + +.PHONY: go.mod.tidy.examples +go.mod.tidy.examples: + @$(LOG_TARGET) + @for app in $(EXAMPLE_APPS); do \ + pushd $(ROOT_DIR)/examples/$$app; \ + go mod tidy -compat=$(GO_VERSION); \ + popd; \ done \ No newline at end of file diff --git a/tools/make/golang.mk b/tools/make/golang.mk index 4c0d38bf83e..4f4dce00faa 100644 --- a/tools/make/golang.mk +++ b/tools/make/golang.mk @@ -84,7 +84,7 @@ go.mod.tidy: ## Update and check dependences with go mod tidy. .PHONY: go.mod.lint lint: go.mod.lint -go.mod.lint: go.mod.tidy ## Check if go.mod is clean +go.mod.lint: go.mod.tidy go.mod.tidy.examples ## Check if go.mod is clean @$(LOG_TARGET) @if test -n "$$(git status -s -- go.mod go.sum)"; then \ git diff --exit-code go.mod; \ diff --git a/tools/src/buf/go.mod b/tools/src/buf/go.mod index d8bea4a9f7c..b276538c15a 100644 --- a/tools/src/buf/go.mod +++ b/tools/src/buf/go.mod @@ -1,6 +1,6 @@ module local -go 1.23.1 +go 1.23.3 require github.com/bufbuild/buf v1.46.0 diff --git a/tools/src/crd-ref-docs/go.mod b/tools/src/crd-ref-docs/go.mod index 017b54837b8..5d5bcd374a3 100644 --- a/tools/src/crd-ref-docs/go.mod +++ b/tools/src/crd-ref-docs/go.mod @@ -1,6 +1,6 @@ module local -go 1.23.1 +go 1.23.3 require github.com/elastic/crd-ref-docs v0.1.0 diff --git a/tools/src/gci/go.mod b/tools/src/gci/go.mod index 382ffae2274..bf8d0ac7a5c 100644 --- a/tools/src/gci/go.mod +++ b/tools/src/gci/go.mod @@ -1,6 +1,6 @@ module local -go 1.23.1 +go 1.23.3 require github.com/daixiang0/gci v0.13.4 diff --git a/tools/src/golangci-lint/go.mod b/tools/src/golangci-lint/go.mod index e88d8a1a325..d7d2cdce1f2 100644 --- a/tools/src/golangci-lint/go.mod +++ b/tools/src/golangci-lint/go.mod @@ -1,6 +1,6 @@ module local -go 1.23.1 +go 1.23.3 require github.com/golangci/golangci-lint v1.62.0 diff --git a/tools/src/helm-docs/go.mod b/tools/src/helm-docs/go.mod index 2f61f2bf33a..05180f8b0f0 100644 --- a/tools/src/helm-docs/go.mod +++ b/tools/src/helm-docs/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway/tools/src/helm-docs -go 1.23.1 +go 1.23.3 require github.com/norwoodj/helm-docs v1.14.2 diff --git a/tools/src/jb/go.mod b/tools/src/jb/go.mod index fb8807bab20..9915adc8bfd 100644 --- a/tools/src/jb/go.mod +++ b/tools/src/jb/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway/tools/src/jb -go 1.23.1 +go 1.23.3 require github.com/jsonnet-bundler/jsonnet-bundler v0.5.1 diff --git a/tools/src/jsonnet/go.mod b/tools/src/jsonnet/go.mod index 2cf5cfd4c7b..aec5a71feeb 100644 --- a/tools/src/jsonnet/go.mod +++ b/tools/src/jsonnet/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway/tools/src/jsonnet -go 1.23.1 +go 1.23.3 require github.com/google/go-jsonnet v0.20.0 diff --git a/tools/src/kind/go.mod b/tools/src/kind/go.mod index 42dd6426e94..398e0d90a29 100644 --- a/tools/src/kind/go.mod +++ b/tools/src/kind/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway/tools/src/kind -go 1.23.1 +go 1.23.3 require sigs.k8s.io/kind v0.25.0 diff --git a/tools/src/protoc-gen-go-grpc/go.mod b/tools/src/protoc-gen-go-grpc/go.mod index 11e0bc567bd..1b6f5e9f0c6 100644 --- a/tools/src/protoc-gen-go-grpc/go.mod +++ b/tools/src/protoc-gen-go-grpc/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway/tools/src/protoc-gen-go-grpc -go 1.23.1 +go 1.23.3 require google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 diff --git a/tools/src/protoc-gen-go/go.mod b/tools/src/protoc-gen-go/go.mod index 588c433426f..86ccc619362 100644 --- a/tools/src/protoc-gen-go/go.mod +++ b/tools/src/protoc-gen-go/go.mod @@ -1,5 +1,5 @@ module github.com/envoyproxy/gateway/tools/src/protoc-gen-go -go 1.23.1 +go 1.23.3 require google.golang.org/protobuf v1.33.0 diff --git a/tools/src/setup-envtest/go.mod b/tools/src/setup-envtest/go.mod index 33e82a774e7..53ea509481f 100644 --- a/tools/src/setup-envtest/go.mod +++ b/tools/src/setup-envtest/go.mod @@ -1,6 +1,6 @@ module local -go 1.23.1 +go 1.23.3 require sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240813183042-b901db121e1f From 1c29f66f851ae4bc76f5e270331b0059f56a9efe Mon Sep 17 00:00:00 2001 From: Lior Okman Date: Thu, 14 Nov 2024 18:00:22 +0200 Subject: [PATCH 2/3] fix: recover from panics that occur during envoy gateway's reconciliation (#4643) * Added a panic recovery flow for HandleSubscription. Signed-off-by: Lior Okman * Panic recovery should not be a one-off occurrence Signed-off-by: Lior Okman * Added a metric for recovered panics Signed-off-by: Lior Okman * Verify that the correct number of calls were received by the HandleSubscription handler function, Signed-off-by: Lior Okman * Typo and align the metric name with other metrics in the same area. Signed-off-by: Lior Okman --------- Signed-off-by: Lior Okman --- internal/message/metrics.go | 5 ++++ internal/message/watchutil.go | 37 ++++++++++++++++++++++-------- internal/message/watchutil_test.go | 28 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/internal/message/metrics.go b/internal/message/metrics.go index 5f120124191..de744f47aa8 100644 --- a/internal/message/metrics.go +++ b/internal/message/metrics.go @@ -13,6 +13,11 @@ var ( "Current depth of watchable queue.", ) + panicCounter = metrics.NewCounter( + "watchable_panics_recovered_total", + "Total number of panics recovered while handling items in queue.", + ) + watchableSubscribeDurationSeconds = metrics.NewHistogram( "watchable_subscribe_duration_seconds", "How long in seconds a subscribed watchable queue is handled.", diff --git a/internal/message/watchutil.go b/internal/message/watchutil.go index f8391cbc47a..77caa4af3d9 100644 --- a/internal/message/watchutil.go +++ b/internal/message/watchutil.go @@ -6,6 +6,8 @@ package message import ( + "fmt" + "runtime/debug" "time" "github.com/telepresenceio/watchable" @@ -36,6 +38,28 @@ func (m Metadata) LabelValues() []metrics.LabelValue { return labels } +// handleWithCrashRecovery calls the provided handle function and gracefully recovers from any panics +// that might occur when the handle function is called. +func handleWithCrashRecovery[K comparable, V any]( + handle func(updateFunc Update[K, V], errChans chan error), + update Update[K, V], + meta Metadata, + errChans chan error, +) { + defer func() { + if r := recover(); r != nil { + logger.WithValues("runner", meta.Runner).Error(fmt.Errorf("%+v", r), "observed a panic", + "stackTrace", string(debug.Stack())) + watchableSubscribeTotal.WithFailure(metrics.ReasonError, meta.LabelValues()...).Increment() + panicCounter.WithFailure(metrics.ReasonError, meta.LabelValues()...).Increment() + } + }() + startHandleTime := time.Now() + handle(update, errChans) + watchableSubscribeTotal.WithSuccess(meta.LabelValues()...).Increment() + watchableSubscribeDurationSeconds.With(meta.LabelValues()...).Record(time.Since(startHandleTime).Seconds()) +} + // HandleSubscription takes a channel returned by // watchable.Map.Subscribe() (or .SubscribeSubset()), and calls the // given function for each initial value in the map, and for any @@ -57,25 +81,20 @@ func HandleSubscription[K comparable, V any]( watchableSubscribeTotal.WithFailure(metrics.ReasonError, meta.LabelValues()...).Increment() } }() + defer close(errChans) if snapshot, ok := <-subscription; ok { for k, v := range snapshot.State { - startHandleTime := time.Now() - handle(Update[K, V]{ + handleWithCrashRecovery(handle, Update[K, V]{ Key: k, Value: v, - }, errChans) - watchableSubscribeTotal.WithSuccess(meta.LabelValues()...).Increment() - watchableSubscribeDurationSeconds.With(meta.LabelValues()...).Record(time.Since(startHandleTime).Seconds()) + }, meta, errChans) } } for snapshot := range subscription { watchableDepth.With(meta.LabelValues()...).Record(float64(len(subscription))) for _, update := range snapshot.Updates { - startHandleTime := time.Now() - handle(Update[K, V](update), errChans) - watchableSubscribeTotal.WithSuccess(meta.LabelValues()...).Increment() - watchableSubscribeDurationSeconds.With(meta.LabelValues()...).Record(time.Since(startHandleTime).Seconds()) + handleWithCrashRecovery(handle, Update[K, V](update), meta, errChans) } } } diff --git a/internal/message/watchutil_test.go b/internal/message/watchutil_test.go index 2c08821b211..6e6472d14f0 100644 --- a/internal/message/watchutil_test.go +++ b/internal/message/watchutil_test.go @@ -30,6 +30,34 @@ func TestHandleSubscriptionAlreadyClosed(t *testing.T) { assert.Equal(t, 0, calls) } +func TestPanicInSubscriptionHandler(t *testing.T) { + defer func() { + if r := recover(); r != nil { + assert.Fail(t, "recovered from an unexpected panic") + } + }() + var m watchable.Map[string, any] + m.Store("foo", "bar") + + go func() { + time.Sleep(100 * time.Millisecond) + m.Store("baz", "qux") + time.Sleep(100 * time.Millisecond) + m.Close() + }() + + numCalls := 0 + message.HandleSubscription[string, any]( + message.Metadata{Runner: "demo", Message: "demo"}, + m.Subscribe(context.Background()), + func(update message.Update[string, any], errChans chan error) { + numCalls++ + panic("oops " + update.Key) + }, + ) + assert.Equal(t, 2, numCalls) +} + func TestHandleSubscriptionAlreadyInitialized(t *testing.T) { var m watchable.Map[string, any] m.Store("foo", "bar") From c2b0ee38e84666f41486dfdaba092f4dfdd1e480 Mon Sep 17 00:00:00 2001 From: Steve Gargan Date: Thu, 14 Nov 2024 17:25:40 +0000 Subject: [PATCH 3/3] feat(translator): allow configuration of hostEnvKeys on WASM extensions (#4470) feat(translation): allow configuration of hostEnvKeys on WASM extensions exposes the hostEnvKeys configuration for WASM extensons through envoy extension policies. This enables access to env vars that are set on the host envoy processes and is a convenient way to share secret meterial with WASM extensions. Signed-off-by: Steve Gargan --- api/v1alpha1/wasm_types.go | 12 + api/v1alpha1/zz_generated.deepcopy.go | 25 ++ ....envoyproxy.io_envoyextensionpolicies.yaml | 11 + internal/gatewayapi/envoyextensionpolicy.go | 4 + ...extensionpolicy-with-wasm-env-vars.in.yaml | 123 +++++++ ...xtensionpolicy-with-wasm-env-vars.out.yaml | 342 ++++++++++++++++++ internal/ir/xds.go | 4 + internal/ir/zz_generated.deepcopy.go | 5 + .../translator/testdata/in/xds-ir/wasm.yaml | 3 + .../testdata/out/xds-ir/wasm.listeners.yaml | 4 + internal/xds/translator/wasm.go | 48 ++- site/content/en/latest/api/extension_types.md | 15 + .../en/v1.1/tasks/extensibility/wasm.md | 143 +++++++- site/content/zh/latest/api/extension_types.md | 15 + 14 files changed, 732 insertions(+), 22 deletions(-) create mode 100644 internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.in.yaml create mode 100644 internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml diff --git a/api/v1alpha1/wasm_types.go b/api/v1alpha1/wasm_types.go index 66c0e1fc84f..8913486d6f1 100644 --- a/api/v1alpha1/wasm_types.go +++ b/api/v1alpha1/wasm_types.go @@ -10,6 +10,14 @@ import ( gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) +// WasmEnv defines the environment variables for the VM of a Wasm extension +type WasmEnv struct { + // HostKeys is a list of keys for environment variables from the host envoy process + // that should be passed into the Wasm VM. This is useful for passing secrets to to Wasm extensions. + // +optional + HostKeys []string `json:"hostKeys,omitempty"` +} + // Wasm defines a Wasm extension. // // Note: at the moment, Envoy Gateway does not support configuring Wasm runtime. @@ -52,6 +60,10 @@ type Wasm struct { // Priority defines the location of the Wasm extension in the HTTP filter chain. // If not specified, the Wasm extension will be inserted before the router filter. // Priority *uint32 `json:"priority,omitempty"` + + // Env configures the environment for the Wasm extension + // +optional + Env *WasmEnv `json:"env,omitempty"` } // WasmCodeSource defines the source of the Wasm code. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 3368e73dd70..12f634586c6 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -5479,6 +5479,11 @@ func (in *Wasm) DeepCopyInto(out *Wasm) { *out = new(bool) **out = **in } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = new(WasmEnv) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Wasm. @@ -5521,6 +5526,26 @@ func (in *WasmCodeSource) DeepCopy() *WasmCodeSource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WasmEnv) DeepCopyInto(out *WasmEnv) { + *out = *in + if in.HostKeys != nil { + in, out := &in.HostKeys, &out.HostKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WasmEnv. +func (in *WasmEnv) DeepCopy() *WasmEnv { + if in == nil { + return nil + } + out := new(WasmEnv) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *XDSTranslatorHooks) DeepCopyInto(out *XDSTranslatorHooks) { *out = *in 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 6baa2842c0c..e6cb298d3a8 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -1232,6 +1232,17 @@ spec: Config is the configuration for the Wasm extension. This configuration will be passed as a JSON string to the Wasm extension. x-kubernetes-preserve-unknown-fields: true + env: + description: Env configures the environment for the Wasm extension + properties: + hostKeys: + description: |- + HostKeys is a list of keys for environment variables from the host envoy process + that should be passed into the Wasm VM. This is useful for passing secrets to to Wasm extensions. + items: + type: string + type: array + type: object failOpen: default: false description: |- diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index 9ba561f1b5d..64e0f9e9a2a 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -675,6 +675,10 @@ func (t *Translator) buildWasm( Code: code, } + if config.Env != nil && len(config.Env.HostKeys) > 0 { + wasmIR.HostKeys = config.Env.HostKeys + } + return wasmIR, nil } diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.in.yaml new file mode 100644 index 00000000000..c4184d15476 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.in.yaml @@ -0,0 +1,123 @@ +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: my-pull-secret + data: + .dockerconfigjson: VGhpc0lzTm90QVJlYWxEb2NrZXJDb25maWdKc29u +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 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-2 + spec: + hostnames: + - www.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/bar" + backendRefs: + - name: service-1 + port: 8080 +envoyextensionpolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway # This policy should attach httproute-2 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + wasm: + - name: wasm-filter-1 + code: + type: HTTP + http: + url: https://www.example.com/wasm-filter-1.wasm + sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4 + env: + hostKeys: + - SOME_KEY + - ANOTHER_KEY + - name: wasm-filter-2 + rootID: "my-root-id" + code: + type: Image + image: + url: oci://www.example.com/wasm-filter-2:v1.0.0 + pullSecretRef: + name: my-pull-secret + sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 + env: + hostKeys: + - SOME_KEY + - ANOTHER_KEY + - code: + type: Image + image: + url: www.example.com:8080/wasm-filter-3 +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + namespace: default + name: policy-for-http-route # This policy should attach httproute-1 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + wasm: + - name: wasm-filter-4 + code: + type: HTTP + http: + url: https://www.test.com/wasm-filter-4.wasm + sha256: b6922722ab58109abfaa8d9eb16f339b38b2bb1c17076b083b34438b934e7463 + failOpen: true + env: + hostKeys: + - SOME_KEY + - ANOTHER_KEY diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml new file mode 100644 index 00000000000..4a19852eea0 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml @@ -0,0 +1,342 @@ +envoyExtensionPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + creationTimestamp: null + name: policy-for-http-route + namespace: default + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + wasm: + - code: + http: + sha256: b6922722ab58109abfaa8d9eb16f339b38b2bb1c17076b083b34438b934e7463 + url: https://www.test.com/wasm-filter-4.wasm + type: HTTP + env: + hostKeys: + - SOME_KEY + - ANOTHER_KEY + failOpen: true + name: wasm-filter-4 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + creationTimestamp: null + name: policy-for-gateway + namespace: envoy-gateway + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + wasm: + - code: + http: + sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4 + url: https://www.example.com/wasm-filter-1.wasm + type: HTTP + env: + hostKeys: + - SOME_KEY + - ANOTHER_KEY + name: wasm-filter-1 + - code: + image: + pullSecretRef: + group: null + kind: null + name: my-pull-secret + sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 + url: oci://www.example.com/wasm-filter-2:v1.0.0 + type: Image + env: + hostKeys: + - SOME_KEY + - ANOTHER_KEY + name: wasm-filter-2 + rootID: my-root-id + - code: + image: + sha256: null + url: www.example.com:8080/wasm-filter-3 + type: Image + 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 + - lastTransitionTime: null + message: 'This policy is being overridden by other envoyExtensionPolicies + for these routes: [default/httproute-1]' + reason: Overridden + status: "True" + type: Overridden + controllerName: gateway.envoyproxy.io/gatewayclass-controller +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: 2 + 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 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-2 + 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: /bar + 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 +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 + envoyExtensions: + wasms: + - config: null + failOpen: true + hostKeys: + - SOME_KEY + - ANOTHER_KEY + httpWasmCode: + originalDownloadingURL: https://www.test.com/wasm-filter-4.wasm + servingURL: https://envoy-gateway:18002/fe571e7b1ef5dc626ceb2c2c86782a134a92989a2643485238951696ae4334c3.wasm + sha256: b6922722ab58109abfaa8d9eb16f339b38b2bb1c17076b083b34438b934e7463 + name: envoyextensionpolicy/default/policy-for-http-route/wasm/0 + wasmName: wasm-filter-4 + 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 + - destination: + name: httproute/default/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + envoyExtensions: + wasms: + - config: null + failOpen: false + hostKeys: + - SOME_KEY + - ANOTHER_KEY + httpWasmCode: + originalDownloadingURL: https://www.example.com/wasm-filter-1.wasm + servingURL: https://envoy-gateway:18002/5c90b9a82642ce00a7753923fabead306b9d9a54a7c0bd2463a1af3efcfb110b.wasm + sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/0 + wasmName: wasm-filter-1 + - config: null + failOpen: false + hostKeys: + - SOME_KEY + - ANOTHER_KEY + httpWasmCode: + originalDownloadingURL: oci://www.example.com/wasm-filter-2:v1.0.0 + servingURL: https://envoy-gateway:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm + sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 + rootID: my-root-id + wasmName: wasm-filter-2 + - config: null + failOpen: false + httpWasmCode: + originalDownloadingURL: oci://www.example.com:8080/wasm-filter-3:latest + servingURL: https://envoy-gateway:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm + sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 + wasmName: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 + hostname: www.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-2 + namespace: default + name: httproute/default/httproute-2/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /bar diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 5103d3ea81a..b0b9a1594b1 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -2634,6 +2634,10 @@ type Wasm struct { // original URL(either an HTTP URL or an OCI image) and serves it through the // local HTTP server. Code *HTTPWasmCode `json:"httpWasmCode,omitempty"` + + // HostKeys is a list of keys for environment variables from the host envoy process + // that should be passed into the Wasm VM. + HostKeys []string `json:"hostKeys,omitempty"` } // HTTPWasmCode holds the information associated with the HTTP Wasm code source. diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 59f1973b22a..de0be09ff0f 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -3425,6 +3425,11 @@ func (in *Wasm) DeepCopyInto(out *Wasm) { *out = new(HTTPWasmCode) **out = **in } + if in.HostKeys != nil { + in, out := &in.HostKeys, &out.HostKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Wasm. diff --git a/internal/xds/translator/testdata/in/xds-ir/wasm.yaml b/internal/xds/translator/testdata/in/xds-ir/wasm.yaml index 9afa2c97c9c..756e38952fa 100644 --- a/internal/xds/translator/testdata/in/xds-ir/wasm.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/wasm.yaml @@ -89,3 +89,6 @@ http: sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 wasmName: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 + hostKeys: + - SOME_KEY + - ANOTHER_KEY diff --git a/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml index a4545e62e2c..e3a679d1ae0 100755 --- a/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml @@ -90,6 +90,10 @@ timeout: 10s uri: https://envoy-gateway:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee + environmentVariables: + hostEnvKeys: + - SOME_KEY + - ANOTHER_KEY runtime: envoy.wasm.runtime.v8 vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 - name: envoy.filters.http.router diff --git a/internal/xds/translator/wasm.go b/internal/xds/translator/wasm.go index b8777e3805c..34b1087d5cc 100644 --- a/internal/xds/translator/wasm.go +++ b/internal/xds/translator/wasm.go @@ -118,30 +118,38 @@ func wasmConfig(wasm ir.Wasm) (*wasmfilterv3.Wasm, error) { return nil, err } + vmConfig := &wasmv3.VmConfig{ + VmId: wasm.Name, // Do not share VMs across different filters + Runtime: vmRuntimeV8, + Code: &corev3.AsyncDataSource{ + Specifier: &corev3.AsyncDataSource_Remote{ + Remote: &corev3.RemoteDataSource{ + HttpUri: &corev3.HttpUri{ + Uri: wasm.Code.ServingURL, + HttpUpstreamType: &corev3.HttpUri_Cluster{ + Cluster: wasmHTTPServerCluster, + }, + Timeout: &durationpb.Duration{ + Seconds: defaultExtServiceRequestTimeout, + }, + }, + Sha256: wasm.Code.SHA256, + }, + }, + }, + } + + if wasm.HostKeys != nil { + vmConfig.EnvironmentVariables = &wasmv3.EnvironmentVariables{ + HostEnvKeys: wasm.HostKeys, + } + } + filterConfig = &wasmfilterv3.Wasm{ Config: &wasmv3.PluginConfig{ Name: wasm.WasmName, Vm: &wasmv3.PluginConfig_VmConfig{ - VmConfig: &wasmv3.VmConfig{ - VmId: wasm.Name, // Do not share VMs across different filters - Runtime: vmRuntimeV8, - Code: &corev3.AsyncDataSource{ - Specifier: &corev3.AsyncDataSource_Remote{ - Remote: &corev3.RemoteDataSource{ - HttpUri: &corev3.HttpUri{ - Uri: wasm.Code.ServingURL, - HttpUpstreamType: &corev3.HttpUri_Cluster{ - Cluster: wasmHTTPServerCluster, - }, - Timeout: &durationpb.Duration{ - Seconds: defaultExtServiceRequestTimeout, - }, - }, - Sha256: wasm.Code.SHA256, - }, - }, - }, - }, + VmConfig: vmConfig, }, Configuration: configAny, FailOpen: wasm.FailOpen, diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index a519fc34ea7..77a28384c06 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -4204,6 +4204,7 @@ _Appears in:_ | `code` | _[WasmCodeSource](#wasmcodesource)_ | true | Code is the Wasm code for the extension. | | `config` | _[JSON](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#json-v1-apiextensions-k8s-io)_ | false | Config is the configuration for the Wasm extension.
This configuration will be passed as a JSON string to the Wasm extension. | | `failOpen` | _boolean_ | false | FailOpen is a switch used to control the behavior when a fatal error occurs
during the initialization or the execution of the Wasm extension.
If FailOpen is set to true, the system bypasses the Wasm extension and
allows the traffic to pass through. Otherwise, if it is set to false or
not set (defaulting to false), the system blocks the traffic and returns
an HTTP 5xx error. | +| `env` | _[WasmEnv](#wasmenv)_ | false | Env configures the environment for the Wasm extension | #### WasmCodeSource @@ -4238,6 +4239,20 @@ _Appears in:_ | `Image` | ImageWasmCodeSourceType allows the user to specify the Wasm code in an OCI image.
| +#### WasmEnv + + + +WasmEnv defines the environment variables for the VM of a Wasm extension + +_Appears in:_ +- [Wasm](#wasm) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `hostKeys` | _string array_ | false | HostKeys is a list of keys for environment variables from the host envoy process
that should be passed into the Wasm VM. This is useful for passing secrets to to Wasm extensions. | + + #### WithUnderscoresAction _Underlying type:_ _string_ diff --git a/site/content/en/v1.1/tasks/extensibility/wasm.md b/site/content/en/v1.1/tasks/extensibility/wasm.md index 1b1d32f9ecb..5d2495cf566 100644 --- a/site/content/en/v1.1/tasks/extensibility/wasm.md +++ b/site/content/en/v1.1/tasks/extensibility/wasm.md @@ -90,7 +90,7 @@ spec: Verify the EnvoyExtensionPolicy status: ```shell -kubectl get envoyextensionpolicy/http-wasm-source-test -o yaml +kubectl get envoyextensionpolicy/wasm-test -o yaml ``` ### Image Wasm Extension @@ -151,9 +151,148 @@ spec: Verify the EnvoyExtensionPolicy status: ```shell -kubectl get envoyextensionpolicy/http-wasm-source-test -o yaml +kubectl get envoyextensionpolicy/wasm-test -o yaml ``` +### Wasm Extension Configuration + +This [EnvoyExtensionPolicy][] configuration fetches the Wasm extension from an OCI image and uses a config block to pass parameters to the extension when it's loaded. + +{{< tabpane text=true >}} +{{% tab header="Apply from stdin" %}} + +```shell +cat <}} + +Verify the EnvoyExtensionPolicy status: + +```shell +kubectl get envoyextensionpolicy/wasm-test-o yaml +``` + +### Wasm Extension Configuration through Environment variables + +It is also possible to configure a wasm extension using environment variables from the host envoy process. Keys for the env vars to be shared are defined in a `hostKeys` block. + +This is especially useful for sharing secure data from environment vars on the envoy process set using [valueFrom](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables) a Kubernetes secret. + +Note that setting an env var on the envoy process requires a custom [EnvoyProxy](../../api/extension_types#envoyproxy) configuration. + +{{< tabpane text=true >}} +{{% tab header="Apply from stdin" %}} + +```shell +cat <}} + + ### Testing Ensure the `GATEWAY_HOST` environment variable from the [Quickstart](../../quickstart) is set. If not, follow the diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index a519fc34ea7..77a28384c06 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -4204,6 +4204,7 @@ _Appears in:_ | `code` | _[WasmCodeSource](#wasmcodesource)_ | true | Code is the Wasm code for the extension. | | `config` | _[JSON](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#json-v1-apiextensions-k8s-io)_ | false | Config is the configuration for the Wasm extension.
This configuration will be passed as a JSON string to the Wasm extension. | | `failOpen` | _boolean_ | false | FailOpen is a switch used to control the behavior when a fatal error occurs
during the initialization or the execution of the Wasm extension.
If FailOpen is set to true, the system bypasses the Wasm extension and
allows the traffic to pass through. Otherwise, if it is set to false or
not set (defaulting to false), the system blocks the traffic and returns
an HTTP 5xx error. | +| `env` | _[WasmEnv](#wasmenv)_ | false | Env configures the environment for the Wasm extension | #### WasmCodeSource @@ -4238,6 +4239,20 @@ _Appears in:_ | `Image` | ImageWasmCodeSourceType allows the user to specify the Wasm code in an OCI image.
| +#### WasmEnv + + + +WasmEnv defines the environment variables for the VM of a Wasm extension + +_Appears in:_ +- [Wasm](#wasm) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `hostKeys` | _string array_ | false | HostKeys is a list of keys for environment variables from the host envoy process
that should be passed into the Wasm VM. This is useful for passing secrets to to Wasm extensions. | + + #### WithUnderscoresAction _Underlying type:_ _string_