diff --git a/extensions/v1alpha1/extension_filter.pb.go b/extensions/v1alpha1/extension_filter.pb.go new file mode 100644 index 0000000000..07d19fdcd9 --- /dev/null +++ b/extensions/v1alpha1/extension_filter.pb.go @@ -0,0 +1,947 @@ +// Copyright Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: extensions/v1alpha1/extension_filter.proto + +// $schema: istio.extensions.v1alpha1.ExtensionFilter +// $title: Extension Filter +// $description: Extend the functionality provided by the Istio proxy through WebAssembly or Lua filters. +// $location: https://istio.io/docs/reference/config/proxy_extensions/v1alpha1/extension_filter.html +// $aliases: [/docs/reference/config/extensions/v1alpha1/extension_filter] + +// ExtensionFilter provides a mechanism to extend the functionality provided by +// the Istio proxy through WebAssembly or Lua filters. +// +// This API supersedes WasmPlugin by providing a unified mechanism for configuring +// multiple extension types (WebAssembly and Lua) while maintaining consistent +// targeting and configuration patterns. +// +// The order of execution (as part of Envoy's filter chain) is determined by +// phase and priority settings, allowing the configuration of complex +// interactions between user-supplied WebAssembly or Lua and Istio's internal +// filters. +// +// Examples: +// +// AuthN Filter deployed to ingress-gateway that implements an OpenID flow +// and populates the `Authorization` header with a JWT to be consumed by +// Istio AuthN. +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: openid-connect +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// phase: AUTHN +// wasm: +// url: file:///opt/filters/openid.wasm +// sha256: 1ef0c9a92b0420cf25f7fe5d481b231464bc88f486ca3b9c83ed5cc21d2f6210 +// pluginConfig: +// openid_server: authn +// openid_realm: ingress +// ``` +// +// This is the same as the last example, but using an OCI image. +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: openid-connect +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// phase: AUTHN +// wasm: +// url: oci://private-registry:5000/openid-connect/openid:latest +// imagePullPolicy: IfNotPresent +// imagePullSecret: private-registry-pull-secret +// pluginConfig: +// openid_server: authn +// openid_realm: ingress +// ``` +// +// This is the same as the last example, but using VmConfig to configure environment variables in the VM. +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: openid-connect +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// phase: AUTHN +// wasm: +// url: oci://private-registry:5000/openid-connect/openid:latest +// imagePullPolicy: IfNotPresent +// imagePullSecret: private-registry-pull-secret +// pluginConfig: +// openid_server: authn +// openid_realm: ingress +// vmConfig: +// env: +// - name: POD_NAME +// valueFrom: HOST +// - name: TRUST_DOMAIN +// value: "cluster.local" +// ``` +// +// This is also the same as the last example, but the Wasm module is pulled via https and updated for each time when this plugin resource is changed. +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: openid-connect +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// phase: AUTHN +// wasm: +// url: https://private-bucket/filters/openid.wasm +// imagePullPolicy: Always +// pluginConfig: +// openid_server: authn +// openid_realm: ingress +// vmConfig: +// env: +// - name: POD_NAME +// valueFrom: HOST +// - name: TRUST_DOMAIN +// value: "cluster.local" +// ``` +// +// And a more complex example that deploys three ExtensionFilters and orders them +// using `phase` and `priority`. The (hypothetical) setup is that the +// `openid-connect` filter performs an OpenID Connect flow to authenticate the +// user, writing a signed JWT into the Authorization header of the request, +// which can be verified by the Istio authn plugin. Then, the `acl-check` plugin +// kicks in, passing the JWT to a policy server, which in turn responds with a +// signed token that contains information about which files and functions of the +// system are available to the user that was previously authenticated. The +// `acl-check` filter writes this token to a header. Finally, the `check-header` +// filter verifies the token in that header and makes sure that the token's +// contents (the permitted 'function') matches its plugin configuration. +// +// The resulting filter chain looks like this: +// -> openid-connect -> istio.authn -> acl-check -> check-header -> router +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: openid-connect +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// phase: AUTHN +// wasm: +// url: oci://private-registry:5000/openid-connect/openid:latest +// imagePullPolicy: IfNotPresent +// imagePullSecret: private-registry-pull-secret +// pluginConfig: +// openid_server: authn +// openid_realm: ingress +// ``` +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: acl-check +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// phase: AUTHZ +// priority: 1000 +// wasm: +// url: oci://private-registry:5000/acl-check/acl:latest +// imagePullPolicy: Always +// imagePullSecret: private-registry-pull-secret +// pluginConfig: +// acl_server: some_server +// set_header: authz_complete +// ``` +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: check-header +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// phase: AUTHZ +// priority: 10 +// wasm: +// url: oci://private-registry:5000/check-header:latest +// imagePullPolicy: IfNotPresent +// imagePullSecret: private-registry-pull-secret +// pluginConfig: +// read_header: authz_complete +// verification_key: a89gAzxvls0JKAKIJSBnnvvvkIO +// function: read_data +// ``` +// +// Gateway with Lua filter for conditional header modification: +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: conditional-header-modifier +// namespace: istio-ingress +// spec: +// selector: +// matchLabels: +// istio: ingressgateway +// match: +// - mode: CLIENT +// ports: +// - number: 8080 +// - number: 8081 +// phase: AUTHN +// priority: 1000 +// lua: +// inlineCode: | +// function envoy_on_request(request_handle) +// local domain = "foo.com" +// local headers = request_handle:headers() +// local host = headers:get(":authority") +// local existing_auth_header = headers:get("Authorization") +// if (domain ~= nil and host ~= nil and existing_auth_header == nil and domain == host) then +// local bearer_token = headers:get("cookie"):match("foo") +// if (bearer_token ~= nil) then +// headers:add("Authorization", "Bearer " .. bearer_token) +// end +// end +// end +// ``` +// +// Waypoint with Lua filter for header count logging: +// +// ```yaml +// apiVersion: extensions.istio.io/v1alpha1 +// kind: ExtensionFilter +// metadata: +// name: reviews-header-logger +// namespace: default +// spec: +// targetRefs: +// - kind: Service +// name: reviews +// match: +// - mode: SERVER +// phase: STATS +// lua: +// inlineCode: | +// function envoy_on_request(request_handle) +// local headers = request_handle:headers() +// local num_headers = 0 +// for key, value in pairs(headers) do +// num_headers = num_headers + 1 +// end +// request_handle:logInfo("Request to reviews service has " .. num_headers .. " headers") +// end +// ``` + +package v1alpha1 + +import ( + _struct "github.com/golang/protobuf/ptypes/struct" + wrappers "github.com/golang/protobuf/ptypes/wrappers" + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + v1beta1 "istio.io/api/type/v1beta1" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// +// +// +// +kubebuilder:validation:XValidation:message="only one of targetRefs or selector can be set",rule="(has(self.selector)?1:0)+(has(self.targetRef)?1:0)+(has(self.targetRefs)?1:0)<=1" +// +kubebuilder:validation:XValidation:message="exactly one of wasm or lua must be set",rule="has(self.wasm) != has(self.lua)" +type ExtensionFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Criteria used to select the specific set of pods/VMs on which + // this plugin configuration should be applied. If omitted, this + // configuration will be applied to all workload instances in the same + // namespace. If the `ExtensionFilter` is present in the config root + // namespace, it will be applied to all applicable workloads in any + // namespace. + // + // At most, only one of `selector` or `targetRefs` can be set for a given policy. + Selector *v1beta1.WorkloadSelector `protobuf:"bytes,1,opt,name=selector,proto3" json:"selector,omitempty"` + // Optional. The targetRef specifies the gateway the policy should be + // applied to. The targeted resource specified will determine which + // workloads the extension filter applies to. The targeted resource + // must be a resource in the same namespace as the ExtensionFilter. + // + // If the targeted resource is a Gateway, the extension filter will be + // applied to all pods that match the targeted Gateway. If the targeted + // resource is a Service, the extension filter will be applied to all pods + // that match the service selector. + // + // If not set, the extension filter is applied to all workloads in the same + // namespace as the ExtensionFilter resource. + // + // At most one of `selector` or `targetRefs` can be set for a given policy. + // + // NOTE: If you are using the `targetRefs` field in "WAYPOINT" mode, you + // should either set a single `targetRef` or set multiple `targetRefs` (using + // the `targetRefs` field). You should not set both the `targetRef` and + // `targetRefs` fields at the same time as it is invalid. + // + // +kubebuilder:validation:XValidation:message="targetRef namespace must be unset",rule="!has(self.__namespace__)" + // + // Deprecated: Marked as deprecated in extensions/v1alpha1/extension_filter.proto. + TargetRef *v1beta1.PolicyTargetReference `protobuf:"bytes,2,opt,name=targetRef,proto3" json:"targetRef,omitempty"` + // Optional. The targetRefs specifies a list of resources the policy should be + // applied to. The targeted resources specified will determine which workloads + // the policy applies to. + // + // Currently, the following resource attachment types are supported: + // * `kind: Gateway` with `group: gateway.networking.k8s.io` in the same namespace. + // * `kind: GatewayClass` with `group: gateway.networking.k8s.io` in the root namespace. + // * `kind: Service` with `group: ""` or `group: "core"` in the same namespace. This type is only supported for waypoints. + // * `kind: ServiceEntry` with `group: networking.istio.io` in the same namespace. + // + // If not set, the policy is applied as defined by the selector. + // At most one of the selector and targetRefs can be set. + // + // NOTE: If you are using the `targetRefs` field in a multi-revision environment with Istio versions prior to 1.22, + // it is highly recommended that you pin the policy to a revision running 1.22+ via the `istio.io/rev` label. + // This is to prevent proxies connected to older control planes (that don't know about the `targetRefs` field) + // from misinterpreting the policy as namespace-wide during the upgrade process. + // + // NOTE: Waypoint proxies are required to use this field for policies to apply; `selector` policies will be ignored. + // +kubebuilder:validation:MaxItems=16 + TargetRefs []*v1beta1.PolicyTargetReference `protobuf:"bytes,3,rep,name=targetRefs,proto3" json:"targetRefs,omitempty"` + // Determines where in the filter chain this `ExtensionFilter` is to be injected. + Phase PluginPhase `protobuf:"varint,4,opt,name=phase,proto3,enum=istio.extensions.v1alpha1.PluginPhase" json:"phase,omitempty"` + // Determines ordering of `ExtensionFilters` in the same `phase`. + // When multiple `ExtensionFilters` are applied to the same workload in the + // same `phase`, they will be applied by priority, in descending order. + // If `priority` is not set, or two `ExtensionFilters` exist with the same + // value, the ordering will be deterministically derived from name and + // namespace of the `ExtensionFilters`. Defaults to `0`. + Priority *wrappers.Int32Value `protobuf:"bytes,5,opt,name=priority,proto3" json:"priority,omitempty"` + // Specifies the criteria to determine which traffic is passed to ExtensionFilter. + // If a traffic satisfies any of TrafficSelectors, + // the traffic passes the ExtensionFilter. + Match []*TrafficSelector `protobuf:"bytes,6,rep,name=match,proto3" json:"match,omitempty"` + // WebAssembly filter configuration. Mutually exclusive with `lua`. + Wasm *WasmConfig `protobuf:"bytes,10,opt,name=wasm,proto3" json:"wasm,omitempty"` + // Lua filter configuration. Mutually exclusive with `wasm`. + Lua *LuaConfig `protobuf:"bytes,11,opt,name=lua,proto3" json:"lua,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExtensionFilter) Reset() { + *x = ExtensionFilter{} + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExtensionFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExtensionFilter) ProtoMessage() {} + +func (x *ExtensionFilter) ProtoReflect() protoreflect.Message { + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExtensionFilter.ProtoReflect.Descriptor instead. +func (*ExtensionFilter) Descriptor() ([]byte, []int) { + return file_extensions_v1alpha1_extension_filter_proto_rawDescGZIP(), []int{0} +} + +func (x *ExtensionFilter) GetSelector() *v1beta1.WorkloadSelector { + if x != nil { + return x.Selector + } + return nil +} + +// Deprecated: Marked as deprecated in extensions/v1alpha1/extension_filter.proto. +func (x *ExtensionFilter) GetTargetRef() *v1beta1.PolicyTargetReference { + if x != nil { + return x.TargetRef + } + return nil +} + +func (x *ExtensionFilter) GetTargetRefs() []*v1beta1.PolicyTargetReference { + if x != nil { + return x.TargetRefs + } + return nil +} + +func (x *ExtensionFilter) GetPhase() PluginPhase { + if x != nil { + return x.Phase + } + return PluginPhase_UNSPECIFIED_PHASE +} + +func (x *ExtensionFilter) GetPriority() *wrappers.Int32Value { + if x != nil { + return x.Priority + } + return nil +} + +func (x *ExtensionFilter) GetMatch() []*TrafficSelector { + if x != nil { + return x.Match + } + return nil +} + +func (x *ExtensionFilter) GetWasm() *WasmConfig { + if x != nil { + return x.Wasm + } + return nil +} + +func (x *ExtensionFilter) GetLua() *LuaConfig { + if x != nil { + return x.Lua + } + return nil +} + +// WasmConfig configures a WebAssembly filter. +// +// Example: +// +// ```yaml +// wasm: +// +// url: oci://gcr.io/myproject/filter:v1.0.0 +// sha256: abc123... +// imagePullPolicy: IfNotPresent +// imagePullSecret: gcr-secret +// pluginName: my-filter +// pluginConfig: +// key1: value1 +// key2: value2 +// failStrategy: FAIL_CLOSE +// vmConfig: +// env: +// - name: SOME_ENV_VAR +// value: some_value +// type: HTTP +// +// ``` +type WasmConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // URL of a Wasm module or OCI container. If no scheme is present, + // defaults to `oci://`, referencing an OCI image. Other valid schemes + // are `file://` for referencing .wasm module files present locally + // within the proxy container, and `http[s]://` for .wasm module files + // hosted remotely. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:XValidation:message="url must have schema one of [http, https, file, oci]",rule="isURL(self) ? (url(self).getScheme() in [”, 'http', 'https', 'file', 'oci']) : (isURL('http://' + self) && url('http://' + self).getScheme() in [”, 'http', 'https', 'file', 'oci'])" + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + // SHA256 checksum that will be used to verify Wasm module or OCI container. + // If the `url` field already references a SHA256 (using the `@sha256:` + // notation), it must match the value of this field. If an OCI image is + // referenced by tag and this field is set, its checksum will be verified + // against the contents of this field after pulling. + // +kubebuilder:validation:Pattern="(^$|^[a-f0-9]{64}$)" + Sha256 string `protobuf:"bytes,2,opt,name=sha256,proto3" json:"sha256,omitempty"` + // The pull behaviour to be applied when fetching Wasm module by either + // OCI image or `http/https`. Only relevant when referencing Wasm module without + // any digest, including the digest in OCI image URL or `sha256` field in `vm_config`. + // Defaults to `IfNotPresent`, except when an OCI image is referenced in the `url` + // and the `latest` tag is used, in which case `Always` is the default, + // mirroring Kubernetes behaviour. + ImagePullPolicy PullPolicy `protobuf:"varint,3,opt,name=image_pull_policy,json=imagePullPolicy,proto3,enum=istio.extensions.v1alpha1.PullPolicy" json:"image_pull_policy,omitempty"` + // Credentials to use for OCI image pulling. + // Name of a Kubernetes Secret in the same namespace as the `ExtensionFilter` that + // contains a Docker pull secret which is to be used to authenticate + // against the registry when pulling the image. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + ImagePullSecret string `protobuf:"bytes,4,opt,name=image_pull_secret,json=imagePullSecret,proto3" json:"image_pull_secret,omitempty"` + // $hide_from_docs + // Public key that will be used to verify signatures of signed OCI images + // or Wasm modules. + // + // At this moment, various ways for signing/verifying are emerging and being proposed. + // We can observe two major streams for signing OCI images: Cosign from Sigstore and Notary, + // which is used in Docker Content Trust. + // In case of Wasm module, multiple approaches are still in discussion. + // - https://github.com/WebAssembly/design/issues/1413 + // - https://github.com/wasm-signatures/design (various signing tools are enumerated) + // + // In addition, for each method for signing&verifying, we may need to consider to provide + // additional data or configuration (e.g., key rolling, KMS, root certs, ...) as well. + // + // To deal with this situation, we need to elaborate more generic way to describe + // how to sign and verify the image or wasm binary, and how to specify relevant data, + // including this `verification_key`. + // + // Therefore, this field will not be implemented until the detailed design is established. + // For the future use, just keep this field in proto and hide from documentation. + VerificationKey string `protobuf:"bytes,5,opt,name=verification_key,json=verificationKey,proto3" json:"verification_key,omitempty"` + // The configuration that will be passed on to the plugin. + PluginConfig *_struct.Struct `protobuf:"bytes,6,opt,name=plugin_config,json=pluginConfig,proto3" json:"plugin_config,omitempty"` + // The plugin name to be used in the Envoy configuration (used to be called + // `rootID`). Some .wasm modules might require this value to select the Wasm + // plugin to execute. + // +kubebuilder:validation:MaxLength=256 + // +kubebuilder:validation:MinLength=1 + PluginName string `protobuf:"bytes,7,opt,name=plugin_name,json=pluginName,proto3" json:"plugin_name,omitempty"` + // Specifies the failure behavior for the plugin due to fatal errors. + FailStrategy FailStrategy `protobuf:"varint,8,opt,name=fail_strategy,json=failStrategy,proto3,enum=istio.extensions.v1alpha1.FailStrategy" json:"fail_strategy,omitempty"` + // Configuration for a Wasm VM. + // More details can be found [here](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/wasm/v3/wasm.proto#extensions-wasm-v3-vmconfig). + VmConfig *VmConfig `protobuf:"bytes,9,opt,name=vm_config,json=vmConfig,proto3" json:"vm_config,omitempty"` + // Specifies the type of Wasm Extension to be used. + Type PluginType `protobuf:"varint,10,opt,name=type,proto3,enum=istio.extensions.v1alpha1.PluginType" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WasmConfig) Reset() { + *x = WasmConfig{} + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WasmConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WasmConfig) ProtoMessage() {} + +func (x *WasmConfig) ProtoReflect() protoreflect.Message { + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WasmConfig.ProtoReflect.Descriptor instead. +func (*WasmConfig) Descriptor() ([]byte, []int) { + return file_extensions_v1alpha1_extension_filter_proto_rawDescGZIP(), []int{1} +} + +func (x *WasmConfig) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *WasmConfig) GetSha256() string { + if x != nil { + return x.Sha256 + } + return "" +} + +func (x *WasmConfig) GetImagePullPolicy() PullPolicy { + if x != nil { + return x.ImagePullPolicy + } + return PullPolicy_UNSPECIFIED_POLICY +} + +func (x *WasmConfig) GetImagePullSecret() string { + if x != nil { + return x.ImagePullSecret + } + return "" +} + +func (x *WasmConfig) GetVerificationKey() string { + if x != nil { + return x.VerificationKey + } + return "" +} + +func (x *WasmConfig) GetPluginConfig() *_struct.Struct { + if x != nil { + return x.PluginConfig + } + return nil +} + +func (x *WasmConfig) GetPluginName() string { + if x != nil { + return x.PluginName + } + return "" +} + +func (x *WasmConfig) GetFailStrategy() FailStrategy { + if x != nil { + return x.FailStrategy + } + return FailStrategy_FAIL_CLOSE +} + +func (x *WasmConfig) GetVmConfig() *VmConfig { + if x != nil { + return x.VmConfig + } + return nil +} + +func (x *WasmConfig) GetType() PluginType { + if x != nil { + return x.Type + } + return PluginType_UNSPECIFIED_PLUGIN_TYPE +} + +// LuaConfig configures a Lua filter. +// +// Lua filters provide a lightweight alternative to WebAssembly for simple +// request/response transformations. The Lua code is executed inline within +// the Envoy proxy. +// +// Example: Simple header manipulation +// +// ```yaml +// lua: +// +// inlineCode: | +// function envoy_on_request(request_handle) +// request_handle:headers():add("x-custom-header", "custom-value") +// end +// +// ``` +// +// The Lua script must define one or both of the following functions: +// - `envoy_on_request(request_handle)`: Called when a request is received +// - `envoy_on_response(response_handle)`: Called when a response is received +// +// The request_handle and response_handle provide access to headers, body, +// metadata, and other request/response attributes. See the Envoy Lua filter +// documentation for the complete API: +// https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter +type LuaConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The inline Lua code to be executed. The code must be a valid Lua script + // that defines the appropriate callback functions (`envoy_on_request` and/or + // `envoy_on_response`). + // + // The maximum size is 64KB. For larger or more complex filters, use a + // WebAssembly filter instead. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=65536 + InlineCode string `protobuf:"bytes,1,opt,name=inline_code,json=inlineCode,proto3" json:"inline_code,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LuaConfig) Reset() { + *x = LuaConfig{} + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LuaConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LuaConfig) ProtoMessage() {} + +func (x *LuaConfig) ProtoReflect() protoreflect.Message { + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LuaConfig.ProtoReflect.Descriptor instead. +func (*LuaConfig) Descriptor() ([]byte, []int) { + return file_extensions_v1alpha1_extension_filter_proto_rawDescGZIP(), []int{2} +} + +func (x *LuaConfig) GetInlineCode() string { + if x != nil { + return x.InlineCode + } + return "" +} + +// TrafficSelector provides a mechanism to select a specific traffic flow +// for which this Extension Filter will be enabled. +// When all the sub conditions in the TrafficSelector are satisfied, the +// traffic will be selected. +type TrafficSelector struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Criteria for selecting traffic by their direction. + // Note that `CLIENT` and `SERVER` are analogous to OUTBOUND and INBOUND, + // respectively. + // For the gateway, the field should be `CLIENT` or `CLIENT_AND_SERVER`. + // If not specified, the default value is `CLIENT_AND_SERVER`. + Mode v1beta1.WorkloadMode `protobuf:"varint,1,opt,name=mode,proto3,enum=istio.type.v1beta1.WorkloadMode" json:"mode,omitempty"` + // Criteria for selecting traffic by their destination port. + // More specifically, for the outbound traffic, the destination port would be + // the port of the target service. On the other hand, for the inbound traffic, + // the destination port is the port bound by the server process in the same Pod. + // + // If one of the given `ports` is matched, this condition is evaluated to true. + // If not specified, this condition is evaluated to true for any port. + // +listType=map + // +listMapKey=number + Ports []*v1beta1.PortSelector `protobuf:"bytes,2,rep,name=ports,proto3" json:"ports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TrafficSelector) Reset() { + *x = TrafficSelector{} + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TrafficSelector) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TrafficSelector) ProtoMessage() {} + +func (x *TrafficSelector) ProtoReflect() protoreflect.Message { + mi := &file_extensions_v1alpha1_extension_filter_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TrafficSelector.ProtoReflect.Descriptor instead. +func (*TrafficSelector) Descriptor() ([]byte, []int) { + return file_extensions_v1alpha1_extension_filter_proto_rawDescGZIP(), []int{3} +} + +func (x *TrafficSelector) GetMode() v1beta1.WorkloadMode { + if x != nil { + return x.Mode + } + return v1beta1.WorkloadMode(0) +} + +func (x *TrafficSelector) GetPorts() []*v1beta1.PortSelector { + if x != nil { + return x.Ports + } + return nil +} + +var File_extensions_v1alpha1_extension_filter_proto protoreflect.FileDescriptor + +const file_extensions_v1alpha1_extension_filter_proto_rawDesc = "" + + "\n" + + "*extensions/v1alpha1/extension_filter.proto\x12\x19istio.extensions.v1alpha1\x1a\x1eextensions/v1alpha1/wasm.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1btype/v1beta1/selector.proto\"\x97\x04\n" + + "\x0fExtensionFilter\x12@\n" + + "\bselector\x18\x01 \x01(\v2$.istio.type.v1beta1.WorkloadSelectorR\bselector\x12K\n" + + "\ttargetRef\x18\x02 \x01(\v2).istio.type.v1beta1.PolicyTargetReferenceB\x02\x18\x01R\ttargetRef\x12I\n" + + "\n" + + "targetRefs\x18\x03 \x03(\v2).istio.type.v1beta1.PolicyTargetReferenceR\n" + + "targetRefs\x12<\n" + + "\x05phase\x18\x04 \x01(\x0e2&.istio.extensions.v1alpha1.PluginPhaseR\x05phase\x127\n" + + "\bpriority\x18\x05 \x01(\v2\x1b.google.protobuf.Int32ValueR\bpriority\x12@\n" + + "\x05match\x18\x06 \x03(\v2*.istio.extensions.v1alpha1.TrafficSelectorR\x05match\x129\n" + + "\x04wasm\x18\n" + + " \x01(\v2%.istio.extensions.v1alpha1.WasmConfigR\x04wasm\x126\n" + + "\x03lua\x18\v \x01(\v2$.istio.extensions.v1alpha1.LuaConfigR\x03lua\"\x90\x04\n" + + "\n" + + "WasmConfig\x12\x16\n" + + "\x03url\x18\x01 \x01(\tB\x04\xe2A\x01\x02R\x03url\x12\x16\n" + + "\x06sha256\x18\x02 \x01(\tR\x06sha256\x12Q\n" + + "\x11image_pull_policy\x18\x03 \x01(\x0e2%.istio.extensions.v1alpha1.PullPolicyR\x0fimagePullPolicy\x12*\n" + + "\x11image_pull_secret\x18\x04 \x01(\tR\x0fimagePullSecret\x12)\n" + + "\x10verification_key\x18\x05 \x01(\tR\x0fverificationKey\x12<\n" + + "\rplugin_config\x18\x06 \x01(\v2\x17.google.protobuf.StructR\fpluginConfig\x12\x1f\n" + + "\vplugin_name\x18\a \x01(\tR\n" + + "pluginName\x12L\n" + + "\rfail_strategy\x18\b \x01(\x0e2'.istio.extensions.v1alpha1.FailStrategyR\ffailStrategy\x12@\n" + + "\tvm_config\x18\t \x01(\v2#.istio.extensions.v1alpha1.VmConfigR\bvmConfig\x129\n" + + "\x04type\x18\n" + + " \x01(\x0e2%.istio.extensions.v1alpha1.PluginTypeR\x04type\"2\n" + + "\tLuaConfig\x12%\n" + + "\vinline_code\x18\x01 \x01(\tB\x04\xe2A\x01\x02R\n" + + "inlineCode\"\x7f\n" + + "\x0fTrafficSelector\x124\n" + + "\x04mode\x18\x01 \x01(\x0e2 .istio.type.v1beta1.WorkloadModeR\x04mode\x126\n" + + "\x05ports\x18\x02 \x03(\v2 .istio.type.v1beta1.PortSelectorR\x05portsB\"Z istio.io/api/extensions/v1alpha1b\x06proto3" + +var ( + file_extensions_v1alpha1_extension_filter_proto_rawDescOnce sync.Once + file_extensions_v1alpha1_extension_filter_proto_rawDescData []byte +) + +func file_extensions_v1alpha1_extension_filter_proto_rawDescGZIP() []byte { + file_extensions_v1alpha1_extension_filter_proto_rawDescOnce.Do(func() { + file_extensions_v1alpha1_extension_filter_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_extensions_v1alpha1_extension_filter_proto_rawDesc), len(file_extensions_v1alpha1_extension_filter_proto_rawDesc))) + }) + return file_extensions_v1alpha1_extension_filter_proto_rawDescData +} + +var file_extensions_v1alpha1_extension_filter_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_extensions_v1alpha1_extension_filter_proto_goTypes = []any{ + (*ExtensionFilter)(nil), // 0: istio.extensions.v1alpha1.ExtensionFilter + (*WasmConfig)(nil), // 1: istio.extensions.v1alpha1.WasmConfig + (*LuaConfig)(nil), // 2: istio.extensions.v1alpha1.LuaConfig + (*TrafficSelector)(nil), // 3: istio.extensions.v1alpha1.TrafficSelector + (*v1beta1.WorkloadSelector)(nil), // 4: istio.type.v1beta1.WorkloadSelector + (*v1beta1.PolicyTargetReference)(nil), // 5: istio.type.v1beta1.PolicyTargetReference + (PluginPhase)(0), // 6: istio.extensions.v1alpha1.PluginPhase + (*wrappers.Int32Value)(nil), // 7: google.protobuf.Int32Value + (PullPolicy)(0), // 8: istio.extensions.v1alpha1.PullPolicy + (*_struct.Struct)(nil), // 9: google.protobuf.Struct + (FailStrategy)(0), // 10: istio.extensions.v1alpha1.FailStrategy + (*VmConfig)(nil), // 11: istio.extensions.v1alpha1.VmConfig + (PluginType)(0), // 12: istio.extensions.v1alpha1.PluginType + (v1beta1.WorkloadMode)(0), // 13: istio.type.v1beta1.WorkloadMode + (*v1beta1.PortSelector)(nil), // 14: istio.type.v1beta1.PortSelector +} +var file_extensions_v1alpha1_extension_filter_proto_depIdxs = []int32{ + 4, // 0: istio.extensions.v1alpha1.ExtensionFilter.selector:type_name -> istio.type.v1beta1.WorkloadSelector + 5, // 1: istio.extensions.v1alpha1.ExtensionFilter.targetRef:type_name -> istio.type.v1beta1.PolicyTargetReference + 5, // 2: istio.extensions.v1alpha1.ExtensionFilter.targetRefs:type_name -> istio.type.v1beta1.PolicyTargetReference + 6, // 3: istio.extensions.v1alpha1.ExtensionFilter.phase:type_name -> istio.extensions.v1alpha1.PluginPhase + 7, // 4: istio.extensions.v1alpha1.ExtensionFilter.priority:type_name -> google.protobuf.Int32Value + 3, // 5: istio.extensions.v1alpha1.ExtensionFilter.match:type_name -> istio.extensions.v1alpha1.TrafficSelector + 1, // 6: istio.extensions.v1alpha1.ExtensionFilter.wasm:type_name -> istio.extensions.v1alpha1.WasmConfig + 2, // 7: istio.extensions.v1alpha1.ExtensionFilter.lua:type_name -> istio.extensions.v1alpha1.LuaConfig + 8, // 8: istio.extensions.v1alpha1.WasmConfig.image_pull_policy:type_name -> istio.extensions.v1alpha1.PullPolicy + 9, // 9: istio.extensions.v1alpha1.WasmConfig.plugin_config:type_name -> google.protobuf.Struct + 10, // 10: istio.extensions.v1alpha1.WasmConfig.fail_strategy:type_name -> istio.extensions.v1alpha1.FailStrategy + 11, // 11: istio.extensions.v1alpha1.WasmConfig.vm_config:type_name -> istio.extensions.v1alpha1.VmConfig + 12, // 12: istio.extensions.v1alpha1.WasmConfig.type:type_name -> istio.extensions.v1alpha1.PluginType + 13, // 13: istio.extensions.v1alpha1.TrafficSelector.mode:type_name -> istio.type.v1beta1.WorkloadMode + 14, // 14: istio.extensions.v1alpha1.TrafficSelector.ports:type_name -> istio.type.v1beta1.PortSelector + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name +} + +func init() { file_extensions_v1alpha1_extension_filter_proto_init() } +func file_extensions_v1alpha1_extension_filter_proto_init() { + if File_extensions_v1alpha1_extension_filter_proto != nil { + return + } + file_extensions_v1alpha1_wasm_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_extensions_v1alpha1_extension_filter_proto_rawDesc), len(file_extensions_v1alpha1_extension_filter_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_extensions_v1alpha1_extension_filter_proto_goTypes, + DependencyIndexes: file_extensions_v1alpha1_extension_filter_proto_depIdxs, + MessageInfos: file_extensions_v1alpha1_extension_filter_proto_msgTypes, + }.Build() + File_extensions_v1alpha1_extension_filter_proto = out.File + file_extensions_v1alpha1_extension_filter_proto_goTypes = nil + file_extensions_v1alpha1_extension_filter_proto_depIdxs = nil +} diff --git a/extensions/v1alpha1/extension_filter.pb.html b/extensions/v1alpha1/extension_filter.pb.html new file mode 100644 index 0000000000..2f5f646148 --- /dev/null +++ b/extensions/v1alpha1/extension_filter.pb.html @@ -0,0 +1,592 @@ +--- +title: Extension Filter +description: Extend the functionality provided by the Istio proxy through WebAssembly or Lua filters. +location: https://istio.io/docs/reference/config/proxy_extensions/v1alpha1/extension_filter.html +layout: protoc-gen-docs +generator: protoc-gen-docs +schema: istio.extensions.v1alpha1.ExtensionFilter +aliases: [/docs/reference/config/extensions/v1alpha1/extension_filter] +number_of_entries: 4 +--- +
ExtensionFilter provides a mechanism to extend the functionality provided by +the Istio proxy through WebAssembly or Lua filters.
+This API supersedes WasmPlugin by providing a unified mechanism for configuring +multiple extension types (WebAssembly and Lua) while maintaining consistent +targeting and configuration patterns.
+The order of execution (as part of Envoy’s filter chain) is determined by +phase and priority settings, allowing the configuration of complex +interactions between user-supplied WebAssembly or Lua and Istio’s internal +filters.
+Examples:
+AuthN Filter deployed to ingress-gateway that implements an OpenID flow
+and populates the Authorization header with a JWT to be consumed by
+Istio AuthN.
apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: openid-connect
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ phase: AUTHN
+ wasm:
+ url: file:///opt/filters/openid.wasm
+ sha256: 1ef0c9a92b0420cf25f7fe5d481b231464bc88f486ca3b9c83ed5cc21d2f6210
+ pluginConfig:
+ openid_server: authn
+ openid_realm: ingress
+
+This is the same as the last example, but using an OCI image.
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: openid-connect
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ phase: AUTHN
+ wasm:
+ url: oci://private-registry:5000/openid-connect/openid:latest
+ imagePullPolicy: IfNotPresent
+ imagePullSecret: private-registry-pull-secret
+ pluginConfig:
+ openid_server: authn
+ openid_realm: ingress
+
+This is the same as the last example, but using VmConfig to configure environment variables in the VM.
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: openid-connect
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ phase: AUTHN
+ wasm:
+ url: oci://private-registry:5000/openid-connect/openid:latest
+ imagePullPolicy: IfNotPresent
+ imagePullSecret: private-registry-pull-secret
+ pluginConfig:
+ openid_server: authn
+ openid_realm: ingress
+ vmConfig:
+ env:
+ - name: POD_NAME
+ valueFrom: HOST
+ - name: TRUST_DOMAIN
+ value: "cluster.local"
+
+This is also the same as the last example, but the Wasm module is pulled via https and updated for each time when this plugin resource is changed.
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: openid-connect
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ phase: AUTHN
+ wasm:
+ url: https://private-bucket/filters/openid.wasm
+ imagePullPolicy: Always
+ pluginConfig:
+ openid_server: authn
+ openid_realm: ingress
+ vmConfig:
+ env:
+ - name: POD_NAME
+ valueFrom: HOST
+ - name: TRUST_DOMAIN
+ value: "cluster.local"
+
+And a more complex example that deploys three ExtensionFilters and orders them
+using phase and priority. The (hypothetical) setup is that the
+openid-connect filter performs an OpenID Connect flow to authenticate the
+user, writing a signed JWT into the Authorization header of the request,
+which can be verified by the Istio authn plugin. Then, the acl-check plugin
+kicks in, passing the JWT to a policy server, which in turn responds with a
+signed token that contains information about which files and functions of the
+system are available to the user that was previously authenticated. The
+acl-check filter writes this token to a header. Finally, the check-header
+filter verifies the token in that header and makes sure that the token’s
+contents (the permitted ‘function’) matches its plugin configuration.
The resulting filter chain looks like this: +-> openid-connect -> istio.authn -> acl-check -> check-header -> router
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: openid-connect
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ phase: AUTHN
+ wasm:
+ url: oci://private-registry:5000/openid-connect/openid:latest
+ imagePullPolicy: IfNotPresent
+ imagePullSecret: private-registry-pull-secret
+ pluginConfig:
+ openid_server: authn
+ openid_realm: ingress
+
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: acl-check
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ phase: AUTHZ
+ priority: 1000
+ wasm:
+ url: oci://private-registry:5000/acl-check/acl:latest
+ imagePullPolicy: Always
+ imagePullSecret: private-registry-pull-secret
+ pluginConfig:
+ acl_server: some_server
+ set_header: authz_complete
+
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: check-header
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ phase: AUTHZ
+ priority: 10
+ wasm:
+ url: oci://private-registry:5000/check-header:latest
+ imagePullPolicy: IfNotPresent
+ imagePullSecret: private-registry-pull-secret
+ pluginConfig:
+ read_header: authz_complete
+ verification_key: a89gAzxvls0JKAKIJSBnnvvvkIO
+ function: read_data
+
+Gateway with Lua filter for conditional header modification:
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: conditional-header-modifier
+ namespace: istio-ingress
+spec:
+ selector:
+ matchLabels:
+ istio: ingressgateway
+ match:
+ - mode: CLIENT
+ ports:
+ - number: 8080
+ - number: 8081
+ phase: AUTHN
+ priority: 1000
+ lua:
+ inlineCode: |
+ function envoy_on_request(request_handle)
+ local domain = "foo.com"
+ local headers = request_handle:headers()
+ local host = headers:get(":authority")
+ local existing_auth_header = headers:get("Authorization")
+ if (domain ~= nil and host ~= nil and existing_auth_header == nil and domain == host) then
+ local bearer_token = headers:get("cookie"):match("foo")
+ if (bearer_token ~= nil) then
+ headers:add("Authorization", "Bearer " .. bearer_token)
+ end
+ end
+ end
+
+Waypoint with Lua filter for header count logging:
+apiVersion: extensions.istio.io/v1alpha1
+kind: ExtensionFilter
+metadata:
+ name: reviews-header-logger
+ namespace: default
+spec:
+ targetRefs:
+ - kind: Service
+ name: reviews
+ match:
+ - mode: SERVER
+ phase: STATS
+ lua:
+ inlineCode: |
+ function envoy_on_request(request_handle)
+ local headers = request_handle:headers()
+ local num_headers = 0
+ for key, value in pairs(headers) do
+ num_headers = num_headers + 1
+ end
+ request_handle:logInfo("Request to reviews service has " .. num_headers .. " headers")
+ end
+
+
++kubebuilder:validation:XValidation:message=“only one of targetRefs or selector can be set”,rule="(has(self.selector)?1:0)+(has(self.targetRef)?1:0)+(has(self.targetRefs)?1:0)<=1" ++kubebuilder:validation:XValidation:message=“exactly one of wasm or lua must be set”,rule=“has(self.wasm) != has(self.lua)”
+ + +WasmConfig configures a WebAssembly filter.
+Example:
+wasm:
+ url: oci://gcr.io/myproject/filter:v1.0.0
+ sha256: abc123...
+ imagePullPolicy: IfNotPresent
+ imagePullSecret: gcr-secret
+ pluginName: my-filter
+ pluginConfig:
+ key1: value1
+ key2: value2
+ failStrategy: FAIL_CLOSE
+ vmConfig:
+ env:
+ - name: SOME_ENV_VAR
+ value: some_value
+ type: HTTP
+
+
+
+LuaConfig configures a Lua filter.
+Lua filters provide a lightweight alternative to WebAssembly for simple +request/response transformations. The Lua code is executed inline within +the Envoy proxy.
+Example: Simple header manipulation
+lua:
+ inlineCode: |
+ function envoy_on_request(request_handle)
+ request_handle:headers():add("x-custom-header", "custom-value")
+ end
+
+The Lua script must define one or both of the following functions:
+envoy_on_request(request_handle): Called when a request is receivedenvoy_on_response(response_handle): Called when a response is receivedThe request_handle and response_handle provide access to headers, body, +metadata, and other request/response attributes. See the Envoy Lua filter +documentation for the complete API: +https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter
+ + +TrafficSelector provides a mechanism to select a specific traffic flow +for which this Extension Filter will be enabled. +When all the sub conditions in the TrafficSelector are satisfied, the +traffic will be selected.
+ + +