diff --git a/agent/consul/config_endpoint_test.go b/agent/consul/config_endpoint_test.go index dc0c8d82f..bbed2bf1b 100644 --- a/agent/consul/config_endpoint_test.go +++ b/agent/consul/config_endpoint_test.go @@ -1141,8 +1141,8 @@ func TestConfigEntry_ResolveServiceConfig_TransparentProxy(t *testing.T) { Name: "foo", Mode: structs.ProxyModeTransparent, Destination: &structs.DestinationConfig{ - Address: "hello.world.com", - Port: 443, + Addresses: []string{"hello.world.com"}, + Port: 443, }, }, }, @@ -1153,8 +1153,8 @@ func TestConfigEntry_ResolveServiceConfig_TransparentProxy(t *testing.T) { expect: structs.ServiceConfigResponse{ Mode: structs.ProxyModeTransparent, Destination: structs.DestinationConfig{ - Address: "hello.world.com", - Port: 443, + Addresses: []string{"hello.world.com"}, + Port: 443, }, }, }, diff --git a/agent/consul/helper_test.go b/agent/consul/helper_test.go index 957653ad2..48186b548 100644 --- a/agent/consul/helper_test.go +++ b/agent/consul/helper_test.go @@ -1462,8 +1462,8 @@ func registerIntentionUpstreamEntries(t *testing.T, codec rpc.ClientCodec, token Kind: structs.ServiceDefaults, Name: "api.example.com", Destination: &structs.DestinationConfig{ - Address: "api.example.com", - Port: 443, + Addresses: []string{"api.example.com"}, + Port: 443, }, }, WriteRequest: structs.WriteRequest{Token: token}, @@ -1474,8 +1474,8 @@ func registerIntentionUpstreamEntries(t *testing.T, codec rpc.ClientCodec, token Kind: structs.ServiceDefaults, Name: "kafka.store.com", Destination: &structs.DestinationConfig{ - Address: "172.168.2.1", - Port: 9003, + Addresses: []string{"172.168.2.1"}, + Port: 9003, }, }, WriteRequest: structs.WriteRequest{Token: token}, diff --git a/agent/consul/internal_endpoint_test.go b/agent/consul/internal_endpoint_test.go index f02150b8c..6d35f55b6 100644 --- a/agent/consul/internal_endpoint_test.go +++ b/agent/consul/internal_endpoint_test.go @@ -3177,7 +3177,7 @@ func TestInternal_ServiceGatewayService_Terminating_Destination(t *testing.T) { Datacenter: "dc1", Entry: &structs.ServiceConfigEntry{ Name: "google", - Destination: &structs.DestinationConfig{Address: "www.google.com", Port: 443}, + Destination: &structs.DestinationConfig{Addresses: []string{"www.google.com"}, Port: 443}, EnterpriseMeta: *acl.DefaultEnterpriseMeta(), }, } diff --git a/agent/consul/state/catalog_events_test.go b/agent/consul/state/catalog_events_test.go index ef398ed6c..d4e1175cd 100644 --- a/agent/consul/state/catalog_events_test.go +++ b/agent/consul/state/catalog_events_test.go @@ -1675,7 +1675,7 @@ func TestServiceHealthEventsFromChanges(t *testing.T) { configEntryDest := &structs.ServiceConfigEntry{ Kind: structs.ServiceDefaults, Name: "destination1", - Destination: &structs.DestinationConfig{Port: 9000, Address: "kafka.test.com"}, + Destination: &structs.DestinationConfig{Port: 9000, Addresses: []string{"kafka.test.com"}}, } return ensureConfigEntryTxn(tx, tx.Index, configEntryDest) }, @@ -1721,7 +1721,7 @@ func TestServiceHealthEventsFromChanges(t *testing.T) { configEntryDest := &structs.ServiceConfigEntry{ Kind: structs.ServiceDefaults, Name: "destination1", - Destination: &structs.DestinationConfig{Port: 9000, Address: "kafka.test.com"}, + Destination: &structs.DestinationConfig{Port: 9000, Addresses: []string{"kafka.test.com"}}, } return ensureConfigEntryTxn(tx, tx.Index, configEntryDest) }, diff --git a/agent/proxycfg/snapshot.go b/agent/proxycfg/snapshot.go index b96994c21..8d2d81bed 100644 --- a/agent/proxycfg/snapshot.go +++ b/agent/proxycfg/snapshot.go @@ -307,7 +307,7 @@ func (c *configSnapshotTerminatingGateway) ValidDestinations() []structs.Service // Skip the service if we haven't gotten our service config yet to know // the protocol. - if _, ok := c.ServiceConfigs[svc]; !ok || c.ServiceConfigs[svc].Destination.Address == "" { + if conf, ok := c.ServiceConfigs[svc]; !ok || len(conf.Destination.Addresses) == 0 { continue } diff --git a/agent/proxycfg/testing_terminating_gateway.go b/agent/proxycfg/testing_terminating_gateway.go index 64a624e70..fda659173 100644 --- a/agent/proxycfg/testing_terminating_gateway.go +++ b/agent/proxycfg/testing_terminating_gateway.go @@ -429,8 +429,12 @@ func TestConfigSnapshotTerminatingGatewayDestinations(t testing.T, populateDesti Mode: structs.ProxyModeTransparent, ProxyConfig: map[string]interface{}{"protocol": "tcp"}, Destination: structs.DestinationConfig{ - Address: "192.168.0.1", - Port: 80, + Addresses: []string{ + "192.168.0.1", + "192.168.0.2", + "192.168.0.3", + }, + Port: 80, }, }, }, @@ -440,8 +444,11 @@ func TestConfigSnapshotTerminatingGatewayDestinations(t testing.T, populateDesti Mode: structs.ProxyModeTransparent, ProxyConfig: map[string]interface{}{"protocol": "tcp"}, Destination: structs.DestinationConfig{ - Address: "api.hashicorp.com", - Port: 8089, + Addresses: []string{ + "api.hashicorp.com", + "web.hashicorp.com", + }, + Port: 8089, }, }, }, @@ -451,8 +458,8 @@ func TestConfigSnapshotTerminatingGatewayDestinations(t testing.T, populateDesti Mode: structs.ProxyModeTransparent, ProxyConfig: map[string]interface{}{"protocol": "http"}, Destination: structs.DestinationConfig{ - Address: "192.168.0.2", - Port: 80, + Addresses: []string{"192.168.0.2"}, + Port: 80, }, }, }, @@ -462,8 +469,8 @@ func TestConfigSnapshotTerminatingGatewayDestinations(t testing.T, populateDesti Mode: structs.ProxyModeTransparent, ProxyConfig: map[string]interface{}{"protocol": "http"}, Destination: structs.DestinationConfig{ - Address: "httpbin.org", - Port: 80, + Addresses: []string{"httpbin.org"}, + Port: 80, }, }, }, diff --git a/agent/proxycfg/testing_tproxy.go b/agent/proxycfg/testing_tproxy.go index ab55f3313..45d0236a0 100644 --- a/agent/proxycfg/testing_tproxy.go +++ b/agent/proxycfg/testing_tproxy.go @@ -530,11 +530,29 @@ func TestConfigSnapshotTransparentProxyDestination(t testing.T) *ConfigSnapshot var ( google = structs.NewServiceName("google", nil) googleUID = NewUpstreamIDFromServiceName(google) - googleCE = structs.ServiceConfigEntry{Name: "google", Destination: &structs.DestinationConfig{Address: "www.google.com", Port: 443}} + googleCE = structs.ServiceConfigEntry{ + Name: "google", + Destination: &structs.DestinationConfig{ + Addresses: []string{ + "www.google.com", + "api.google.com", + }, + Port: 443, + }, + } kafka = structs.NewServiceName("kafka", nil) kafkaUID = NewUpstreamIDFromServiceName(kafka) - kafkaCE = structs.ServiceConfigEntry{Name: "kafka", Destination: &structs.DestinationConfig{Address: "192.168.2.1", Port: 9093}} + kafkaCE = structs.ServiceConfigEntry{ + Name: "kafka", + Destination: &structs.DestinationConfig{ + Addresses: []string{ + "192.168.2.1", + "192.168.2.2", + }, + Port: 9093, + }, + } ) return TestConfigSnapshot(t, func(ns *structs.NodeService) { diff --git a/agent/structs/config_entry.go b/agent/structs/config_entry.go index 05d7480cb..8b3b0a8d2 100644 --- a/agent/structs/config_entry.go +++ b/agent/structs/config_entry.go @@ -3,6 +3,7 @@ package structs import ( "errors" "fmt" + "github.com/miekg/dns" "net" "strconv" "strings" @@ -201,8 +202,21 @@ func (e *ServiceConfigEntry) Validate() error { } if e.Destination != nil { - if err := validateEndpointAddress(e.Destination.Address); err != nil { - validationErr = multierror.Append(validationErr, fmt.Errorf("Destination address is invalid %w", err)) + if e.Destination.Addresses == nil || len(e.Destination.Addresses) == 0 { + validationErr = multierror.Append(validationErr, errors.New("Destination must contain at least one valid address")) + } + + seen := make(map[string]bool, len(e.Destination.Addresses)) + for _, address := range e.Destination.Addresses { + if _, ok := seen[address]; ok { + validationErr = multierror.Append(validationErr, fmt.Errorf("Duplicate address '%s' is not allowed", address)) + continue + } + seen[address] = true + + if err := validateEndpointAddress(address); err != nil { + validationErr = multierror.Append(validationErr, fmt.Errorf("Destination address '%s' is invalid %w", address, err)) + } } if e.Destination.Port < 1 || e.Destination.Port > 65535 { @@ -219,15 +233,12 @@ func validateEndpointAddress(address string) error { ip := net.ParseIP(address) valid = ip != nil - _, _, err := net.ParseCIDR(address) - valid = valid || err == nil - - // Since we don't know if this will be a TLS connection, setting tlsEnabled to false will be more permissive with wildcards - err = validateHost(false, address) - valid = valid || err == nil + hasWildcard := strings.Contains(address, "*") + _, ok := dns.IsDomainName(address) + valid = valid || (ok && !hasWildcard) if !valid { - return fmt.Errorf("Could not validate address %s as an IP, CIDR block or Hostname", address) + return fmt.Errorf("Could not validate address %s as an IP or Hostname", address) } return nil } @@ -294,20 +305,20 @@ func (c *UpstreamConfiguration) Clone() *UpstreamConfiguration { // DestinationConfig represents a virtual service, i.e. one that is external to Consul type DestinationConfig struct { - // Address of the endpoint; hostname, IP, or CIDR - Address string `json:",omitempty"` + // Addresses of the endpoint; hostname or IP + Addresses []string `json:",omitempty"` // Port allowed within this endpoint Port int `json:",omitempty"` } -func (d *DestinationConfig) HasHostname() bool { - ip := net.ParseIP(d.Address) +func IsHostname(address string) bool { + ip := net.ParseIP(address) return ip == nil } -func (d *DestinationConfig) HasIP() bool { - ip := net.ParseIP(d.Address) +func IsIP(address string) bool { + ip := net.ParseIP(address) return ip != nil } diff --git a/agent/structs/config_entry_test.go b/agent/structs/config_entry_test.go index afbd737f8..c3f5c7a98 100644 --- a/agent/structs/config_entry_test.go +++ b/agent/structs/config_entry_test.go @@ -434,7 +434,10 @@ func TestDecodeConfigEntry(t *testing.T) { name = "external" protocol = "tcp" destination { - address = "1.2.3.4/24" + addresses = [ + "api.google.com", + "web.google.com" + ] port = 8080 } `, @@ -443,7 +446,10 @@ func TestDecodeConfigEntry(t *testing.T) { Name = "external" Protocol = "tcp" Destination { - Address = "1.2.3.4/24" + Addresses = [ + "api.google.com", + "web.google.com" + ] Port = 8080 } `, @@ -452,8 +458,11 @@ func TestDecodeConfigEntry(t *testing.T) { Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "1.2.3.4/24", - Port: 8080, + Addresses: []string{ + "api.google.com", + "web.google.com", + }, + Port: 8080, }, }, }, @@ -2421,17 +2430,29 @@ func TestServiceConfigEntry(t *testing.T) { EnterpriseMeta: *DefaultEnterpriseMetaInDefaultPartition(), }, }, - "validate: missing destination address": { + "validate: nil destination address": { entry: &ServiceConfigEntry{ Kind: ServiceDefaults, Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "", - Port: 443, + Addresses: nil, + Port: 443, }, }, - validateErr: "Could not validate address", + validateErr: "must contain at least one valid address", + }, + "validate: empty destination address": { + entry: &ServiceConfigEntry{ + Kind: ServiceDefaults, + Name: "external", + Protocol: "tcp", + Destination: &DestinationConfig{ + Addresses: []string{}, + Port: 443, + }, + }, + validateErr: "must contain at least one valid address", }, "validate: destination ipv4 address": { entry: &ServiceConfigEntry{ @@ -2439,19 +2460,8 @@ func TestServiceConfigEntry(t *testing.T) { Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "1.2.3.4", - Port: 443, - }, - }, - }, - "validate: destination ipv4 CIDR address": { - entry: &ServiceConfigEntry{ - Kind: ServiceDefaults, - Name: "external", - Protocol: "tcp", - Destination: &DestinationConfig{ - Address: "10.0.0.1/16", - Port: 8080, + Addresses: []string{"1.2.3.4"}, + Port: 443, }, }, }, @@ -2461,8 +2471,8 @@ func TestServiceConfigEntry(t *testing.T) { Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "2001:0db8:0000:8a2e:0370:7334:1234:5678", - Port: 443, + Addresses: []string{"2001:0db8:0000:8a2e:0370:7334:1234:5678"}, + Port: 443, }, }, }, @@ -2472,19 +2482,8 @@ func TestServiceConfigEntry(t *testing.T) { Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "2001:db8::8a2e:370:7334", - Port: 443, - }, - }, - }, - "validate: destination ipv6 CIDR address": { - entry: &ServiceConfigEntry{ - Kind: ServiceDefaults, - Name: "external", - Protocol: "tcp", - Destination: &DestinationConfig{ - Address: "2001:db8::8a2e:370:7334/64", - Port: 443, + Addresses: []string{"2001:db8::8a2e:370:7334"}, + Port: 443, }, }, }, @@ -2494,7 +2493,7 @@ func TestServiceConfigEntry(t *testing.T) { Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "2001:db8::8a2e:370:7334/64", + Addresses: []string{"2001:db8::8a2e:370:7334"}, }, }, validateErr: "Invalid Port number", @@ -2505,8 +2504,8 @@ func TestServiceConfigEntry(t *testing.T) { Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "*external.com", - Port: 443, + Addresses: []string{"*external.com"}, + Port: 443, }, }, validateErr: "Could not validate address", @@ -2517,8 +2516,8 @@ func TestServiceConfigEntry(t *testing.T) { Name: "external", Protocol: "tcp", Destination: &DestinationConfig{ - Address: "..hello.", - Port: 443, + Addresses: []string{"..hello."}, + Port: 443, }, }, validateErr: "Could not validate address", @@ -2529,10 +2528,40 @@ func TestServiceConfigEntry(t *testing.T) { Name: "external", Protocol: "http", Destination: &DestinationConfig{ - Address: "*", - Port: 443, + Addresses: []string{"*"}, + Port: 443, }, }, + validateErr: "Could not validate address", + }, + "validate: multiple hostnames": { + entry: &ServiceConfigEntry{ + Kind: ServiceDefaults, + Name: "external", + Protocol: "http", + Destination: &DestinationConfig{ + Addresses: []string{ + "api.google.com", + "web.google.com", + }, + Port: 443, + }, + }, + }, + "validate: duplicate addresses not allowed": { + entry: &ServiceConfigEntry{ + Kind: ServiceDefaults, + Name: "external", + Protocol: "http", + Destination: &DestinationConfig{ + Addresses: []string{ + "api.google.com", + "api.google.com", + }, + Port: 443, + }, + }, + validateErr: "Duplicate address", }, } testConfigEntryNormalizeAndValidate(t, cases) diff --git a/agent/xds/clusters.go b/agent/xds/clusters.go index ed7f8af1a..2e7dc6f3c 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "sort" + "strings" "time" envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" @@ -249,38 +250,46 @@ func makePassthroughClusters(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, } err := cfgSnap.ConnectProxy.DestinationsUpstream.ForEachKeyE(func(uid proxycfg.UpstreamID) error { - name := clusterNameForDestination(cfgSnap, uid.Name, uid.NamespaceOrDefault(), uid.PartitionOrDefault()) + svcConfig, ok := cfgSnap.ConnectProxy.DestinationsUpstream.Get(uid) + if !ok || svcConfig.Destination == nil { + return nil + } - c := envoy_cluster_v3.Cluster{ - Name: name, - AltStatName: name, - ConnectTimeout: durationpb.New(5 * time.Second), - CommonLbConfig: &envoy_cluster_v3.Cluster_CommonLbConfig{ - HealthyPanicThreshold: &envoy_type_v3.Percent{ - Value: 0, // disable panic threshold - }, - }, - ClusterDiscoveryType: &envoy_cluster_v3.Cluster_Type{Type: envoy_cluster_v3.Cluster_EDS}, - EdsClusterConfig: &envoy_cluster_v3.Cluster_EdsClusterConfig{ - EdsConfig: &envoy_core_v3.ConfigSource{ - ResourceApiVersion: envoy_core_v3.ApiVersion_V3, - ConfigSourceSpecifier: &envoy_core_v3.ConfigSource_Ads{ - Ads: &envoy_core_v3.AggregatedConfigSource{}, + // One Cluster per Destination Address + for _, address := range svcConfig.Destination.Addresses { + name := clusterNameForDestination(cfgSnap, uid.Name, address, uid.NamespaceOrDefault(), uid.PartitionOrDefault()) + + c := envoy_cluster_v3.Cluster{ + Name: name, + AltStatName: name, + ConnectTimeout: durationpb.New(5 * time.Second), + CommonLbConfig: &envoy_cluster_v3.Cluster_CommonLbConfig{ + HealthyPanicThreshold: &envoy_type_v3.Percent{ + Value: 0, // disable panic threshold }, }, - }, - // Endpoints are managed separately by EDS - // Having an empty config enables outlier detection with default config. - OutlierDetection: &envoy_cluster_v3.OutlierDetection{}, - } + ClusterDiscoveryType: &envoy_cluster_v3.Cluster_Type{Type: envoy_cluster_v3.Cluster_EDS}, + EdsClusterConfig: &envoy_cluster_v3.Cluster_EdsClusterConfig{ + EdsConfig: &envoy_core_v3.ConfigSource{ + ResourceApiVersion: envoy_core_v3.ApiVersion_V3, + ConfigSourceSpecifier: &envoy_core_v3.ConfigSource_Ads{ + Ads: &envoy_core_v3.AggregatedConfigSource{}, + }, + }, + }, + // Endpoints are managed separately by EDS + // Having an empty config enables outlier detection with default config. + OutlierDetection: &envoy_cluster_v3.OutlierDetection{}, + } - // Use the cluster name as the SNI to match on in the terminating gateway - transportSocket, err := makeMTLSTransportSocket(cfgSnap, uid, name) - if err != nil { - return err + // Use the cluster name as the SNI to match on in the terminating gateway + transportSocket, err := makeMTLSTransportSocket(cfgSnap, uid, name) + if err != nil { + return err + } + c.TransportSocket = transportSocket + clusters = append(clusters, &c) } - c.TransportSocket = transportSocket - clusters = append(clusters, &c) return nil }) if err != nil { @@ -319,11 +328,18 @@ func makeMTLSTransportSocket(cfgSnap *proxycfg.ConfigSnapshot, uid proxycfg.Upst return transportSocket, nil } -func clusterNameForDestination(cfgSnap *proxycfg.ConfigSnapshot, name string, namespace string, partition string) string { +func clusterNameForDestination(cfgSnap *proxycfg.ConfigSnapshot, name string, address string, namespace string, partition string) string { + name = destinationSpecificServiceName(name, address) sni := connect.ServiceSNI(name, "", namespace, partition, cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) // Prefixed with destination to distinguish from non-passthrough clusters for the same upstream. - return "destination~" + sni + return "destination." + sni +} + +func destinationSpecificServiceName(name string, address string) string { + address = strings.ReplaceAll(address, ":", "-") + address = strings.ReplaceAll(address, ".", "-") + return fmt.Sprintf("%s.%s", address, name) } // clustersFromSnapshotMeshGateway returns the xDS API representation of the "clusters" @@ -529,18 +545,21 @@ func (s *ResourceGenerator) makeDestinationClusters(cfgSnap *proxycfg.ConfigSnap svcConfig, _ := serviceConfigs[svcName] dest := svcConfig.Destination - opts := clusterOpts{ - name: clusterNameForDestination(cfgSnap, svcName.Name, svcName.NamespaceOrDefault(), svcName.PartitionOrDefault()), - addressEndpoint: dest, - } + for _, address := range dest.Addresses { + opts := clusterOpts{ + name: clusterNameForDestination(cfgSnap, svcName.Name, address, svcName.NamespaceOrDefault(), svcName.PartitionOrDefault()), + address: address, + port: dest.Port, + } - var cluster *envoy_cluster_v3.Cluster - if dest.HasIP() { - cluster = s.makeTerminatingIPCluster(cfgSnap, opts) - } else { - cluster = s.makeTerminatingHostnameCluster(cfgSnap, opts) + var cluster *envoy_cluster_v3.Cluster + if structs.IsIP(address) { + cluster = s.makeTerminatingIPCluster(cfgSnap, opts) + } else { + cluster = s.makeTerminatingHostnameCluster(cfgSnap, opts) + } + clusters = append(clusters, cluster) } - clusters = append(clusters, cluster) } return clusters, nil } @@ -1261,8 +1280,9 @@ type clusterOpts struct { // hostnameEndpoints is a list of endpoints with a hostname as their address hostnameEndpoints structs.CheckServiceNodes - // addressEndpoint is a singular ip/port endpoint - addressEndpoint structs.DestinationConfig + // Corresponds to a valid ip/port in a Destination + address string + port int } // makeGatewayCluster creates an Envoy cluster for a mesh or terminating gateway @@ -1412,7 +1432,7 @@ func (s *ResourceGenerator) makeTerminatingIPCluster(snap *proxycfg.ConfigSnapsh } endpoints := []*envoy_endpoint_v3.LbEndpoint{ - makeEndpoint(opts.addressEndpoint.Address, opts.addressEndpoint.Port), + makeEndpoint(opts.address, opts.port), } cluster.LoadAssignment = &envoy_endpoint_v3.ClusterLoadAssignment{ @@ -1449,7 +1469,7 @@ func (s *ResourceGenerator) makeTerminatingHostnameCluster(snap *proxycfg.Config rate := 10 * time.Second cluster.DnsRefreshRate = durationpb.New(rate) - address := makeAddress(opts.addressEndpoint.Address, opts.addressEndpoint.Port) + address := makeAddress(opts.address, opts.port) endpoints := []*envoy_endpoint_v3.LbEndpoint{ { diff --git a/agent/xds/endpoints.go b/agent/xds/endpoints.go index 8fda9adc2..cc59a77a0 100644 --- a/agent/xds/endpoints.go +++ b/agent/xds/endpoints.go @@ -151,19 +151,27 @@ func (s *ResourceGenerator) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg. // Loop over potential destinations in the mesh, then grab the gateway nodes associated with each cfgSnap.ConnectProxy.DestinationsUpstream.ForEachKey(func(uid proxycfg.UpstreamID) bool { - name := clusterNameForDestination(cfgSnap, uid.Name, uid.NamespaceOrDefault(), uid.PartitionOrDefault()) - - endpoints, ok := cfgSnap.ConnectProxy.DestinationGateways.Get(uid) - if ok { - la := makeLoadAssignment( - name, - []loadAssignmentEndpointGroup{ - {Endpoints: endpoints}, - }, - proxycfg.GatewayKey{ /*empty so it never matches*/ }, - ) - resources = append(resources, la) + svcConfig, ok := cfgSnap.ConnectProxy.DestinationsUpstream.Get(uid) + if !ok || svcConfig.Destination == nil { + return true } + + for _, address := range svcConfig.Destination.Addresses { + name := clusterNameForDestination(cfgSnap, uid.Name, address, uid.NamespaceOrDefault(), uid.PartitionOrDefault()) + + endpoints, ok := cfgSnap.ConnectProxy.DestinationGateways.Get(uid) + if ok { + la := makeLoadAssignment( + name, + []loadAssignmentEndpointGroup{ + {Endpoints: endpoints}, + }, + proxycfg.GatewayKey{ /*empty so it never matches*/ }, + ) + resources = append(resources, la) + } + } + return true }) diff --git a/agent/xds/listeners.go b/agent/xds/listeners.go index 5b7b0d61f..ce0e9b1b8 100644 --- a/agent/xds/listeners.go +++ b/agent/xds/listeners.go @@ -226,30 +226,31 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg. outboundListener.FilterChains = append(outboundListener.FilterChains, filterChain) } } - hasDestination := false + requiresTLSInspector := false err = cfgSnap.ConnectProxy.DestinationsUpstream.ForEachKeyE(func(uid proxycfg.UpstreamID) error { - destination, ok := cfgSnap.ConnectProxy.DestinationsUpstream.Get(uid) + svcConfig, ok := cfgSnap.ConnectProxy.DestinationsUpstream.Get(uid) + if !ok || svcConfig == nil { + return nil + } - if ok && destination != nil { - upstreamCfg := cfgSnap.ConnectProxy.UpstreamConfig[uid] - cfg := s.getAndModifyUpstreamConfigForListener(uid, upstreamCfg, nil) - - clusterName := clusterNameForDestination(cfgSnap, uid.Name, uid.NamespaceOrDefault(), uid.PartitionOrDefault()) + for _, address := range svcConfig.Destination.Addresses { + clusterName := clusterNameForDestination(cfgSnap, uid.Name, address, uid.NamespaceOrDefault(), uid.PartitionOrDefault()) filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{ routeName: uid.EnvoyID(), clusterName: clusterName, filterName: clusterName, - protocol: cfg.Protocol, - useRDS: cfg.Protocol != "tcp", + protocol: svcConfig.Protocol, + useRDS: structs.IsProtocolHTTPLike(svcConfig.Protocol), }) if err != nil { return err } - filterChain.FilterChainMatch = makeFilterChainMatchFromAddressWithPort(destination.Destination.Address, destination.Destination.Port) + + filterChain.FilterChainMatch = makeFilterChainMatchFromAddressWithPort(address, svcConfig.Destination.Port) outboundListener.FilterChains = append(outboundListener.FilterChains, filterChain) - hasDestination = len(filterChain.FilterChainMatch.ServerNames) != 0 || hasDestination + requiresTLSInspector = len(filterChain.FilterChainMatch.ServerNames) != 0 || requiresTLSInspector } return nil }) @@ -257,7 +258,7 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg. return nil, err } - if hasDestination { + if requiresTLSInspector { tlsInspector, err := makeTLSInspectorListenerFilter() if err != nil { return nil, err @@ -1327,7 +1328,14 @@ func (s *ResourceGenerator) makeTerminatingGatewayListener( ) } - clusterChain, err := s.makeFilterChainTerminatingGateway(cfgSnap, clusterName, svc, intentions, cfg.Protocol, nil) + opts := terminatingGatewayFilterChainOpts{ + cluster: clusterName, + service: svc, + intentions: intentions, + protocol: cfg.Protocol, + } + + clusterChain, err := s.makeFilterChainTerminatingGateway(cfgSnap, opts) if err != nil { return nil, fmt.Errorf("failed to make filter chain for cluster %q: %v", clusterName, err) } @@ -1339,7 +1347,8 @@ func (s *ResourceGenerator) makeTerminatingGatewayListener( for subsetName := range resolver.Subsets { subsetClusterName := connect.ServiceSNI(svc.Name, subsetName, svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) - subsetClusterChain, err := s.makeFilterChainTerminatingGateway(cfgSnap, subsetClusterName, svc, intentions, cfg.Protocol, nil) + opts.cluster = subsetClusterName + subsetClusterChain, err := s.makeFilterChainTerminatingGateway(cfgSnap, opts) if err != nil { return nil, fmt.Errorf("failed to make filter chain for cluster %q: %v", subsetClusterName, err) } @@ -1349,8 +1358,6 @@ func (s *ResourceGenerator) makeTerminatingGatewayListener( } for _, svc := range cfgSnap.TerminatingGateway.ValidDestinations() { - clusterName := clusterNameForDestination(cfgSnap, svc.Name, svc.NamespaceOrDefault(), svc.PartitionOrDefault()) - intentions := cfgSnap.TerminatingGateway.Intentions[svc] svcConfig := cfgSnap.TerminatingGateway.ServiceConfigs[svc] @@ -1367,11 +1374,25 @@ func (s *ResourceGenerator) makeTerminatingGatewayListener( var dest *structs.DestinationConfig dest = &svcConfig.Destination - clusterChain, err := s.makeFilterChainTerminatingGateway(cfgSnap, clusterName, svc, intentions, cfg.Protocol, dest) - if err != nil { - return nil, fmt.Errorf("failed to make filter chain for cluster %q: %v", clusterName, err) + + opts := terminatingGatewayFilterChainOpts{ + service: svc, + intentions: intentions, + protocol: cfg.Protocol, + port: dest.Port, } - l.FilterChains = append(l.FilterChains, clusterChain) + for _, address := range dest.Addresses { + clusterName := clusterNameForDestination(cfgSnap, svc.Name, address, svc.NamespaceOrDefault(), svc.PartitionOrDefault()) + + opts.cluster = clusterName + opts.address = address + clusterChain, err := s.makeFilterChainTerminatingGateway(cfgSnap, opts) + if err != nil { + return nil, fmt.Errorf("failed to make filter chain for cluster %q: %v", clusterName, err) + } + l.FilterChains = append(l.FilterChains, clusterChain) + } + } // Before we add the fallback, sort these chains by the matched name. All @@ -1407,10 +1428,19 @@ func (s *ResourceGenerator) makeTerminatingGatewayListener( return l, nil } -func (s *ResourceGenerator) makeFilterChainTerminatingGateway(cfgSnap *proxycfg.ConfigSnapshot, cluster string, service structs.ServiceName, intentions structs.Intentions, protocol string, dest *structs.DestinationConfig) (*envoy_listener_v3.FilterChain, error) { +type terminatingGatewayFilterChainOpts struct { + cluster string + service structs.ServiceName + intentions structs.Intentions + protocol string + address string // only valid for destination listeners + port int // only valid for destination listeners +} + +func (s *ResourceGenerator) makeFilterChainTerminatingGateway(cfgSnap *proxycfg.ConfigSnapshot, tgtwyOpts terminatingGatewayFilterChainOpts) (*envoy_listener_v3.FilterChain, error) { tlsContext := &envoy_tls_v3.DownstreamTlsContext{ CommonTlsContext: makeCommonTLSContext( - cfgSnap.TerminatingGateway.ServiceLeaves[service], + cfgSnap.TerminatingGateway.ServiceLeaves[tgtwyOpts.service], cfgSnap.RootPEMs(), makeTLSParametersFromProxyTLSConfig(cfgSnap.MeshConfigTLSIncoming()), ), @@ -1422,18 +1452,18 @@ func (s *ResourceGenerator) makeFilterChainTerminatingGateway(cfgSnap *proxycfg. } filterChain := &envoy_listener_v3.FilterChain{ - FilterChainMatch: makeSNIFilterChainMatch(cluster), + FilterChainMatch: makeSNIFilterChainMatch(tgtwyOpts.cluster), Filters: make([]*envoy_listener_v3.Filter, 0, 3), TransportSocket: transportSocket, } // This controls if we do L4 or L7 intention checks. - useHTTPFilter := structs.IsProtocolHTTPLike(protocol) + useHTTPFilter := structs.IsProtocolHTTPLike(tgtwyOpts.protocol) // If this is L4, the first filter we setup is to do intention checks. if !useHTTPFilter { authFilter, err := makeRBACNetworkFilter( - intentions, + tgtwyOpts.intentions, cfgSnap.IntentionDefaultAllow, rbacLocalInfo{ trustDomain: cfgSnap.Roots.TrustDomain, @@ -1452,10 +1482,10 @@ func (s *ResourceGenerator) makeFilterChainTerminatingGateway(cfgSnap *proxycfg. // tcp proxy. For L7 this is a very hands-off HTTP proxy just to inject an // HTTP filter to do intention checks here instead. opts := listenerFilterOpts{ - protocol: protocol, - filterName: fmt.Sprintf("%s.%s.%s.%s", service.Name, service.NamespaceOrDefault(), service.PartitionOrDefault(), cfgSnap.Datacenter), - routeName: cluster, // Set cluster name for route config since each will have its own - cluster: cluster, + protocol: tgtwyOpts.protocol, + filterName: fmt.Sprintf("%s.%s.%s.%s", tgtwyOpts.service.Name, tgtwyOpts.service.NamespaceOrDefault(), tgtwyOpts.service.PartitionOrDefault(), cfgSnap.Datacenter), + routeName: tgtwyOpts.cluster, // Set cluster name for route config since each will have its own + cluster: tgtwyOpts.cluster, statPrefix: "upstream.", routePath: "", } @@ -1463,7 +1493,7 @@ func (s *ResourceGenerator) makeFilterChainTerminatingGateway(cfgSnap *proxycfg. if useHTTPFilter { var err error opts.httpAuthzFilter, err = makeRBACHTTPFilter( - intentions, + tgtwyOpts.intentions, cfgSnap.IntentionDefaultAllow, rbacLocalInfo{ trustDomain: cfgSnap.Roots.TrustDomain, @@ -1488,7 +1518,7 @@ func (s *ResourceGenerator) makeFilterChainTerminatingGateway(cfgSnap *proxycfg. filter, err := makeListenerFilter(opts) if err != nil { - s.Logger.Error("failed to make listener", "cluster", cluster, "error", err) + s.Logger.Error("failed to make listener", "cluster", tgtwyOpts.cluster, "error", err) return nil, err } filterChain.Filters = append(filterChain.Filters, filter) diff --git a/agent/xds/routes.go b/agent/xds/routes.go index dd0beacb2..35fc03455 100644 --- a/agent/xds/routes.go +++ b/agent/xds/routes.go @@ -96,13 +96,17 @@ func (s *ResourceGenerator) routesForTerminatingGateway(cfgSnap *proxycfg.Config } for _, svc := range cfgSnap.TerminatingGateway.ValidDestinations() { - clusterName := clusterNameForDestination(cfgSnap, svc.Name, svc.NamespaceOrDefault(), svc.PartitionOrDefault()) - routes, err := s.makeRoutes(cfgSnap, svc, clusterName, false) - if err != nil { - return nil, err - } - if routes != nil { - resources = append(resources, routes...) + svcConfig := cfgSnap.TerminatingGateway.ServiceConfigs[svc] + + for _, address := range svcConfig.Destination.Addresses { + clusterName := clusterNameForDestination(cfgSnap, svc.Name, address, svc.NamespaceOrDefault(), svc.PartitionOrDefault()) + routes, err := s.makeRoutes(cfgSnap, svc, clusterName, false) + if err != nil { + return nil, err + } + if routes != nil { + resources = append(resources, routes...) + } } } diff --git a/agent/xds/testdata/clusters/transparent-proxy-destination.latest.golden b/agent/xds/testdata/clusters/transparent-proxy-destination.latest.golden index 1a5311ab9..dd5d736e5 100644 --- a/agent/xds/testdata/clusters/transparent-proxy-destination.latest.golden +++ b/agent/xds/testdata/clusters/transparent-proxy-destination.latest.golden @@ -61,63 +61,8 @@ }, { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "destination~google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "altStatName": "destination~google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "type": "EDS", - "edsClusterConfig": { - "edsConfig": { - "ads": { - - }, - "resourceApiVersion": "V3" - } - }, - "connectTimeout": "5s", - "outlierDetection": { - - }, - "commonLbConfig": { - "healthyPanicThreshold": { - - } - }, - "transportSocket": { - "name": "tls", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", - "commonTlsContext": { - "tlsParams": { - - }, - "tlsCertificates": [ - { - "certificateChain": { - "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" - }, - "privateKey": { - "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" - } - } - ], - "validationContext": { - "trustedCa": { - "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" - }, - "matchSubjectAltNames": [ - { - "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/google" - } - ] - } - }, - "sni": "destination~google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" - } - } - }, - { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "destination~kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "altStatName": "destination~kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.192-168-2-1.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "destination.192-168-2-1.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "type": "EDS", "edsClusterConfig": { "edsConfig": { @@ -165,7 +110,172 @@ ] } }, - "sni": "destination~kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "sni": "destination.192-168-2-1.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "destination.192-168-2-2.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "destination.192-168-2-2.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + }, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + }, + "matchSubjectAltNames": [ + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/kafka" + } + ] + } + }, + "sni": "destination.192-168-2-2.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "destination.api-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "destination.api-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + }, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + }, + "matchSubjectAltNames": [ + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/google" + } + ] + } + }, + "sni": "destination.api-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "destination.www-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "destination.www-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + }, + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + }, + "matchSubjectAltNames": [ + { + "exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/google" + } + ] + } + }, + "sni": "destination.www-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } }, diff --git a/agent/xds/testdata/clusters/transparent-proxy-terminating-gateway-destinations-only.latest.golden b/agent/xds/testdata/clusters/transparent-proxy-terminating-gateway-destinations-only.latest.golden index 3cc818f59..87569ad32 100644 --- a/agent/xds/testdata/clusters/transparent-proxy-terminating-gateway-destinations-only.latest.golden +++ b/agent/xds/testdata/clusters/transparent-proxy-terminating-gateway-destinations-only.latest.golden @@ -3,39 +3,11 @@ "resources": [ { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "destination~external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.192-168-0-1.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "type": "STATIC", "connectTimeout": "5s", "loadAssignment": { - "clusterName": "destination~external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "endpoints": [ - { - "lbEndpoints": [ - { - "endpoint": { - "address": { - "socketAddress": { - "address": "192.168.0.2", - "portValue": 80 - } - } - } - } - ] - } - ] - }, - "outlierDetection": { - - } - }, - { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "destination~external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "type": "STATIC", - "connectTimeout": "5s", - "loadAssignment": { - "clusterName": "destination~external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "clusterName": "destination.192-168-0-1.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "endpoints": [ { "lbEndpoints": [ @@ -59,11 +31,124 @@ }, { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "destination~external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.192-168-0-2.external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "destination.192-168-0-2.external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "192.168.0.2", + "portValue": 80 + } + } + } + } + ] + } + ] + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "destination.192-168-0-2.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "destination.192-168-0-2.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "192.168.0.2", + "portValue": 80 + } + } + } + } + ] + } + ] + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "destination.192-168-0-3.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "destination.192-168-0-3.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "192.168.0.3", + "portValue": 80 + } + } + } + } + ] + } + ] + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "destination.api-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "type": "LOGICAL_DNS", "connectTimeout": "5s", "loadAssignment": { - "clusterName": "destination~external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "clusterName": "destination.api-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "api.hashicorp.com", + "portValue": 8089 + } + } + } + } + ] + } + ] + }, + "dnsRefreshRate": "10s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "destination.httpbin-org.external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "LOGICAL_DNS", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "destination.httpbin-org.external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "endpoints": [ { "lbEndpoints": [ @@ -88,11 +173,11 @@ }, { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "destination~external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.web-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "type": "LOGICAL_DNS", "connectTimeout": "5s", "loadAssignment": { - "clusterName": "destination~external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "clusterName": "destination.web-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "endpoints": [ { "lbEndpoints": [ @@ -100,7 +185,7 @@ "endpoint": { "address": { "socketAddress": { - "address": "api.hashicorp.com", + "address": "web.hashicorp.com", "portValue": 8089 } } diff --git a/agent/xds/testdata/endpoints/transparent-proxy-destination.latest.golden b/agent/xds/testdata/endpoints/transparent-proxy-destination.latest.golden index d51ea93da..33fa4f708 100644 --- a/agent/xds/testdata/endpoints/transparent-proxy-destination.latest.golden +++ b/agent/xds/testdata/endpoints/transparent-proxy-destination.latest.golden @@ -37,7 +37,7 @@ }, { "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", - "clusterName": "destination~google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "clusterName": "destination.192-168-2-1.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "endpoints": [ { "lbEndpoints": [ @@ -59,7 +59,51 @@ }, { "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", - "clusterName": "destination~kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "clusterName": "destination.192-168-2-2.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "172.168.0.1", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "destination.api-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "172.168.0.1", + "portValue": 8443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "destination.www-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "endpoints": [ { "lbEndpoints": [ diff --git a/agent/xds/testdata/listeners/transparent-proxy-destination.latest.golden b/agent/xds/testdata/listeners/transparent-proxy-destination.latest.golden index c61302c5e..9ebe59696 100644 --- a/agent/xds/testdata/listeners/transparent-proxy-destination.latest.golden +++ b/agent/xds/testdata/listeners/transparent-proxy-destination.latest.golden @@ -51,8 +51,47 @@ "name": "envoy.filters.network.tcp_proxy", "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "upstream.destination~kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "cluster": "destination~kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "statPrefix": "upstream.destination.192-168-2-1.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "cluster": "destination.192-168-2-1.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + }, + { + "filterChainMatch": { + "destinationPort": 9093, + "prefixRanges": [ + { + "addressPrefix": "192.168.2.2", + "prefixLen": 32 + } + ] + }, + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.destination.192-168-2-2.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "cluster": "destination.192-168-2-2.kafka.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + }, + { + "filterChainMatch": { + "destinationPort": 443, + "serverNames": [ + "api.google.com" + ] + }, + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.destination.api-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "cluster": "destination.api-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] @@ -69,8 +108,8 @@ "name": "envoy.filters.network.tcp_proxy", "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "upstream.destination~google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", - "cluster": "destination~google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "statPrefix": "upstream.destination.www-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "cluster": "destination.www-google-com.google.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] diff --git a/agent/xds/testdata/listeners/transparent-proxy-terminating-gateway-destinations-only.latest.golden b/agent/xds/testdata/listeners/transparent-proxy-terminating-gateway-destinations-only.latest.golden index e281eb734..fc39c5da9 100644 --- a/agent/xds/testdata/listeners/transparent-proxy-terminating-gateway-destinations-only.latest.golden +++ b/agent/xds/testdata/listeners/transparent-proxy-terminating-gateway-destinations-only.latest.golden @@ -14,89 +14,7 @@ { "filterChainMatch": { "serverNames": [ - "destination~external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" - ] - }, - "filters": [ - { - "name": "envoy.filters.network.http_connection_manager", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", - "statPrefix": "upstream.external-IP-HTTP.default.default.dc1", - "rds": { - "configSource": { - "ads": { - - }, - "resourceApiVersion": "V3" - }, - "routeConfigName": "destination~external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" - }, - "httpFilters": [ - { - "name": "envoy.filters.http.rbac", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC", - "rules": { - - } - } - }, - { - "name": "envoy.filters.http.router", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" - } - } - ], - "tracing": { - "randomSampling": { - - } - }, - "forwardClientCertDetails": "APPEND_FORWARD", - "setCurrentClientCertDetails": { - "subject": true, - "cert": true, - "chain": true, - "dns": true, - "uri": true - } - } - } - ], - "transportSocket": { - "name": "tls", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", - "commonTlsContext": { - "tlsParams": { - - }, - "tlsCertificates": [ - { - "certificateChain": { - "inlineString": "placeholder.crt\n" - }, - "privateKey": { - "inlineString": "placeholder.key\n" - } - } - ], - "validationContext": { - "trustedCa": { - "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" - } - } - }, - "requireClientCertificate": true - } - } - }, - { - "filterChainMatch": { - "serverNames": [ - "destination~external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "destination.192-168-0-1.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" ] }, "filters": [ @@ -115,7 +33,7 @@ "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", "statPrefix": "upstream.external-IP-TCP.default.default.dc1", - "cluster": "destination~external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "destination.192-168-0-1.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ], @@ -150,7 +68,7 @@ { "filterChainMatch": { "serverNames": [ - "destination~external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "destination.192-168-0-2.external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" ] }, "filters": [ @@ -158,7 +76,7 @@ "name": "envoy.filters.network.http_connection_manager", "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", - "statPrefix": "upstream.external-hostname-HTTP.default.default.dc1", + "statPrefix": "upstream.external-IP-HTTP.default.default.dc1", "rds": { "configSource": { "ads": { @@ -166,7 +84,7 @@ }, "resourceApiVersion": "V3" }, - "routeConfigName": "destination~external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "routeConfigName": "destination.192-168-0-2.external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" }, "httpFilters": [ { @@ -232,7 +150,115 @@ { "filterChainMatch": { "serverNames": [ - "destination~external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "destination.192-168-0-2.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + ] + }, + "filters": [ + { + "name": "envoy.filters.network.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC", + "rules": { + + }, + "statPrefix": "connect_authz" + } + }, + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.external-IP-TCP.default.default.dc1", + "cluster": "destination.192-168-0-2.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "placeholder.crt\n" + }, + "privateKey": { + "inlineString": "placeholder.key\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "destination.192-168-0-3.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + ] + }, + "filters": [ + { + "name": "envoy.filters.network.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC", + "rules": { + + }, + "statPrefix": "connect_authz" + } + }, + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.external-IP-TCP.default.default.dc1", + "cluster": "destination.192-168-0-3.external-IP-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "placeholder.crt\n" + }, + "privateKey": { + "inlineString": "placeholder.key\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "destination.api-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" ] }, "filters": [ @@ -251,7 +277,143 @@ "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", "statPrefix": "upstream.external-hostname-TCP.default.default.dc1", - "cluster": "destination~external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "destination.api-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "placeholder.crt\n" + }, + "privateKey": { + "inlineString": "placeholder.key\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "destination.httpbin-org.external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + ] + }, + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "upstream.external-hostname-HTTP.default.default.dc1", + "rds": { + "configSource": { + "ads": { + + }, + "resourceApiVersion": "V3" + }, + "routeConfigName": "destination.httpbin-org.external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC", + "rules": { + + } + } + }, + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": { + + } + }, + "forwardClientCertDetails": "APPEND_FORWARD", + "setCurrentClientCertDetails": { + "subject": true, + "cert": true, + "chain": true, + "dns": true, + "uri": true + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "placeholder.crt\n" + }, + "privateKey": { + "inlineString": "placeholder.key\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "destination.web-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + ] + }, + "filters": [ + { + "name": "envoy.filters.network.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC", + "rules": { + + }, + "statPrefix": "connect_authz" + } + }, + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.external-hostname-TCP.default.default.dc1", + "cluster": "destination.web-hashicorp-com.external-hostname-TCP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ], diff --git a/agent/xds/testdata/routes/transparent-proxy-terminating-gateway-destinations-only.latest.golden b/agent/xds/testdata/routes/transparent-proxy-terminating-gateway-destinations-only.latest.golden index 5eb099010..37cf2c0b0 100644 --- a/agent/xds/testdata/routes/transparent-proxy-terminating-gateway-destinations-only.latest.golden +++ b/agent/xds/testdata/routes/transparent-proxy-terminating-gateway-destinations-only.latest.golden @@ -3,10 +3,10 @@ "resources": [ { "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", - "name": "destination~external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.192-168-0-2.external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "virtualHosts": [ { - "name": "destination~external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.192-168-0-2.external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "domains": [ "*" ], @@ -16,7 +16,7 @@ "prefix": "/" }, "route": { - "cluster": "destination~external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "destination.192-168-0-2.external-IP-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] @@ -26,10 +26,10 @@ }, { "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", - "name": "destination~external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.httpbin-org.external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "virtualHosts": [ { - "name": "destination~external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "destination.httpbin-org.external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "domains": [ "*" ], @@ -39,7 +39,7 @@ "prefix": "/" }, "route": { - "cluster": "destination~external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "destination.httpbin-org.external-hostname-HTTP.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] diff --git a/api/config_entry.go b/api/config_entry.go index 79c50b62e..ee55b55ad 100644 --- a/api/config_entry.go +++ b/api/config_entry.go @@ -181,8 +181,8 @@ type UpstreamConfig struct { // DestinationConfig represents a virtual service, i.e. one that is external to Consul type DestinationConfig struct { - // Address of the endpoint; hostname, IP, or CIDR - Address string `json:",omitempty"` + // Addresses of the endpoint; hostname or IP + Addresses []string `json:",omitempty"` // Port allowed within this endpoint Port int `json:",omitempty"` diff --git a/api/config_entry_test.go b/api/config_entry_test.go index f43cc7935..4249e7547 100644 --- a/api/config_entry_test.go +++ b/api/config_entry_test.go @@ -107,8 +107,8 @@ func TestAPI_ConfigEntries(t *testing.T) { } dest := &DestinationConfig{ - Address: "my.example.com", - Port: 80, + Addresses: []string{"my.example.com"}, + Port: 80, } service2 := &ServiceConfigEntry{ @@ -531,7 +531,9 @@ func TestDecodeConfigEntry(t *testing.T) { "Name": "external", "Protocol": "http", "Destination": { - "Address": "1.2.3.4/24", + "Addresses": [ + "1.2.3.4" + ], "Port": 443 } } @@ -541,8 +543,8 @@ func TestDecodeConfigEntry(t *testing.T) { Name: "external", Protocol: "http", Destination: &DestinationConfig{ - Address: "1.2.3.4/24", - Port: 443, + Addresses: []string{"1.2.3.4"}, + Port: 443, }, }, }, diff --git a/command/helpers/helpers_test.go b/command/helpers/helpers_test.go index 82759159f..bbf649296 100644 --- a/command/helpers/helpers_test.go +++ b/command/helpers/helpers_test.go @@ -671,7 +671,7 @@ func TestParseConfigEntry(t *testing.T) { dialed_directly = true } destination = { - address = "10.0.0.0/16", + addresses = ["10.0.0.0", "10.0.0.1"] port = 443 } `, @@ -692,7 +692,7 @@ func TestParseConfigEntry(t *testing.T) { dialed_directly = true } Destination = { - Address = "10.0.0.0/16", + Addresses = ["10.0.0.0", "10.0.0.1"] Port = 443 } `, @@ -714,7 +714,10 @@ func TestParseConfigEntry(t *testing.T) { "dialed_directly": true }, "destination": { - "address": "10.0.0.0/16", + "addresses": [ + "10.0.0.0", + "10.0.0.1" + ], "port": 443 } } @@ -737,7 +740,10 @@ func TestParseConfigEntry(t *testing.T) { "DialedDirectly": true }, "Destination": { - "Address": "10.0.0.0/16", + "Addresses": [ + "10.0.0.0", + "10.0.0.1" + ], "Port": 443 } } @@ -759,8 +765,8 @@ func TestParseConfigEntry(t *testing.T) { DialedDirectly: true, }, Destination: &api.DestinationConfig{ - Address: "10.0.0.0/16", - Port: 443, + Addresses: []string{"10.0.0.0", "10.0.0.1"}, + Port: 443, }, }, },