istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/validation/agent/extensionprovider.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 agent
    16  
    17  import (
    18  	"fmt"
    19  	"net/url"
    20  	"strconv"
    21  	"strings"
    22  
    23  	envoytypev3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
    24  	"github.com/hashicorp/go-multierror"
    25  
    26  	meshconfig "istio.io/api/mesh/v1alpha1"
    27  	"istio.io/istio/pkg/util/sets"
    28  )
    29  
    30  func validateExtensionProviderService(service string) error {
    31  	if service == "" {
    32  		return fmt.Errorf("service must not be empty")
    33  	}
    34  	parts := strings.Split(service, "/")
    35  	if len(parts) == 1 {
    36  		if err := ValidateFQDN(service); err != nil {
    37  			if err2 := ValidateIPAddress(service); err2 != nil {
    38  				return fmt.Errorf("invalid service fmt %s: %s", service, err2)
    39  			}
    40  		}
    41  	} else {
    42  		if err := ValidateNamespaceSlashWildcardHostname(service, false, false); err != nil {
    43  			return err
    44  		}
    45  	}
    46  	return nil
    47  }
    48  
    49  func validateExtensionProviderEnvoyExtAuthzStatusOnError(status string) error {
    50  	if status == "" {
    51  		return nil
    52  	}
    53  	code, err := strconv.ParseInt(status, 10, 32)
    54  	if err != nil {
    55  		return fmt.Errorf("invalid statusOnError value %s: %v", status, err)
    56  	}
    57  	if _, found := envoytypev3.StatusCode_name[int32(code)]; !found {
    58  		return fmt.Errorf("unsupported statusOnError value %s, supported values: %v", status, envoytypev3.StatusCode_name)
    59  	}
    60  	return nil
    61  }
    62  
    63  func ValidateExtensionProviderEnvoyExtAuthzHTTP(config *meshconfig.MeshConfig_ExtensionProvider_EnvoyExternalAuthorizationHttpProvider) (errs error) {
    64  	if config == nil {
    65  		return fmt.Errorf("nil EnvoyExternalAuthorizationHttpProvider")
    66  	}
    67  	if err := ValidatePort(int(config.Port)); err != nil {
    68  		errs = AppendErrors(errs, err)
    69  	}
    70  	if err := validateExtensionProviderService(config.Service); err != nil {
    71  		errs = AppendErrors(errs, err)
    72  	}
    73  	if err := validateExtensionProviderEnvoyExtAuthzStatusOnError(config.StatusOnError); err != nil {
    74  		errs = AppendErrors(errs, err)
    75  	}
    76  	if config.PathPrefix != "" {
    77  		if _, err := url.Parse(config.PathPrefix); err != nil {
    78  			errs = AppendErrors(errs, fmt.Errorf("invalid pathPrefix %s: %v", config.PathPrefix, err))
    79  		}
    80  		if !strings.HasPrefix(config.PathPrefix, "/") {
    81  			errs = AppendErrors(errs, fmt.Errorf("pathPrefix should begin with `/` but found %q", config.PathPrefix))
    82  		}
    83  	}
    84  	return
    85  }
    86  
    87  func ValidateExtensionProviderEnvoyExtAuthzGRPC(config *meshconfig.MeshConfig_ExtensionProvider_EnvoyExternalAuthorizationGrpcProvider) (errs error) {
    88  	if config == nil {
    89  		return fmt.Errorf("nil EnvoyExternalAuthorizationGrpcProvider")
    90  	}
    91  	if err := ValidatePort(int(config.Port)); err != nil {
    92  		errs = AppendErrors(errs, fmt.Errorf("invalid service port: %v", err))
    93  	}
    94  	if err := validateExtensionProviderService(config.Service); err != nil {
    95  		errs = AppendErrors(errs, err)
    96  	}
    97  	if err := validateExtensionProviderEnvoyExtAuthzStatusOnError(config.StatusOnError); err != nil {
    98  		errs = AppendErrors(errs, err)
    99  	}
   100  	return
   101  }
   102  
   103  func validateExtensionProviderTracingZipkin(config *meshconfig.MeshConfig_ExtensionProvider_ZipkinTracingProvider) (errs error) {
   104  	if config == nil {
   105  		return fmt.Errorf("nil TracingZipkinProvider")
   106  	}
   107  	if err := validateExtensionProviderService(config.Service); err != nil {
   108  		errs = AppendErrors(errs, err)
   109  	}
   110  	if err := ValidatePort(int(config.Port)); err != nil {
   111  		errs = AppendErrors(errs, fmt.Errorf("invalid service port: %v", err))
   112  	}
   113  	return
   114  }
   115  
   116  func validateExtensionProviderTracingLightStep(config *meshconfig.MeshConfig_ExtensionProvider_LightstepTracingProvider) (errs error) {
   117  	if config == nil {
   118  		return fmt.Errorf("nil TracingLightStepProvider")
   119  	}
   120  	if err := validateExtensionProviderService(config.Service); err != nil {
   121  		errs = AppendErrors(errs, err)
   122  	}
   123  	if err := ValidatePort(int(config.Port)); err != nil {
   124  		errs = AppendErrors(errs, fmt.Errorf("invalid service port: %v", err))
   125  	}
   126  	if config.AccessToken == "" {
   127  		errs = AppendErrors(errs, fmt.Errorf("access token is required"))
   128  	}
   129  	return
   130  }
   131  
   132  func validateExtensionProviderTracingDatadog(config *meshconfig.MeshConfig_ExtensionProvider_DatadogTracingProvider) (errs error) {
   133  	if config == nil {
   134  		return fmt.Errorf("nil TracingDatadogProvider")
   135  	}
   136  	if err := validateExtensionProviderService(config.Service); err != nil {
   137  		errs = AppendErrors(errs, err)
   138  	}
   139  	if err := ValidatePort(int(config.Port)); err != nil {
   140  		errs = AppendErrors(errs, fmt.Errorf("invalid service port: %v", err))
   141  	}
   142  	return
   143  }
   144  
   145  func validateExtensionProviderTracingOpenCensusAgent(config *meshconfig.MeshConfig_ExtensionProvider_OpenCensusAgentTracingProvider) (errs error) {
   146  	if config == nil {
   147  		return fmt.Errorf("nil OpenCensusAgent")
   148  	}
   149  	if err := validateExtensionProviderService(config.Service); err != nil {
   150  		errs = AppendErrors(errs, err)
   151  	}
   152  	if err := ValidatePort(int(config.Port)); err != nil {
   153  		errs = AppendErrors(errs, fmt.Errorf("invalid service port: %v", err))
   154  	}
   155  	return
   156  }
   157  
   158  func validateExtensionProviderTracingSkyWalking(config *meshconfig.MeshConfig_ExtensionProvider_SkyWalkingTracingProvider) (errs error) {
   159  	if config == nil {
   160  		return fmt.Errorf("nil TracingSkyWalkingProvider")
   161  	}
   162  	if err := validateExtensionProviderService(config.Service); err != nil {
   163  		errs = AppendErrors(errs, err)
   164  	}
   165  	if err := ValidatePort(int(config.Port)); err != nil {
   166  		errs = AppendErrors(errs, fmt.Errorf("invalid service port: %v", err))
   167  	}
   168  	return
   169  }
   170  
   171  func validateExtensionProviderMetricsPrometheus(_ *meshconfig.MeshConfig_ExtensionProvider_PrometheusMetricsProvider) error {
   172  	return nil
   173  }
   174  
   175  func validateExtensionProviderStackdriver(_ *meshconfig.MeshConfig_ExtensionProvider_StackdriverProvider) error {
   176  	return nil
   177  }
   178  
   179  func validateExtensionProviderEnvoyFileAccessLog(_ *meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLogProvider) error {
   180  	return nil
   181  }
   182  
   183  func ValidateExtensionProviderEnvoyOtelAls(provider *meshconfig.MeshConfig_ExtensionProvider_EnvoyOpenTelemetryLogProvider) (errs error) {
   184  	if provider == nil {
   185  		return fmt.Errorf("nil EnvoyOpenTelemetryLogProvider")
   186  	}
   187  	if err := ValidatePort(int(provider.Port)); err != nil {
   188  		errs = AppendErrors(errs, err)
   189  	}
   190  	if err := validateExtensionProviderService(provider.Service); err != nil {
   191  		errs = AppendErrors(errs, err)
   192  	}
   193  	return
   194  }
   195  
   196  func ValidateExtensionProviderTracingOpentelemetry(provider *meshconfig.MeshConfig_ExtensionProvider_OpenTelemetryTracingProvider) (errs error) {
   197  	if provider == nil {
   198  		return fmt.Errorf("nil OpenTelemetryTracingProvider")
   199  	}
   200  	if err := ValidatePort(int(provider.Port)); err != nil {
   201  		errs = AppendErrors(errs, err)
   202  	}
   203  	if err := validateExtensionProviderService(provider.Service); err != nil {
   204  		errs = AppendErrors(errs, err)
   205  	}
   206  	return
   207  }
   208  
   209  func ValidateExtensionProviderEnvoyHTTPAls(provider *meshconfig.MeshConfig_ExtensionProvider_EnvoyHttpGrpcV3LogProvider) (errs error) {
   210  	if provider == nil {
   211  		return fmt.Errorf("nil EnvoyHttpGrpcV3LogProvider")
   212  	}
   213  	if err := ValidatePort(int(provider.Port)); err != nil {
   214  		errs = AppendErrors(errs, err)
   215  	}
   216  	if err := validateExtensionProviderService(provider.Service); err != nil {
   217  		errs = AppendErrors(errs, err)
   218  	}
   219  	return
   220  }
   221  
   222  func ValidateExtensionProviderEnvoyTCPAls(provider *meshconfig.MeshConfig_ExtensionProvider_EnvoyTcpGrpcV3LogProvider) (errs error) {
   223  	if provider == nil {
   224  		return fmt.Errorf("nil EnvoyTcpGrpcV3LogProvider")
   225  	}
   226  	if err := ValidatePort(int(provider.Port)); err != nil {
   227  		errs = AppendErrors(errs, err)
   228  	}
   229  	if err := validateExtensionProviderService(provider.Service); err != nil {
   230  		errs = AppendErrors(errs, err)
   231  	}
   232  	return
   233  }
   234  
   235  func validateExtensionProvider(config *meshconfig.MeshConfig) (errs error) {
   236  	definedProviders := sets.String{}
   237  	for _, c := range config.ExtensionProviders {
   238  		var currentErrs error
   239  		// Provider name must be unique and not empty.
   240  		if c.Name == "" {
   241  			currentErrs = AppendErrors(currentErrs, fmt.Errorf("empty extension provider name"))
   242  		} else {
   243  			if definedProviders.Contains(c.Name) {
   244  				currentErrs = AppendErrors(currentErrs, fmt.Errorf("duplicate extension provider name %s", c.Name))
   245  			}
   246  			definedProviders.Insert(c.Name)
   247  		}
   248  
   249  		switch provider := c.Provider.(type) {
   250  		case *meshconfig.MeshConfig_ExtensionProvider_EnvoyExtAuthzHttp:
   251  			currentErrs = AppendErrors(currentErrs, ValidateExtensionProviderEnvoyExtAuthzHTTP(provider.EnvoyExtAuthzHttp))
   252  		case *meshconfig.MeshConfig_ExtensionProvider_EnvoyExtAuthzGrpc:
   253  			currentErrs = AppendErrors(currentErrs, ValidateExtensionProviderEnvoyExtAuthzGRPC(provider.EnvoyExtAuthzGrpc))
   254  		case *meshconfig.MeshConfig_ExtensionProvider_Zipkin:
   255  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderTracingZipkin(provider.Zipkin))
   256  		//nolint: staticcheck  // Lightstep deprecated
   257  		case *meshconfig.MeshConfig_ExtensionProvider_Lightstep:
   258  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderTracingLightStep(provider.Lightstep))
   259  		case *meshconfig.MeshConfig_ExtensionProvider_Datadog:
   260  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderTracingDatadog(provider.Datadog))
   261  		//nolint: staticcheck
   262  		case *meshconfig.MeshConfig_ExtensionProvider_Opencensus:
   263  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderTracingOpenCensusAgent(provider.Opencensus))
   264  		case *meshconfig.MeshConfig_ExtensionProvider_Skywalking:
   265  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderTracingSkyWalking(provider.Skywalking))
   266  		case *meshconfig.MeshConfig_ExtensionProvider_Prometheus:
   267  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderMetricsPrometheus(provider.Prometheus))
   268  		case *meshconfig.MeshConfig_ExtensionProvider_Stackdriver:
   269  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderStackdriver(provider.Stackdriver))
   270  		case *meshconfig.MeshConfig_ExtensionProvider_EnvoyFileAccessLog:
   271  			currentErrs = AppendErrors(currentErrs, validateExtensionProviderEnvoyFileAccessLog(provider.EnvoyFileAccessLog))
   272  		case *meshconfig.MeshConfig_ExtensionProvider_EnvoyOtelAls:
   273  			currentErrs = AppendErrors(currentErrs, ValidateExtensionProviderEnvoyOtelAls(provider.EnvoyOtelAls))
   274  		case *meshconfig.MeshConfig_ExtensionProvider_Opentelemetry:
   275  			currentErrs = AppendErrors(currentErrs, ValidateExtensionProviderTracingOpentelemetry(provider.Opentelemetry))
   276  		case *meshconfig.MeshConfig_ExtensionProvider_EnvoyHttpAls:
   277  			currentErrs = AppendErrors(currentErrs, ValidateExtensionProviderEnvoyHTTPAls(provider.EnvoyHttpAls))
   278  		case *meshconfig.MeshConfig_ExtensionProvider_EnvoyTcpAls:
   279  			currentErrs = AppendErrors(currentErrs, ValidateExtensionProviderEnvoyTCPAls(provider.EnvoyTcpAls))
   280  			// TODO: add exhaustiveness test
   281  		default:
   282  			currentErrs = AppendErrors(currentErrs, fmt.Errorf("unsupported provider: %v of type %T", provider, provider))
   283  		}
   284  		currentErrs = multierror.Prefix(currentErrs, fmt.Sprintf("invalid extension provider %s:", c.Name))
   285  		errs = AppendErrors(errs, currentErrs)
   286  	}
   287  	return
   288  }