import "istio.io/istio/pkg/config/validation"
extensionprovider.go validation.go virtualservice.go
const ( // UnixAddressPrefix is the prefix used to indicate an address is for a Unix Domain socket. It is used in // ServiceEntry.Endpoint.Address message. UnixAddressPrefix = "unix://" )
Constants for duration fields
var ( // EmptyValidate is a Validate that does nothing and returns no error. EmptyValidate = registerValidateFunc("EmptyValidate", func(config.Config) (Warning, error) { return nil, nil }) )
var ValidateAuthorizationPolicy = registerValidateFunc("ValidateAuthorizationPolicy", func(cfg config.Config) (Warning, error) { in, ok := cfg.Spec.(*security_beta.AuthorizationPolicy) if !ok { return nil, fmt.Errorf("cannot cast to AuthorizationPolicy") } var errs error if err := validateWorkloadSelector(in.Selector); err != nil { errs = appendErrors(errs, err) } if in.Action == security_beta.AuthorizationPolicy_CUSTOM { if in.Rules == nil { errs = appendErrors(errs, fmt.Errorf("CUSTOM action without `rules` is meaningless as it will never be triggered, "+ "add an empty rule `{}` if you want it be triggered for every request")) } else { if in.GetProvider() == nil || in.GetProvider().GetName() == "" { errs = appendErrors(errs, fmt.Errorf("`provider.name` must not be empty")) } } for _, rule := range in.GetRules() { check := func(invalid bool, name string) error { if invalid { return fmt.Errorf("%s is currently not supported with CUSTOM action", name) } return nil } for _, from := range rule.GetFrom() { if src := from.GetSource(); src != nil { errs = appendErrors(errs, check(len(src.Namespaces) != 0, "From.Namespaces")) errs = appendErrors(errs, check(len(src.NotNamespaces) != 0, "From.NotNamespaces")) errs = appendErrors(errs, check(len(src.Principals) != 0, "From.Principals")) errs = appendErrors(errs, check(len(src.NotPrincipals) != 0, "From.NotPrincipals")) errs = appendErrors(errs, check(len(src.RequestPrincipals) != 0, "From.RequestPrincipals")) errs = appendErrors(errs, check(len(src.NotRequestPrincipals) != 0, "From.NotRequestPrincipals")) } } for _, when := range rule.GetWhen() { errs = appendErrors(errs, check(when.Key == "source.namespace", when.Key)) errs = appendErrors(errs, check(when.Key == "source.principal", when.Key)) errs = appendErrors(errs, check(strings.HasPrefix(when.Key, "request.auth."), when.Key)) } } } if in.GetProvider() != nil && in.Action != security_beta.AuthorizationPolicy_CUSTOM { errs = appendErrors(errs, fmt.Errorf("`provider` must not be with non CUSTOM action, found %s", in.Action)) } if in.Action == security_beta.AuthorizationPolicy_DENY && in.Rules == nil { errs = appendErrors(errs, fmt.Errorf("DENY action without `rules` is meaningless as it will never be triggered, "+ "add an empty rule `{}` if you want it be triggered for every request")) } for i, rule := range in.GetRules() { if rule == nil { errs = appendErrors(errs, fmt.Errorf("`rule` must not be nil, found at rule %d", i)) continue } if rule.From != nil && len(rule.From) == 0 { errs = appendErrors(errs, fmt.Errorf("`from` must not be empty, found at rule %d", i)) } for _, from := range rule.From { if from == nil { errs = appendErrors(errs, fmt.Errorf("`from` must not be nil, found at rule %d", i)) continue } if from.Source == nil { errs = appendErrors(errs, fmt.Errorf("`from.source` must not be nil, found at rule %d", i)) } else { src := from.Source if len(src.Principals) == 0 && len(src.RequestPrincipals) == 0 && len(src.Namespaces) == 0 && len(src.IpBlocks) == 0 && len(src.RemoteIpBlocks) == 0 && len(src.NotPrincipals) == 0 && len(src.NotRequestPrincipals) == 0 && len(src.NotNamespaces) == 0 && len(src.NotIpBlocks) == 0 && len(src.NotRemoteIpBlocks) == 0 { errs = appendErrors(errs, fmt.Errorf("`from.source` must not be empty, found at rule %d", i)) } errs = appendErrors(errs, security.ValidateIPs(from.Source.GetIpBlocks())) errs = appendErrors(errs, security.ValidateIPs(from.Source.GetNotIpBlocks())) errs = appendErrors(errs, security.ValidateIPs(from.Source.GetRemoteIpBlocks())) errs = appendErrors(errs, security.ValidateIPs(from.Source.GetNotRemoteIpBlocks())) errs = appendErrors(errs, security.CheckEmptyValues("Principals", src.Principals)) errs = appendErrors(errs, security.CheckEmptyValues("RequestPrincipals", src.RequestPrincipals)) errs = appendErrors(errs, security.CheckEmptyValues("Namespaces", src.Namespaces)) errs = appendErrors(errs, security.CheckEmptyValues("IpBlocks", src.IpBlocks)) errs = appendErrors(errs, security.CheckEmptyValues("RemoteIpBlocks", src.RemoteIpBlocks)) errs = appendErrors(errs, security.CheckEmptyValues("NotPrincipals", src.NotPrincipals)) errs = appendErrors(errs, security.CheckEmptyValues("NotRequestPrincipals", src.NotRequestPrincipals)) errs = appendErrors(errs, security.CheckEmptyValues("NotNamespaces", src.NotNamespaces)) errs = appendErrors(errs, security.CheckEmptyValues("NotIpBlocks", src.NotIpBlocks)) errs = appendErrors(errs, security.CheckEmptyValues("NotRemoteIpBlocks", src.NotRemoteIpBlocks)) } } if rule.To != nil && len(rule.To) == 0 { errs = appendErrors(errs, fmt.Errorf("`to` must not be empty, found at rule %d", i)) } for _, to := range rule.To { if to == nil { errs = appendErrors(errs, fmt.Errorf("`to` must not be nil, found at rule %d", i)) continue } if to.Operation == nil { errs = appendErrors(errs, fmt.Errorf("`to.operation` must not be nil, found at rule %d", i)) } else { op := to.Operation if len(op.Ports) == 0 && len(op.Methods) == 0 && len(op.Paths) == 0 && len(op.Hosts) == 0 && len(op.NotPorts) == 0 && len(op.NotMethods) == 0 && len(op.NotPaths) == 0 && len(op.NotHosts) == 0 { errs = appendErrors(errs, fmt.Errorf("`to.operation` must not be empty, found at rule %d", i)) } errs = appendErrors(errs, security.ValidatePorts(to.Operation.GetPorts())) errs = appendErrors(errs, security.ValidatePorts(to.Operation.GetNotPorts())) errs = appendErrors(errs, security.CheckEmptyValues("Ports", op.Ports)) errs = appendErrors(errs, security.CheckEmptyValues("Methods", op.Methods)) errs = appendErrors(errs, security.CheckEmptyValues("Paths", op.Paths)) errs = appendErrors(errs, security.CheckEmptyValues("Hosts", op.Hosts)) errs = appendErrors(errs, security.CheckEmptyValues("NotPorts", op.NotPorts)) errs = appendErrors(errs, security.CheckEmptyValues("NotMethods", op.NotMethods)) errs = appendErrors(errs, security.CheckEmptyValues("NotPaths", op.NotPaths)) errs = appendErrors(errs, security.CheckEmptyValues("NotHosts", op.NotHosts)) } } for _, condition := range rule.GetWhen() { key := condition.GetKey() if key == "" { errs = appendErrors(errs, fmt.Errorf("`key` must not be empty")) } else { if len(condition.GetValues()) == 0 && len(condition.GetNotValues()) == 0 { errs = appendErrors(errs, fmt.Errorf("at least one of `values` or `notValues` must be set for key %s", key)) } else { if err := security.ValidateAttribute(key, condition.GetValues()); err != nil { errs = appendErrors(errs, fmt.Errorf("invalid `value` for `key` %s: %v", key, err)) } if err := security.ValidateAttribute(key, condition.GetNotValues()); err != nil { errs = appendErrors(errs, fmt.Errorf("invalid `notValue` for `key` %s: %v", key, err)) } } } } } return nil, multierror.Prefix(errs, fmt.Sprintf("invalid policy %s.%s:", cfg.Name, cfg.Namespace)) })
ValidateAuthorizationPolicy checks that AuthorizationPolicy is well-formed.
var ValidateDestinationRule = registerValidateFunc("ValidateDestinationRule", func(cfg config.Config) (Warning, error) { rule, ok := cfg.Spec.(*networking.DestinationRule) if !ok { return nil, fmt.Errorf("cannot cast to destination rule") } v := Validation{} v = appendValidation(v, ValidateWildcardDomain(rule.Host), validateTrafficPolicy(rule.TrafficPolicy)) for _, subset := range rule.Subsets { if subset == nil { v = appendValidation(v, errors.New("subset may not be null")) continue } v = appendValidation(v, validateSubset(subset)) } v = appendValidation(v, validateExportTo(cfg.Namespace, rule.ExportTo, false)) return v.Unwrap() })
ValidateDestinationRule checks proxy policies
var ValidateEnvoyFilter = registerValidateFunc("ValidateEnvoyFilter", func(cfg config.Config) (Warning, error) { errs := Validation{} rule, ok := cfg.Spec.(*networking.EnvoyFilter) if !ok { return nil, fmt.Errorf("cannot cast to Envoy filter") } if err := validateAlphaWorkloadSelector(rule.WorkloadSelector); err != nil { return nil, err } for _, cp := range rule.ConfigPatches { if cp == nil { errs = appendValidation(errs, fmt.Errorf("Envoy filter: null config patch")) continue } if cp.ApplyTo == networking.EnvoyFilter_INVALID { errs = appendValidation(errs, fmt.Errorf("Envoy filter: missing applyTo")) continue } if cp.Patch == nil { errs = appendValidation(errs, fmt.Errorf("Envoy filter: missing patch")) continue } if cp.Patch.Operation == networking.EnvoyFilter_Patch_INVALID { errs = appendValidation(errs, fmt.Errorf("Envoy filter: missing patch operation")) continue } if cp.Patch.Operation != networking.EnvoyFilter_Patch_REMOVE && cp.Patch.Value == nil { errs = appendValidation(errs, fmt.Errorf("Envoy filter: missing patch value for non-remove operation")) continue } if cp.Match != nil && cp.Match.Proxy != nil && cp.Match.Proxy.ProxyVersion != "" { if _, err := regexp.Compile(cp.Match.Proxy.ProxyVersion); err != nil { errs = appendValidation(errs, fmt.Errorf("Envoy filter: invalid regex for proxy version, [%v]", err)) continue } } switch cp.ApplyTo { case networking.EnvoyFilter_LISTENER, networking.EnvoyFilter_FILTER_CHAIN, networking.EnvoyFilter_NETWORK_FILTER, networking.EnvoyFilter_HTTP_FILTER: if cp.Match != nil && cp.Match.ObjectTypes != nil { if cp.Match.GetListener() == nil { errs = appendValidation(errs, fmt.Errorf("Envoy filter: applyTo for listener class objects cannot have non listener match")) continue } listenerMatch := cp.Match.GetListener() if listenerMatch.FilterChain != nil { if listenerMatch.FilterChain.Filter != nil { if listenerMatch.FilterChain.Filter.Name == "" { errs = appendValidation(errs, fmt.Errorf("Envoy filter: filter match has no name to match on")) continue } else if listenerMatch.FilterChain.Filter.SubFilter != nil { if cp.ApplyTo != networking.EnvoyFilter_HTTP_FILTER { errs = appendValidation(errs, fmt.Errorf("Envoy filter: subfilter match can be used with applyTo HTTP_FILTER only")) continue } if listenerMatch.FilterChain.Filter.Name != wellknown.HTTPConnectionManager && listenerMatch.FilterChain.Filter.Name != "envoy.http_connection_manager" { errs = appendValidation(errs, fmt.Errorf("Envoy filter: subfilter match requires filter match with %s", wellknown.HTTPConnectionManager)) continue } if listenerMatch.FilterChain.Filter.SubFilter.Name == "" { errs = appendValidation(errs, fmt.Errorf("Envoy filter: subfilter match has no name to match on")) continue } } errs = appendValidation(errs, validateListenerMatchName(listenerMatch.FilterChain.Filter.GetName())) errs = appendValidation(errs, validateListenerMatchName(listenerMatch.FilterChain.Filter.GetSubFilter().GetName())) } } } case networking.EnvoyFilter_ROUTE_CONFIGURATION, networking.EnvoyFilter_VIRTUAL_HOST, networking.EnvoyFilter_HTTP_ROUTE: if cp.Match != nil && cp.Match.ObjectTypes != nil { if cp.Match.GetRouteConfiguration() == nil { errs = appendValidation(errs, fmt.Errorf("Envoy filter: applyTo for http route class objects cannot have non route configuration match")) } } case networking.EnvoyFilter_CLUSTER: if cp.Match != nil && cp.Match.ObjectTypes != nil { if cp.Match.GetCluster() == nil { errs = appendValidation(errs, fmt.Errorf("Envoy filter: applyTo for cluster class objects cannot have non cluster match")) } } } if _, err := xds.BuildXDSObjectFromStruct(cp.ApplyTo, cp.Patch.Value, false); err != nil { errs = appendValidation(errs, err) } else { obj, err := xds.BuildXDSObjectFromStruct(cp.ApplyTo, cp.Patch.Value, true) if err != nil { errs = appendValidation(errs, WrapWarning(err)) } errs = appendValidation(errs, validateDeprecatedFilterTypes(obj)) } } return errs.Unwrap() })
ValidateEnvoyFilter checks envoy filter config supplied by user
var ValidateGateway = registerValidateFunc("ValidateGateway", func(cfg config.Config) (Warning, error) { name := cfg.Name v := Validation{} if !labels.IsDNS1123Label(name) { v = appendValidation(v, fmt.Errorf("invalid gateway name: %q", name)) } value, ok := cfg.Spec.(*networking.Gateway) if !ok { v = appendValidation(v, fmt.Errorf("cannot cast to gateway: %#v", cfg.Spec)) return v.Unwrap() } if len(value.Servers) == 0 { v = appendValidation(v, fmt.Errorf("gateway must have at least one server")) } else { for _, server := range value.Servers { v = appendValidation(v, validateServer(server)) } } portNames := make(map[string]bool) for _, s := range value.Servers { if s == nil { v = appendValidation(v, fmt.Errorf("server may not be nil")) continue } if s.Port != nil { if portNames[s.Port.Name] { v = appendValidation(v, fmt.Errorf("port names in servers must be unique: duplicate name %s", s.Port.Name)) } portNames[s.Port.Name] = true if !protocol.Parse(s.Port.Protocol).IsHTTP() && s.GetTls().GetHttpsRedirect() { v = appendValidation(v, WrapWarning(fmt.Errorf("tls.httpsRedirect should only be used with http servers"))) } } } return v.Unwrap() })
ValidateGateway checks gateway specifications
var ValidatePeerAuthentication = registerValidateFunc("ValidatePeerAuthentication", func(cfg config.Config) (Warning, error) { in, ok := cfg.Spec.(*security_beta.PeerAuthentication) if !ok { return nil, errors.New("cannot cast to PeerAuthentication") } var errs error emptySelector := in.Selector == nil || len(in.Selector.MatchLabels) == 0 if emptySelector && len(in.PortLevelMtls) != 0 { errs = appendErrors(errs, fmt.Errorf("mesh/namespace peer authentication cannot have port level mTLS")) } if in.PortLevelMtls != nil && len(in.PortLevelMtls) == 0 { errs = appendErrors(errs, fmt.Errorf("port level mTLS, if defined, must have at least one element")) } for port := range in.PortLevelMtls { if port == 0 { errs = appendErrors(errs, fmt.Errorf("port cannot be 0")) } } errs = appendErrors(errs, validateWorkloadSelector(in.Selector)) return nil, errs })
ValidatePeerAuthentication checks that peer authentication spec is well-formed.
var ValidateRequestAuthentication = registerValidateFunc("ValidateRequestAuthentication", func(cfg config.Config) (Warning, error) { in, ok := cfg.Spec.(*security_beta.RequestAuthentication) if !ok { return nil, errors.New("cannot cast to RequestAuthentication") } var errs error errs = appendErrors(errs, validateWorkloadSelector(in.Selector)) for _, rule := range in.JwtRules { errs = appendErrors(errs, validateJwtRule(rule)) } return nil, errs })
ValidateRequestAuthentication checks that request authentication spec is well-formed.
var ValidateServiceEntry = registerValidateFunc("ValidateServiceEntry", func(cfg config.Config) (warnings Warning, errs error) { serviceEntry, ok := cfg.Spec.(*networking.ServiceEntry) if !ok { return nil, fmt.Errorf("cannot cast to service entry") } if err := validateAlphaWorkloadSelector(serviceEntry.WorkloadSelector); err != nil { return nil, err } if serviceEntry.WorkloadSelector != nil && serviceEntry.Endpoints != nil { errs = appendErrors(errs, fmt.Errorf("only one of WorkloadSelector or Endpoints is allowed in Service Entry")) } if len(serviceEntry.Hosts) == 0 { errs = appendErrors(errs, fmt.Errorf("service entry must have at least one host")) } for _, hostname := range serviceEntry.Hosts { if hostname == "*" { errs = appendErrors(errs, fmt.Errorf("invalid host %s", hostname)) } else { errs = appendErrors(errs, ValidateWildcardDomain(hostname)) } } cidrFound := false for _, address := range serviceEntry.Addresses { cidrFound = cidrFound || strings.Contains(address, "/") errs = appendErrors(errs, ValidateIPSubnet(address)) } if cidrFound { if serviceEntry.Resolution != networking.ServiceEntry_NONE && serviceEntry.Resolution != networking.ServiceEntry_STATIC { errs = appendErrors(errs, fmt.Errorf("CIDR addresses are allowed only for NONE/STATIC resolution types")) } } servicePortNumbers := make(map[uint32]bool) servicePorts := make(map[string]bool, len(serviceEntry.Ports)) for _, port := range serviceEntry.Ports { if port == nil { errs = appendErrors(errs, fmt.Errorf("service entry port may not be null")) continue } if servicePorts[port.Name] { errs = appendErrors(errs, fmt.Errorf("service entry port name %q already defined", port.Name)) } servicePorts[port.Name] = true if servicePortNumbers[port.Number] { errs = appendErrors(errs, fmt.Errorf("service entry port %d already defined", port.Number)) } servicePortNumbers[port.Number] = true } switch serviceEntry.Resolution { case networking.ServiceEntry_NONE: if len(serviceEntry.Endpoints) != 0 { errs = appendErrors(errs, fmt.Errorf("no endpoints should be provided for resolution type none")) } case networking.ServiceEntry_STATIC: unixEndpoint := false for _, endpoint := range serviceEntry.Endpoints { addr := endpoint.GetAddress() if strings.HasPrefix(addr, UnixAddressPrefix) { unixEndpoint = true errs = appendErrors(errs, ValidateUnixAddress(strings.TrimPrefix(addr, UnixAddressPrefix))) if len(endpoint.Ports) != 0 { errs = appendErrors(errs, fmt.Errorf("unix endpoint %s must not include ports", addr)) } } else { errs = appendErrors(errs, ValidateIPAddress(addr)) for name, port := range endpoint.Ports { if !servicePorts[name] { errs = appendErrors(errs, fmt.Errorf("endpoint port %v is not defined by the service entry", port)) } } } errs = appendErrors(errs, labels.Instance(endpoint.Labels).Validate()) } if unixEndpoint && len(serviceEntry.Ports) != 1 { errs = appendErrors(errs, errors.New("exactly 1 service port required for unix endpoints")) } case networking.ServiceEntry_DNS: if len(serviceEntry.Endpoints) == 0 { for _, hostname := range serviceEntry.Hosts { if err := ValidateFQDN(hostname); err != nil { errs = appendErrors(errs, fmt.Errorf("hosts must be FQDN if no endpoints are provided for resolution mode DNS")) } } } for _, endpoint := range serviceEntry.Endpoints { ipAddr := net.ParseIP(endpoint.Address) if ipAddr == nil { if err := ValidateFQDN(endpoint.Address); err != nil { errs = appendErrors(errs, fmt.Errorf("endpoint address %q is not a valid FQDN or an IP address", endpoint.Address)) } } errs = appendErrors(errs, labels.Instance(endpoint.Labels).Validate()) for name, port := range endpoint.Ports { if !servicePorts[name] { errs = appendErrors(errs, fmt.Errorf("endpoint port %v is not defined by the service entry", port)) } errs = appendErrors(errs, ValidatePortName(name), ValidatePort(int(port))) } } default: errs = appendErrors(errs, fmt.Errorf("unsupported resolution type %s", networking.ServiceEntry_Resolution_name[int32(serviceEntry.Resolution)])) } if serviceEntry.Resolution != networking.ServiceEntry_NONE && len(serviceEntry.Hosts) > 1 { canDifferentiate := true for _, port := range serviceEntry.Ports { p := protocol.Parse(port.Protocol) if !p.IsHTTP() && !p.IsTLS() { canDifferentiate = false break } } if !canDifferentiate { errs = appendErrors(errs, fmt.Errorf("multiple hosts provided with non-HTTP, non-TLS ports")) } } for _, port := range serviceEntry.Ports { if port == nil { errs = appendErrors(errs, errors.New("port may not be null")) continue } errs = appendErrors(errs, ValidatePortName(port.Name), ValidateProtocol(port.Protocol), ValidatePort(int(port.Number))) } errs = appendErrors(errs, validateExportTo(cfg.Namespace, serviceEntry.ExportTo, true)) return })
ValidateServiceEntry validates a service entry.
var ValidateSidecar = registerValidateFunc("ValidateSidecar", func(cfg config.Config) (warnings Warning, errs error) { rule, ok := cfg.Spec.(*networking.Sidecar) if !ok { return nil, fmt.Errorf("cannot cast to Sidecar") } if err := validateAlphaWorkloadSelector(rule.WorkloadSelector); err != nil { return nil, err } if len(rule.Egress) == 0 && len(rule.Ingress) == 0 && rule.OutboundTrafficPolicy == nil { return nil, fmt.Errorf("sidecar: empty configuration provided") } portMap := make(map[uint32]struct{}) for _, i := range rule.Ingress { if i == nil { errs = appendErrors(errs, fmt.Errorf("sidecar: ingress may not be null")) continue } if i.Port == nil { errs = appendErrors(errs, fmt.Errorf("sidecar: port is required for ingress listeners")) continue } bind := i.GetBind() errs = appendErrors(errs, validateSidecarIngressPortAndBind(i.Port, bind)) if _, found := portMap[i.Port.Number]; found { errs = appendErrors(errs, fmt.Errorf("sidecar: ports on IP bound listeners must be unique")) } portMap[i.Port.Number] = struct{}{} if len(i.DefaultEndpoint) == 0 { errs = appendErrors(errs, fmt.Errorf("sidecar: default endpoint must be set for all ingress listeners")) } else { if strings.HasPrefix(i.DefaultEndpoint, UnixAddressPrefix) { errs = appendErrors(errs, ValidateUnixAddress(strings.TrimPrefix(i.DefaultEndpoint, UnixAddressPrefix))) } else { parts := strings.Split(i.DefaultEndpoint, ":") if len(parts) < 2 { errs = appendErrors(errs, fmt.Errorf("sidecar: defaultEndpoint must be of form 127.0.0.1:<port> or 0.0.0.0:<port>")) } else { if len(parts[0]) > 0 && parts[0] != "127.0.0.1" && parts[0] != "0.0.0.0" { errs = appendErrors(errs, fmt.Errorf("sidecar: defaultEndpoint must be of form 127.0.0.1:<port> or 0.0.0.0:<port>")) } port, err := strconv.Atoi(parts[1]) if err != nil { errs = appendErrors(errs, fmt.Errorf("sidecar: defaultEndpoint port (%s) is not a number: %v", parts[1], err)) } else { errs = appendErrors(errs, ValidatePort(port)) } } } } } portMap = make(map[uint32]struct{}) udsMap := make(map[string]struct{}) catchAllEgressListenerFound := false for index, i := range rule.Egress { if i == nil { errs = appendErrors(errs, errors.New("egress listener may not be null")) continue } if i.Port == nil { if !catchAllEgressListenerFound { if index == len(rule.Egress)-1 { catchAllEgressListenerFound = true } else { errs = appendErrors(errs, fmt.Errorf("sidecar: the egress listener with empty port should be the last listener in the list")) } } else { errs = appendErrors(errs, fmt.Errorf("sidecar: egress can have only one listener with empty port")) continue } } else { bind := i.GetBind() captureMode := i.GetCaptureMode() errs = appendErrors(errs, validateSidecarEgressPortBindAndCaptureMode(i.Port, bind, captureMode)) if i.Port.Number == 0 { if _, found := udsMap[bind]; found { errs = appendErrors(errs, fmt.Errorf("sidecar: unix domain socket values for listeners must be unique")) } udsMap[bind] = struct{}{} } else { if _, found := portMap[i.Port.Number]; found { errs = appendErrors(errs, fmt.Errorf("sidecar: ports on IP bound listeners must be unique")) } portMap[i.Port.Number] = struct{}{} } } if len(i.Hosts) == 0 { errs = appendErrors(errs, fmt.Errorf("sidecar: egress listener must contain at least one host")) } else { for _, hostname := range i.Hosts { errs = appendErrors(errs, validateNamespaceSlashWildcardHostname(hostname, false)) } } } errs = appendErrors(errs, validateSidecarOutboundTrafficPolicy(rule.OutboundTrafficPolicy)) return })
ValidateSidecar checks sidecar config supplied by user
var ValidateVirtualService = registerValidateFunc("ValidateVirtualService", func(cfg config.Config) (Warning, error) { virtualService, ok := cfg.Spec.(*networking.VirtualService) if !ok { return nil, errors.New("cannot cast to virtual service") } errs := Validation{} isDelegate := false if len(virtualService.Hosts) == 0 { if features.EnableVirtualServiceDelegate { isDelegate = true } else { errs = appendValidation(errs, fmt.Errorf("virtual service must have at least one host")) } } if isDelegate { if len(virtualService.Gateways) != 0 { errs = appendValidation(errs, fmt.Errorf("delegate virtual service must have no gateways specified")) } if len(virtualService.Tls) != 0 { errs = appendValidation(errs, fmt.Errorf("delegate virtual service must have no tls route specified")) } if len(virtualService.Tcp) != 0 { errs = appendValidation(errs, fmt.Errorf("delegate virtual service must have no tcp route specified")) } } appliesToMesh := false if len(virtualService.Gateways) == 0 { appliesToMesh = true } errs = appendValidation(errs, validateGatewayNames(virtualService.Gateways)) for _, gatewayName := range virtualService.Gateways { if gatewayName == constants.IstioMeshGateway { appliesToMesh = true } } allHostsValid := true for _, virtualHost := range virtualService.Hosts { if err := ValidateWildcardDomain(virtualHost); err != nil { ipAddr := net.ParseIP(virtualHost) if ipAddr == nil { errs = appendValidation(errs, err) allHostsValid = false } } else if appliesToMesh && virtualHost == "*" { errs = appendValidation(errs, fmt.Errorf("wildcard host * is not allowed for virtual services bound to the mesh gateway")) allHostsValid = false } } if allHostsValid { for i := 0; i < len(virtualService.Hosts); i++ { hostI := host.Name(virtualService.Hosts[i]) for j := i + 1; j < len(virtualService.Hosts); j++ { hostJ := host.Name(virtualService.Hosts[j]) if hostI.Matches(hostJ) { errs = appendValidation(errs, fmt.Errorf("duplicate hosts in virtual service: %s & %s", hostI, hostJ)) } } } } if len(virtualService.Http) == 0 && len(virtualService.Tcp) == 0 && len(virtualService.Tls) == 0 { errs = appendValidation(errs, errors.New("http, tcp or tls must be provided in virtual service")) } for _, httpRoute := range virtualService.Http { if httpRoute == nil { errs = appendValidation(errs, errors.New("http route may not be null")) continue } errs = appendValidation(errs, validateHTTPRoute(httpRoute, isDelegate)) } for _, tlsRoute := range virtualService.Tls { errs = appendValidation(errs, validateTLSRoute(tlsRoute, virtualService)) } for _, tcpRoute := range virtualService.Tcp { errs = appendValidation(errs, validateTCPRoute(tcpRoute)) } errs = appendValidation(errs, validateExportTo(cfg.Namespace, virtualService.ExportTo, false)) return errs.Unwrap() })
ValidateVirtualService checks that a v1alpha3 route rule is well-formed.
var ValidateWorkloadEntry = registerValidateFunc("ValidateWorkloadEntry", func(cfg config.Config) (warnings Warning, errs error) { we, ok := cfg.Spec.(*networking.WorkloadEntry) if !ok { return nil, fmt.Errorf("cannot cast to workload entry") } return validateWorkloadEntry(we) })
ValidateWorkloadEntry validates a workload entry.
var ValidateWorkloadGroup = registerValidateFunc("ValidateWorkloadGroup", func(cfg config.Config) (warnings Warning, errs error) { wg, ok := cfg.Spec.(*networking.WorkloadGroup) if !ok { return nil, fmt.Errorf("cannot cast to workload entry") } if wg.Template == nil { return nil, fmt.Errorf("template is required") } if wg.Metadata != nil { if err := labels.Instance(wg.Metadata.Labels).Validate(); err != nil { return nil, fmt.Errorf("invalid labels: %v", err) } } return nil, validateReadinessProbe(wg.Probe) })
ValidateWorkloadGroup validates a workload group.
IsNegativeDuration check if the duration is negative
IsValidateFunc indicates whether there is a validation function with the given name.
ValidateConnectTimeout validates the envoy conncection timeout
func ValidateDatadogCollector(d *meshconfig.Tracing_Datadog) error
ValidateDatadogCollector validates the configuration for sending envoy spans to Datadog
ValidateDuration checks that a proto duration is well-formed
ValidateDurationGogo checks that a gogo proto duration is well-formed
ValidateDurationRange verifies range is in specified duration
ValidateFQDN checks a fully-qualified domain name
ValidateHTTPHeaderName validates a header name
ValidateHTTPHeaderValue validates a header value for Envoy Valid: "foo", "%HOSTNAME%", "100%%", "prefix %HOSTNAME% suffix" Invalid: "abc%123" We don't try to check that what is inside the %% is one of Envoy recognized values, we just prevent invalid config. See: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers.html#custom-request-response-headers
ValidateIPAddress validates that a string in "CIDR notation" or "Dot-decimal notation"
ValidateIPSubnet checks that a string is in "CIDR notation" or "Dot-decimal notation"
func ValidateLightstepCollector(ls *meshconfig.Tracing_Lightstep) error
ValidateLightstepCollector validates the configuration for sending envoy spans to LightStep
ValidateMaxServerConnectionAge validate negative duration
func ValidateMeshConfig(mesh *meshconfig.MeshConfig) (errs error)
ValidateMeshConfig checks that the mesh config is well-formed
func ValidateMeshNetworks(meshnetworks *meshconfig.MeshNetworks) (errs error)
ValidateMeshNetworks validates meshnetworks.
ValidateParentAndDrain checks that parent and drain durations are valid
ValidatePercent checks that percent is in range
ValidatePort checks that the network port is in range
ValidatePortName validates a port name to DNS-1123
ValidateProtocol validates a portocol name is known
ValidateProtocolDetectionTimeout validates the envoy protocol detection timeout
ValidateProxyAddress checks that a network address is well-formed
func ValidateProxyConfig(config *meshconfig.ProxyConfig) (errs error)
ValidateProxyConfig checks that the mesh config is well-formed
validate the trust domain format
ValidateUnixAddress validates that the string is a valid unix domain socket path.
ValidateWildcardDomain checks that a domain is a valid FQDN, but also allows wildcard prefixes.
func ValidateZipkinCollector(z *meshconfig.Tracing_Zipkin) error
ValidateZipkinCollector validates the configuration for sending envoy spans to Zipkin
ValidateFunc defines a validation func for an API proto.
func GetValidateFunc(name string) ValidateFunc
GetValidateFunc returns the validation function with the given name, or null if it does not exist.
Validation holds errors and warnings. They can be joined with additional errors by called appendValidation
func WrapError(e error) Validation
WrapError turns an error into a Validation
func WrapWarning(e error) Validation
WrapWarning turns an error into a Validation as a warning
func (v Validation) Error() string
func (v Validation) Unwrap() (Warning, error)
Package validation imports 36 packages (graph) and is imported by 26 packages. Updated 2021-01-21. Refresh now. Tools for package owners.