diff --git a/agent/proxycfg/proxycfg.deepcopy.go b/agent/proxycfg/proxycfg.deepcopy.go index 4c0318f67b..f1772ae72e 100644 --- a/agent/proxycfg/proxycfg.deepcopy.go +++ b/agent/proxycfg/proxycfg.deepcopy.go @@ -310,6 +310,23 @@ func (o *configSnapshotAPIGateway) DeepCopy() *configSnapshotAPIGateway { cp.Listeners[k2] = cp_Listeners_v2 } } + if o.ListenerCertificates != nil { + cp.ListenerCertificates = make(map[IngressListenerKey][]structs.InlineCertificateConfigEntry, len(o.ListenerCertificates)) + for k2, v2 := range o.ListenerCertificates { + var cp_ListenerCertificates_v2 []structs.InlineCertificateConfigEntry + if v2 != nil { + cp_ListenerCertificates_v2 = make([]structs.InlineCertificateConfigEntry, len(v2)) + copy(cp_ListenerCertificates_v2, v2) + for i3 := range v2 { + { + retV := v2[i3].DeepCopy() + cp_ListenerCertificates_v2[i3] = *retV + } + } + } + cp.ListenerCertificates[k2] = cp_ListenerCertificates_v2 + } + } if o.BoundListeners != nil { cp.BoundListeners = make(map[string]structs.BoundAPIGatewayListener, len(o.BoundListeners)) for k2, v2 := range o.BoundListeners { diff --git a/agent/proxycfg/snapshot.go b/agent/proxycfg/snapshot.go index 13c8540056..6ce5a30083 100644 --- a/agent/proxycfg/snapshot.go +++ b/agent/proxycfg/snapshot.go @@ -734,6 +734,8 @@ type configSnapshotAPIGateway struct { // Listeners is the original listener config from the api-gateway config // entry to save us trying to pass fields through Upstreams Listeners map[string]structs.APIGatewayListener + // this acts as an intermediary for inlining certificates + ListenerCertificates map[IngressListenerKey][]structs.InlineCertificateConfigEntry BoundListeners map[string]structs.BoundAPIGatewayListener } @@ -751,6 +753,9 @@ func (c *configSnapshotAPIGateway) ToIngress(datacenter string) (configSnapshotI watchedUpstreamEndpoints := make(map[UpstreamID]map[string]structs.CheckServiceNodes) watchedGatewayEndpoints := make(map[UpstreamID]map[string]structs.CheckServiceNodes) + // reset the cached certificates + c.ListenerCertificates = make(map[IngressListenerKey][]structs.InlineCertificateConfigEntry) + for name, listener := range c.Listeners { boundListener, ok := c.BoundListeners[name] if !ok { @@ -802,17 +807,18 @@ func (c *configSnapshotAPIGateway) ToIngress(datacenter string) (configSnapshotI watchedGatewayEndpoints[id] = gatewayEndpoints } - // Configure TLS for the ingress listener - tls, err := c.toIngressTLS() - if err != nil { - return configSnapshotIngressGateway{}, err - } - ingressListener.TLS = tls - key := IngressListenerKey{ Port: listener.Port, Protocol: string(listener.Protocol), } + + // Configure TLS for the ingress listener + tls, err := c.toIngressTLS(key, listener, boundListener) + if err != nil { + return configSnapshotIngressGateway{}, err + } + + ingressListener.TLS = tls ingressListeners[key] = ingressListener ingressUpstreams[key] = upstreams } @@ -905,9 +911,25 @@ DOMAIN_LOOP: return services, upstreams, compiled, err } -func (c *configSnapshotAPIGateway) toIngressTLS() (*structs.GatewayTLSConfig, error) { - // TODO (t-eckert) this is dependent on future SDS work. - return &structs.GatewayTLSConfig{}, nil +func (c *configSnapshotAPIGateway) toIngressTLS(key IngressListenerKey, listener structs.APIGatewayListener, bound structs.BoundAPIGatewayListener) (*structs.GatewayTLSConfig, error) { + if len(listener.TLS.Certificates) == 0 { + return nil, nil + } + + for _, certRef := range bound.Certificates { + cert, ok := c.Certificates.Get(certRef) + if !ok { + continue + } + c.ListenerCertificates[key] = append(c.ListenerCertificates[key], *cert) + } + + return &structs.GatewayTLSConfig{ + Enabled: true, + TLSMinVersion: listener.TLS.MinVersion, + TLSMaxVersion: listener.TLS.MaxVersion, + CipherSuites: listener.TLS.CipherSuites, + }, nil } type configSnapshotIngressGateway struct { diff --git a/agent/proxycfg/testing_api_gateway.go b/agent/proxycfg/testing_api_gateway.go new file mode 100644 index 0000000000..dd55f2eec5 --- /dev/null +++ b/agent/proxycfg/testing_api_gateway.go @@ -0,0 +1,157 @@ +package proxycfg + +import ( + "fmt" + + "github.com/hashicorp/consul/agent/connect" + "github.com/hashicorp/consul/agent/consul/discoverychain" + "github.com/mitchellh/go-testing-interface" + + "github.com/hashicorp/consul/agent/structs" +) + +func TestConfigSnapshotAPIGateway( + t testing.T, + variation string, + nsFn func(ns *structs.NodeService), + configFn func(entry *structs.APIGatewayConfigEntry, boundEntry *structs.BoundAPIGatewayConfigEntry), + routes []structs.BoundRoute, + certificates []structs.InlineCertificateConfigEntry, + extraUpdates []UpdateEvent, + additionalEntries ...structs.ConfigEntry, +) *ConfigSnapshot { + roots, placeholderLeaf := TestCerts(t) + + entry := &structs.APIGatewayConfigEntry{ + Kind: structs.APIGateway, + Name: "api-gateway", + } + boundEntry := &structs.BoundAPIGatewayConfigEntry{ + Kind: structs.BoundAPIGateway, + Name: "api-gateway", + } + + if configFn != nil { + configFn(entry, boundEntry) + } + + baseEvents := []UpdateEvent{ + { + CorrelationID: rootsWatchID, + Result: roots, + }, + { + CorrelationID: leafWatchID, + Result: placeholderLeaf, + }, + { + CorrelationID: gatewayConfigWatchID, + Result: &structs.ConfigEntryResponse{ + Entry: entry, + }, + }, + { + CorrelationID: gatewayConfigWatchID, + Result: &structs.ConfigEntryResponse{ + Entry: boundEntry, + }, + }, + } + + for _, route := range routes { + // Add the watch event for the route. + watch := UpdateEvent{ + CorrelationID: routeConfigWatchID, + Result: &structs.ConfigEntryResponse{ + Entry: route, + }, + } + baseEvents = append(baseEvents, watch) + + // Add the watch event for the discovery chain. + entries := []structs.ConfigEntry{ + &structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + Config: map[string]interface{}{ + "protocol": route.GetProtocol(), + }, + }, + &structs.ServiceResolverConfigEntry{ + Kind: structs.ServiceResolver, + Name: "api-gateway", + }, + } + + // Add a discovery chain watch event for each service. + for _, serviceName := range route.GetServiceNames() { + discoChain := UpdateEvent{ + CorrelationID: fmt.Sprintf("discovery-chain:%s", UpstreamIDString("", "", serviceName.Name, &serviceName.EnterpriseMeta, "")), + Result: &structs.DiscoveryChainResponse{ + Chain: discoverychain.TestCompileConfigEntries(t, serviceName.Name, "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...), + }, + } + baseEvents = append(baseEvents, discoChain) + } + } + + for _, certificate := range certificates { + inlineCertificate := certificate + baseEvents = append(baseEvents, UpdateEvent{ + CorrelationID: inlineCertificateConfigWatchID, + Result: &structs.ConfigEntryResponse{ + Entry: &inlineCertificate, + }, + }) + } + + upstreams := structs.TestUpstreams(t) + + baseEvents = testSpliceEvents(baseEvents, setupTestVariationConfigEntriesAndSnapshot( + t, variation, upstreams, additionalEntries..., + )) + + return testConfigSnapshotFixture(t, &structs.NodeService{ + Kind: structs.ServiceKindAPIGateway, + Service: "api-gateway", + Address: "1.2.3.4", + Meta: nil, + TaggedAddresses: nil, + }, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates)) +} + +// TestConfigSnapshotAPIGateway_NilConfigEntry is used to test when +// the update event for the config entry returns nil +// since this always happens on the first watch if it doesn't exist. +func TestConfigSnapshotAPIGateway_NilConfigEntry( + t testing.T, +) *ConfigSnapshot { + roots, _ := TestCerts(t) + + baseEvents := []UpdateEvent{ + { + CorrelationID: rootsWatchID, + Result: roots, + }, + { + CorrelationID: gatewayConfigWatchID, + Result: &structs.ConfigEntryResponse{ + Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist. + }, + }, + { + CorrelationID: gatewayConfigWatchID, + Result: &structs.ConfigEntryResponse{ + Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist. + }, + }, + } + + return testConfigSnapshotFixture(t, &structs.NodeService{ + Kind: structs.ServiceKindAPIGateway, + Service: "api-gateway", + Address: "1.2.3.4", + Meta: nil, + TaggedAddresses: nil, + }, nil, nil, testSpliceEvents(baseEvents, nil)) +} diff --git a/agent/structs/config_entry_inline_certificate.go b/agent/structs/config_entry_inline_certificate.go index 24028ffff2..18e3c7716d 100644 --- a/agent/structs/config_entry_inline_certificate.go +++ b/agent/structs/config_entry_inline_certificate.go @@ -64,6 +64,30 @@ func (e *InlineCertificateConfigEntry) Validate() error { return nil } +func (e *InlineCertificateConfigEntry) Hosts() ([]string, error) { + certificateBlock, _ := pem.Decode([]byte(e.Certificate)) + if certificateBlock == nil { + return nil, errors.New("failed to parse certificate PEM") + } + + certificate, err := x509.ParseCertificate(certificateBlock.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse certificate: %w", err) + } + + hosts := []string{certificate.Subject.CommonName} + + for _, name := range certificate.DNSNames { + hosts = append(hosts, name) + } + + for _, ip := range certificate.IPAddresses { + hosts = append(hosts, ip.String()) + } + + return hosts, nil +} + func (e *InlineCertificateConfigEntry) CanRead(authz acl.Authorizer) error { var authzContext acl.AuthorizerContext e.FillAuthzContext(&authzContext) diff --git a/agent/structs/config_entry_status.go b/agent/structs/config_entry_status.go index faafd34d7b..5485a6ccaf 100644 --- a/agent/structs/config_entry_status.go +++ b/agent/structs/config_entry_status.go @@ -1,6 +1,7 @@ package structs import ( + "fmt" "sort" "time" @@ -24,6 +25,10 @@ type ResourceReference struct { acl.EnterpriseMeta } +func (r *ResourceReference) String() string { + return fmt.Sprintf("%s:%s/%s/%s/%s", r.Kind, r.PartitionOrDefault(), r.NamespaceOrDefault(), r.Name, r.SectionName) +} + func (r *ResourceReference) IsSame(other *ResourceReference) bool { if r == nil && other == nil { return true diff --git a/agent/xds/delta.go b/agent/xds/delta.go index 5a1ef17d24..62a725b8f1 100644 --- a/agent/xds/delta.go +++ b/agent/xds/delta.go @@ -466,20 +466,21 @@ func (s *Server) applyEnvoyExtensions(resources *xdscommon.IndexedResources, cfg return nil } +// https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#eventual-consistency-considerations var xDSUpdateOrder = []xDSUpdateOperation{ - // TODO Update comments + // 1. SDS updates (if any) can be pushed here with no harm. {TypeUrl: xdscommon.SecretType, Upsert: true}, - // 1. CDS updates (if any) must always be pushed first. + // 2. CDS updates (if any) must always be pushed before the following types. {TypeUrl: xdscommon.ClusterType, Upsert: true}, - // 2. EDS updates (if any) must arrive after CDS updates for the respective clusters. + // 3. EDS updates (if any) must arrive after CDS updates for the respective clusters. {TypeUrl: xdscommon.EndpointType, Upsert: true}, - // 3. LDS updates must arrive after corresponding CDS/EDS updates. + // 4. LDS updates must arrive after corresponding CDS/EDS updates. {TypeUrl: xdscommon.ListenerType, Upsert: true, Remove: true}, - // 4. RDS updates related to the newly added listeners must arrive after CDS/EDS/LDS updates. + // 5. RDS updates related to the newly added listeners must arrive after CDS/EDS/LDS updates. {TypeUrl: xdscommon.RouteType, Upsert: true, Remove: true}, - // 5. (NOT IMPLEMENTED YET IN CONSUL) VHDS updates (if any) related to the newly added RouteConfigurations must arrive after RDS updates. + // 6. (NOT IMPLEMENTED YET IN CONSUL) VHDS updates (if any) related to the newly added RouteConfigurations must arrive after RDS updates. // {}, - // 6. Stale CDS clusters, related EDS endpoints (ones no longer being referenced) and SDS secrets can then be removed. + // 7. Stale CDS clusters, related EDS endpoints (ones no longer being referenced) and SDS secrets can then be removed. {TypeUrl: xdscommon.ClusterType, Remove: true}, {TypeUrl: xdscommon.EndpointType, Remove: true}, {TypeUrl: xdscommon.SecretType, Remove: true}, diff --git a/agent/xds/listeners.go b/agent/xds/listeners.go index 291e715176..0c31c42384 100644 --- a/agent/xds/listeners.go +++ b/agent/xds/listeners.go @@ -2328,6 +2328,9 @@ func makeHTTPInspectorListenerFilter() (*envoy_listener_v3.ListenerFilter, error } func makeSNIFilterChainMatch(sniMatches ...string) *envoy_listener_v3.FilterChainMatch { + if sniMatches == nil { + return nil + } return &envoy_listener_v3.FilterChainMatch{ ServerNames: sniMatches, } diff --git a/agent/xds/listeners_ingress.go b/agent/xds/listeners_ingress.go index 6083529849..40eb24230e 100644 --- a/agent/xds/listeners_ingress.go +++ b/agent/xds/listeners_ingress.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/types" ) @@ -25,6 +26,15 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap return nil, fmt.Errorf("no listener config found for listener on proto/port %s/%d", listenerKey.Protocol, listenerKey.Port) } + var isAPIGatewayWithTLS bool + var certs []structs.InlineCertificateConfigEntry + if cfgSnap.APIGateway.ListenerCertificates != nil { + certs = cfgSnap.APIGateway.ListenerCertificates[listenerKey] + } + if certs != nil { + isAPIGatewayWithTLS = true + } + tlsContext, err := makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg) if err != nil { return nil, err @@ -72,6 +82,7 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap logger: s.Logger, } l := makeListener(opts) + filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{ accessLogs: &cfgSnap.Proxy.AccessLogs, routeName: uid.EnvoyID(), @@ -87,8 +98,30 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap l.FilterChains = []*envoy_listener_v3.FilterChain{ filterChain, } - resources = append(resources, l) + if isAPIGatewayWithTLS { + // construct SNI filter chains + l.FilterChains, err = makeInlineOverrideFilterChains(cfgSnap, cfgSnap.IngressGateway.TLSConfig, listenerKey, listenerFilterOpts{ + useRDS: useRDS, + protocol: listenerKey.Protocol, + routeName: listenerKey.RouteName(), + cluster: clusterName, + statPrefix: "ingress_upstream_", + accessLogs: &cfgSnap.Proxy.AccessLogs, + logger: s.Logger, + }, certs) + if err != nil { + return nil, err + } + // add the tls inspector to do SNI introspection + tlsInspector, err := makeTLSInspectorListenerFilter() + if err != nil { + return nil, err + } + l.ListenerFilters = []*envoy_listener_v3.ListenerFilter{tlsInspector} + } + + resources = append(resources, l) } else { // If multiple upstreams share this port, make a special listener for the protocol. listenerOpts := makeListenerOpts{ @@ -121,6 +154,13 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap return nil, err } + if isAPIGatewayWithTLS { + sniFilterChains, err = makeInlineOverrideFilterChains(cfgSnap, cfgSnap.IngressGateway.TLSConfig, listenerKey, filterOpts, certs) + if err != nil { + return nil, err + } + } + // If there are any sni filter chains, we need a TLS inspector filter! if len(sniFilterChains) > 0 { tlsInspector, err := makeTLSInspectorListenerFilter() @@ -134,7 +174,7 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap // See if there are other services that didn't have specific SNI-matching // filter chains. If so add a default filterchain to serve them. - if len(sniFilterChains) < len(upstreams) { + if len(sniFilterChains) < len(upstreams) && !isAPIGatewayWithTLS { defaultFilter, err := makeListenerFilter(filterOpts) if err != nil { return nil, err @@ -379,10 +419,133 @@ func makeSDSOverrideFilterChains(cfgSnap *proxycfg.ConfigSnapshot, return chains, nil } +// when we have multiple certificates on a single listener, we need +// to duplicate the filter chains with multiple TLS contexts +func makeInlineOverrideFilterChains(cfgSnap *proxycfg.ConfigSnapshot, + tlsCfg structs.GatewayTLSConfig, + listenerKey proxycfg.IngressListenerKey, + filterOpts listenerFilterOpts, + certs []structs.InlineCertificateConfigEntry) ([]*envoy_listener_v3.FilterChain, error) { + + listenerCfg, ok := cfgSnap.IngressGateway.Listeners[listenerKey] + if !ok { + return nil, fmt.Errorf("no listener config found for listener on port %d", listenerKey.Port) + } + + var chains []*envoy_listener_v3.FilterChain + + constructChain := func(name string, hosts []string, tlsContext *envoy_tls_v3.CommonTlsContext) error { + filterOpts.filterName = name + filter, err := makeListenerFilter(filterOpts) + if err != nil { + return err + } + + // Configure alpn protocols on TLSContext + tlsContext.AlpnProtocols = getAlpnProtocols(listenerCfg.Protocol) + transportSocket, err := makeDownstreamTLSTransportSocket(&envoy_tls_v3.DownstreamTlsContext{ + CommonTlsContext: tlsContext, + RequireClientCertificate: &wrapperspb.BoolValue{Value: false}, + }) + if err != nil { + return err + } + + chains = append(chains, &envoy_listener_v3.FilterChain{ + FilterChainMatch: makeSNIFilterChainMatch(hosts...), + Filters: []*envoy_listener_v3.Filter{ + filter, + }, + TransportSocket: transportSocket, + }) + + return nil + } + + multipleCerts := len(certs) > 1 + + allCertHosts := map[string]struct{}{} + overlappingHosts := map[string]struct{}{} + + if multipleCerts { + // we only need to prune out overlapping hosts if we have more than + // one certificate + for _, cert := range certs { + hosts, err := cert.Hosts() + if err != nil { + return nil, fmt.Errorf("unable to parse hosts from x509 certificate: %v", hosts) + } + for _, host := range hosts { + if _, ok := allCertHosts[host]; ok { + overlappingHosts[host] = struct{}{} + } + allCertHosts[host] = struct{}{} + } + } + } + + for _, cert := range certs { + var hosts []string + + // if we only have one cert, we just use it for all ingress + if multipleCerts { + // otherwise, we need an SNI per cert and to fallback to our ingress + // gateway certificate signed by our Consul CA + certHosts, err := cert.Hosts() + if err != nil { + return nil, fmt.Errorf("unable to parse hosts from x509 certificate: %v", hosts) + } + // filter out any overlapping hosts so we don't have collisions in our filter chains + for _, host := range certHosts { + if _, ok := overlappingHosts[host]; !ok { + hosts = append(hosts, host) + } + } + + if len(hosts) == 0 { + // all of our hosts are overlapping, so we just skip this filter and it'll be + // handled by the default filter chain + continue + } + } + + if err := constructChain(cert.Name, hosts, makeInlineTLSContextFromGatewayTLSConfig(tlsCfg, cert)); err != nil { + return nil, err + } + } + + if multipleCerts { + // if we have more than one cert, add a default handler that uses the leaf cert from connect + if err := constructChain("default", nil, makeCommonTLSContext(cfgSnap.Leaf(), cfgSnap.RootPEMs(), makeTLSParametersFromGatewayTLSConfig(tlsCfg))); err != nil { + return nil, err + } + } + + return chains, nil +} + func makeTLSParametersFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.TlsParameters { return makeTLSParametersFromTLSConfig(tlsCfg.TLSMinVersion, tlsCfg.TLSMaxVersion, tlsCfg.CipherSuites) } +func makeInlineTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig, cert structs.InlineCertificateConfigEntry) *envoy_tls_v3.CommonTlsContext { + return &envoy_tls_v3.CommonTlsContext{ + TlsParams: makeTLSParametersFromGatewayTLSConfig(tlsCfg), + TlsCertificates: []*envoy_tls_v3.TlsCertificate{{ + CertificateChain: &envoy_core_v3.DataSource{ + Specifier: &envoy_core_v3.DataSource_InlineString{ + InlineString: lib.EnsureTrailingNewline(cert.Certificate), + }, + }, + PrivateKey: &envoy_core_v3.DataSource{ + Specifier: &envoy_core_v3.DataSource_InlineString{ + InlineString: lib.EnsureTrailingNewline(cert.PrivateKey), + }, + }, + }}, + } +} + func makeCommonTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.CommonTlsContext { return &envoy_tls_v3.CommonTlsContext{ TlsParams: makeTLSParametersFromGatewayTLSConfig(tlsCfg), @@ -396,6 +559,7 @@ func makeCommonTLSContextFromGatewayServiceTLSConfig(tlsCfg structs.GatewayServi TlsCertificateSdsSecretConfigs: makeTLSCertificateSdsSecretConfigsFromSDS(*tlsCfg.SDS), } } + func makeTLSCertificateSdsSecretConfigsFromSDS(sdsCfg structs.GatewayTLSSDSConfig) []*envoy_tls_v3.SdsSecretConfig { return []*envoy_tls_v3.SdsSecretConfig{ { diff --git a/agent/xds/listeners_test.go b/agent/xds/listeners_test.go index fffe3dc342..6d0d64407b 100644 --- a/agent/xds/listeners_test.go +++ b/agent/xds/listeners_test.go @@ -527,6 +527,210 @@ func TestListenersFromSnapshot(t *testing.T) { }, nil) }, }, + { + name: "api-gateway", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, nil, nil, nil, nil) + }, + }, + { + name: "api-gateway-nil-config-entry", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway_NilConfigEntry(t) + }, + }, + { + name: "api-gateway-tcp-listener", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) { + entry.Listeners = []structs.APIGatewayListener{ + { + Name: "listener", + Protocol: structs.ListenerProtocolTCP, + Port: 8080, + }, + } + bound.Listeners = []structs.BoundAPIGatewayListener{ + { + Name: "listener", + }, + } + }, nil, nil, nil) + }, + }, + { + name: "api-gateway-tcp-listener-with-tcp-route", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) { + entry.Listeners = []structs.APIGatewayListener{ + { + Name: "listener", + Protocol: structs.ListenerProtocolTCP, + Port: 8080, + }, + } + bound.Listeners = []structs.BoundAPIGatewayListener{ + { + Name: "listener", + Routes: []structs.ResourceReference{ + { + Name: "tcp-route", + Kind: structs.TCPRoute, + }, + }, + }, + } + + }, []structs.BoundRoute{ + &structs.TCPRouteConfigEntry{ + Name: "tcp-route", + Kind: structs.TCPRoute, + Parents: []structs.ResourceReference{ + { + Kind: structs.APIGateway, + Name: "api-gateway", + }, + }, + Services: []structs.TCPService{ + {Name: "tcp-service"}, + }, + }, + }, nil, nil) + }, + }, + { + name: "api-gateway-http-listener", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) { + entry.Listeners = []structs.APIGatewayListener{ + { + Name: "listener", + Protocol: structs.ListenerProtocolHTTP, + Port: 8080, + }, + } + bound.Listeners = []structs.BoundAPIGatewayListener{ + { + Name: "listener", + Routes: []structs.ResourceReference{}, + }, + } + }, nil, nil, nil) + }, + }, + { + name: "api-gateway-http-listener-with-http-route", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) { + entry.Listeners = []structs.APIGatewayListener{ + { + Name: "listener", + Protocol: structs.ListenerProtocolHTTP, + Port: 8080, + }, + } + bound.Listeners = []structs.BoundAPIGatewayListener{ + { + Name: "listener", + Routes: []structs.ResourceReference{ + { + Name: "http-route", + Kind: structs.HTTPRoute, + }, + }, + }, + } + }, []structs.BoundRoute{ + &structs.HTTPRouteConfigEntry{ + Name: "http-route", + Kind: structs.HTTPRoute, + Parents: []structs.ResourceReference{ + { + Kind: structs.APIGateway, + Name: "api-gateway", + }, + }, + Rules: []structs.HTTPRouteRule{ + { + Services: []structs.HTTPService{ + {Name: "http-service"}, + }, + }, + }, + }, + }, nil, nil) + }, + }, + { + name: "api-gateway-tcp-listener-with-tcp-and-http-route", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) { + entry.Listeners = []structs.APIGatewayListener{ + { + Name: "listener-tcp", + Protocol: structs.ListenerProtocolTCP, + Port: 8080, + }, + { + Name: "listener-http", + Protocol: structs.ListenerProtocolHTTP, + Port: 8081, + }, + } + bound.Listeners = []structs.BoundAPIGatewayListener{ + { + Name: "listener-tcp", + Routes: []structs.ResourceReference{ + { + Name: "tcp-route", + Kind: structs.TCPRoute, + }, + }, + }, + { + Name: "listener-http", + Routes: []structs.ResourceReference{ + { + Name: "http-route", + Kind: structs.HTTPRoute, + }, + }, + }, + } + }, []structs.BoundRoute{ + &structs.TCPRouteConfigEntry{ + Name: "tcp-route", + Kind: structs.TCPRoute, + Parents: []structs.ResourceReference{ + { + Kind: structs.APIGateway, + Name: "api-gateway", + }, + }, + Services: []structs.TCPService{ + {Name: "tcp-service"}, + }, + }, + &structs.HTTPRouteConfigEntry{ + Name: "http-route", + Kind: structs.HTTPRoute, + Parents: []structs.ResourceReference{ + { + Kind: structs.APIGateway, + Name: "api-gateway", + }, + }, + Rules: []structs.HTTPRouteRule{ + { + Services: []structs.HTTPService{ + {Name: "http-service"}, + }, + }, + }, + }, + }, nil, nil) + }, + }, { name: "ingress-gateway", create: func(t testinf.T) *proxycfg.ConfigSnapshot { diff --git a/agent/xds/resources.go b/agent/xds/resources.go index 6bd6709343..cab494da4c 100644 --- a/agent/xds/resources.go +++ b/agent/xds/resources.go @@ -35,8 +35,7 @@ func NewResourceGenerator( func (g *ResourceGenerator) AllResourcesFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) (map[string][]proto.Message, error) { all := make(map[string][]proto.Message) - // TODO Add xdscommon.SecretType - for _, typeUrl := range []string{xdscommon.ListenerType, xdscommon.RouteType, xdscommon.ClusterType, xdscommon.EndpointType} { + for _, typeUrl := range []string{xdscommon.ListenerType, xdscommon.RouteType, xdscommon.ClusterType, xdscommon.EndpointType, xdscommon.SecretType} { res, err := g.resourcesFromSnapshot(typeUrl, cfgSnap) if err != nil { return nil, fmt.Errorf("failed to generate xDS resources for %q: %v", typeUrl, err) diff --git a/agent/xds/resources_test.go b/agent/xds/resources_test.go index ad3c1b396c..5fc31dc9e2 100644 --- a/agent/xds/resources_test.go +++ b/agent/xds/resources_test.go @@ -9,6 +9,8 @@ import ( envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" + envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" + "github.com/hashicorp/consul/agent/xds/testcommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" @@ -25,6 +27,7 @@ var testTypeUrlToPrettyName = map[string]string{ xdscommon.RouteType: "routes", xdscommon.ClusterType: "clusters", xdscommon.EndpointType: "endpoints", + xdscommon.SecretType: "secrets", } type goldenTestCase struct { @@ -60,7 +63,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) { // We need to replace the TLS certs with deterministic ones to make golden // files workable. Note we don't update these otherwise they'd change - // golder files for every test case and so not be any use! + // golden files for every test case and so not be any use! testcommon.SetupTLSRootsAndLeaf(t, snap) if tt.setup != nil { @@ -82,6 +85,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) { xdscommon.RouteType, xdscommon.ClusterType, xdscommon.EndpointType, + xdscommon.SecretType, } require.Len(t, resources, len(typeUrls)) @@ -101,6 +105,8 @@ func TestAllResourcesFromSnapshot(t *testing.T) { return items[i].(*envoy_cluster_v3.Cluster).Name < items[j].(*envoy_cluster_v3.Cluster).Name case xdscommon.EndpointType: return items[i].(*envoy_endpoint_v3.ClusterLoadAssignment).ClusterName < items[j].(*envoy_endpoint_v3.ClusterLoadAssignment).ClusterName + case xdscommon.SecretType: + return items[i].(*envoy_tls_v3.Secret).Name < items[j].(*envoy_tls_v3.Secret).Name default: panic("not possible") } @@ -165,6 +171,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) { tests = append(tests, getMeshGatewayPeeringGoldenTestCases()...) tests = append(tests, getTrafficControlPeeringGoldenTestCases()...) tests = append(tests, getEnterpriseGoldenTestCases()...) + tests = append(tests, getAPIGatewayGoldenTestCases()...) latestEnvoyVersion := xdscommon.EnvoyVersions[0] for _, envoyVersion := range xdscommon.EnvoyVersions { @@ -256,3 +263,100 @@ func getTrafficControlPeeringGoldenTestCases() []goldenTestCase { }, } } + +const ( + gatewayTestPrivateKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAx95Opa6t4lGEpiTUogEBptqOdam2ch4BHQGhNhX/MrDwwuZQ +httBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2jQlhqTodElkbsd5vWY8R/bxJWQSo +NvVE12TlzECxGpJEiHt4W0r8pGffk+rvpljiUyCfnT1kGF3znOSjK1hRMTn6RKWC +yYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409g9X5VU88/Bmmrz4cMyxce86Kc2ug +5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftrXOvuCbO5IBRHMOBHiHTZ4rtGuhMa +Ir21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+WmQIDAQABAoIBACYvceUzp2MK4gYA +GWPOP2uKbBdM0l+hHeNV0WAM+dHMfmMuL4pkT36ucqt0ySOLjw6rQyOZG5nmA6t9 +sv0g4ae2eCMlyDIeNi1Yavu4Wt6YX4cTXbQKThm83C6W2X9THKbauBbxD621bsDK +7PhiGPN60yPue7YwFQAPqqD4YaK+s22HFIzk9gwM/rkvAUNwRv7SyHMiFe4Igc1C +Eev7iHWzvj5Heoz6XfF+XNF9DU+TieSUAdjd56VyUb8XL4+uBTOhHwLiXvAmfaMR +HvpcxeKnYZusS6NaOxcUHiJnsLNWrxmJj9WEGgQzuLxcLjTe4vVmELVZD8t3QUKj +PAxu8tUCgYEA7KIWVn9dfVpokReorFym+J8FzLwSktP9RZYEMonJo00i8aii3K9s +u/aSwRWQSCzmON1ZcxZzWhwQF9usz6kGCk//9+4hlVW90GtNK0RD+j7sp4aT2JI8 +9eLEjTG+xSXa7XWe98QncjjL9lu/yrRncSTxHs13q/XP198nn2aYuQ8CgYEA2Dnt +sRBzv0fFEvzzFv7G/5f85mouN38TUYvxNRTjBLCXl9DeKjDkOVZ2b6qlfQnYXIru +H+W+v+AZEb6fySXc8FRab7lkgTMrwE+aeI4rkW7asVwtclv01QJ5wMnyT84AgDD/ +Dgt/RThFaHgtU9TW5GOZveL+l9fVPn7vKFdTJdcCgYEArJ99zjHxwJ1whNAOk1av +09UmRPm6TvRo4heTDk8oEoIWCNatoHI0z1YMLuENNSnT9Q280FFDayvnrY/qnD7A +kktT/sjwJOG8q8trKzIMqQS4XWm2dxoPcIyyOBJfCbEY6XuRsUuePxwh5qF942EB +yS9a2s6nC4Ix0lgPrqAIr48CgYBgS/Q6riwOXSU8nqCYdiEkBYlhCJrKpnJxF9T1 +ofa0yPzKZP/8ZEfP7VzTwHjxJehQ1qLUW9pG08P2biH1UEKEWdzo8vT6wVJT1F/k +HtTycR8+a+Hlk2SHVRHqNUYQGpuIe8mrdJ1as4Pd0d/F/P0zO9Rlh+mAsGPM8HUM +T0+9gwKBgHDoerX7NTskg0H0t8O+iSMevdxpEWp34ZYa9gHiftTQGyrRgERCa7Gj +nZPAxKb2JoWyfnu3v7G5gZ8fhDFsiOxLbZv6UZJBbUIh1MjJISpXrForDrC2QNLX +kHrHfwBFDB3KMudhQknsJzEJKCL/KmFH6o0MvsoaT9yzEl3K+ah/ +-----END RSA PRIVATE KEY-----` + gatewayTestCertificate = `-----BEGIN CERTIFICATE----- +MIICljCCAX4CCQCQMDsYO8FrPjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJV +UzAeFw0yMjEyMjAxNzUwMjVaFw0yNzEyMTkxNzUwMjVaMA0xCzAJBgNVBAYTAlVT +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx95Opa6t4lGEpiTUogEB +ptqOdam2ch4BHQGhNhX/MrDwwuZQhttBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2 +jQlhqTodElkbsd5vWY8R/bxJWQSoNvVE12TlzECxGpJEiHt4W0r8pGffk+rvplji +UyCfnT1kGF3znOSjK1hRMTn6RKWCyYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409 +g9X5VU88/Bmmrz4cMyxce86Kc2ug5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftr +XOvuCbO5IBRHMOBHiHTZ4rtGuhMaIr21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+W +mQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfCqoUIdPf/HGSbOorPyZWbyizNtHJ +GL7x9cAeIYxpI5Y/WcO1o5v94lvrgm3FNfJoGKbV66+JxOge731FrfMpHplhar1Z +RahYIzNLRBTLrwadLAZkApUpZvB8qDK4knsTWFYujNsylCww2A6ajzIMFNU4GkUK +NtyHRuD+KYRmjXtyX1yHNqfGN3vOQmwavHq2R8wHYuBSc6LAHHV9vG+j0VsgMELO +qwxn8SmLkSKbf2+MsQVzLCXXN5u+D8Yv+4py+oKP4EQ5aFZuDEx+r/G/31rTthww +AAJAMaoXmoYVdgXV+CPuBb2M4XCpuzLu3bcA2PXm5ipSyIgntMKwXV7r +-----END CERTIFICATE-----` +) + +func getAPIGatewayGoldenTestCases() []goldenTestCase { + return []goldenTestCase{ + { + name: "api-gateway-with-tcp-route-and-inline-certificate", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) { + entry.Listeners = []structs.APIGatewayListener{ + { + Name: "listener", + Protocol: structs.ListenerProtocolTCP, + Port: 8080, + TLS: structs.APIGatewayTLSConfiguration{ + Certificates: []structs.ResourceReference{{ + Kind: structs.InlineCertificate, + Name: "certificate", + }}, + }, + }, + } + bound.Listeners = []structs.BoundAPIGatewayListener{ + { + Name: "listener", + Certificates: []structs.ResourceReference{{ + Kind: structs.InlineCertificate, + Name: "certificate", + }}, + Routes: []structs.ResourceReference{{ + Kind: structs.TCPRoute, + Name: "route", + }}, + }, + } + }, []structs.BoundRoute{ + &structs.TCPRouteConfigEntry{ + Kind: structs.TCPRoute, + Name: "route", + Services: []structs.TCPService{{ + Name: "service", + }}, + }, + }, []structs.InlineCertificateConfigEntry{{ + Kind: structs.InlineCertificate, + Name: "certificate", + PrivateKey: gatewayTestPrivateKey, + Certificate: gatewayTestCertificate, + }}, nil) + }, + }, + } +} diff --git a/agent/xds/secrets.go b/agent/xds/secrets.go index 5547b6d203..a1ef50e44c 100644 --- a/agent/xds/secrets.go +++ b/agent/xds/secrets.go @@ -21,18 +21,10 @@ func (s *ResourceGenerator) secretsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot case structs.ServiceKindConnectProxy, structs.ServiceKindTerminatingGateway, structs.ServiceKindMeshGateway, - structs.ServiceKindIngressGateway: + structs.ServiceKindIngressGateway, + structs.ServiceKindAPIGateway: return nil, nil - // Only API gateways utilize secrets - case structs.ServiceKindAPIGateway: - return s.secretsFromSnapshotAPIGateway(cfgSnap) default: return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind) } } - -func (s *ResourceGenerator) secretsFromSnapshotAPIGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) { - var res []proto.Message - // TODO - return res, nil -} diff --git a/agent/xds/testcommon/testcommon.go b/agent/xds/testcommon/testcommon.go index c310d0980a..ba75cf9ae9 100644 --- a/agent/xds/testcommon/testcommon.go +++ b/agent/xds/testcommon/testcommon.go @@ -22,6 +22,9 @@ func SetupTLSRootsAndLeaf(t *testing.T, snap *proxycfg.ConfigSnapshot) { case structs.ServiceKindMeshGateway: snap.MeshGateway.Leaf.CertPEM = loadTestResource(t, "test-leaf-cert") snap.MeshGateway.Leaf.PrivateKeyPEM = loadTestResource(t, "test-leaf-key") + case structs.ServiceKindAPIGateway: + snap.APIGateway.Leaf.CertPEM = loadTestResource(t, "test-leaf-cert") + snap.APIGateway.Leaf.PrivateKeyPEM = loadTestResource(t, "test-leaf-key") } } if snap.Roots != nil { diff --git a/agent/xds/testdata/clusters/api-gateway-with-tcp-route-and-inline-certificate.latest.golden b/agent/xds/testdata/clusters/api-gateway-with-tcp-route-and-inline-certificate.latest.golden new file mode 100644 index 0000000000..e20479dfd1 --- /dev/null +++ b/agent/xds/testdata/clusters/api-gateway-with-tcp-route-and-inline-certificate.latest.golden @@ -0,0 +1,55 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "service.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/service" + } + ] + } + }, + "sni": "service.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/endpoints/api-gateway-with-tcp-route-and-inline-certificate.latest.golden b/agent/xds/testdata/endpoints/api-gateway-with-tcp-route-and-inline-certificate.latest.golden new file mode 100644 index 0000000000..47b46bca22 --- /dev/null +++ b/agent/xds/testdata/endpoints/api-gateway-with-tcp-route-and-inline-certificate.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-http-listener-with-http-route.latest.golden b/agent/xds/testdata/listeners/api-gateway-http-listener-with-http-route.latest.golden new file mode 100644 index 0000000000..e9bee988de --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-http-listener-with-http-route.latest.golden @@ -0,0 +1,49 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "http:1.2.3.4:8080", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "ingress_upstream_8080", + "rds": { + "configSource": { + "ads": {}, + "resourceApiVersion": "V3" + }, + "routeConfigName": "8080" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + } + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-http-listener.latest.golden b/agent/xds/testdata/listeners/api-gateway-http-listener.latest.golden new file mode 100644 index 0000000000..d2d839adf9 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-http-listener.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-nil-config-entry.latest.golden b/agent/xds/testdata/listeners/api-gateway-nil-config-entry.latest.golden new file mode 100644 index 0000000000..d2d839adf9 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-nil-config-entry.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-and-http-route.latest.golden b/agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-and-http-route.latest.golden new file mode 100644 index 0000000000..9e13678076 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-and-http-route.latest.golden @@ -0,0 +1,74 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "http:1.2.3.4:8081", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8081 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "ingress_upstream_8081", + "rds": { + "configSource": { + "ads": {}, + "resourceApiVersion": "V3" + }, + "routeConfigName": "8081" + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + } + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "tcp-service:1.2.3.4:8080", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.tcp-service.default.default.dc1", + "cluster": "tcp-service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-route.latest.golden b/agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-route.latest.golden new file mode 100644 index 0000000000..ffcb5830b9 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-route.latest.golden @@ -0,0 +1,32 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "tcp-service:1.2.3.4:8080", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.tcp-service.default.default.dc1", + "cluster": "tcp-service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-tcp-listener.latest.golden b/agent/xds/testdata/listeners/api-gateway-tcp-listener.latest.golden new file mode 100644 index 0000000000..d2d839adf9 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-tcp-listener.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway-with-tcp-route-and-inline-certificate.latest.golden b/agent/xds/testdata/listeners/api-gateway-with-tcp-route-and-inline-certificate.latest.golden new file mode 100644 index 0000000000..3bfbb71f06 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway-with-tcp-route-and-inline-certificate.latest.golden @@ -0,0 +1,60 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "service:1.2.3.4:8080", + "address": { + "socketAddress": { + "address": "1.2.3.4", + "portValue": 8080 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "ingress_upstream_certificate", + "cluster": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICljCCAX4CCQCQMDsYO8FrPjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJV\nUzAeFw0yMjEyMjAxNzUwMjVaFw0yNzEyMTkxNzUwMjVaMA0xCzAJBgNVBAYTAlVT\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx95Opa6t4lGEpiTUogEB\nptqOdam2ch4BHQGhNhX/MrDwwuZQhttBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2\njQlhqTodElkbsd5vWY8R/bxJWQSoNvVE12TlzECxGpJEiHt4W0r8pGffk+rvplji\nUyCfnT1kGF3znOSjK1hRMTn6RKWCyYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409\ng9X5VU88/Bmmrz4cMyxce86Kc2ug5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftr\nXOvuCbO5IBRHMOBHiHTZ4rtGuhMaIr21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+W\nmQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfCqoUIdPf/HGSbOorPyZWbyizNtHJ\nGL7x9cAeIYxpI5Y/WcO1o5v94lvrgm3FNfJoGKbV66+JxOge731FrfMpHplhar1Z\nRahYIzNLRBTLrwadLAZkApUpZvB8qDK4knsTWFYujNsylCww2A6ajzIMFNU4GkUK\nNtyHRuD+KYRmjXtyX1yHNqfGN3vOQmwavHq2R8wHYuBSc6LAHHV9vG+j0VsgMELO\nqwxn8SmLkSKbf2+MsQVzLCXXN5u+D8Yv+4py+oKP4EQ5aFZuDEx+r/G/31rTthww\nAAJAMaoXmoYVdgXV+CPuBb2M4XCpuzLu3bcA2PXm5ipSyIgntMKwXV7r\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAx95Opa6t4lGEpiTUogEBptqOdam2ch4BHQGhNhX/MrDwwuZQ\nhttBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2jQlhqTodElkbsd5vWY8R/bxJWQSo\nNvVE12TlzECxGpJEiHt4W0r8pGffk+rvpljiUyCfnT1kGF3znOSjK1hRMTn6RKWC\nyYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409g9X5VU88/Bmmrz4cMyxce86Kc2ug\n5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftrXOvuCbO5IBRHMOBHiHTZ4rtGuhMa\nIr21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+WmQIDAQABAoIBACYvceUzp2MK4gYA\nGWPOP2uKbBdM0l+hHeNV0WAM+dHMfmMuL4pkT36ucqt0ySOLjw6rQyOZG5nmA6t9\nsv0g4ae2eCMlyDIeNi1Yavu4Wt6YX4cTXbQKThm83C6W2X9THKbauBbxD621bsDK\n7PhiGPN60yPue7YwFQAPqqD4YaK+s22HFIzk9gwM/rkvAUNwRv7SyHMiFe4Igc1C\nEev7iHWzvj5Heoz6XfF+XNF9DU+TieSUAdjd56VyUb8XL4+uBTOhHwLiXvAmfaMR\nHvpcxeKnYZusS6NaOxcUHiJnsLNWrxmJj9WEGgQzuLxcLjTe4vVmELVZD8t3QUKj\nPAxu8tUCgYEA7KIWVn9dfVpokReorFym+J8FzLwSktP9RZYEMonJo00i8aii3K9s\nu/aSwRWQSCzmON1ZcxZzWhwQF9usz6kGCk//9+4hlVW90GtNK0RD+j7sp4aT2JI8\n9eLEjTG+xSXa7XWe98QncjjL9lu/yrRncSTxHs13q/XP198nn2aYuQ8CgYEA2Dnt\nsRBzv0fFEvzzFv7G/5f85mouN38TUYvxNRTjBLCXl9DeKjDkOVZ2b6qlfQnYXIru\nH+W+v+AZEb6fySXc8FRab7lkgTMrwE+aeI4rkW7asVwtclv01QJ5wMnyT84AgDD/\nDgt/RThFaHgtU9TW5GOZveL+l9fVPn7vKFdTJdcCgYEArJ99zjHxwJ1whNAOk1av\n09UmRPm6TvRo4heTDk8oEoIWCNatoHI0z1YMLuENNSnT9Q280FFDayvnrY/qnD7A\nkktT/sjwJOG8q8trKzIMqQS4XWm2dxoPcIyyOBJfCbEY6XuRsUuePxwh5qF942EB\nyS9a2s6nC4Ix0lgPrqAIr48CgYBgS/Q6riwOXSU8nqCYdiEkBYlhCJrKpnJxF9T1\nofa0yPzKZP/8ZEfP7VzTwHjxJehQ1qLUW9pG08P2biH1UEKEWdzo8vT6wVJT1F/k\nHtTycR8+a+Hlk2SHVRHqNUYQGpuIe8mrdJ1as4Pd0d/F/P0zO9Rlh+mAsGPM8HUM\nT0+9gwKBgHDoerX7NTskg0H0t8O+iSMevdxpEWp34ZYa9gHiftTQGyrRgERCa7Gj\nnZPAxKb2JoWyfnu3v7G5gZ8fhDFsiOxLbZv6UZJBbUIh1MjJISpXrForDrC2QNLX\nkHrHfwBFDB3KMudhQknsJzEJKCL/KmFH6o0MvsoaT9yzEl3K+ah/\n-----END RSA PRIVATE KEY-----\n" + } + } + ] + }, + "requireClientCertificate": false + } + } + } + ], + "listenerFilters": [ + { + "name": "envoy.filters.listener.tls_inspector", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector" + } + } + ], + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/listeners/api-gateway.latest.golden b/agent/xds/testdata/listeners/api-gateway.latest.golden new file mode 100644 index 0000000000..d2d839adf9 --- /dev/null +++ b/agent/xds/testdata/listeners/api-gateway.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/routes/api-gateway-with-tcp-route-and-inline-certificate.latest.golden b/agent/xds/testdata/routes/api-gateway-with-tcp-route-and-inline-certificate.latest.golden new file mode 100644 index 0000000000..306f5220e7 --- /dev/null +++ b/agent/xds/testdata/routes/api-gateway-with-tcp-route-and-inline-certificate.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/api-gateway-with-tcp-route-and-inline-certificate.latest.golden b/agent/xds/testdata/secrets/api-gateway-with-tcp-route-and-inline-certificate.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/api-gateway-with-tcp-route-and-inline-certificate.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/connect-proxy-exported-to-peers.latest.golden b/agent/xds/testdata/secrets/connect-proxy-exported-to-peers.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/connect-proxy-exported-to-peers.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/connect-proxy-with-chain-and-failover-to-cluster-peer.latest.golden b/agent/xds/testdata/secrets/connect-proxy-with-chain-and-failover-to-cluster-peer.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/connect-proxy-with-chain-and-failover-to-cluster-peer.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden b/agent/xds/testdata/secrets/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/connect-proxy-with-peered-upstreams.latest.golden b/agent/xds/testdata/secrets/connect-proxy-with-peered-upstreams.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/connect-proxy-with-peered-upstreams.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/defaults.latest.golden b/agent/xds/testdata/secrets/defaults.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/defaults.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/local-mesh-gateway-with-peered-upstreams.latest.golden b/agent/xds/testdata/secrets/local-mesh-gateway-with-peered-upstreams.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/local-mesh-gateway-with-peered-upstreams.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/mesh-gateway-peering-control-plane.latest.golden b/agent/xds/testdata/secrets/mesh-gateway-peering-control-plane.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/mesh-gateway-peering-control-plane.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden b/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http-with-router.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http.latest.golden b/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services.latest.golden b/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/mesh-gateway-with-imported-peered-services.latest.golden b/agent/xds/testdata/secrets/mesh-gateway-with-imported-peered-services.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/mesh-gateway-with-imported-peered-services.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/mesh-gateway-with-peer-through-mesh-gateway-enabled.latest.golden b/agent/xds/testdata/secrets/mesh-gateway-with-peer-through-mesh-gateway-enabled.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/mesh-gateway-with-peer-through-mesh-gateway-enabled.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/transparent-proxy-destination-http.latest.golden b/agent/xds/testdata/secrets/transparent-proxy-destination-http.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/transparent-proxy-destination-http.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/transparent-proxy-destination.latest.golden b/agent/xds/testdata/secrets/transparent-proxy-destination.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/transparent-proxy-destination.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/transparent-proxy-terminating-gateway-destinations-only.latest.golden b/agent/xds/testdata/secrets/transparent-proxy-terminating-gateway-destinations-only.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/transparent-proxy-terminating-gateway-destinations-only.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/transparent-proxy-with-peered-upstreams.latest.golden b/agent/xds/testdata/secrets/transparent-proxy-with-peered-upstreams.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/transparent-proxy-with-peered-upstreams.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/secrets/transparent-proxy.latest.golden b/agent/xds/testdata/secrets/transparent-proxy.latest.golden new file mode 100644 index 0000000000..e6c25e165c --- /dev/null +++ b/agent/xds/testdata/secrets/transparent-proxy.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "nonce": "00000001" +} \ No newline at end of file diff --git a/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/capture.sh b/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/capture.sh new file mode 100644 index 0000000000..8ba0e0ddab --- /dev/null +++ b/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/capture.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +snapshot_envoy_admin localhost:20000 api-gateway primary || true \ No newline at end of file diff --git a/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/service_gateway.hcl b/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/service_gateway.hcl new file mode 100644 index 0000000000..486c25c59e --- /dev/null +++ b/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/service_gateway.hcl @@ -0,0 +1,4 @@ +services { + name = "api-gateway" + kind = "api-gateway" +} diff --git a/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/setup.sh b/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/setup.sh new file mode 100644 index 0000000000..2b2cbd160f --- /dev/null +++ b/test/integration/connect/envoy/case-api-gateway-http-tls-overlapping-hosts/setup.sh @@ -0,0 +1,287 @@ +#!/bin/bash + +set -euo pipefail + +upsert_config_entry primary ' +kind = "api-gateway" +name = "api-gateway" +listeners = [ + { + name = "listener-one" + port = 9999 + protocol = "http" + tls = { + certificates = [ + { + kind = "inline-certificate" + name = "host-consul-example" + } + ] + } + }, + { + name = "listener-two" + port = 9998 + protocol = "http" + tls = { + certificates = [ + { + kind = "inline-certificate" + name = "host-consul-example" + }, + { + kind = "inline-certificate" + name = "also-host-consul-example" + }, + { + kind = "inline-certificate" + name = "other-consul-example" + } + ] + } + } +] +' + +upsert_config_entry primary ' +kind = "inline-certificate" +name = "host-consul-example" +private_key = </dev/null) + + echo "WANT CN: ${CN} (SNI: ${SERVER_NAME})" + echo "GOT CERT:" + echo "$CERT" + + echo "$CERT" | grep "CN = ${CN}" +} + function assert_envoy_version { local ADMINPORT=$1 run retry_default curl -f -s localhost:$ADMINPORT/server_info