diff --git a/agent/proxycfg/mesh_gateway.go b/agent/proxycfg/mesh_gateway.go index 5b5987516..b5c3f6755 100644 --- a/agent/proxycfg/mesh_gateway.go +++ b/agent/proxycfg/mesh_gateway.go @@ -522,8 +522,6 @@ func (s *handlerMeshGateway) handleUpdate(ctx context.Context, u UpdateEvent, sn snap.MeshGateway.DiscoveryChain[svc] = resp.Chain - // TODO(peering): we need to do this if we are going to setup a cross-partition or cross-datacenter target - default: if err := s.handleEntUpdate(meshLogger, ctx, u, snap); err != nil { return err diff --git a/agent/proxycfg/snapshot.go b/agent/proxycfg/snapshot.go index e56c169e8..7af7d3fd3 100644 --- a/agent/proxycfg/snapshot.go +++ b/agent/proxycfg/snapshot.go @@ -413,6 +413,76 @@ type configSnapshotMeshGateway struct { PeeringTrustBundlesSet bool } +// MeshGatewayValidExportedServices ensures that the following data is present +// if it exists for a service before it returns that in the set of services to +// expose. +// +// - peering info +// - discovery chain +func (c *ConfigSnapshot) MeshGatewayValidExportedServices() []structs.ServiceName { + out := make([]structs.ServiceName, 0, len(c.MeshGateway.ExportedServicesSlice)) + for _, svc := range c.MeshGateway.ExportedServicesSlice { + if _, ok := c.MeshGateway.ExportedServicesWithPeers[svc]; !ok { + continue // not possible + } + if _, ok := c.MeshGateway.DiscoveryChain[svc]; !ok { + continue // ignore; not ready + } + out = append(out, svc) + } + return out +} + +func (c *ConfigSnapshot) GetMeshGatewayEndpoints(key GatewayKey) structs.CheckServiceNodes { + // Mesh gateways in remote DCs are discovered in two ways: + // + // 1. Via an Internal.ServiceDump RPC in the remote DC (GatewayGroups). + // 2. In the federation state that is replicated from the primary DC (FedStateGateways). + // + // We determine which set to use based on whichever contains the highest + // raft ModifyIndex (and is therefore most up-to-date). + // + // Previously, GatewayGroups was always given presedence over FedStateGateways + // but this was problematic when using mesh gateways for WAN federation. + // + // Consider the following example: + // + // - Primary and Secondary DCs are WAN Federated via local mesh gateways. + // + // - Secondary DC's mesh gateway is running on an ephemeral compute instance + // and is abruptly terminated and rescheduled with a *new IP address*. + // + // - Primary DC's mesh gateway is no longer able to connect to the Secondary + // DC as its proxy is configured with the old IP address. Therefore any RPC + // from the Primary to the Secondary DC will fail (including the one to + // discover the gateway's new IP address). + // + // - Secondary DC performs its regular anti-entropy of federation state data + // to the Primary DC (this succeeds as there is still connectivity in this + // direction). + // + // - At this point the Primary DC's mesh gateway should observe the new IP + // address and reconfigure its proxy, however as we always prioritised + // GatewayGroups this didn't happen and the connection remained severed. + maxModifyIndex := func(vals structs.CheckServiceNodes) uint64 { + var max uint64 + for _, v := range vals { + if i := v.Service.RaftIndex.ModifyIndex; i > max { + max = i + } + } + return max + } + + endpoints := c.MeshGateway.GatewayGroups[key.String()] + fedStateEndpoints := c.MeshGateway.FedStateGateways[key.String()] + + if maxModifyIndex(fedStateEndpoints) > maxModifyIndex(endpoints) { + return fedStateEndpoints + } + return endpoints +} + func (c *configSnapshotMeshGateway) IsServiceExported(svc structs.ServiceName) bool { if c == nil || len(c.ExportedServicesWithPeers) == 0 { return false diff --git a/agent/proxycfg/testing_mesh_gateway.go b/agent/proxycfg/testing_mesh_gateway.go index 82f4ff0bf..2c81d85fe 100644 --- a/agent/proxycfg/testing_mesh_gateway.go +++ b/agent/proxycfg/testing_mesh_gateway.go @@ -6,6 +6,7 @@ import ( "github.com/mitchellh/go-testing-interface" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul/discoverychain" @@ -14,7 +15,7 @@ import ( ) func TestConfigSnapshotMeshGateway(t testing.T, variant string, nsFn func(ns *structs.NodeService), extraUpdates []UpdateEvent) *ConfigSnapshot { - roots, leaf := TestCertsForMeshGateway(t) + roots, _ := TestCertsForMeshGateway(t) var ( populateServices = true @@ -24,58 +25,6 @@ func TestConfigSnapshotMeshGateway(t testing.T, variant string, nsFn func(ns *st switch variant { case "default": - case "peered-services": - var ( - fooSN = structs.NewServiceName("foo", nil) - barSN = structs.NewServiceName("bar", nil) - girSN = structs.NewServiceName("gir", nil) - - fooChain = discoverychain.TestCompileConfigEntries(t, "foo", "default", "default", "dc1", connect.TestClusterID+".consul", nil) - barChain = discoverychain.TestCompileConfigEntries(t, "bar", "default", "default", "dc1", connect.TestClusterID+".consul", nil) - girChain = discoverychain.TestCompileConfigEntries(t, "gir", "default", "default", "dc1", connect.TestClusterID+".consul", nil) - ) - - assert.True(t, fooChain.Default) - assert.True(t, barChain.Default) - assert.True(t, girChain.Default) - - extraUpdates = append(extraUpdates, - UpdateEvent{ - CorrelationID: exportedServiceListWatchID, - Result: &structs.IndexedExportedServiceList{ - Services: map[string]structs.ServiceList{ - "peer-a": []structs.ServiceName{fooSN, barSN}, - "peer-b": []structs.ServiceName{girSN}, - }, - }, - }, - UpdateEvent{ - CorrelationID: "discovery-chain:" + fooSN.String(), - Result: &structs.DiscoveryChainResponse{ - Chain: fooChain, - }, - }, - UpdateEvent{ - CorrelationID: "discovery-chain:" + barSN.String(), - Result: &structs.DiscoveryChainResponse{ - Chain: barChain, - }, - }, - UpdateEvent{ - CorrelationID: "discovery-chain:" + girSN.String(), - Result: &structs.DiscoveryChainResponse{ - Chain: girChain, - }, - }, - UpdateEvent{ - CorrelationID: peeringTrustBundlesWatchID, - Result: TestPeerTrustBundles(t), - }, - UpdateEvent{ - CorrelationID: leafWatchID, - Result: leaf, - }, - ) case "federation-states": populateServices = true useFederationStates = true @@ -513,3 +462,275 @@ func TestConfigSnapshotMeshGateway(t testing.T, variant string, nsFn func(ns *st }, }, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates)) } + +func TestConfigSnapshotPeeredMeshGateway(t testing.T, variant string, nsFn func(ns *structs.NodeService), extraUpdates []UpdateEvent) *ConfigSnapshot { + roots, leaf := TestCertsForMeshGateway(t) + + var ( + needPeerA bool + needPeerB bool + needLeaf bool + discoChains = make(map[structs.ServiceName]*structs.CompiledDiscoveryChain) + endpoints = make(map[structs.ServiceName]structs.CheckServiceNodes) + entries []structs.ConfigEntry + ) + + switch variant { + case "default-services-http": + proxyDefaults := &structs.ProxyConfigEntry{ + Config: map[string]interface{}{ + "protocol": "http", + }, + } + require.NoError(t, proxyDefaults.Normalize()) + require.NoError(t, proxyDefaults.Validate()) + entries = append(entries, proxyDefaults) + fallthrough // to-case: "default-services-tcp" + case "default-services-tcp": + var ( + fooSN = structs.NewServiceName("foo", nil) + barSN = structs.NewServiceName("bar", nil) + girSN = structs.NewServiceName("gir", nil) + + fooChain = discoverychain.TestCompileConfigEntries(t, "foo", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...) + barChain = discoverychain.TestCompileConfigEntries(t, "bar", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...) + girChain = discoverychain.TestCompileConfigEntries(t, "gir", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...) + ) + + assert.True(t, fooChain.Default) + assert.True(t, barChain.Default) + assert.True(t, girChain.Default) + + needPeerA = true + needPeerB = true + needLeaf = true + discoChains[fooSN] = fooChain + discoChains[barSN] = barChain + discoChains[girSN] = girChain + endpoints[fooSN] = TestUpstreamNodes(t, "foo") + endpoints[barSN] = TestUpstreamNodes(t, "bar") + endpoints[girSN] = TestUpstreamNodes(t, "gir") + + extraUpdates = append(extraUpdates, + UpdateEvent{ + CorrelationID: exportedServiceListWatchID, + Result: &structs.IndexedExportedServiceList{ + Services: map[string]structs.ServiceList{ + "peer-a": []structs.ServiceName{fooSN, barSN}, + "peer-b": []structs.ServiceName{girSN}, + }, + }, + }, + UpdateEvent{ + CorrelationID: serviceListWatchID, + Result: &structs.IndexedServiceList{ + Services: []structs.ServiceName{ + fooSN, + barSN, + girSN, + }, + }, + }, + ) + case "chain-and-l7-stuff": + entries = []structs.ConfigEntry{ + &structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + Config: map[string]interface{}{ + "protocol": "http", + }, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "db", + ConnectTimeout: 33 * time.Second, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "api-dc2", + Redirect: &structs.ServiceResolverRedirect{ + Service: "api", + Datacenter: "dc2", + }, + }, + &structs.ServiceSplitterConfigEntry{ + Kind: structs.ServiceSplitter, + Name: "split", + Splits: []structs.ServiceSplit{ + {Weight: 60, Service: "alt"}, + {Weight: 40, Service: "db"}, + }, + }, + &structs.ServiceRouterConfigEntry{ + Kind: structs.ServiceRouter, + Name: "db", + Routes: []structs.ServiceRoute{ + { + Match: httpMatch(&structs.ServiceRouteHTTPMatch{ + PathPrefix: "/split", + }), + Destination: toService("split"), + }, + { + Match: httpMatch(&structs.ServiceRouteHTTPMatch{ + PathPrefix: "/api", + }), + Destination: toService("api-dc2"), + }, + }, + }, + } + for _, entry := range entries { + require.NoError(t, entry.Normalize()) + require.NoError(t, entry.Validate()) + } + + var ( + dbSN = structs.NewServiceName("db", nil) + altSN = structs.NewServiceName("alt", nil) + + dbChain = discoverychain.TestCompileConfigEntries(t, "db", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...) + ) + + needPeerA = true + needLeaf = true + discoChains[dbSN] = dbChain + endpoints[dbSN] = TestUpstreamNodes(t, "db") + endpoints[altSN] = TestUpstreamNodes(t, "alt") + + extraUpdates = append(extraUpdates, + UpdateEvent{ + CorrelationID: datacentersWatchID, + Result: &[]string{"dc1", "dc2"}, + }, + UpdateEvent{ + CorrelationID: "mesh-gateway:dc2", + Result: &structs.IndexedNodesWithGateways{ + Nodes: TestGatewayNodesDC2(t), + }, + }, + UpdateEvent{ + CorrelationID: exportedServiceListWatchID, + Result: &structs.IndexedExportedServiceList{ + Services: map[string]structs.ServiceList{ + "peer-a": []structs.ServiceName{dbSN}, + }, + }, + }, + UpdateEvent{ + CorrelationID: serviceListWatchID, + Result: &structs.IndexedServiceList{ + Services: []structs.ServiceName{ + dbSN, + altSN, + }, + }, + }, + ) + + default: + t.Fatalf("unknown variant: %s", variant) + return nil + } + + var peerTrustBundles []*pbpeering.PeeringTrustBundle + switch { + case needPeerA && needPeerB: + peerTrustBundles = TestPeerTrustBundles(t).Bundles + case needPeerA: + ptb := TestPeerTrustBundles(t) + peerTrustBundles = ptb.Bundles[0:1] + case needPeerB: + ptb := TestPeerTrustBundles(t) + peerTrustBundles = ptb.Bundles[1:2] + } + + if needLeaf { + extraUpdates = append(extraUpdates, UpdateEvent{ + CorrelationID: leafWatchID, + Result: leaf, + }) + } + + for suffix, chain := range discoChains { + extraUpdates = append(extraUpdates, UpdateEvent{ + CorrelationID: "discovery-chain:" + suffix.String(), + Result: &structs.DiscoveryChainResponse{ + Chain: chain, + }, + }) + } + + for suffix, nodes := range endpoints { + extraUpdates = append(extraUpdates, UpdateEvent{ + CorrelationID: "connect-service:" + suffix.String(), + Result: &structs.IndexedCheckServiceNodes{ + Nodes: nodes, + }, + }) + } + + baseEvents := []UpdateEvent{ + { + CorrelationID: rootsWatchID, + Result: roots, + }, + { + CorrelationID: peeringTrustBundlesWatchID, + Result: &pbpeering.TrustBundleListByServiceResponse{ + Bundles: peerTrustBundles, + }, + }, + { + CorrelationID: serviceListWatchID, + Result: &structs.IndexedServiceList{ + Services: nil, + }, + }, + { + CorrelationID: serviceResolversWatchID, + Result: &structs.IndexedConfigEntries{ + Kind: structs.ServiceResolver, + Entries: nil, + }, + }, + { + CorrelationID: datacentersWatchID, + Result: &[]string{"dc1"}, + }, + { + CorrelationID: meshConfigEntryID, + Result: &structs.ConfigEntryResponse{ + Entry: nil, + }, + }, + { + CorrelationID: exportedServiceListWatchID, + Result: &structs.IndexedExportedServiceList{ + Services: nil, + }, + }, + } + + return testConfigSnapshotFixture(t, &structs.NodeService{ + Kind: structs.ServiceKindMeshGateway, + Service: "mesh-gateway", + Address: "1.2.3.4", + Port: 8443, + Proxy: structs.ConnectProxyConfig{ + Config: map[string]interface{}{}, + }, + Meta: make(map[string]string), + TaggedAddresses: map[string]structs.ServiceAddress{ + structs.TaggedAddressLAN: { + Address: "1.2.3.4", + Port: 8443, + }, + structs.TaggedAddressWAN: { + Address: "198.18.0.1", + Port: 443, + }, + }, + }, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates)) +} diff --git a/agent/xds/clusters.go b/agent/xds/clusters.go index feb488a63..3f2efdef7 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -35,6 +35,10 @@ const ( dynamicForwardProxyClusterDNSCacheName = "dynamic_forward_proxy_cache_config" ) +const ( + meshGatewayExportedClusterNamePrefix = "exported~" +) + // clustersFromSnapshot returns the xDS API representation of the "clusters" in the snapshot. func (s *ResourceGenerator) clustersFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { if cfgSnap == nil { @@ -91,9 +95,9 @@ func (s *ResourceGenerator) clustersFromSnapshotConnectProxy(cfgSnap *proxycfg.C // NOTE: Any time we skip a chain below we MUST also skip that discovery chain in endpoints.go // so that the sets of endpoints generated matches the sets of clusters. for uid, chain := range cfgSnap.ConnectProxy.DiscoveryChain { - upstreamCfg := cfgSnap.ConnectProxy.UpstreamConfig[uid] + upstream := cfgSnap.ConnectProxy.UpstreamConfig[uid] - explicit := upstreamCfg.HasLocalPortOrSocket() + explicit := upstream.HasLocalPortOrSocket() if _, implicit := cfgSnap.ConnectProxy.IntentionUpstreams[uid]; !implicit && !explicit { // Discovery chain is not associated with a known explicit or implicit upstream so it is skipped. continue @@ -105,7 +109,14 @@ func (s *ResourceGenerator) clustersFromSnapshotConnectProxy(cfgSnap *proxycfg.C return nil, fmt.Errorf("no endpoint map for upstream %q", uid) } - upstreamClusters, err := s.makeUpstreamClustersForDiscoveryChain(uid, upstreamCfg, chain, chainEndpoints, cfgSnap) + upstreamClusters, err := s.makeUpstreamClustersForDiscoveryChain( + uid, + upstream, + chain, + chainEndpoints, + cfgSnap, + false, + ) if err != nil { return nil, err } @@ -332,6 +343,13 @@ func (s *ResourceGenerator) clustersFromSnapshotMeshGateway(cfgSnap *proxycfg.Co } clusters = append(clusters, c...) + // Generate per-target clusters for all exported discovery chains. + c, err = s.makeExportedUpstreamClustersForMeshGateway(cfgSnap) + if err != nil { + return nil, err + } + clusters = append(clusters, c...) + return clusters, nil } @@ -535,7 +553,14 @@ func (s *ResourceGenerator) clustersFromSnapshotIngressGateway(cfgSnap *proxycfg return nil, fmt.Errorf("no endpoint map for upstream %q", uid) } - upstreamClusters, err := s.makeUpstreamClustersForDiscoveryChain(uid, &u, chain, chainEndpoints, cfgSnap) + upstreamClusters, err := s.makeUpstreamClustersForDiscoveryChain( + uid, + &u, + chain, + chainEndpoints, + cfgSnap, + false, + ) if err != nil { return nil, err } @@ -831,16 +856,22 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( chain *structs.CompiledDiscoveryChain, chainEndpoints map[string]structs.CheckServiceNodes, cfgSnap *proxycfg.ConfigSnapshot, + forMeshGateway bool, ) ([]*envoy_cluster_v3.Cluster, error) { if chain == nil { return nil, fmt.Errorf("cannot create upstream cluster without discovery chain for %s", uid) } - configMap := make(map[string]interface{}) - if upstream != nil { - configMap = upstream.Config + if uid.Peer != "" && forMeshGateway { + return nil, fmt.Errorf("impossible to get a peer discovery chain in a mesh gateway") } - cfg, err := structs.ParseUpstreamConfigNoDefaults(configMap) + + upstreamConfigMap := make(map[string]interface{}) + if upstream != nil { + upstreamConfigMap = upstream.Config + } + + cfg, err := structs.ParseUpstreamConfigNoDefaults(upstreamConfigMap) if err != nil { // Don't hard fail on a config typo, just warn. The parse func returns // default config if there is an error so it's safe to continue. @@ -849,18 +880,20 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( } var escapeHatchCluster *envoy_cluster_v3.Cluster - if cfg.EnvoyClusterJSON != "" { - if chain.Default { - // If you haven't done anything to setup the discovery chain, then - // you can use the envoy_cluster_json escape hatch. - escapeHatchCluster, err = makeClusterFromUserConfig(cfg.EnvoyClusterJSON) - if err != nil { - return nil, err + if !forMeshGateway { + if cfg.EnvoyClusterJSON != "" { + if chain.Default { + // If you haven't done anything to setup the discovery chain, then + // you can use the envoy_cluster_json escape hatch. + escapeHatchCluster, err = makeClusterFromUserConfig(cfg.EnvoyClusterJSON) + if err != nil { + return nil, err + } + } else { + s.Logger.Warn("ignoring escape hatch setting, because a discovery chain is configured for", + "discovery chain", chain.ServiceName, "upstream", uid, + "envoy_cluster_json", chain.ServiceName) } - } else { - s.Logger.Warn("ignoring escape hatch setting, because a discovery chain is configured for", - "discovery chain", chain.ServiceName, "upstream", uid, - "envoy_cluster_json", chain.ServiceName) } } @@ -875,21 +908,26 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( target := chain.Targets[targetID] // Determine if we have to generate the entire cluster differently. - failoverThroughMeshGateway := chain.WillFailoverThroughMeshGateway(node) + failoverThroughMeshGateway := chain.WillFailoverThroughMeshGateway(node) && !forMeshGateway sni := target.SNI clusterName := CustomizeClusterName(target.Name, chain) + if forMeshGateway { + clusterName = meshGatewayExportedClusterNamePrefix + clusterName + } // Get the SpiffeID for upstream SAN validation. // // For imported services the SpiffeID is embedded in the proxy instances. // Whereas for local services we can construct the SpiffeID from the chain target. var targetSpiffeID string + var additionalSpiffeIDs []string if uid.Peer != "" { for _, e := range chainEndpoints[targetID] { targetSpiffeID = e.Service.Connect.PeerMeta.SpiffeID[0] + additionalSpiffeIDs = e.Service.Connect.PeerMeta.SpiffeID[1:] - // Only grab the first because it is the same for all instances. + // Only grab the first instance because it is the same for all instances. break } } else { @@ -916,7 +954,7 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( } } - spiffeIDs := []string{targetSpiffeID} + spiffeIDs := append([]string{targetSpiffeID}, additionalSpiffeIDs...) seenIDs := map[string]struct{}{ targetSpiffeID: {}, } @@ -968,6 +1006,7 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( }, }, }, + // TODO(peering): make circuit breakers or outlier detection work? CircuitBreakers: &envoy_cluster_v3.CircuitBreakers{ Thresholds: makeThresholdsIfNeeded(cfg.Limits), }, @@ -982,7 +1021,10 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( return nil, fmt.Errorf("failed to apply load balancer configuration to cluster %q: %v", clusterName, err) } - proto := cfg.Protocol + var proto string + if !forMeshGateway { + proto = cfg.Protocol + } if proto == "" { proto = chain.Protocol } @@ -997,30 +1039,38 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( } } - rootPEMs := cfgSnap.RootPEMs() - if uid.Peer != "" { - rootPEMs = cfgSnap.ConnectProxy.UpstreamPeerTrustBundles[uid.Peer].ConcatenatedRootPEMs() - } - commonTLSContext := makeCommonTLSContext( - cfgSnap.Leaf(), - rootPEMs, - makeTLSParametersFromProxyTLSConfig(cfgSnap.MeshConfigTLSOutgoing()), - ) - - err = injectSANMatcher(commonTLSContext, spiffeIDs...) - if err != nil { - return nil, fmt.Errorf("failed to inject SAN matcher rules for cluster %q: %v", sni, err) + configureTLS := true + if forMeshGateway { + // We only initiate TLS if we're doing an L7 proxy. + configureTLS = structs.IsProtocolHTTPLike(proto) } - tlsContext := &envoy_tls_v3.UpstreamTlsContext{ - CommonTlsContext: commonTLSContext, - Sni: sni, + if configureTLS { + rootPEMs := cfgSnap.RootPEMs() + if uid.Peer != "" { + rootPEMs = cfgSnap.ConnectProxy.UpstreamPeerTrustBundles[uid.Peer].ConcatenatedRootPEMs() + } + commonTLSContext := makeCommonTLSContext( + cfgSnap.Leaf(), + rootPEMs, + makeTLSParametersFromProxyTLSConfig(cfgSnap.MeshConfigTLSOutgoing()), + ) + + err = injectSANMatcher(commonTLSContext, spiffeIDs...) + if err != nil { + return nil, fmt.Errorf("failed to inject SAN matcher rules for cluster %q: %v", sni, err) + } + + tlsContext := &envoy_tls_v3.UpstreamTlsContext{ + CommonTlsContext: commonTLSContext, + Sni: sni, + } + transportSocket, err := makeUpstreamTLSTransportSocket(tlsContext) + if err != nil { + return nil, err + } + c.TransportSocket = transportSocket } - transportSocket, err := makeUpstreamTLSTransportSocket(tlsContext) - if err != nil { - return nil, err - } - c.TransportSocket = transportSocket out = append(out, c) } @@ -1040,6 +1090,52 @@ func (s *ResourceGenerator) makeUpstreamClustersForDiscoveryChain( return out, nil } +func (s *ResourceGenerator) makeExportedUpstreamClustersForMeshGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { + // NOTE: Despite the mesh gateway already having one cluster per service + // (and subset) in the local datacenter we cannot reliably use those to + // send inbound peered traffic targeting a discovery chain. + // + // For starters, none of those add TLS so they'd be unusable for http-like + // L7 protocols. + // + // Additionally, those other clusters are all thin wrappers around simple + // catalog resolutions and are largely not impacted by various + // customizations related to a service-resolver, such as configuring the + // failover section. + // + // Instead we create brand new clusters solely to accept incoming peered + // traffic and give them a unique cluster prefix name to avoid collisions + // to keep the two use cases separate. + var clusters []proto.Message + + createdExportedClusters := make(map[string]struct{}) // key=clusterName + for _, svc := range cfgSnap.MeshGatewayValidExportedServices() { + chain := cfgSnap.MeshGateway.DiscoveryChain[svc] + + exportClusters, err := s.makeUpstreamClustersForDiscoveryChain( + proxycfg.NewUpstreamIDFromServiceName(svc), + nil, + chain, + nil, + cfgSnap, + true, + ) + if err != nil { + return nil, err + } + + for _, cluster := range exportClusters { + if _, ok := createdExportedClusters[cluster.Name]; ok { + continue + } + createdExportedClusters[cluster.Name] = struct{}{} + clusters = append(clusters, cluster) + } + } + + return clusters, nil +} + // injectSANMatcher updates a TLS context so that it verifies the upstream SAN. func injectSANMatcher(tlsContext *envoy_tls_v3.CommonTlsContext, matchStrings ...string) error { validationCtx, ok := tlsContext.ValidationContextType.(*envoy_tls_v3.CommonTlsContext_ValidationContext) diff --git a/agent/xds/endpoints.go b/agent/xds/endpoints.go index 2a60c05ec..aca8760d3 100644 --- a/agent/xds/endpoints.go +++ b/agent/xds/endpoints.go @@ -11,7 +11,6 @@ import ( "github.com/golang/protobuf/proto" bexpr "github.com/hashicorp/go-bexpr" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" @@ -54,22 +53,31 @@ func (s *ResourceGenerator) endpointsFromSnapshotConnectProxy(cfgSnap *proxycfg. // NOTE: Any time we skip a chain below we MUST also skip that discovery chain in clusters.go // so that the sets of endpoints generated matches the sets of clusters. for uid, chain := range cfgSnap.ConnectProxy.DiscoveryChain { - upstreamCfg := cfgSnap.ConnectProxy.UpstreamConfig[uid] + upstream := cfgSnap.ConnectProxy.UpstreamConfig[uid] - explicit := upstreamCfg.HasLocalPortOrSocket() + explicit := upstream.HasLocalPortOrSocket() if _, implicit := cfgSnap.ConnectProxy.IntentionUpstreams[uid]; !implicit && !explicit { // Discovery chain is not associated with a known explicit or implicit upstream so it is skipped. continue } - es := s.endpointsFromDiscoveryChain( + var upstreamConfigMap map[string]interface{} + if upstream != nil { + upstreamConfigMap = upstream.Config + } + + es, err := s.endpointsFromDiscoveryChain( uid, chain, cfgSnap.Locality, - upstreamCfg, + upstreamConfigMap, cfgSnap.ConnectProxy.WatchedUpstreamEndpoints[uid], cfgSnap.ConnectProxy.WatchedGatewayEndpoints[uid], + false, ) + if err != nil { + return nil, err + } resources = append(resources, es...) } @@ -169,6 +177,7 @@ func (s *ResourceGenerator) endpointsFromSnapshotMeshGateway(cfgSnap *proxycfg.C keys := cfgSnap.MeshGateway.GatewayKeys() resources := make([]proto.Message, 0, len(keys)+len(cfgSnap.MeshGateway.ServiceGroups)) + endpointsPerRemoteGateway := make(map[string]structs.CheckServiceNodes) for _, key := range keys { if key.Matches(cfgSnap.Datacenter, cfgSnap.ProxyID.PartitionOrDefault()) { continue // skip local @@ -179,58 +188,14 @@ func (s *ResourceGenerator) endpointsFromSnapshotMeshGateway(cfgSnap *proxycfg.C continue } - // Mesh gateways in remote DCs are discovered in two ways: - // - // 1. Via an Internal.ServiceDump RPC in the remote DC (GatewayGroups). - // 2. In the federation state that is replicated from the primary DC (FedStateGateways). - // - // We determine which set to use based on whichever contains the highest - // raft ModifyIndex (and is therefore most up-to-date). - // - // Previously, GatewayGroups was always given presedence over FedStateGateways - // but this was problematic when using mesh gateways for WAN federation. - // - // Consider the following example: - // - // - Primary and Secondary DCs are WAN Federated via local mesh gateways. - // - // - Secondary DC's mesh gateway is running on an ephemeral compute instance - // and is abruptly terminated and rescheduled with a *new IP address*. - // - // - Primary DC's mesh gateway is no longer able to connect to the Secondary - // DC as its proxy is configured with the old IP address. Therefore any RPC - // from the Primary to the Secondary DC will fail (including the one to - // discover the gateway's new IP address). - // - // - Secondary DC performs its regular anti-entropy of federation state data - // to the Primary DC (this succeeds as there is still connectivity in this - // direction). - // - // - At this point the Primary DC's mesh gateway should observe the new IP - // address and reconfigure its proxy, however as we always prioritised - // GatewayGroups this didn't happen and the connection remained severed. - maxModifyIndex := func(vals structs.CheckServiceNodes) uint64 { - var max uint64 - for _, v := range vals { - if i := v.Service.RaftIndex.ModifyIndex; i > max { - max = i - } - } - return max - } - - endpoints := cfgSnap.MeshGateway.GatewayGroups[key.String()] - fedStateEndpoints := cfgSnap.MeshGateway.FedStateGateways[key.String()] - - if maxModifyIndex(fedStateEndpoints) > maxModifyIndex(endpoints) { - endpoints = fedStateEndpoints - } - + endpoints := cfgSnap.GetMeshGatewayEndpoints(key) if len(endpoints) == 0 { s.Logger.Error("skipping mesh gateway endpoints because no definition found", "datacenter", key) continue } + endpointsPerRemoteGateway[key.String()] = endpoints + { // standard connect clusterName := connect.GatewaySNI(key.Datacenter, key.Partition, cfgSnap.Roots.TrustDomain) @@ -308,6 +273,13 @@ func (s *ResourceGenerator) endpointsFromSnapshotMeshGateway(cfgSnap *proxycfg.C } resources = append(resources, e...) + // Generate the endpoints for exported discovery chain targets. + e, err = s.makeExportedUpstreamEndpointsForMeshGateway(cfgSnap, endpointsPerRemoteGateway) + if err != nil { + return nil, err + } + resources = append(resources, e...) + return resources, nil } @@ -377,14 +349,18 @@ func (s *ResourceGenerator) endpointsFromSnapshotIngressGateway(cfgSnap *proxycf continue } - es := s.endpointsFromDiscoveryChain( + es, err := s.endpointsFromDiscoveryChain( uid, cfgSnap.IngressGateway.DiscoveryChain[uid], proxycfg.GatewayKey{Datacenter: cfgSnap.Datacenter, Partition: u.DestinationPartition}, - &u, + u.Config, cfgSnap.IngressGateway.WatchedUpstreamEndpoints[uid], cfgSnap.IngressGateway.WatchedGatewayEndpoints[uid], + false, ) + if err != nil { + return nil, err + } resources = append(resources, es...) createdClusters[uid] = true } @@ -417,41 +393,47 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( uid proxycfg.UpstreamID, chain *structs.CompiledDiscoveryChain, gatewayKey proxycfg.GatewayKey, - upstream *structs.Upstream, + upstreamConfigMap map[string]interface{}, upstreamEndpoints map[string]structs.CheckServiceNodes, gatewayEndpoints map[string]structs.CheckServiceNodes, -) []proto.Message { + forMeshGateway bool, +) ([]proto.Message, error) { + if chain == nil { + if forMeshGateway { + return nil, fmt.Errorf("missing discovery chain for %s", uid) + } + return nil, nil + } + + if upstreamConfigMap == nil { + upstreamConfigMap = make(map[string]interface{}) // TODO:needed? + } + var resources []proto.Message - if chain == nil { - return resources - } - - configMap := make(map[string]interface{}) - if upstream != nil { - configMap = upstream.Config - } - cfg, err := structs.ParseUpstreamConfigNoDefaults(configMap) - if err != nil { - // Don't hard fail on a config typo, just warn. The parse func returns - // default config if there is an error so it's safe to continue. - s.Logger.Warn("failed to parse", "upstream", uid, - "error", err) - } - var escapeHatchCluster *envoy_cluster_v3.Cluster - if cfg.EnvoyClusterJSON != "" { - if chain.Default { - // If you haven't done anything to setup the discovery chain, then - // you can use the envoy_cluster_json escape hatch. - escapeHatchCluster, err = makeClusterFromUserConfig(cfg.EnvoyClusterJSON) - if err != nil { - return resources + if !forMeshGateway { + cfg, err := structs.ParseUpstreamConfigNoDefaults(upstreamConfigMap) + if err != nil { + // Don't hard fail on a config typo, just warn. The parse func returns + // default config if there is an error so it's safe to continue. + s.Logger.Warn("failed to parse", "upstream", uid, + "error", err) + } + + if cfg.EnvoyClusterJSON != "" { + if chain.Default { + // If you haven't done anything to setup the discovery chain, then + // you can use the envoy_cluster_json escape hatch. + escapeHatchCluster, err = makeClusterFromUserConfig(cfg.EnvoyClusterJSON) + if err != nil { + return resources, nil + } + } else { + s.Logger.Warn("ignoring escape hatch setting, because a discovery chain is configued for", + "discovery chain", chain.ServiceName, "upstream", uid, + "envoy_cluster_json", chain.ServiceName) } - } else { - s.Logger.Warn("ignoring escape hatch setting, because a discovery chain is configued for", - "discovery chain", chain.ServiceName, "upstream", uid, - "envoy_cluster_json", chain.ServiceName) } } @@ -469,10 +451,13 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( if escapeHatchCluster != nil { clusterName = escapeHatchCluster.Name } + if forMeshGateway { + clusterName = meshGatewayExportedClusterNamePrefix + clusterName + } s.Logger.Debug("generating endpoints for", "cluster", clusterName) // Determine if we have to generate the entire cluster differently. - failoverThroughMeshGateway := chain.WillFailoverThroughMeshGateway(node) + failoverThroughMeshGateway := chain.WillFailoverThroughMeshGateway(node) && !forMeshGateway if failoverThroughMeshGateway { actualTargetID := firstHealthyTarget( @@ -499,13 +484,15 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( continue // skip the cluster if we're still populating the snapshot } - var endpointGroups []loadAssignmentEndpointGroup + var numFailoverTargets int + if failover != nil { + numFailoverTargets = len(failover.Targets) + } + + endpointGroups := make([]loadAssignmentEndpointGroup, 0, numFailoverTargets+1) + endpointGroups = append(endpointGroups, primaryGroup) if failover != nil && len(failover.Targets) > 0 { - endpointGroups = make([]loadAssignmentEndpointGroup, 0, len(failover.Targets)+1) - - endpointGroups = append(endpointGroups, primaryGroup) - for _, failTargetID := range failover.Targets { failoverGroup, valid := makeLoadAssignmentEndpointGroup( chain.Targets, @@ -519,8 +506,6 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( } endpointGroups = append(endpointGroups, failoverGroup) } - } else { - endpointGroups = append(endpointGroups, primaryGroup) } la := makeLoadAssignment( @@ -531,7 +516,81 @@ func (s *ResourceGenerator) endpointsFromDiscoveryChain( resources = append(resources, la) } - return resources + return resources, nil +} + +func (s *ResourceGenerator) makeExportedUpstreamEndpointsForMeshGateway( + cfgSnap *proxycfg.ConfigSnapshot, + endpointsPerRemoteGateway map[string]structs.CheckServiceNodes, +) ([]proto.Message, error) { + var resources []proto.Message + + populatedExportedClusters := make(map[string]struct{}) // key=clusterName + for _, svc := range cfgSnap.MeshGatewayValidExportedServices() { + chain := cfgSnap.MeshGateway.DiscoveryChain[svc] + + chainEndpoints := make(map[string]structs.CheckServiceNodes) + for _, target := range chain.Targets { + if cfgSnap.Locality.Matches(target.Datacenter, target.Partition) { + // served locally + targetSvc := target.ServiceName() + + endpoints, ok := cfgSnap.MeshGateway.ServiceGroups[targetSvc] + if !ok { + continue // ignore; not ready + } + + if target.ServiceSubset == "" { + chainEndpoints[target.ID] = endpoints + } else { + resolver, ok := cfgSnap.MeshGateway.ServiceResolvers[targetSvc] + if !ok { + continue // ignore; not ready + } + subset, ok := resolver.Subsets[target.ServiceSubset] + if !ok { + continue // ignore; not ready + } + + subsetEndpoints, err := s.filterSubsetEndpoints(&subset, endpoints) + if err != nil { + return nil, err + } + chainEndpoints[target.ID] = subsetEndpoints + } + } else { + // serve remotely + gk := proxycfg.GatewayKey{ + Datacenter: target.Datacenter, + Partition: target.Partition, + } + // TODO(peering): handle hostname endpoints logic + chainEndpoints[target.ID] = cfgSnap.GetMeshGatewayEndpoints(gk) + } + } + + clusterEndpoints, err := s.endpointsFromDiscoveryChain( + proxycfg.NewUpstreamIDFromServiceName(svc), + chain, + cfgSnap.Locality, + nil, + chainEndpoints, + endpointsPerRemoteGateway, + true, + ) + if err != nil { + return nil, err + } + for _, endpoints := range clusterEndpoints { + clusterName := getResourceName(endpoints) + if _, ok := populatedExportedClusters[clusterName]; ok { + continue + } + populatedExportedClusters[clusterName] = struct{}{} + resources = append(resources, endpoints) + } + } + return resources, nil } type loadAssignmentEndpointGroup struct { @@ -612,7 +671,7 @@ func makeLoadAssignmentEndpointGroup( gatewayKey = localKey } - if gatewayKey.IsEmpty() || (acl.EqualPartitions(localKey.Partition, target.Partition) && localKey.Datacenter == target.Datacenter) { + if gatewayKey.IsEmpty() || localKey.Matches(target.Datacenter, target.Partition) { // Gateways are not needed if the request isn't for a remote DC or partition. return loadAssignmentEndpointGroup{ Endpoints: realEndpoints, diff --git a/agent/xds/listeners.go b/agent/xds/listeners.go index a364ecce1..f9495168a 100644 --- a/agent/xds/listeners.go +++ b/agent/xds/listeners.go @@ -1419,75 +1419,15 @@ func (s *ResourceGenerator) makeMeshGatewayListener(name, addr string, port int, l := makePortListener(name, addr, port, envoy_core_v3.TrafficDirection_UNSPECIFIED) l.ListenerFilters = []*envoy_listener_v3.ListenerFilter{tlsInspector} - // Add in TCP filter chains for plain peered passthrough. - // - // TODO(peering): make this work for L7 as well - // TODO(peering): make failover work - for _, svc := range cfgSnap.MeshGateway.ExportedServicesSlice { - peerNames, ok := cfgSnap.MeshGateway.ExportedServicesWithPeers[svc] - if !ok { - continue // not possible - } - chain, ok := cfgSnap.MeshGateway.DiscoveryChain[svc] - if !ok { - continue // ignore; not ready - } + for _, svc := range cfgSnap.MeshGatewayValidExportedServices() { + peerNames := cfgSnap.MeshGateway.ExportedServicesWithPeers[svc] + chain := cfgSnap.MeshGateway.DiscoveryChain[svc] - useHTTPFilter := structs.IsProtocolHTTPLike(chain.Protocol) - if useHTTPFilter { - if cfgSnap.MeshGateway.Leaf == nil { - continue // ignore not ready - } - continue // temporary skip - } - - target, err := simpleChainTarget(chain) + filterChain, err := s.makeMeshGatewayPeerFilterChain(cfgSnap, svc, peerNames, chain) if err != nil { return nil, err - } - clusterName := CustomizeClusterName(target.Name, chain) - - filterName := fmt.Sprintf("%s.%s.%s.%s", chain.ServiceName, chain.Namespace, chain.Partition, chain.Datacenter) - - tcpProxy, err := makeTCPProxyFilter(filterName, clusterName, "mesh_gateway_local_peered.") - if err != nil { - return nil, err - } - - var peeredServerNames []string - for _, peerName := range peerNames { - peeredSNI := connect.PeeredServiceSNI( - svc.Name, - svc.NamespaceOrDefault(), - svc.PartitionOrDefault(), - peerName, - cfgSnap.Roots.TrustDomain, - ) - peeredServerNames = append(peeredServerNames, peeredSNI) - } - - filterChain := &envoy_listener_v3.FilterChain{ - FilterChainMatch: &envoy_listener_v3.FilterChainMatch{ - ServerNames: peeredServerNames, - }, - Filters: []*envoy_listener_v3.Filter{ - tcpProxy, - }, - } - - if useHTTPFilter { - var peerBundles []*pbpeering.PeeringTrustBundle - for _, bundle := range cfgSnap.MeshGateway.PeeringTrustBundles { - if stringslice.Contains(peerNames, bundle.PeerName) { - peerBundles = append(peerBundles, bundle) - } - } - - peeredTransportSocket, err := createDownstreamTransportSocketForConnectTLS(cfgSnap, peerBundles) - if err != nil { - return nil, err - } - filterChain.TransportSocket = peeredTransportSocket + } else if filterChain == nil { + continue } l.FilterChains = append(l.FilterChains, filterChain) @@ -1570,6 +1510,79 @@ func (s *ResourceGenerator) makeMeshGatewayListener(name, addr string, port int, return l, nil } +func (s *ResourceGenerator) makeMeshGatewayPeerFilterChain( + cfgSnap *proxycfg.ConfigSnapshot, + svc structs.ServiceName, + peerNames []string, + chain *structs.CompiledDiscoveryChain, +) (*envoy_listener_v3.FilterChain, error) { + var ( + useHTTPFilter = structs.IsProtocolHTTPLike(chain.Protocol) + // RDS, Envoy's Route Discovery Service, is only used for HTTP services. + useRDS = useHTTPFilter + ) + + var clusterName string + if !useRDS { + // When not using RDS we must generate a cluster name to attach to the filter chain. + // With RDS, cluster names get attached to the dynamic routes instead. + target, err := simpleChainTarget(chain) + if err != nil { + return nil, err + } + clusterName = meshGatewayExportedClusterNamePrefix + CustomizeClusterName(target.Name, chain) + } + + uid := proxycfg.NewUpstreamIDFromServiceName(svc) + + filterName := fmt.Sprintf("%s.%s.%s.%s", chain.ServiceName, chain.Namespace, chain.Partition, chain.Datacenter) + + filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{ + routeName: uid.EnvoyID(), + clusterName: clusterName, + filterName: filterName, + protocol: chain.Protocol, + useRDS: useRDS, + statPrefix: "mesh_gateway_local_peered.", + }) + if err != nil { + return nil, err + } + + var peeredServerNames []string + for _, peerName := range peerNames { + peeredSNI := connect.PeeredServiceSNI( + svc.Name, + svc.NamespaceOrDefault(), + svc.PartitionOrDefault(), + peerName, + cfgSnap.Roots.TrustDomain, + ) + peeredServerNames = append(peeredServerNames, peeredSNI) + } + filterChain.FilterChainMatch = &envoy_listener_v3.FilterChainMatch{ + ServerNames: peeredServerNames, + } + + if useHTTPFilter { + // We only terminate TLS if we're doing an L7 proxy. + var peerBundles []*pbpeering.PeeringTrustBundle + for _, bundle := range cfgSnap.MeshGateway.PeeringTrustBundles { + if stringslice.Contains(peerNames, bundle.PeerName) { + peerBundles = append(peerBundles, bundle) + } + } + + peeredTransportSocket, err := createDownstreamTransportSocketForConnectTLS(cfgSnap, peerBundles) + if err != nil { + return nil, err + } + filterChain.TransportSocket = peeredTransportSocket + } + + return filterChain, nil +} + type filterChainOpts struct { routeName string clusterName string @@ -1577,16 +1590,20 @@ type filterChainOpts struct { protocol string useRDS bool tlsContext *envoy_tls_v3.DownstreamTlsContext + statPrefix string } func (s *ResourceGenerator) makeUpstreamFilterChain(opts filterChainOpts) (*envoy_listener_v3.FilterChain, error) { + if opts.statPrefix == "" { + opts.statPrefix = "upstream." + } filter, err := makeListenerFilter(listenerFilterOpts{ useRDS: opts.useRDS, protocol: opts.protocol, filterName: opts.filterName, routeName: opts.routeName, cluster: opts.clusterName, - statPrefix: "upstream.", + statPrefix: opts.statPrefix, }) if err != nil { return nil, err diff --git a/agent/xds/resources_test.go b/agent/xds/resources_test.go index 84cb52ca4..45070a8c1 100644 --- a/agent/xds/resources_test.go +++ b/agent/xds/resources_test.go @@ -148,13 +148,8 @@ func TestAllResourcesFromSnapshot(t *testing.T) { name: "connect-proxy-with-peered-upstreams", create: proxycfg.TestConfigSnapshotPeering, }, - { - name: "mesh-gateway-with-exported-peered-services", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotMeshGateway(t, "peered-services", nil, nil) - }, - }, } + tests = append(tests, getMeshGatewayPeeringGoldenTestCases()...) tests = append(tests, getEnterpriseGoldenTestCases()...) latestEnvoyVersion := proxysupport.EnvoyVersions[0] @@ -170,3 +165,26 @@ func TestAllResourcesFromSnapshot(t *testing.T) { }) } } + +func getMeshGatewayPeeringGoldenTestCases() []goldenTestCase { + return []goldenTestCase{ + { + name: "mesh-gateway-with-exported-peered-services", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotPeeredMeshGateway(t, "default-services-tcp", nil, nil) + }, + }, + { + name: "mesh-gateway-with-exported-peered-services-http", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotPeeredMeshGateway(t, "default-services-http", nil, nil) + }, + }, + { + name: "mesh-gateway-with-exported-peered-services-http-with-router", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotPeeredMeshGateway(t, "chain-and-l7-stuff", nil, nil) + }, + }, + } +} diff --git a/agent/xds/routes.go b/agent/xds/routes.go index 2df52feef..42be5b53b 100644 --- a/agent/xds/routes.go +++ b/agent/xds/routes.go @@ -10,9 +10,9 @@ import ( envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" envoy_matcher_v3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3" - "google.golang.org/protobuf/types/known/durationpb" "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/proxycfg" @@ -32,9 +32,9 @@ func (s *ResourceGenerator) routesFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) case structs.ServiceKindIngressGateway: return s.routesForIngressGateway(cfgSnap) case structs.ServiceKindTerminatingGateway: - return s.routesFromSnapshotTerminatingGateway(cfgSnap) + return s.routesForTerminatingGateway(cfgSnap) case structs.ServiceKindMeshGateway: - return nil, nil // mesh gateways will never have routes + return s.routesForMeshGateway(cfgSnap) default: return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind) } @@ -55,7 +55,7 @@ func (s *ResourceGenerator) routesForConnectProxy(cfgSnap *proxycfg.ConfigSnapsh continue } - virtualHost, err := makeUpstreamRouteForDiscoveryChain(uid.EnvoyID(), chain, []string{"*"}) + virtualHost, err := makeUpstreamRouteForDiscoveryChain(uid.EnvoyID(), chain, []string{"*"}, "") if err != nil { return nil, err } @@ -77,7 +77,7 @@ func (s *ResourceGenerator) routesForConnectProxy(cfgSnap *proxycfg.ConfigSnapsh // routesFromSnapshotTerminatingGateway returns the xDS API representation of the "routes" in the snapshot. // For any HTTP service we will return a default route. -func (s *ResourceGenerator) routesFromSnapshotTerminatingGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { +func (s *ResourceGenerator) routesForTerminatingGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { if cfgSnap == nil { return nil, errors.New("nil config given") } @@ -129,6 +129,45 @@ func (s *ResourceGenerator) routesFromSnapshotTerminatingGateway(cfgSnap *proxyc return resources, nil } +func (s *ResourceGenerator) routesForMeshGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { + if cfgSnap == nil { + return nil, errors.New("nil config given") + } + + var resources []proto.Message + for _, svc := range cfgSnap.MeshGatewayValidExportedServices() { + chain := cfgSnap.MeshGateway.DiscoveryChain[svc] + + if !structs.IsProtocolHTTPLike(chain.Protocol) { + continue + } + + uid := proxycfg.NewUpstreamIDFromServiceName(svc) + + virtualHost, err := makeUpstreamRouteForDiscoveryChain( + uid.EnvoyID(), + chain, + []string{"*"}, + meshGatewayExportedClusterNamePrefix, + ) + if err != nil { + return nil, err + } + + route := &envoy_route_v3.RouteConfiguration{ + Name: uid.EnvoyID(), + VirtualHosts: []*envoy_route_v3.VirtualHost{virtualHost}, + // ValidateClusters defaults to true when defined statically and false + // when done via RDS. Re-set the reasonable value of true to prevent + // null-routing traffic. + ValidateClusters: makeBoolValue(true), + } + resources = append(resources, route) + } + + return resources, nil +} + func makeNamedDefaultRouteWithLB(clusterName string, lb *structs.LoadBalancer, autoHostRewrite bool) (*envoy_route_v3.RouteConfiguration, error) { action := makeRouteActionFromName(clusterName) @@ -193,7 +232,7 @@ func (s *ResourceGenerator) routesForIngressGateway(cfgSnap *proxycfg.ConfigSnap } domains := generateUpstreamIngressDomains(listenerKey, u) - virtualHost, err := makeUpstreamRouteForDiscoveryChain(uid.EnvoyID(), chain, domains) + virtualHost, err := makeUpstreamRouteForDiscoveryChain(uid.EnvoyID(), chain, domains, "") if err != nil { return nil, err } @@ -330,6 +369,7 @@ func makeUpstreamRouteForDiscoveryChain( routeName string, chain *structs.CompiledDiscoveryChain, serviceDomains []string, + clusterNamePrefix string, ) (*envoy_route_v3.VirtualHost, error) { var routes []*envoy_route_v3.Route @@ -359,13 +399,13 @@ func makeUpstreamRouteForDiscoveryChain( switch nextNode.Type { case structs.DiscoveryGraphNodeTypeSplitter: - routeAction, err = makeRouteActionForSplitter(nextNode.Splits, chain) + routeAction, err = makeRouteActionForSplitter(nextNode.Splits, chain, clusterNamePrefix) if err != nil { return nil, err } case structs.DiscoveryGraphNodeTypeResolver: - routeAction = makeRouteActionForChainCluster(nextNode.Resolver.Target, chain) + routeAction = makeRouteActionForChainCluster(nextNode.Resolver.Target, chain, clusterNamePrefix) default: return nil, fmt.Errorf("unexpected graph node after route %q", nextNode.Type) @@ -424,7 +464,7 @@ func makeUpstreamRouteForDiscoveryChain( } case structs.DiscoveryGraphNodeTypeSplitter: - routeAction, err := makeRouteActionForSplitter(startNode.Splits, chain) + routeAction, err := makeRouteActionForSplitter(startNode.Splits, chain, clusterNamePrefix) if err != nil { return nil, err } @@ -445,7 +485,7 @@ func makeUpstreamRouteForDiscoveryChain( routes = []*envoy_route_v3.Route{defaultRoute} case structs.DiscoveryGraphNodeTypeResolver: - routeAction := makeRouteActionForChainCluster(startNode.Resolver.Target, chain) + routeAction := makeRouteActionForChainCluster(startNode.Resolver.Target, chain, clusterNamePrefix) var lb *structs.LoadBalancer if startNode.LoadBalancer != nil { @@ -607,9 +647,13 @@ func makeDefaultRouteMatch() *envoy_route_v3.RouteMatch { } } -func makeRouteActionForChainCluster(targetID string, chain *structs.CompiledDiscoveryChain) *envoy_route_v3.Route_Route { +func makeRouteActionForChainCluster( + targetID string, + chain *structs.CompiledDiscoveryChain, + clusterNamePrefix string, +) *envoy_route_v3.Route_Route { target := chain.Targets[targetID] - return makeRouteActionFromName(CustomizeClusterName(target.Name, chain)) + return makeRouteActionFromName(clusterNamePrefix + CustomizeClusterName(target.Name, chain)) } func makeRouteActionFromName(clusterName string) *envoy_route_v3.Route_Route { @@ -622,7 +666,11 @@ func makeRouteActionFromName(clusterName string) *envoy_route_v3.Route_Route { } } -func makeRouteActionForSplitter(splits []*structs.DiscoverySplit, chain *structs.CompiledDiscoveryChain) (*envoy_route_v3.Route_Route, error) { +func makeRouteActionForSplitter( + splits []*structs.DiscoverySplit, + chain *structs.CompiledDiscoveryChain, + clusterNamePrefix string, +) (*envoy_route_v3.Route_Route, error) { clusters := make([]*envoy_route_v3.WeightedCluster_ClusterWeight, 0, len(splits)) for _, split := range splits { nextNode := chain.Nodes[split.NextNode] @@ -634,7 +682,7 @@ func makeRouteActionForSplitter(splits []*structs.DiscoverySplit, chain *structs target := chain.Targets[targetID] - clusterName := CustomizeClusterName(target.Name, chain) + clusterName := clusterNamePrefix + CustomizeClusterName(target.Name, chain) // The smallest representable weight is 1/10000 or .01% but envoy // deals with integers so scale everything up by 100x. diff --git a/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden new file mode 100644 index 000000000..c65f4f9c1 --- /dev/null +++ b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden @@ -0,0 +1,232 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "alt.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "dc2.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~alt.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~alt.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "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/alt" + } + ] + } + }, + "sni": "alt.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~api.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~api.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "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/dc2/svc/api" + } + ] + } + }, + "sni": "api.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "33s", + "circuitBreakers": { + + }, + "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/db" + } + ] + } + }, + "sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden new file mode 100644 index 000000000..f5081bd7f --- /dev/null +++ b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden @@ -0,0 +1,232 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "alt.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "db.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~alt.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~alt.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "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/ap/ap1/ns/default/dc/dc1/svc/alt" + } + ] + } + }, + "sni": "alt.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~cross.default.ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~cross.default.ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "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/ap/ap2/ns/default/dc/dc1/svc/cross" + } + ] + } + }, + "sni": "cross.default.ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~db.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~db.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "33s", + "circuitBreakers": { + + }, + "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/ap/ap1/ns/default/dc/dc1/svc/db" + } + ] + } + }, + "sni": "db.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul" + } + } + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http.latest.golden b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http.latest.golden new file mode 100644 index 000000000..a41025e9f --- /dev/null +++ b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services-http.latest.golden @@ -0,0 +1,232 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "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/bar" + } + ] + } + }, + "sni": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "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/foo" + } + ] + } + }, + "sni": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + + }, + "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/gir" + } + ] + } + }, + "sni": "gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + + } + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services.latest.golden b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services.latest.golden index bc9669bef..eea8fc86a 100644 --- a/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services.latest.golden +++ b/agent/xds/testdata/clusters/mesh-gateway-with-exported-peered-services.latest.golden @@ -20,7 +20,8 @@ }, { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "dc2.internal.11111111-2222-3333-4444-555555555555.consul", + "name": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "type": "EDS", "edsClusterConfig": { "edsConfig": { @@ -31,72 +32,68 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "outlierDetection": { + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } } }, { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "dc4.internal.11111111-2222-3333-4444-555555555555.consul", - "type": "LOGICAL_DNS", - "connectTimeout": "5s", - "loadAssignment": { - "clusterName": "dc4.internal.11111111-2222-3333-4444-555555555555.consul", - "endpoints": [ - { - "lbEndpoints": [ - { - "endpoint": { - "address": { - "socketAddress": { - "address": "123.us-west-2.elb.notaws.com", - "portValue": 443 - } - } - }, - "healthStatus": "HEALTHY", - "loadBalancingWeight": 1 - } - ] - } - ] + "name": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + }, - "dnsRefreshRate": "10s", - "dnsLookupFamily": "V4_ONLY", "outlierDetection": { + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } } }, { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "dc6.internal.11111111-2222-3333-4444-555555555555.consul", - "type": "LOGICAL_DNS", - "connectTimeout": "5s", - "loadAssignment": { - "clusterName": "dc6.internal.11111111-2222-3333-4444-555555555555.consul", - "endpoints": [ - { - "lbEndpoints": [ - { - "endpoint": { - "address": { - "socketAddress": { - "address": "123.us-east-1.elb.notaws.com", - "portValue": 443 - } - } - }, - "healthStatus": "UNHEALTHY", - "loadBalancingWeight": 1 - } - ] - } - ] + "name": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + }, - "dnsRefreshRate": "10s", - "dnsLookupFamily": "V4_ONLY", "outlierDetection": { + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } } }, { @@ -114,6 +111,23 @@ "connectTimeout": "5s", "outlierDetection": { + } + }, + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + }, + "resourceApiVersion": "V3" + } + }, + "connectTimeout": "5s", + "outlierDetection": { + } } ], diff --git a/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden new file mode 100644 index 000000000..da1e19b7b --- /dev/null +++ b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden @@ -0,0 +1,211 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "alt.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "dc2.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.18.1.1", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.18.1.2", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~alt.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~api.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.18.1.1", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "198.18.1.2", + "portValue": 443 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden new file mode 100644 index 000000000..073d3718f --- /dev/null +++ b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden @@ -0,0 +1,187 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "alt.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "172.100.0.14", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "db.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~alt.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~cross.default.ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "172.100.0.14", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~db.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http.latest.golden b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http.latest.golden new file mode 100644 index 000000000..2d3e39d30 --- /dev/null +++ b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services-http.latest.golden @@ -0,0 +1,211 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services.latest.golden b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services.latest.golden index 81f2a3eec..2d3e39d30 100644 --- a/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services.latest.golden +++ b/agent/xds/testdata/endpoints/mesh-gateway-with-exported-peered-services.latest.golden @@ -11,8 +11,8 @@ "endpoint": { "address": { "socketAddress": { - "address": "172.16.1.6", - "portValue": 2222 + "address": "10.10.1.1", + "portValue": 8080 } } }, @@ -23,20 +23,8 @@ "endpoint": { "address": { "socketAddress": { - "address": "172.16.1.7", - "portValue": 2222 - } - } - }, - "healthStatus": "HEALTHY", - "loadBalancingWeight": 1 - }, - { - "endpoint": { - "address": { - "socketAddress": { - "address": "172.16.1.8", - "portValue": 2222 + "address": "10.10.1.2", + "portValue": 8080 } } }, @@ -49,7 +37,7 @@ }, { "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", - "clusterName": "dc2.internal.11111111-2222-3333-4444-555555555555.consul", + "clusterName": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "endpoints": [ { "lbEndpoints": [ @@ -57,8 +45,8 @@ "endpoint": { "address": { "socketAddress": { - "address": "198.18.1.1", - "portValue": 443 + "address": "10.10.1.1", + "portValue": 8080 } } }, @@ -69,8 +57,76 @@ "endpoint": { "address": { "socketAddress": { - "address": "198.18.1.2", - "portValue": 443 + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + }, + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.2", + "portValue": 8080 } } }, @@ -91,8 +147,8 @@ "endpoint": { "address": { "socketAddress": { - "address": "172.16.1.3", - "portValue": 2222 + "address": "10.10.1.1", + "portValue": 8080 } } }, @@ -103,8 +159,30 @@ "endpoint": { "address": { "socketAddress": { - "address": "172.16.1.4", - "portValue": 2222 + "address": "10.10.1.2", + "portValue": 8080 + } + } + }, + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 + } + ] + } + ] + }, + { + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 } } }, @@ -115,20 +193,8 @@ "endpoint": { "address": { "socketAddress": { - "address": "172.16.1.5", - "portValue": 2222 - } - } - }, - "healthStatus": "HEALTHY", - "loadBalancingWeight": 1 - }, - { - "endpoint": { - "address": { - "socketAddress": { - "address": "172.16.1.9", - "portValue": 2222 + "address": "10.10.1.2", + "portValue": 8080 } } }, diff --git a/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden new file mode 100644 index 000000000..e6c1280e0 --- /dev/null +++ b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden @@ -0,0 +1,144 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "default:1.2.3.4:8443", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8443 + } + }, + "filterChains": [ + { + "filterChainMatch": { + "serverNames": [ + "db.default.default.peer-a.external.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": "mesh_gateway_local_peered.db.default.default.dc1", + "rds": { + "configSource": { + "ads": { + + }, + "resourceApiVersion": "V3" + }, + "routeConfigName": "db" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": { + + } + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "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": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ + { + "name": "11111111-2222-3333-4444-555555555555.consul", + "trustBundle": { + "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" + } + }, + { + "name": "1c053652-8512-4373-90cf-5a7f6263a994.consul", + "trustBundle": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICczCCAdwCCQC3BLnEmLCrSjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQVoxEjAQBgNVBAcMCUZsYWdzdGFmZjEMMAoGA1UECgwDRm9v\nMRAwDgYDVQQLDAdleGFtcGxlMQ8wDQYDVQQDDAZwZWVyLWExHTAbBgkqhkiG9w0B\nCQEWDmZvb0BwZWVyLWEuY29tMB4XDTIyMDUyNjAxMDQ0NFoXDTIzMDUyNjAxMDQ0\nNFowfjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkFaMRIwEAYDVQQHDAlGbGFnc3Rh\nZmYxDDAKBgNVBAoMA0ZvbzEQMA4GA1UECwwHZXhhbXBsZTEPMA0GA1UEAwwGcGVl\nci1hMR0wGwYJKoZIhvcNAQkBFg5mb29AcGVlci1hLmNvbTCBnzANBgkqhkiG9w0B\nAQEFAAOBjQAwgYkCgYEA2zFYGTbXDAntT5pLTpZ2+VTiqx4J63VRJH1kdu11f0FV\nc2jl1pqCuYDbQXknDU0Pv1Q5y0+nSAihD2KqGS571r+vHQiPtKYPYRqPEe9FzAhR\n2KhWH6v/tk5DG1HqOjV9/zWRKB12gdFNZZqnw/e7NjLNq3wZ2UAwxXip5uJ8uwMC\nAwEAATANBgkqhkiG9w0BAQsFAAOBgQC/CJ9Syf4aL91wZizKTejwouRYoWv4gRAk\nyto45ZcNMHfJ0G2z+XAMl9ZbQsLgXmzAx4IM6y5Jckq8pKC4PEijCjlKTktLHlEy\n0ggmFxtNB1tid2NC8dOzcQ3l45+gDjDqdILhAvLDjlAIebdkqVqb2CfFNW/I2CQH\nZAuKN1aoKA==\n-----END CERTIFICATE-----\n" + } + } + ] + } + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "*.dc2.internal.11111111-2222-3333-4444-555555555555.consul" + ] + }, + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "mesh_gateway_remote.default.dc2", + "cluster": "dc2.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + }, + { + "filters": [ + { + "name": "envoy.filters.network.sni_cluster", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.sni_cluster.v3.SniCluster" + } + }, + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "mesh_gateway_local.default", + "cluster": "" + } + } + ] + } + ], + "listenerFilters": [ + { + "name": "envoy.filters.listener.tls_inspector", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector" + } + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden new file mode 100644 index 000000000..341979b5b --- /dev/null +++ b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden @@ -0,0 +1,144 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "default:1.2.3.4:8443", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8443 + } + }, + "filterChains": [ + { + "filterChainMatch": { + "serverNames": [ + "db.default.ap1.peer-a.external.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": "mesh_gateway_local_peered.db.default.ap1.dc1", + "rds": { + "configSource": { + "ads": { + + }, + "resourceApiVersion": "V3" + }, + "routeConfigName": "ap1/default/db" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": { + + } + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "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": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ + { + "name": "11111111-2222-3333-4444-555555555555.consul", + "trustBundle": { + "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" + } + }, + { + "name": "1c053652-8512-4373-90cf-5a7f6263a994.consul", + "trustBundle": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICczCCAdwCCQC3BLnEmLCrSjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQVoxEjAQBgNVBAcMCUZsYWdzdGFmZjEMMAoGA1UECgwDRm9v\nMRAwDgYDVQQLDAdleGFtcGxlMQ8wDQYDVQQDDAZwZWVyLWExHTAbBgkqhkiG9w0B\nCQEWDmZvb0BwZWVyLWEuY29tMB4XDTIyMDUyNjAxMDQ0NFoXDTIzMDUyNjAxMDQ0\nNFowfjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkFaMRIwEAYDVQQHDAlGbGFnc3Rh\nZmYxDDAKBgNVBAoMA0ZvbzEQMA4GA1UECwwHZXhhbXBsZTEPMA0GA1UEAwwGcGVl\nci1hMR0wGwYJKoZIhvcNAQkBFg5mb29AcGVlci1hLmNvbTCBnzANBgkqhkiG9w0B\nAQEFAAOBjQAwgYkCgYEA2zFYGTbXDAntT5pLTpZ2+VTiqx4J63VRJH1kdu11f0FV\nc2jl1pqCuYDbQXknDU0Pv1Q5y0+nSAihD2KqGS571r+vHQiPtKYPYRqPEe9FzAhR\n2KhWH6v/tk5DG1HqOjV9/zWRKB12gdFNZZqnw/e7NjLNq3wZ2UAwxXip5uJ8uwMC\nAwEAATANBgkqhkiG9w0BAQsFAAOBgQC/CJ9Syf4aL91wZizKTejwouRYoWv4gRAk\nyto45ZcNMHfJ0G2z+XAMl9ZbQsLgXmzAx4IM6y5Jckq8pKC4PEijCjlKTktLHlEy\n0ggmFxtNB1tid2NC8dOzcQ3l45+gDjDqdILhAvLDjlAIebdkqVqb2CfFNW/I2CQH\nZAuKN1aoKA==\n-----END CERTIFICATE-----\n" + } + } + ] + } + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "*.ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul" + ] + }, + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "mesh_gateway_remote.default.ap2.dc1", + "cluster": "ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + }, + { + "filters": [ + { + "name": "envoy.filters.network.sni_cluster", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.sni_cluster.v3.SniCluster" + } + }, + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "mesh_gateway_local.default", + "cluster": "" + } + } + ] + } + ], + "listenerFilters": [ + { + "name": "envoy.filters.listener.tls_inspector", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector" + } + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http.latest.golden b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http.latest.golden new file mode 100644 index 000000000..cf5ae5a9e --- /dev/null +++ b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services-http.latest.golden @@ -0,0 +1,291 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "default:1.2.3.4:8443", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8443 + } + }, + "filterChains": [ + { + "filterChainMatch": { + "serverNames": [ + "bar.default.default.peer-a.external.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": "mesh_gateway_local_peered.bar.default.default.dc1", + "rds": { + "configSource": { + "ads": { + + }, + "resourceApiVersion": "V3" + }, + "routeConfigName": "bar" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": { + + } + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "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": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ + { + "name": "11111111-2222-3333-4444-555555555555.consul", + "trustBundle": { + "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" + } + }, + { + "name": "1c053652-8512-4373-90cf-5a7f6263a994.consul", + "trustBundle": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICczCCAdwCCQC3BLnEmLCrSjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQVoxEjAQBgNVBAcMCUZsYWdzdGFmZjEMMAoGA1UECgwDRm9v\nMRAwDgYDVQQLDAdleGFtcGxlMQ8wDQYDVQQDDAZwZWVyLWExHTAbBgkqhkiG9w0B\nCQEWDmZvb0BwZWVyLWEuY29tMB4XDTIyMDUyNjAxMDQ0NFoXDTIzMDUyNjAxMDQ0\nNFowfjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkFaMRIwEAYDVQQHDAlGbGFnc3Rh\nZmYxDDAKBgNVBAoMA0ZvbzEQMA4GA1UECwwHZXhhbXBsZTEPMA0GA1UEAwwGcGVl\nci1hMR0wGwYJKoZIhvcNAQkBFg5mb29AcGVlci1hLmNvbTCBnzANBgkqhkiG9w0B\nAQEFAAOBjQAwgYkCgYEA2zFYGTbXDAntT5pLTpZ2+VTiqx4J63VRJH1kdu11f0FV\nc2jl1pqCuYDbQXknDU0Pv1Q5y0+nSAihD2KqGS571r+vHQiPtKYPYRqPEe9FzAhR\n2KhWH6v/tk5DG1HqOjV9/zWRKB12gdFNZZqnw/e7NjLNq3wZ2UAwxXip5uJ8uwMC\nAwEAATANBgkqhkiG9w0BAQsFAAOBgQC/CJ9Syf4aL91wZizKTejwouRYoWv4gRAk\nyto45ZcNMHfJ0G2z+XAMl9ZbQsLgXmzAx4IM6y5Jckq8pKC4PEijCjlKTktLHlEy\n0ggmFxtNB1tid2NC8dOzcQ3l45+gDjDqdILhAvLDjlAIebdkqVqb2CfFNW/I2CQH\nZAuKN1aoKA==\n-----END CERTIFICATE-----\n" + } + } + ] + } + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "foo.default.default.peer-a.external.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": "mesh_gateway_local_peered.foo.default.default.dc1", + "rds": { + "configSource": { + "ads": { + + }, + "resourceApiVersion": "V3" + }, + "routeConfigName": "foo" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": { + + } + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "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": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ + { + "name": "11111111-2222-3333-4444-555555555555.consul", + "trustBundle": { + "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" + } + }, + { + "name": "1c053652-8512-4373-90cf-5a7f6263a994.consul", + "trustBundle": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICczCCAdwCCQC3BLnEmLCrSjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQVoxEjAQBgNVBAcMCUZsYWdzdGFmZjEMMAoGA1UECgwDRm9v\nMRAwDgYDVQQLDAdleGFtcGxlMQ8wDQYDVQQDDAZwZWVyLWExHTAbBgkqhkiG9w0B\nCQEWDmZvb0BwZWVyLWEuY29tMB4XDTIyMDUyNjAxMDQ0NFoXDTIzMDUyNjAxMDQ0\nNFowfjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkFaMRIwEAYDVQQHDAlGbGFnc3Rh\nZmYxDDAKBgNVBAoMA0ZvbzEQMA4GA1UECwwHZXhhbXBsZTEPMA0GA1UEAwwGcGVl\nci1hMR0wGwYJKoZIhvcNAQkBFg5mb29AcGVlci1hLmNvbTCBnzANBgkqhkiG9w0B\nAQEFAAOBjQAwgYkCgYEA2zFYGTbXDAntT5pLTpZ2+VTiqx4J63VRJH1kdu11f0FV\nc2jl1pqCuYDbQXknDU0Pv1Q5y0+nSAihD2KqGS571r+vHQiPtKYPYRqPEe9FzAhR\n2KhWH6v/tk5DG1HqOjV9/zWRKB12gdFNZZqnw/e7NjLNq3wZ2UAwxXip5uJ8uwMC\nAwEAATANBgkqhkiG9w0BAQsFAAOBgQC/CJ9Syf4aL91wZizKTejwouRYoWv4gRAk\nyto45ZcNMHfJ0G2z+XAMl9ZbQsLgXmzAx4IM6y5Jckq8pKC4PEijCjlKTktLHlEy\n0ggmFxtNB1tid2NC8dOzcQ3l45+gDjDqdILhAvLDjlAIebdkqVqb2CfFNW/I2CQH\nZAuKN1aoKA==\n-----END CERTIFICATE-----\n" + } + } + ] + } + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filterChainMatch": { + "serverNames": [ + "gir.default.default.peer-b.external.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": "mesh_gateway_local_peered.gir.default.default.dc1", + "rds": { + "configSource": { + "ads": { + + }, + "resourceApiVersion": "V3" + }, + "routeConfigName": "gir" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": { + + } + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "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": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ + { + "name": "11111111-2222-3333-4444-555555555555.consul", + "trustBundle": { + "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" + } + }, + { + "name": "d89ac423-e95a-475d-94f2-1c557c57bf31.consul", + "trustBundle": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICcTCCAdoCCQDyGxC08cD0BDANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCENhcmxzYmFkMQwwCgYDVQQKDANGb28x\nEDAOBgNVBAsMB2V4YW1wbGUxDzANBgNVBAMMBnBlZXItYjEdMBsGCSqGSIb3DQEJ\nARYOZm9vQHBlZXItYi5jb20wHhcNMjIwNTI2MDExNjE2WhcNMjMwNTI2MDExNjE2\nWjB9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCENhcmxzYmFk\nMQwwCgYDVQQKDANGb28xEDAOBgNVBAsMB2V4YW1wbGUxDzANBgNVBAMMBnBlZXIt\nYjEdMBsGCSqGSIb3DQEJARYOZm9vQHBlZXItYi5jb20wgZ8wDQYJKoZIhvcNAQEB\nBQADgY0AMIGJAoGBAL4i5erdZ5vKk3mzW9Qt6Wvw/WN/IpMDlL0a28wz9oDCtMLN\ncD/XQB9yT5jUwb2s4mD1lCDZtee8MHeD8zygICozufWVB+u2KvMaoA50T9GMQD0E\nz/0nz/Z703I4q13VHeTpltmEpYcfxw/7nJ3leKA34+Nj3zteJ70iqvD/TNBBAgMB\nAAEwDQYJKoZIhvcNAQELBQADgYEAbL04gicH+EIznDNhZJEb1guMBtBBJ8kujPyU\nao8xhlUuorDTLwhLpkKsOhD8619oSS8KynjEBichidQRkwxIaze0a2mrGT+tGBMf\npVz6UeCkqpde6bSJ/ozEe/2seQzKqYvRT1oUjLwYvY7OIh2DzYibOAxh6fewYAmU\n5j5qNLc=\n-----END CERTIFICATE-----\n" + } + } + ] + } + } + } + }, + "requireClientCertificate": true + } + } + }, + { + "filters": [ + { + "name": "envoy.filters.network.sni_cluster", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.sni_cluster.v3.SniCluster" + } + }, + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "mesh_gateway_local.default", + "cluster": "" + } + } + ] + } + ], + "listenerFilters": [ + { + "name": "envoy.filters.listener.tls_inspector", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector" + } + } + ] + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services.latest.golden b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services.latest.golden index 6b291791a..5d5ecb30f 100644 --- a/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services.latest.golden +++ b/agent/xds/testdata/listeners/mesh-gateway-with-exported-peered-services.latest.golden @@ -23,7 +23,7 @@ "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", "statPrefix": "mesh_gateway_local_peered.bar.default.default.dc1", - "cluster": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] @@ -40,7 +40,7 @@ "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", "statPrefix": "mesh_gateway_local_peered.foo.default.default.dc1", - "cluster": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] @@ -57,58 +57,7 @@ "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", "statPrefix": "mesh_gateway_local_peered.gir.default.default.dc1", - "cluster": "gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" - } - } - ] - }, - { - "filterChainMatch": { - "serverNames": [ - "*.dc2.internal.11111111-2222-3333-4444-555555555555.consul" - ] - }, - "filters": [ - { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "mesh_gateway_remote.default.dc2", - "cluster": "dc2.internal.11111111-2222-3333-4444-555555555555.consul" - } - } - ] - }, - { - "filterChainMatch": { - "serverNames": [ - "*.dc4.internal.11111111-2222-3333-4444-555555555555.consul" - ] - }, - "filters": [ - { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "mesh_gateway_remote.default.dc4", - "cluster": "dc4.internal.11111111-2222-3333-4444-555555555555.consul" - } - } - ] - }, - { - "filterChainMatch": { - "serverNames": [ - "*.dc6.internal.11111111-2222-3333-4444-555555555555.consul" - ] - }, - "filters": [ - { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "mesh_gateway_remote.default.dc6", - "cluster": "dc6.internal.11111111-2222-3333-4444-555555555555.consul" + "cluster": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] diff --git a/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden b/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden new file mode 100644 index 000000000..d504294d0 --- /dev/null +++ b/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden @@ -0,0 +1,58 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "db", + "virtualHosts": [ + { + "name": "db", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/split" + }, + "route": { + "weightedClusters": { + "clusters": [ + { + "name": "exported~alt.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "weight": 6000 + }, + { + "name": "exported~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "weight": 4000 + } + ], + "totalWeight": 10000 + } + } + }, + { + "match": { + "prefix": "/api" + }, + "route": { + "cluster": "exported~api.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul" + } + }, + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "exported~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "validateClusters": true + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden b/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden new file mode 100644 index 000000000..edce6fc1c --- /dev/null +++ b/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http-with-splitter-crossing-partitions.latest.golden @@ -0,0 +1,46 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "ap1/default/db", + "virtualHosts": [ + { + "name": "ap1/default/db", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "weightedClusters": { + "clusters": [ + { + "name": "exported~alt.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "weight": 5000 + }, + { + "name": "exported~db.default.ap1.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "weight": 4000 + }, + { + "name": "exported~cross.default.ap2.dc1.internal-v1.11111111-2222-3333-4444-555555555555.consul", + "weight": 1000 + } + ], + "totalWeight": 10000 + } + } + } + ] + } + ], + "validateClusters": true + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http.latest.golden b/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http.latest.golden new file mode 100644 index 000000000..5b64a2c7e --- /dev/null +++ b/agent/xds/testdata/routes/mesh-gateway-with-exported-peered-services-http.latest.golden @@ -0,0 +1,76 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "bar", + "virtualHosts": [ + { + "name": "bar", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "exported~bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "validateClusters": true + }, + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "foo", + "virtualHosts": [ + { + "name": "foo", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "exported~foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "validateClusters": true + }, + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "gir", + "virtualHosts": [ + { + "name": "gir", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "exported~gir.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "validateClusters": true + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/base.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/base.hcl new file mode 100644 index 000000000..68265638f --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/base.hcl @@ -0,0 +1,2 @@ +primary_datacenter = "alpha" +log_level = "trace" diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/config_entries.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/config_entries.hcl new file mode 100644 index 000000000..9a01d60fd --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/config_entries.hcl @@ -0,0 +1,39 @@ +config_entries { + bootstrap = [ + { + kind = "proxy-defaults" + name = "global" + + config { + protocol = "http" + } + }, + { + kind = "service-router" + name = "s2" + routes = [ + { + match { http { path_prefix = "/s3/" } } + destination { + service = "s3" + prefix_rewrite = "/" + } + }, + ] + }, + { + kind = "exported-services" + name = "default" + services = [ + { + name = "s2" + consumers = [ + { + peer_name = "alpha-to-primary" + } + ] + } + ] + } + ] +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_gateway.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_gateway.hcl new file mode 100644 index 000000000..bcdcb2e8b --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4432 +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s1.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s1.hcl new file mode 100644 index 000000000..e97ec2366 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s1.hcl @@ -0,0 +1 @@ +# We don't want an s1 service in this peer diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s2.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s2.hcl new file mode 100644 index 000000000..01d4505c6 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s2.hcl @@ -0,0 +1,7 @@ +services { + name = "s2" + port = 8181 + connect { + sidecar_service {} + } +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s3.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s3.hcl new file mode 100644 index 000000000..c8761365b --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/service_s3.hcl @@ -0,0 +1,5 @@ +services { + name = "s3" + port = 8282 + connect { sidecar_service {} } +} \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/setup.sh b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/setup.sh new file mode 100644 index 000000000..75b38c6f2 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -euo pipefail + +register_services alpha + +gen_envoy_bootstrap s2 19002 alpha +gen_envoy_bootstrap mesh-gateway 19003 alpha true +gen_envoy_bootstrap s3 19004 alpha + +wait_for_config_entry proxy-defaults global alpha +wait_for_config_entry service-router s2 alpha +wait_for_config_entry exported-services default alpha diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/alpha/verify.bats b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/verify.bats new file mode 100644 index 000000000..88bf52ab4 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/alpha/verify.bats @@ -0,0 +1,47 @@ +#!/usr/bin/env bats + +load helpers + +@test "s2 proxy is running correct version" { + assert_envoy_version 19002 +} + +@test "s2 proxy admin is up on :19002" { + retry_default curl -f -s localhost:19002/stats -o /dev/null +} + +@test "s3 proxy is running correct version" { + assert_envoy_version 19004 +} + +@test "s3 proxy admin is up on :19004" { + retry_default curl -f -s localhost:19004/stats -o /dev/null +} + +@test "gateway-alpha proxy admin is up on :19003" { + retry_default curl -f -s localhost:19003/stats -o /dev/null +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s2 alpha +} + +@test "s2 proxy should be healthy" { + assert_service_has_healthy_instances s2 1 alpha +} + +@test "s3 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21001 s3 alpha +} + +@test "s3 proxy should be healthy" { + assert_service_has_healthy_instances s3 1 alpha +} + +@test "gateway-alpha should be up and listening" { + retry_long nc -z consul-alpha-client:4432 +} + +@test "s2 proxies should be healthy" { + assert_service_has_healthy_instances s2 1 alpha +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/bind.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/bind.hcl new file mode 100644 index 000000000..f54393f03 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/bind.hcl @@ -0,0 +1,2 @@ +bind_addr = "0.0.0.0" +advertise_addr = "{{ GetInterfaceIP \"eth0\" }}" \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/capture.sh b/test/integration/connect/envoy/case-cross-peers-http-router/capture.sh new file mode 100644 index 000000000..65ddf9a09 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/capture.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +snapshot_envoy_admin localhost:19000 s1 primary || true +snapshot_envoy_admin localhost:19001 mesh-gateway primary || true +snapshot_envoy_admin localhost:19002 s2 alpha || true +snapshot_envoy_admin localhost:19003 mesh-gateway alpha || true +snapshot_envoy_admin localhost:19004 s3 alpha || true diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/primary/config_entries.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/primary/config_entries.hcl new file mode 100644 index 000000000..3bba32530 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/primary/config_entries.hcl @@ -0,0 +1,12 @@ +config_entries { + bootstrap = [ + { + kind = "proxy-defaults" + name = "global" + + config { + protocol = "http" + } + } + ] +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_gateway.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_gateway.hcl new file mode 100644 index 000000000..831a70ff3 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4431 +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_s1.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_s1.hcl new file mode 100644 index 000000000..0e3dcbc3e --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_s1.hcl @@ -0,0 +1,17 @@ +services { + name = "s1" + port = 8080 + connect { + sidecar_service { + proxy { + upstreams = [ + { + destination_name = "s2" + destination_peer = "primary-to-alpha" + local_bind_port = 5000 + } + ] + } + } + } +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_s2.hcl b/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_s2.hcl new file mode 100644 index 000000000..77164e722 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/primary/service_s2.hcl @@ -0,0 +1 @@ +# We don't want an s2 service in the primary dc \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/primary/setup.sh b/test/integration/connect/envoy/case-cross-peers-http-router/primary/setup.sh new file mode 100644 index 000000000..38122406d --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/primary/setup.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -euo pipefail + +register_services primary + +gen_envoy_bootstrap s1 19000 primary +gen_envoy_bootstrap mesh-gateway 19001 primary true + +wait_for_config_entry proxy-defaults global diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers-http-router/primary/verify.bats new file mode 100644 index 000000000..b357801d4 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/primary/verify.bats @@ -0,0 +1,73 @@ +#!/usr/bin/env bats + +load helpers + +@test "s1 proxy is running correct version" { + assert_envoy_version 19000 +} + +@test "s1 proxy admin is up on :19000" { + retry_default curl -f -s localhost:19000/stats -o /dev/null +} + +@test "gateway-primary proxy admin is up on :19001" { + retry_default curl -f -s localhost:19001/stats -o /dev/null +} + +@test "s1 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s1 +} + +@test "s2 proxies should be healthy in alpha" { + assert_service_has_healthy_instances s2 1 alpha +} + +@test "s3 proxies should be healthy in alpha" { + assert_service_has_healthy_instances s3 1 alpha +} + +@test "gateway-primary should be up and listening" { + retry_long nc -z consul-primary-client:4431 +} + +@test "gateway-alpha should be up and listening" { + retry_long nc -z consul-alpha-client:4432 +} + +@test "peer the two clusters together" { + create_peering primary alpha +} + +@test "s2 alpha proxies should be healthy in primary" { + assert_service_has_healthy_instances s2 1 primary "" "" primary-to-alpha +} + +@test "gateway-alpha should have healthy endpoints for s2" { + assert_upstream_has_endpoints_in_status consul-alpha-client:19003 exported~s2.default.alpha HEALTHY 1 +} + +@test "gateway-alpha should have healthy endpoints for s3" { + assert_upstream_has_endpoints_in_status consul-alpha-client:19003 exported~s3.default.alpha HEALTHY 1 +} + +@test "s1 upstream should have healthy endpoints for s2" { + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.default.alpha-to-primary.external HEALTHY 1 +} + +@test "s1 upstream should be able to connect to s2 with http/1.1" { + run retry_default curl --http1.1 -s -f -d hello localhost:5000 + [ "$status" -eq 0 ] + [ "$output" = "hello" ] +} + +@test "s1 upstream should be able to connect to s2 via s2" { + assert_expected_fortio_name s2-alpha +} + +@test "s1 upstream should be able to connect to s3 via s2 on a path" { + assert_expected_fortio_name s3-alpha localhost 5000 /s3 +} + +@test "s1 upstream made 1 connection to s2" { + assert_envoy_metric_at_least 127.0.0.1:19000 "cluster.s2.default.default.alpha-to-primary.external.*cx_total" 1 +} diff --git a/test/integration/connect/envoy/case-cross-peers-http-router/vars.sh b/test/integration/connect/envoy/case-cross-peers-http-router/vars.sh new file mode 100644 index 000000000..e21a3c0d9 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http-router/vars.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +export REQUIRED_SERVICES="s1 s1-sidecar-proxy gateway-primary s2-alpha s2-sidecar-proxy-alpha s3-alpha s3-sidecar-proxy-alpha gateway-alpha tcpdump-primary tcpdump-alpha" +export REQUIRE_PEERS=1 diff --git a/test/integration/connect/envoy/case-cross-peers-http/alpha/base.hcl b/test/integration/connect/envoy/case-cross-peers-http/alpha/base.hcl new file mode 100644 index 000000000..68265638f --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/alpha/base.hcl @@ -0,0 +1,2 @@ +primary_datacenter = "alpha" +log_level = "trace" diff --git a/test/integration/connect/envoy/case-cross-peers-http/alpha/config_entries.hcl b/test/integration/connect/envoy/case-cross-peers-http/alpha/config_entries.hcl new file mode 100644 index 000000000..2d50ef0fb --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/alpha/config_entries.hcl @@ -0,0 +1,26 @@ +config_entries { + bootstrap = [ + { + kind = "proxy-defaults" + name = "global" + + config { + protocol = "http" + } + }, + { + kind = "exported-services" + name = "default" + services = [ + { + name = "s2" + consumers = [ + { + peer_name = "alpha-to-primary" + } + ] + } + ] + } + ] +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/alpha/service_gateway.hcl b/test/integration/connect/envoy/case-cross-peers-http/alpha/service_gateway.hcl new file mode 100644 index 000000000..bcdcb2e8b --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/alpha/service_gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4432 +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/alpha/service_s1.hcl b/test/integration/connect/envoy/case-cross-peers-http/alpha/service_s1.hcl new file mode 100644 index 000000000..e97ec2366 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/alpha/service_s1.hcl @@ -0,0 +1 @@ +# We don't want an s1 service in this peer diff --git a/test/integration/connect/envoy/case-cross-peers-http/alpha/service_s2.hcl b/test/integration/connect/envoy/case-cross-peers-http/alpha/service_s2.hcl new file mode 100644 index 000000000..01d4505c6 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/alpha/service_s2.hcl @@ -0,0 +1,7 @@ +services { + name = "s2" + port = 8181 + connect { + sidecar_service {} + } +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/alpha/setup.sh b/test/integration/connect/envoy/case-cross-peers-http/alpha/setup.sh new file mode 100644 index 000000000..820506ea9 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/alpha/setup.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -euo pipefail + +register_services alpha + +gen_envoy_bootstrap s2 19002 alpha +gen_envoy_bootstrap mesh-gateway 19003 alpha true + +wait_for_config_entry proxy-defaults global alpha +wait_for_config_entry exported-services default alpha diff --git a/test/integration/connect/envoy/case-cross-peers-http/alpha/verify.bats b/test/integration/connect/envoy/case-cross-peers-http/alpha/verify.bats new file mode 100644 index 000000000..a2fcfaaf3 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/alpha/verify.bats @@ -0,0 +1,31 @@ +#!/usr/bin/env bats + +load helpers + +@test "s2 proxy is running correct version" { + assert_envoy_version 19002 +} + +@test "s2 proxy admin is up on :19002" { + retry_default curl -f -s localhost:19002/stats -o /dev/null +} + +@test "gateway-alpha proxy admin is up on :19003" { + retry_default curl -f -s localhost:19003/stats -o /dev/null +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s2 alpha +} + +@test "s2 proxy should be healthy" { + assert_service_has_healthy_instances s2 1 alpha +} + +@test "gateway-alpha should be up and listening" { + retry_long nc -z consul-alpha-client:4432 +} + +@test "s2 proxies should be healthy" { + assert_service_has_healthy_instances s2 1 alpha +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/bind.hcl b/test/integration/connect/envoy/case-cross-peers-http/bind.hcl new file mode 100644 index 000000000..f54393f03 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/bind.hcl @@ -0,0 +1,2 @@ +bind_addr = "0.0.0.0" +advertise_addr = "{{ GetInterfaceIP \"eth0\" }}" \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-http/capture.sh b/test/integration/connect/envoy/case-cross-peers-http/capture.sh new file mode 100644 index 000000000..2419a58cd --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/capture.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +snapshot_envoy_admin localhost:19000 s1 primary || true +snapshot_envoy_admin localhost:19001 mesh-gateway primary || true +snapshot_envoy_admin localhost:19002 s2 alpha || true +snapshot_envoy_admin localhost:19003 mesh-gateway alpha || true diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/config_entries.hcl b/test/integration/connect/envoy/case-cross-peers-http/primary/config_entries.hcl new file mode 100644 index 000000000..3bba32530 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/config_entries.hcl @@ -0,0 +1,12 @@ +config_entries { + bootstrap = [ + { + kind = "proxy-defaults" + name = "global" + + config { + protocol = "http" + } + } + ] +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/service_gateway.hcl b/test/integration/connect/envoy/case-cross-peers-http/primary/service_gateway.hcl new file mode 100644 index 000000000..831a70ff3 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/service_gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4431 +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/service_s1.hcl b/test/integration/connect/envoy/case-cross-peers-http/primary/service_s1.hcl new file mode 100644 index 000000000..0e3dcbc3e --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/service_s1.hcl @@ -0,0 +1,17 @@ +services { + name = "s1" + port = 8080 + connect { + sidecar_service { + proxy { + upstreams = [ + { + destination_name = "s2" + destination_peer = "primary-to-alpha" + local_bind_port = 5000 + } + ] + } + } + } +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/service_s2.hcl b/test/integration/connect/envoy/case-cross-peers-http/primary/service_s2.hcl new file mode 100644 index 000000000..77164e722 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/service_s2.hcl @@ -0,0 +1 @@ +# We don't want an s2 service in the primary dc \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/setup.sh b/test/integration/connect/envoy/case-cross-peers-http/primary/setup.sh new file mode 100644 index 000000000..38122406d --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/setup.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -euo pipefail + +register_services primary + +gen_envoy_bootstrap s1 19000 primary +gen_envoy_bootstrap mesh-gateway 19001 primary true + +wait_for_config_entry proxy-defaults global diff --git a/test/integration/connect/envoy/case-cross-peers-http/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers-http/primary/verify.bats new file mode 100644 index 000000000..523950f0b --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/primary/verify.bats @@ -0,0 +1,57 @@ +#!/usr/bin/env bats + +load helpers + +@test "s1 proxy is running correct version" { + assert_envoy_version 19000 +} + +@test "s1 proxy admin is up on :19000" { + retry_default curl -f -s localhost:19000/stats -o /dev/null +} + +@test "gateway-primary proxy admin is up on :19001" { + retry_default curl -f -s localhost:19001/stats -o /dev/null +} + +@test "s1 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s1 +} + +@test "s2 proxies should be healthy in alpha" { + assert_service_has_healthy_instances s2 1 alpha +} + +@test "gateway-primary should be up and listening" { + retry_long nc -z consul-primary-client:4431 +} + +@test "gateway-alpha should be up and listening" { + retry_long nc -z consul-alpha-client:4432 +} + +@test "peer the two clusters together" { + create_peering primary alpha +} + +@test "s2 alpha proxies should be healthy in primary" { + assert_service_has_healthy_instances s2 1 primary "" "" primary-to-alpha +} + +@test "gateway-alpha should have healthy endpoints for s2" { + assert_upstream_has_endpoints_in_status consul-alpha-client:19003 exported~s2.default.alpha HEALTHY 1 +} + +@test "s1 upstream should have healthy endpoints for s2" { + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.default.alpha-to-primary.external HEALTHY 1 +} + +@test "s1 upstream should be able to connect to s2 with http/1.1" { + run retry_default curl --http1.1 -s -f -d hello localhost:5000 + [ "$status" -eq 0 ] + [ "$output" = "hello" ] +} + +@test "s1 upstream made 1 connection to s2" { + assert_envoy_metric_at_least 127.0.0.1:19000 "cluster.s2.default.default.alpha-to-primary.external.*cx_total" 1 +} diff --git a/test/integration/connect/envoy/case-cross-peers-http/vars.sh b/test/integration/connect/envoy/case-cross-peers-http/vars.sh new file mode 100644 index 000000000..388d22b8b --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-http/vars.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +export REQUIRED_SERVICES="s1 s1-sidecar-proxy gateway-primary s2-alpha s2-sidecar-proxy-alpha gateway-alpha tcpdump-primary tcpdump-alpha" +export REQUIRE_PEERS=1 diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/base.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/base.hcl new file mode 100644 index 000000000..68265638f --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/base.hcl @@ -0,0 +1,2 @@ +primary_datacenter = "alpha" +log_level = "trace" diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/config_entries.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/config_entries.hcl new file mode 100644 index 000000000..edf5d0bb5 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/config_entries.hcl @@ -0,0 +1,33 @@ +config_entries { + bootstrap = [ + { + kind = "proxy-defaults" + name = "global" + + config { + protocol = "tcp" + } + }, + { + kind = "service-resolver" + name = "s2" + redirect { + service = "s3" + } + }, + { + kind = "exported-services" + name = "default" + services = [ + { + name = "s2" + consumers = [ + { + peer_name = "alpha-to-primary" + } + ] + } + ] + } + ] +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_gateway.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_gateway.hcl new file mode 100644 index 000000000..bcdcb2e8b --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4432 +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s1.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s1.hcl new file mode 100644 index 000000000..e97ec2366 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s1.hcl @@ -0,0 +1 @@ +# We don't want an s1 service in this peer diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s2.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s2.hcl new file mode 100644 index 000000000..01d4505c6 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s2.hcl @@ -0,0 +1,7 @@ +services { + name = "s2" + port = 8181 + connect { + sidecar_service {} + } +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s3.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s3.hcl new file mode 100644 index 000000000..c8761365b --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/service_s3.hcl @@ -0,0 +1,5 @@ +services { + name = "s3" + port = 8282 + connect { sidecar_service {} } +} \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/setup.sh b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/setup.sh new file mode 100644 index 000000000..a2645baf6 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -euo pipefail + +register_services alpha + +gen_envoy_bootstrap s2 19002 alpha +gen_envoy_bootstrap mesh-gateway 19003 alpha true +gen_envoy_bootstrap s3 19004 alpha + +wait_for_config_entry proxy-defaults global alpha +wait_for_config_entry service-resolver s2 alpha +wait_for_config_entry exported-services default alpha diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/verify.bats b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/verify.bats new file mode 100644 index 000000000..88bf52ab4 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/alpha/verify.bats @@ -0,0 +1,47 @@ +#!/usr/bin/env bats + +load helpers + +@test "s2 proxy is running correct version" { + assert_envoy_version 19002 +} + +@test "s2 proxy admin is up on :19002" { + retry_default curl -f -s localhost:19002/stats -o /dev/null +} + +@test "s3 proxy is running correct version" { + assert_envoy_version 19004 +} + +@test "s3 proxy admin is up on :19004" { + retry_default curl -f -s localhost:19004/stats -o /dev/null +} + +@test "gateway-alpha proxy admin is up on :19003" { + retry_default curl -f -s localhost:19003/stats -o /dev/null +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s2 alpha +} + +@test "s2 proxy should be healthy" { + assert_service_has_healthy_instances s2 1 alpha +} + +@test "s3 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21001 s3 alpha +} + +@test "s3 proxy should be healthy" { + assert_service_has_healthy_instances s3 1 alpha +} + +@test "gateway-alpha should be up and listening" { + retry_long nc -z consul-alpha-client:4432 +} + +@test "s2 proxies should be healthy" { + assert_service_has_healthy_instances s2 1 alpha +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/bind.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/bind.hcl new file mode 100644 index 000000000..f54393f03 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/bind.hcl @@ -0,0 +1,2 @@ +bind_addr = "0.0.0.0" +advertise_addr = "{{ GetInterfaceIP \"eth0\" }}" \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/capture.sh b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/capture.sh new file mode 100644 index 000000000..65ddf9a09 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/capture.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +snapshot_envoy_admin localhost:19000 s1 primary || true +snapshot_envoy_admin localhost:19001 mesh-gateway primary || true +snapshot_envoy_admin localhost:19002 s2 alpha || true +snapshot_envoy_admin localhost:19003 mesh-gateway alpha || true +snapshot_envoy_admin localhost:19004 s3 alpha || true diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/config_entries.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/config_entries.hcl new file mode 100644 index 000000000..b3a8d9171 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/config_entries.hcl @@ -0,0 +1,12 @@ +config_entries { + bootstrap = [ + { + kind = "proxy-defaults" + name = "global" + + config { + protocol = "tcp" + } + } + ] +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_gateway.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_gateway.hcl new file mode 100644 index 000000000..831a70ff3 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4431 +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_s1.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_s1.hcl new file mode 100644 index 000000000..0e3dcbc3e --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_s1.hcl @@ -0,0 +1,17 @@ +services { + name = "s1" + port = 8080 + connect { + sidecar_service { + proxy { + upstreams = [ + { + destination_name = "s2" + destination_peer = "primary-to-alpha" + local_bind_port = 5000 + } + ] + } + } + } +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_s2.hcl b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_s2.hcl new file mode 100644 index 000000000..77164e722 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/service_s2.hcl @@ -0,0 +1 @@ +# We don't want an s2 service in the primary dc \ No newline at end of file diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/setup.sh b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/setup.sh new file mode 100644 index 000000000..38122406d --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/setup.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -euo pipefail + +register_services primary + +gen_envoy_bootstrap s1 19000 primary +gen_envoy_bootstrap mesh-gateway 19001 primary true + +wait_for_config_entry proxy-defaults global diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/verify.bats new file mode 100644 index 000000000..55256c67e --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/primary/verify.bats @@ -0,0 +1,62 @@ +#!/usr/bin/env bats + +load helpers + +@test "s1 proxy is running correct version" { + assert_envoy_version 19000 +} + +@test "s1 proxy admin is up on :19000" { + retry_default curl -f -s localhost:19000/stats -o /dev/null +} + +@test "gateway-primary proxy admin is up on :19001" { + retry_default curl -f -s localhost:19001/stats -o /dev/null +} + +@test "s1 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s1 +} + +@test "s3 proxies should be healthy in alpha" { + assert_service_has_healthy_instances s3 1 alpha +} + +@test "gateway-primary should be up and listening" { + retry_long nc -z consul-primary-client:4431 +} + +@test "gateway-alpha should be up and listening" { + retry_long nc -z consul-alpha-client:4432 +} + +@test "peer the two clusters together" { + create_peering primary alpha +} + +@test "s2 alpha proxies should be healthy in primary" { + assert_service_has_healthy_instances s2 1 primary "" "" primary-to-alpha +} + +@test "gateway-alpha should have healthy endpoints for s3" { + assert_upstream_has_endpoints_in_status consul-alpha-client:19003 exported~s3.default.alpha HEALTHY 1 +} + +@test "s1 upstream should have healthy endpoints for s2" { + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.default.alpha-to-primary.external HEALTHY 1 +} + +@test "s1 upstream should be able to connect to s2" { + run retry_default curl -s -f -d hello localhost:5000 + [ "$status" -eq 0 ] + [ "$output" = "hello" ] +} + +@test "s1 upstream should be able to connect to s3 via s2 due to redirect" { + assert_expected_fortio_name s3-alpha +} + +@test "s1 upstream made 1 connection to s2" { + # note this is what the IMPORTING side thinks it is talking to + assert_envoy_metric_at_least 127.0.0.1:19000 "cluster.s2.default.default.alpha-to-primary.external.*cx_total" 1 +} diff --git a/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/vars.sh b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/vars.sh new file mode 100644 index 000000000..e21a3c0d9 --- /dev/null +++ b/test/integration/connect/envoy/case-cross-peers-resolver-redirect-tcp/vars.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +export REQUIRED_SERVICES="s1 s1-sidecar-proxy gateway-primary s2-alpha s2-sidecar-proxy-alpha s3-alpha s3-sidecar-proxy-alpha gateway-alpha tcpdump-primary tcpdump-alpha" +export REQUIRE_PEERS=1 diff --git a/test/integration/connect/envoy/case-cross-peers/primary/verify.bats b/test/integration/connect/envoy/case-cross-peers/primary/verify.bats index d228febfa..5952cc2a1 100644 --- a/test/integration/connect/envoy/case-cross-peers/primary/verify.bats +++ b/test/integration/connect/envoy/case-cross-peers/primary/verify.bats @@ -39,7 +39,7 @@ load helpers } @test "gateway-alpha should have healthy endpoints for s2" { - assert_upstream_has_endpoints_in_status consul-alpha-client:19003 s2.default.alpha HEALTHY 1 + assert_upstream_has_endpoints_in_status consul-alpha-client:19003 exported~s2.default.alpha HEALTHY 1 } @test "s1 upstream should have healthy endpoints for s2" { diff --git a/test/integration/connect/envoy/run-tests.sh b/test/integration/connect/envoy/run-tests.sh index 92bbee4ad..adea350d7 100755 --- a/test/integration/connect/envoy/run-tests.sh +++ b/test/integration/connect/envoy/run-tests.sh @@ -658,6 +658,10 @@ function run_container_s2-alpha { common_run_container_service s2-alpha alpha 8181 8179 } +function run_container_s3-alpha { + common_run_container_service s3-alpha alpha 8282 8279 +} + function common_run_container_sidecar_proxy { local service="$1" local CLUSTER="$2" @@ -740,6 +744,9 @@ function run_container_s1-sidecar-proxy-alpha { function run_container_s2-sidecar-proxy-alpha { common_run_container_sidecar_proxy s2 alpha } +function run_container_s3-sidecar-proxy-alpha { + common_run_container_sidecar_proxy s3 alpha +} function common_run_container_gateway { local name="$1"