istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/extension/wasmplugin.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package extension
    16  
    17  import (
    18  	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    19  	listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
    20  	hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    21  	wasmextensions "github.com/envoyproxy/go-control-plane/envoy/extensions/wasm/v3"
    22  	"google.golang.org/protobuf/types/known/durationpb"
    23  
    24  	extensions "istio.io/api/extensions/v1alpha1"
    25  	"istio.io/istio/pilot/pkg/model"
    26  	"istio.io/istio/pilot/pkg/util/protoconv"
    27  	"istio.io/istio/pkg/config/xds"
    28  	"istio.io/istio/pkg/util/sets"
    29  	_ "istio.io/istio/pkg/wasm" // include for registering wasm logging scope
    30  )
    31  
    32  var defaultConfigSource = &core.ConfigSource{
    33  	ConfigSourceSpecifier: &core.ConfigSource_Ads{
    34  		Ads: &core.AggregatedConfigSource{},
    35  	},
    36  	ResourceApiVersion: core.ApiVersion_V3,
    37  	// we block proxy init until WasmPlugins are loaded because they might be
    38  	// critical for security (e.g. authn/authz)
    39  	InitialFetchTimeout: &durationpb.Duration{Seconds: 0},
    40  }
    41  
    42  // PopAppendHTTP takes a list of filters and a set of WASM plugins, keyed by phase. It will remove all
    43  // plugins of a provided phase from the WASM plugin set and append them to the list of filters
    44  func PopAppendHTTP(list []*hcm.HttpFilter,
    45  	filterMap map[extensions.PluginPhase][]*model.WasmPluginWrapper,
    46  	phase extensions.PluginPhase,
    47  ) []*hcm.HttpFilter {
    48  	for _, ext := range filterMap[phase] {
    49  		list = append(list, toEnvoyHTTPFilter(ext))
    50  	}
    51  	delete(filterMap, phase)
    52  	return list
    53  }
    54  
    55  // PopAppendNetwork takes a list of filters and a set of WASM plugins, keyed by phase. It will remove all
    56  // plugins of a provided phase from the WASM plugin set and append them to the list of filters
    57  func PopAppendNetwork(list []*listener.Filter,
    58  	filterMap map[extensions.PluginPhase][]*model.WasmPluginWrapper,
    59  	phase extensions.PluginPhase,
    60  ) []*listener.Filter {
    61  	for _, ext := range filterMap[phase] {
    62  		list = append(list, toEnvoyNetworkFilter(ext))
    63  	}
    64  	delete(filterMap, phase)
    65  	return list
    66  }
    67  
    68  func toEnvoyHTTPFilter(wasmPlugin *model.WasmPluginWrapper) *hcm.HttpFilter {
    69  	return &hcm.HttpFilter{
    70  		Name: wasmPlugin.ResourceName,
    71  		ConfigType: &hcm.HttpFilter_ConfigDiscovery{
    72  			ConfigDiscovery: &core.ExtensionConfigSource{
    73  				ConfigSource: defaultConfigSource,
    74  				TypeUrls: []string{
    75  					xds.WasmHTTPFilterType,
    76  					xds.RBACHTTPFilterType,
    77  				},
    78  			},
    79  		},
    80  	}
    81  }
    82  
    83  func toEnvoyNetworkFilter(wasmPlugin *model.WasmPluginWrapper) *listener.Filter {
    84  	return &listener.Filter{
    85  		Name: wasmPlugin.ResourceName,
    86  		ConfigType: &listener.Filter_ConfigDiscovery{
    87  			ConfigDiscovery: &core.ExtensionConfigSource{
    88  				ConfigSource: defaultConfigSource,
    89  				TypeUrls: []string{
    90  					xds.WasmNetworkFilterType,
    91  					xds.RBACNetworkFilterType,
    92  				},
    93  			},
    94  		},
    95  	}
    96  }
    97  
    98  // InsertedExtensionConfigurations builds added via WasmPlugin.
    99  func InsertedExtensionConfigurations(
   100  	wasmPlugins []*model.WasmPluginWrapper,
   101  	names []string, pullSecrets map[string][]byte,
   102  ) []*core.TypedExtensionConfig {
   103  	result := make([]*core.TypedExtensionConfig, 0)
   104  	if len(wasmPlugins) == 0 {
   105  		return result
   106  	}
   107  	hasName := sets.New(names...)
   108  	for _, p := range wasmPlugins {
   109  		if !hasName.Contains(p.ResourceName) {
   110  			continue
   111  		}
   112  		switch {
   113  		case p.Type == extensions.PluginType_NETWORK:
   114  			wasmExtensionConfig := p.BuildNetworkWasmFilter()
   115  			if wasmExtensionConfig == nil {
   116  				continue
   117  			}
   118  			updatePluginConfig(wasmExtensionConfig.GetConfig(), pullSecrets)
   119  			typedConfig := protoconv.MessageToAny(wasmExtensionConfig)
   120  			ec := &core.TypedExtensionConfig{
   121  				Name:        p.ResourceName,
   122  				TypedConfig: typedConfig,
   123  			}
   124  			result = append(result, ec)
   125  		default:
   126  			wasmExtensionConfig := p.BuildHTTPWasmFilter()
   127  			if wasmExtensionConfig == nil {
   128  				continue
   129  			}
   130  			updatePluginConfig(wasmExtensionConfig.GetConfig(), pullSecrets)
   131  			typedConfig := protoconv.MessageToAny(wasmExtensionConfig)
   132  			ec := &core.TypedExtensionConfig{
   133  				Name:        p.ResourceName,
   134  				TypedConfig: typedConfig,
   135  			}
   136  			result = append(result, ec)
   137  		}
   138  	}
   139  	return result
   140  }
   141  
   142  func updatePluginConfig(pluginConfig *wasmextensions.PluginConfig, pullSecrets map[string][]byte) {
   143  	// Find the pull secret resource name from wasm vm env variables.
   144  	// The Wasm extension config should already have a `ISTIO_META_WASM_IMAGE_PULL_SECRET` env variable
   145  	// at in the VM env variables, with value being the secret resource name. We try to find the actual
   146  	// secret, and replace the env variable value with it. When ECDS config update reaches the proxy,
   147  	// agent will extract out the secret from env variable, use it for image pulling, and strip the
   148  	// env variable from VM config before forwarding it to envoy.
   149  	envs := pluginConfig.GetVmConfig().GetEnvironmentVariables().GetKeyValues()
   150  	secretName := envs[model.WasmSecretEnv]
   151  	if secretName != "" {
   152  		if sec, found := pullSecrets[secretName]; found {
   153  			envs[model.WasmSecretEnv] = string(sec)
   154  		} else {
   155  			envs[model.WasmSecretEnv] = ""
   156  		}
   157  	}
   158  }