From 62062fd4fd36895c38a162cdc414fedd629c70bd Mon Sep 17 00:00:00 2001 From: John Murret Date: Mon, 11 Sep 2023 19:17:56 -0600 Subject: [PATCH] NET-5132 - Configure multiport routing for connect proxies in TProxy mode (#18606) * mesh-controller: handle L4 protocols for a proxy without upstreams * sidecar-controller: Support explicit destinations for L4 protocols and single ports. * This controller generates and saves ProxyStateTemplate for sidecar proxies. * It currently supports single-port L4 ports only. * It keeps a cache of all destinations to make it easier to compute and retrieve destinations. * It will update the status of the pbmesh.Upstreams resource if anything is invalid. * endpoints-controller: add workload identity to the service endpoints resource * small fixes * review comments * Address PR comments * sidecar-proxy controller: Add support for transparent proxy This currently does not support inferring destinations from intentions. * PR review comments * mesh-controller: handle L4 protocols for a proxy without upstreams * sidecar-controller: Support explicit destinations for L4 protocols and single ports. * This controller generates and saves ProxyStateTemplate for sidecar proxies. * It currently supports single-port L4 ports only. * It keeps a cache of all destinations to make it easier to compute and retrieve destinations. * It will update the status of the pbmesh.Upstreams resource if anything is invalid. * endpoints-controller: add workload identity to the service endpoints resource * small fixes * review comments * Make sure endpoint refs route to mesh port instead of an app port * Address PR comments * fixing copyright * tidy imports * sidecar-proxy controller: Add support for transparent proxy This currently does not support inferring destinations from intentions. * tidy imports * add copyright headers * Prefix sidecar proxy test files with source and destination. * Update controller_test.go * NET-5132 - Configure multiport routing for connect proxies in TProxy mode * formatting golden files * reverting golden files and adding changes in manually. build implicit destinations still has some issues. * fixing files that were incorrectly repeating the outbound listener * PR comments * extract AlpnProtocol naming convention to getAlpnProtocolFromPortName(portName) * removing address level filtering. * adding license to resources_test.go --------- Co-authored-by: Iryna Shustava Co-authored-by: R.B. Boyer Co-authored-by: github-team-consul-core --- agent/agent.go | 36 +- agent/consul/server.go | 2 +- agent/xds/delta.go | 3 +- agent/xdsv2/listener_resources.go | 12 + agent/xdsv2/resources_test.go | 111 ++++++ ...-single-implicit-destination-tproxy.golden | 85 +++++ ...-single-implicit-destination-tproxy.golden | 18 + ...-single-implicit-destination-tproxy.golden | 49 +++ internal/mesh/exports.go | 19 +- .../sidecarproxy/builder/builder_test.go | 13 + .../builder/destination_builder.go | 202 ++++++---- .../destination_builder_multiport_test.go | 182 +++++++++ .../builder/destination_builder_test.go | 47 ++- .../sidecarproxy/builder/local_app.go | 26 +- .../builder/local_app_multiport_test.go | 101 +++++ .../sidecarproxy/builder/naming.go | 7 +- .../sidecarproxy/builder/service_port_info.go | 80 ++++ .../builder/service_port_info_test.go | 49 +++ ...it-and-explicit-destinations-tproxy.golden | 81 +--- .../destination/l4-multi-destination.golden | 18 +- ...ltiple-implicit-destinations-tproxy.golden | 245 +----------- ...le-destination-ip-port-bind-address.golden | 9 +- ...estination-unix-socket-bind-address.golden | 9 +- ...-single-implicit-destination-tproxy.golden | 64 +--- ...tiple-implicit-destinations-tproxy.golden} | 274 +++++++------ ...single-implicit-destination-tproxy.golden} | 188 +++++---- ...ion-with-multiple-workloads-tproxy.golden} | 168 ++++---- ...ltiple-implicit-destinations-tproxy.golden | 360 ------------------ ...l4-single-destination-ip-port-bind-address | 70 ---- ...ingle-destination-unix-socket-bind-address | 70 ---- ...kload-addresses-with-specific-ports.golden | 5 + ...le-workload-addresses-without-ports.golden | 5 + ...ngle-workload-address-without-ports.golden | 5 + ...kload-addresses-with-specific-ports.golden | 113 ++++++ ...le-workload-addresses-without-ports.golden | 113 ++++++ ...ngle-workload-address-without-ports.golden | 113 ++++++ internal/testing/golden/golden.go | 12 +- .../v1alpha1/pbproxystate/listener.pb.go | 247 ++++++------ .../v1alpha1/pbproxystate/listener.proto | 9 +- 39 files changed, 1798 insertions(+), 1422 deletions(-) create mode 100644 agent/xdsv2/resources_test.go create mode 100644 agent/xdsv2/testdata/input/l4-single-implicit-destination-tproxy.golden create mode 100644 agent/xdsv2/testdata/output/clusters/l4-single-implicit-destination-tproxy.golden create mode 100644 agent/xdsv2/testdata/output/listeners/l4-single-implicit-destination-tproxy.golden create mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_multiport_test.go create mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/local_app_multiport_test.go create mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info.go create mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info_test.go rename internal/mesh/internal/controllers/sidecarproxy/builder/testdata/{l4-implicit-and-explicit-destinations-tproxy.golden => destination/multiport-l4-multiple-implicit-destinations-tproxy.golden} (50%) rename internal/mesh/internal/controllers/sidecarproxy/builder/testdata/{l4-single-implicit-destination-tproxy.golden => destination/multiport-l4-single-implicit-destination-tproxy.golden} (55%) rename internal/mesh/internal/controllers/sidecarproxy/builder/testdata/{l4-multi-destination => destination/multiport-l4-single-implicit-destination-with-multiple-workloads-tproxy.golden} (50%) delete mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-multiple-implicit-destinations-tproxy.golden delete mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-ip-port-bind-address delete mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-unix-socket-bind-address create mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-with-specific-ports.golden create mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-without-ports.golden create mode 100644 internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-single-workload-address-without-ports.golden diff --git a/agent/agent.go b/agent/agent.go index 606fbca594..a868b4379c 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -947,20 +947,28 @@ func (a *Agent) configureXDSServer(proxyWatcher xds.ProxyWatcher) { // TODO(agentless): rather than asserting the concrete type of delegate, we // should add a method to the Delegate interface to build a ConfigSource. if server, ok := a.delegate.(*consul.Server); ok { - catalogCfg := catalogproxycfg.NewConfigSource(catalogproxycfg.Config{ - NodeName: a.config.NodeName, - LocalState: a.State, - LocalConfigSource: proxyWatcher, - Manager: a.proxyConfig, - GetStore: func() catalogproxycfg.Store { return server.FSM().State() }, - Logger: a.proxyConfig.Logger.Named("server-catalog"), - SessionLimiter: a.baseDeps.XDSStreamLimiter, - }) - go func() { - <-a.shutdownCh - catalogCfg.Shutdown() - }() - proxyWatcher = catalogCfg + switch proxyWatcher.(type) { + case *proxytracker.ProxyTracker: + go func() { + <-a.shutdownCh + proxyWatcher.(*proxytracker.ProxyTracker).Shutdown() + }() + default: + catalogCfg := catalogproxycfg.NewConfigSource(catalogproxycfg.Config{ + NodeName: a.config.NodeName, + LocalState: a.State, + LocalConfigSource: proxyWatcher, + Manager: a.proxyConfig, + GetStore: func() catalogproxycfg.Store { return server.FSM().State() }, + Logger: a.proxyConfig.Logger.Named("server-catalog"), + SessionLimiter: a.baseDeps.XDSStreamLimiter, + }) + go func() { + <-a.shutdownCh + catalogCfg.Shutdown() + }() + proxyWatcher = catalogCfg + } } a.xdsServer = xds.NewServer( a.config.NodeName, diff --git a/agent/consul/server.go b/agent/consul/server.go index 0b8345947a..4149f337b3 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -909,7 +909,6 @@ func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) { } return &bundle, nil }, - ProxyUpdater: proxyUpdater, // This function is adapted from server_connect.go:getCARoots. TrustDomainFetcher: func() (string, error) { _, caConfig, err := s.fsm.State().CAConfig(nil) @@ -920,6 +919,7 @@ func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) { return s.getTrustDomain(caConfig) }, LocalDatacenter: s.config.Datacenter, + ProxyUpdater: proxyUpdater, }) } diff --git a/agent/xds/delta.go b/agent/xds/delta.go index d239f2bd51..a0894954ea 100644 --- a/agent/xds/delta.go +++ b/agent/xds/delta.go @@ -428,8 +428,9 @@ func newResourceIDFromEnvoyNode(node *envoy_config_core_v3.Node) *pbresource.ID Tenancy: &pbresource.Tenancy{ Namespace: entMeta.NamespaceOrDefault(), Partition: entMeta.PartitionOrDefault(), + PeerName: "local", }, - Type: mesh.ProxyStateTemplateConfigurationV1Alpha1Type, + Type: mesh.ProxyStateTemplateV1AlphaType, } } diff --git a/agent/xdsv2/listener_resources.go b/agent/xdsv2/listener_resources.go index f3a241f0cb..8a5c974ce9 100644 --- a/agent/xdsv2/listener_resources.go +++ b/agent/xdsv2/listener_resources.go @@ -275,6 +275,14 @@ func makeEnvoyFilterChainMatch(routerMatch *pbproxystate.Match) *envoy_listener_ } envoyFilterChainMatch.SourcePrefixRanges = ranges } + if len(routerMatch.AlpnProtocols) > 0 { + sort.Strings(routerMatch.AlpnProtocols) + var alpnProtocols []string + for _, protocol := range routerMatch.AlpnProtocols { + alpnProtocols = append(alpnProtocols, protocol) + } + envoyFilterChainMatch.ApplicationProtocols = alpnProtocols + } } return envoyFilterChainMatch } @@ -527,6 +535,10 @@ func (pr *ProxyResources) makeEnvoyTLSParameters(defaultParams *pbproxystate.TLS } func (pr *ProxyResources) makeEnvoyTransportSocket(ts *pbproxystate.TransportSocket) (*envoy_core_v3.TransportSocket, error) { + // TODO(JM): did this just make tests pass. Figure out whether proxyState.Tls will always be available. + if pr.proxyState.Tls == nil { + return nil, nil + } if ts == nil { return nil, nil } diff --git a/agent/xdsv2/resources_test.go b/agent/xdsv2/resources_test.go new file mode 100644 index 0000000000..edc20bccc4 --- /dev/null +++ b/agent/xdsv2/resources_test.go @@ -0,0 +1,111 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package xdsv2 + +import ( + envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" + envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" + "github.com/hashicorp/consul/agent/xds/response" + "github.com/hashicorp/consul/envoyextensions/xdscommon" + proxytracker "github.com/hashicorp/consul/internal/mesh/proxy-tracker" + meshv1alpha1 "github.com/hashicorp/consul/proto-public/pbmesh/v1alpha1" + "github.com/hashicorp/consul/sdk/testutil" + "os" + "path/filepath" + "sort" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +func TestResources_ImplicitDestinations(t *testing.T) { + + cases := map[string]struct { + }{ + "l4-single-implicit-destination-tproxy": {}, + } + + for name := range cases { + goldenValueInput := goldenValueJSON(t, name, "input") + + proxyTemplate := jsonToProxyTemplate(t, goldenValueInput) + generator := NewResourceGenerator(testutil.Logger(t)) + + resources, err := generator.AllResourcesFromIR(&proxytracker.ProxyState{ProxyState: proxyTemplate.ProxyState}) + require.NoError(t, err) + + verifyClusterResourcesToGolden(t, resources, name) + verifyListenerResourcesToGolden(t, resources, name) + + } +} + +func verifyClusterResourcesToGolden(t *testing.T, resources map[string][]proto.Message, testName string) { + clusters := resources[xdscommon.ClusterType] + + // The order of clusters returned via CDS isn't relevant, so it's safe + // to sort these for the purposes of test comparisons. + sort.Slice(clusters, func(i, j int) bool { + return clusters[i].(*envoy_cluster_v3.Cluster).Name < clusters[j].(*envoy_cluster_v3.Cluster).Name + }) + + resp, err := response.CreateResponse(xdscommon.ClusterType, "00000001", "00000001", clusters) + require.NoError(t, err) + gotJSON := protoToJSON(t, resp) + + expectedJSON := goldenValue(t, filepath.Join("clusters", testName), "output") + require.JSONEq(t, expectedJSON, gotJSON) +} + +func verifyListenerResourcesToGolden(t *testing.T, resources map[string][]proto.Message, testName string) { + listeners := resources[xdscommon.ListenerType] + + // The order of clusters returned via CDS isn't relevant, so it's safe + // to sort these for the purposes of test comparisons. + sort.Slice(listeners, func(i, j int) bool { + return listeners[i].(*envoy_listener_v3.Listener).Name < listeners[j].(*envoy_listener_v3.Listener).Name + }) + + resp, err := response.CreateResponse(xdscommon.ListenerType, "00000001", "00000001", listeners) + require.NoError(t, err) + gotJSON := protoToJSON(t, resp) + + expectedJSON := goldenValue(t, filepath.Join("listeners", testName), "output") + require.JSONEq(t, expectedJSON, gotJSON) +} + +func protoToJSON(t *testing.T, pb proto.Message) string { + t.Helper() + m := protojson.MarshalOptions{ + Indent: " ", + } + gotJSON, err := m.Marshal(pb) + require.NoError(t, err) + return string(gotJSON) +} + +func jsonToProxyTemplate(t *testing.T, json []byte) *meshv1alpha1.ProxyStateTemplate { + t.Helper() + um := protojson.UnmarshalOptions{} + proxyTemplate := &meshv1alpha1.ProxyStateTemplate{} + err := um.Unmarshal(json, proxyTemplate) + require.NoError(t, err) + return proxyTemplate +} + +func goldenValueJSON(t *testing.T, goldenFile, inputOutput string) []byte { + t.Helper() + goldenPath := filepath.Join("testdata", inputOutput, goldenFile) + ".golden" + + content, err := os.ReadFile(goldenPath) + require.NoError(t, err) + return content +} + +func goldenValue(t *testing.T, goldenFile, inputOutput string) string { + t.Helper() + return string(goldenValueJSON(t, goldenFile, inputOutput)) +} diff --git a/agent/xdsv2/testdata/input/l4-single-implicit-destination-tproxy.golden b/agent/xdsv2/testdata/input/l4-single-implicit-destination-tproxy.golden new file mode 100644 index 0000000000..8d0714e86c --- /dev/null +++ b/agent/xdsv2/testdata/input/l4-single-implicit-destination-tproxy.golden @@ -0,0 +1,85 @@ +{ + "proxyState": { + "identity": { + "tenancy": { + "partition": "default", + "namespace": "default", + "peerName": "local" + }, + "name": "test-identity" + }, + "listeners": [ + { + "name": "outbound_listener", + "direction": "DIRECTION_OUTBOUND", + "hostPort": { + "host": "127.0.0.1", + "port": 15001 + }, + "routers": [ + { + "match": { + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ], + "destinationPort": 8080 + }, + "l4": { + "name": "tcp.api-1.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-1.default.default.dc1" + } + } + ], + "capabilities": [ + "CAPABILITY_TRANSPARENT" + ] + } + ], + "clusters": { + "tcp.api-1.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api1-identity" + ] + }, + "sni": "api-1.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~tcp" + ] + } + } + } + } + } + }, + "requiredEndpoints": { + "api-1.default.dc1.internal.foo.consul": { + "id": { + "name": "api-1", + "type": { + "group": "catalog", + "groupVersion": "v1alpha1", + "kind": "ServiceEndpoints" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peerName": "local" + } + }, + "port": "mesh" + } + } +} \ No newline at end of file diff --git a/agent/xdsv2/testdata/output/clusters/l4-single-implicit-destination-tproxy.golden b/agent/xdsv2/testdata/output/clusters/l4-single-implicit-destination-tproxy.golden new file mode 100644 index 0000000000..d4f50e5ccc --- /dev/null +++ b/agent/xdsv2/testdata/output/clusters/l4-single-implicit-destination-tproxy.golden @@ -0,0 +1,18 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "name": "tcp.api-1.default.dc1.internal.foo.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": {}, + "resourceApiVersion": "V3" + } + } + } + ], + "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xdsv2/testdata/output/listeners/l4-single-implicit-destination-tproxy.golden b/agent/xdsv2/testdata/output/listeners/l4-single-implicit-destination-tproxy.golden new file mode 100644 index 0000000000..816161b266 --- /dev/null +++ b/agent/xdsv2/testdata/output/listeners/l4-single-implicit-destination-tproxy.golden @@ -0,0 +1,49 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "outbound_listener", + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 15001 + } + }, + "filterChains": [ + { + "filterChainMatch": { + "destinationPort": 8080, + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ] + }, + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.tcp.api-1.default.default.dc1", + "cluster": "tcp.api-1.default.dc1.internal.foo.consul" + } + } + ] + } + ], + "listenerFilters": [ + { + "name": "envoy.filters.listener.original_dst", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst" + } + } + ], + "trafficDirection": "OUTBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/internal/mesh/exports.go b/internal/mesh/exports.go index dc3c31649b..152847f3b5 100644 --- a/internal/mesh/exports.go +++ b/internal/mesh/exports.go @@ -34,16 +34,15 @@ var ( // Resource Types for the v1alpha1 version. - ProxyConfigurationV1Alpha1Type = types.ProxyConfigurationV1Alpha1Type - UpstreamsV1Alpha1Type = types.UpstreamsV1Alpha1Type - UpstreamsConfigurationV1Alpha1Type = types.UpstreamsConfigurationV1Alpha1Type - ProxyStateTemplateConfigurationV1Alpha1Type = types.ProxyStateTemplateV1Alpha1Type - HTTPRouteV1Alpha1Type = types.HTTPRouteV1Alpha1Type - GRPCRouteV1Alpha1Type = types.GRPCRouteV1Alpha1Type - TCPRouteV1Alpha1Type = types.TCPRouteV1Alpha1Type - DestinationPolicyV1Alpha1Type = types.DestinationPolicyV1Alpha1Type - ComputedRoutesV1Alpha1Type = types.ComputedRoutesV1Alpha1Type - ProxyStateTemplateV1AlphaType = types.ProxyStateTemplateV1Alpha1Type + ProxyConfigurationV1Alpha1Type = types.ProxyConfigurationV1Alpha1Type + UpstreamsV1Alpha1Type = types.UpstreamsV1Alpha1Type + UpstreamsConfigurationV1Alpha1Type = types.UpstreamsConfigurationV1Alpha1Type + HTTPRouteV1Alpha1Type = types.HTTPRouteV1Alpha1Type + GRPCRouteV1Alpha1Type = types.GRPCRouteV1Alpha1Type + TCPRouteV1Alpha1Type = types.TCPRouteV1Alpha1Type + DestinationPolicyV1Alpha1Type = types.DestinationPolicyV1Alpha1Type + ComputedRoutesV1Alpha1Type = types.ComputedRoutesV1Alpha1Type + ProxyStateTemplateV1AlphaType = types.ProxyStateTemplateV1Alpha1Type // Resource Types for the latest version. diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/builder_test.go b/internal/mesh/internal/controllers/sidecarproxy/builder/builder_test.go index eebdb847cb..07004a9d96 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/builder_test.go +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/builder_test.go @@ -8,6 +8,10 @@ import ( "os" "testing" + pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v1alpha1" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "github.com/hashicorp/consul/proto/private/prototest" @@ -21,3 +25,12 @@ func TestMain(m *testing.M) { func protoToJSON(t *testing.T, pb proto.Message) string { return prototest.ProtoToJSON(t, pb) } + +func JSONToProxyTemplate(t *testing.T, json []byte) *pbmesh.ProxyStateTemplate { + t.Helper() + proxyTemplate := &pbmesh.ProxyStateTemplate{} + m := protojson.UnmarshalOptions{} + err := m.Unmarshal(json, proxyTemplate) + require.NoError(t, err) + return proxyTemplate +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder.go b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder.go index 4f65a43cf4..225859226d 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder.go +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder.go @@ -4,6 +4,8 @@ package builder import ( + "fmt" + "google.golang.org/protobuf/types/known/wrapperspb" "github.com/hashicorp/consul/agent/connect" @@ -16,11 +18,12 @@ import ( "github.com/hashicorp/consul/proto-public/pbresource" ) +// BuildDestinations creates listeners, routers, clusters, and endpointRefs for all destinations +// and adds them to the proxyState. func (b *Builder) BuildDestinations(destinations []*intermediate.Destination) *Builder { if b.proxyCfg.GetDynamicConfig() != nil && b.proxyCfg.DynamicConfig.Mode == pbmesh.ProxyMode_PROXY_MODE_TRANSPARENT { - - b.addOutboundListener(b.proxyCfg.DynamicConfig.TransparentProxy.OutboundListenerPort) + b.addTransparentProxyOutboundListener(b.proxyCfg.DynamicConfig.TransparentProxy.OutboundListenerPort) } for _, destination := range destinations { @@ -34,55 +37,71 @@ func (b *Builder) BuildDestinations(destinations []*intermediate.Destination) *B return b } -func (b *Builder) buildExplicitDestination(destination *intermediate.Destination) { - clusterName := DestinationClusterName(destination.Explicit.DestinationRef, destination.Explicit.Datacenter, b.trustDomain) - statPrefix := DestinationStatPrefix(destination.Explicit.DestinationRef, destination.Explicit.Datacenter) +// buildExplicitDestination creates listeners, routers, clusters, and endpointRefs for an explicit destination +// and adds them to the proxyState. +func (b *Builder) buildExplicitDestination(destination *intermediate.Destination) *Builder { + serviceRef := destination.Explicit.DestinationRef + sni := DestinationSNI(serviceRef, b.localDatacenter, b.trustDomain) + portInfo := newServicePortInfo(destination.ServiceEndpoints.Endpoints) - // All endpoints should have the same protocol as the endpoints controller ensures that is the case, - // so it's sufficient to read just the first endpoint. - if len(destination.ServiceEndpoints.Endpoints.Endpoints) > 0 { - // Get destination port so that we can configure this destination correctly based on its protocol. - destPort := destination.ServiceEndpoints.Endpoints.Endpoints[0].Ports[destination.Explicit.DestinationPort] - - // Find the destination proxy's port. - // Endpoints refs will need to route to mesh port instead of the destination port as that - // is the port of the destination's proxy. - meshPortName := findMeshPort(destination.ServiceEndpoints.Endpoints.Endpoints[0].Ports) - - if destPort != nil { - b.addOutboundDestinationListener(destination.Explicit). - addRouter(clusterName, statPrefix, destPort.Protocol). - buildListener(). - addCluster(clusterName, destination.Identities). - addEndpointsRef(clusterName, destination.ServiceEndpoints.Resource.Id, meshPortName) - } - } + return b.addExplicitOutboundListener(destination.Explicit). + addEndpointsRef(sni, destination.ServiceEndpoints.Resource.Id, portInfo.meshPortName). + addRouters(portInfo, destination, serviceRef, sni, b.localDatacenter, false). + addClusters(portInfo, destination, sni) } -func (b *Builder) buildImplicitDestination(destination *intermediate.Destination) { +// buildImplicitDestination creates listeners, routers, clusters, and endpointRefs for an implicit destination +// and adds them to the proxyState. +func (b *Builder) buildImplicitDestination(destination *intermediate.Destination) *Builder { serviceRef := resource.Reference(destination.ServiceEndpoints.Resource.Owner, "") - clusterName := DestinationClusterName(serviceRef, b.localDatacenter, b.trustDomain) - statPrefix := DestinationStatPrefix(serviceRef, b.localDatacenter) + sni := DestinationSNI(serviceRef, b.localDatacenter, b.trustDomain) + portInfo := newServicePortInfo(destination.ServiceEndpoints.Endpoints) - // We assume that all endpoints have the same port protocol and name, and so it's sufficient - // to check ports just from the first endpoint. - if len(destination.ServiceEndpoints.Endpoints.Endpoints) > 0 { - // Find the destination proxy's port. - // Endpoints refs will need to route to mesh port instead of the destination port as that - // is the port of the destination's proxy. - meshPortName := findMeshPort(destination.ServiceEndpoints.Endpoints.Endpoints[0].Ports) - - for _, port := range destination.ServiceEndpoints.Endpoints.Endpoints[0].Ports { - b.outboundListenerBuilder. - addRouterWithIPMatch(clusterName, statPrefix, port.Protocol, destination.VirtualIPs). - buildListener(). - addCluster(clusterName, destination.Identities). - addEndpointsRef(clusterName, destination.ServiceEndpoints.Resource.Id, meshPortName) - } - } + return b.addEndpointsRef(sni, destination.ServiceEndpoints.Resource.Id, portInfo.meshPortName). + addRouters(portInfo, destination, serviceRef, sni, b.localDatacenter, true). + addClusters(portInfo, destination, sni) } -func (b *Builder) addOutboundDestinationListener(explicit *pbmesh.Upstream) *ListenerBuilder { +// addClusters creates clusters for each service port in the pre-processed a servicePortInfo. +func (b *Builder) addClusters(portInfo *servicePortInfo, destination *intermediate.Destination, sni string) *Builder { + for portName, port := range portInfo.servicePorts { + if port.GetProtocol() != pbcatalog.Protocol_PROTOCOL_TCP { + //only implementing L4 at the moment + } else { + clusterName := fmt.Sprintf("%s.%s", portName, sni) + b.addCluster(clusterName, sni, portName, destination.Identities) + } + } + return b +} + +// addRouters creates routers for each service port in the pre-processed a servicePortInfo. +func (b *Builder) addRouters(portInfo *servicePortInfo, destination *intermediate.Destination, + serviceRef *pbresource.Reference, sni, datacenter string, isImplicitDestination bool) *Builder { + + for portName, port := range portInfo.servicePorts { + statPrefix := DestinationStatPrefix(serviceRef, portName, datacenter) + + if port.GetProtocol() != pbcatalog.Protocol_PROTOCOL_TCP { + //only implementing L4 at the moment + continue + } + + clusterName := fmt.Sprintf("%s.%s", portName, sni) + var portForRouterMatch *pbcatalog.WorkloadPort + // router matches based on destination ports should only occur on implicit destinations + // for explicit, nil will get passed to addRouterWithIPAndPortMatch() which will then + // exclude the destinationPort match on the listener router. + if isImplicitDestination { + portForRouterMatch = port + } + b.addRouterWithIPAndPortMatch(clusterName, statPrefix, portForRouterMatch, destination.VirtualIPs) + } + return b +} + +// addExplicitOutboundListener creates an outbound listener for an explicit destination. +func (b *Builder) addExplicitOutboundListener(explicit *pbmesh.Upstream) *Builder { listener := &pbproxystate.Listener{ Direction: pbproxystate.Direction_DIRECTION_OUTBOUND, } @@ -109,10 +128,11 @@ func (b *Builder) addOutboundDestinationListener(explicit *pbmesh.Upstream) *Lis listener.Name = DestinationListenerName(explicit.DestinationRef.Name, explicit.DestinationPort, destinationAddr.Unix.Path, 0) } - return b.NewListenerBuilder(listener) + return b.NewListenerBuilder(listener).buildListener() } -func (b *Builder) addOutboundListener(port uint32) *ListenerBuilder { +// addTransparentProxyOutboundListener creates an outbound listener for transparent proxy mode. +func (b *Builder) addTransparentProxyOutboundListener(port uint32) *Builder { listener := &pbproxystate.Listener{ Name: xdscommon.OutboundListenerName, Direction: pbproxystate.Direction_DIRECTION_OUTBOUND, @@ -125,48 +145,67 @@ func (b *Builder) addOutboundListener(port uint32) *ListenerBuilder { Capabilities: []pbproxystate.Capability{pbproxystate.Capability_CAPABILITY_TRANSPARENT}, } - lb := b.NewListenerBuilder(listener) - - // Save outbound listener builder so we can use it in the future. - b.outboundListenerBuilder = lb - - return lb + return b.NewListenerBuilder(listener).buildListener() } -func (l *ListenerBuilder) addRouter(clusterName, statPrefix string, protocol pbcatalog.Protocol) *ListenerBuilder { - return l.addRouterWithIPMatch(clusterName, statPrefix, protocol, nil) +// addRouterDestination returns the appropriate router destination based on the port protocol. +func (b *Builder) addRouterDestination(router *pbproxystate.Router, clusterName, statPrefix string, _ *pbcatalog.WorkloadPort) *Builder { + //switch port.GetProtocol() { + //case pbcatalog.Protocol_PROTOCOL_TCP: + // router.Destination = &pbproxystate.Router_L4{ + // L4: &pbproxystate.L4Destination{ + // Name: clusterName, + // StatPrefix: statPrefix, + // }, + // } + //case pbcatalog.Protocol_PROTOCOL_HTTP: + // router.Destination = &pbproxystate.Router_L7{ + // L7: &pbproxystate.L7Destination{ + // Name: clusterName, + // StatPrefix: statPrefix, + // }, + // } + //} + // TODO(proxystate): add L7 in future work. + router.Destination = &pbproxystate.Router_L4{ + L4: &pbproxystate.L4Destination{ + Name: clusterName, + StatPrefix: statPrefix, + }, + } + return b } -func (l *ListenerBuilder) addRouterWithIPMatch(clusterName, statPrefix string, protocol pbcatalog.Protocol, vips []string) *ListenerBuilder { +// addRouterWithIPAndPortMatch will create and add a listener router to proxyState that +// matches on the IP and port of the cluster. +func (b *Builder) addRouterWithIPAndPortMatch(clusterName, statPrefix string, port *pbcatalog.WorkloadPort, vips []string) *Builder { + listener := b.getLastBuiltListener() + // For explicit destinations, we have no filter chain match, and filters are based on port protocol. router := &pbproxystate.Router{} - switch protocol { - case pbcatalog.Protocol_PROTOCOL_TCP: - router.Destination = &pbproxystate.Router_L4{ - L4: &pbproxystate.L4Destination{ - Name: clusterName, - StatPrefix: statPrefix, - }, - } - } + b.addRouterDestination(router, clusterName, statPrefix, port) if router.Destination != nil { + if (port != nil || len(vips) > 0) && router.Match == nil { + router.Match = &pbproxystate.Match{} + } + if port != nil { + router.Match.DestinationPort = &wrapperspb.UInt32Value{Value: port.GetPort()} + } for _, vip := range vips { - if router.Match == nil { - router.Match = &pbproxystate.Match{} - } - router.Match.PrefixRanges = append(router.Match.PrefixRanges, &pbproxystate.CidrRange{ AddressPrefix: vip, PrefixLen: &wrapperspb.UInt32Value{Value: 32}, }) } - l.listener.Routers = append(l.listener.Routers, router) + listener.Routers = append(listener.Routers, router) } - return l + + return b } -func (b *Builder) addCluster(clusterName string, destinationIdentities []*pbresource.Reference) *Builder { +// addCluster creates and adds a cluster to the proxyState based on the destination. +func (b *Builder) addCluster(clusterName, sni, portName string, destinationIdentities []*pbresource.Reference) *Builder { var spiffeIDs []string for _, identity := range destinationIdentities { spiffeIDs = append(spiffeIDs, connect.SpiffeIDFromIdentityRef(b.trustDomain, identity)) @@ -188,9 +227,10 @@ func (b *Builder) addCluster(clusterName string, destinationIdentities []*pbreso ValidationContext: &pbproxystate.MeshOutboundValidationContext{ SpiffeIds: spiffeIDs, }, - Sni: clusterName, + Sni: sni, }, }, + AlpnProtocols: []string{getAlpnProtocolFromPortName(portName)}, }, }, }, @@ -199,21 +239,23 @@ func (b *Builder) addCluster(clusterName string, destinationIdentities []*pbreso } b.proxyStateTemplate.ProxyState.Clusters[clusterName] = cluster + return b } -func (b *Builder) addEndpointsRef(clusterName string, serviceEndpointsID *pbresource.ID, destinationPort string) { +// addEndpointsRef creates and add an endpointRef for each serviceEndpoint for a destination and +// adds it to the proxyStateTemplate so it will be processed later during reconciliation by +// the XDS controller. +func (b *Builder) addEndpointsRef(clusterName string, serviceEndpointsID *pbresource.ID, destinationPort string) *Builder { b.proxyStateTemplate.RequiredEndpoints[clusterName] = &pbproxystate.EndpointRef{ Id: serviceEndpointsID, Port: destinationPort, } + return b } -func findMeshPort(ports map[string]*pbcatalog.WorkloadPort) string { - for name, port := range ports { - if port.Protocol == pbcatalog.Protocol_PROTOCOL_MESH { - return name - } - } - return "" +// last +func (b *Builder) getLastBuiltListener() *pbproxystate.Listener { + lastBuiltIndex := len(b.proxyStateTemplate.ProxyState.Listeners) - 1 + return b.proxyStateTemplate.ProxyState.Listeners[lastBuiltIndex] } diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_multiport_test.go b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_multiport_test.go new file mode 100644 index 0000000000..1bd90fcbc6 --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_multiport_test.go @@ -0,0 +1,182 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package builder + +import ( + "fmt" + "github.com/hashicorp/consul/internal/resource" + "github.com/hashicorp/consul/internal/testing/golden" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" + "sort" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/mesh/internal/types/intermediate" + "github.com/hashicorp/consul/internal/resource/resourcetest" + pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v1alpha1" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +func TestBuildMultiportImplicitDestinations(t *testing.T) { + const ( + apiApp = "api-app" + apiApp2 = "api-app2" + trustDomain = "foo.consul" + datacenter = "dc1" + ) + proxyCfg := &pbmesh.ProxyConfiguration{ + DynamicConfig: &pbmesh.DynamicConfig{ + Mode: pbmesh.ProxyMode_PROXY_MODE_TRANSPARENT, + TransparentProxy: &pbmesh.TransparentProxy{ + OutboundListenerPort: 15001, + }, + }, + } + + multiportEndpointsData := &pbcatalog.ServiceEndpoints{ + Endpoints: []*pbcatalog.Endpoint{ + { + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "10.0.0.1"}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "admin-port": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + }, + } + apiAppEndpoints := resourcetest.Resource(catalog.ServiceEndpointsType, apiApp). + WithOwner(resourcetest.Resource(catalog.ServiceType, apiApp). + WithTenancy(resource.DefaultNamespacedTenancy()).ID()). + WithData(t, multiportEndpointsData). + WithTenancy(resource.DefaultNamespacedTenancy()).Build() + + apiApp2Endpoints := resourcetest.Resource(catalog.ServiceEndpointsType, apiApp2). + WithOwner(resourcetest.Resource(catalog.ServiceType, apiApp2). + WithTenancy(resource.DefaultNamespacedTenancy()).ID()). + WithData(t, multiportEndpointsData). + WithTenancy(resource.DefaultNamespacedTenancy()).Build() + + apiAppIdentity := &pbresource.Reference{ + Name: fmt.Sprintf("%s-identity", apiApp), + Tenancy: apiAppEndpoints.Id.Tenancy, + } + + apiApp2Identity := &pbresource.Reference{ + Name: fmt.Sprintf("%s-identity", apiApp2), + Tenancy: apiApp2Endpoints.Id.Tenancy, + } + + destination1 := &intermediate.Destination{ + ServiceEndpoints: &intermediate.ServiceEndpoints{ + Resource: apiAppEndpoints, + Endpoints: multiportEndpointsData, + }, + Identities: []*pbresource.Reference{apiAppIdentity}, + VirtualIPs: []string{"1.1.1.1"}, + } + + destination2 := &intermediate.Destination{ + ServiceEndpoints: &intermediate.ServiceEndpoints{ + Resource: apiApp2Endpoints, + Endpoints: multiportEndpointsData, + }, + Identities: []*pbresource.Reference{apiApp2Identity}, + VirtualIPs: []string{"2.2.2.2", "3.3.3.3"}, + } + + cases := map[string]struct { + getDestinations func() []*intermediate.Destination + }{ + // Most basic test that multiport configuration works + "destination/multiport-l4-single-implicit-destination-tproxy": { + getDestinations: func() []*intermediate.Destination { return []*intermediate.Destination{destination1} }, + }, + // Test shows that with multiple workloads for a service exposing the same ports, the routers + // and clusters do not get duplicated. + "destination/multiport-l4-single-implicit-destination-with-multiple-workloads-tproxy": { + getDestinations: func() []*intermediate.Destination { + mwEndpointsData := &pbcatalog.ServiceEndpoints{ + Endpoints: []*pbcatalog.Endpoint{ + { + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "10.0.0.1"}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "admin-port": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + { + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "10.0.0.2"}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "admin-port": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + }, + } + mwEndpoints := resourcetest.Resource(catalog.ServiceEndpointsType, apiApp). + WithOwner(resourcetest.Resource(catalog.ServiceType, apiApp). + WithTenancy(resource.DefaultNamespacedTenancy()).ID()). + WithData(t, mwEndpointsData). + WithTenancy(resource.DefaultNamespacedTenancy()).Build() + + mwIdentity := &pbresource.Reference{ + Name: fmt.Sprintf("%s-identity", apiApp), + Tenancy: mwEndpoints.Id.Tenancy, + } + + mwDestination := &intermediate.Destination{ + ServiceEndpoints: &intermediate.ServiceEndpoints{ + Resource: mwEndpoints, + Endpoints: mwEndpointsData, + }, + Identities: []*pbresource.Reference{mwIdentity}, + VirtualIPs: []string{"1.1.1.1"}, + } + return []*intermediate.Destination{mwDestination} + }, + }, + // Test shows that with multiple workloads for a service exposing the same ports, the routers + // and clusters do not get duplicated. + "destination/multiport-l4-multiple-implicit-destinations-tproxy": { + getDestinations: func() []*intermediate.Destination { return []*intermediate.Destination{destination1, destination2} }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), trustDomain, datacenter, proxyCfg). + BuildDestinations(c.getDestinations()). + Build() + + // sort routers because of test flakes where order was flip flopping. + actualRouters := proxyTmpl.ProxyState.Listeners[0].Routers + sort.Slice(actualRouters, func(i, j int) bool { + return actualRouters[i].String() < actualRouters[j].String() + }) + + actual := protoToJSON(t, proxyTmpl) + expected := JSONToProxyTemplate(t, golden.GetBytes(t, actual, name+".golden")) + + // sort routers on listener from golden file + expectedRouters := expected.ProxyState.Listeners[0].Routers + sort.Slice(expectedRouters, func(i, j int) bool { + return expectedRouters[i].String() < expectedRouters[j].String() + }) + + // convert back to json after sorting so that test output does not contain extraneous fields. + require.Equal(t, protoToJSON(t, expected), protoToJSON(t, proxyTmpl)) + }) + } +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_test.go b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_test.go index f63ee3e777..74fd5666c9 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_test.go +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_builder_test.go @@ -195,13 +195,48 @@ func TestBuildImplicitDestinations(t *testing.T) { } for name, c := range cases { - proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", proxyCfg). - BuildDestinations(c.destinations). - Build() + t.Run(name, func(t *testing.T) { + proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", proxyCfg). + BuildDestinations(c.destinations). + Build() - actual := protoToJSON(t, proxyTmpl) - expected := golden.Get(t, actual, name+".golden") + actual := protoToJSON(t, proxyTmpl) + expected := golden.Get(t, actual, name+".golden") - require.JSONEq(t, expected, actual) + require.JSONEq(t, expected, actual) + }) + } +} + +func Test_isMeshPort(t *testing.T) { + cases := map[string]struct { + protocol pbcatalog.Protocol + expectedResult bool + }{ + "mesh protocol returns true": { + protocol: pbcatalog.Protocol_PROTOCOL_MESH, + expectedResult: true, + }, + "grpc protocol returns false": { + protocol: pbcatalog.Protocol_PROTOCOL_GRPC, + expectedResult: false, + }, + "tcp protocol returns false": { + protocol: pbcatalog.Protocol_PROTOCOL_TCP, + expectedResult: false, + }, + "http protocol returns false": { + protocol: pbcatalog.Protocol_PROTOCOL_HTTP, + expectedResult: false, + }, + "http2 protocol returns false": { + protocol: pbcatalog.Protocol_PROTOCOL_HTTP2, + expectedResult: false, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + require.Equal(t, tc.expectedResult, isMeshPort(&pbcatalog.WorkloadPort{Protocol: tc.protocol})) + }) } } diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/local_app.go b/internal/mesh/internal/controllers/sidecarproxy/builder/local_app.go index 5a465f503f..3cd02250c0 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/local_app.go +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/local_app.go @@ -12,22 +12,23 @@ import ( ) func (b *Builder) BuildLocalApp(workload *pbcatalog.Workload) *Builder { - // Go through workload ports and add the first non-mesh port we see. + // Add the public listener. + lb := b.addInboundListener(xdscommon.PublicListenerName, workload) + lb.buildListener() + + // Go through workload ports and add the routers, clusters, endpoints, and TLS. // Note that the order of ports is non-deterministic here but the xds generation // code should make sure to send it in the same order to Envoy to avoid unnecessary // updates. - // todo (ishustava): Note we will need to support multiple ports in the future. for portName, port := range workload.Ports { clusterName := fmt.Sprintf("%s:%s", xdscommon.LocalAppClusterName, portName) if port.Protocol != pbcatalog.Protocol_PROTOCOL_MESH { - b.addInboundListener(xdscommon.PublicListenerName, workload). - addInboundRouter(clusterName, port). - addInboundTLS(). - buildListener(). - addLocalAppCluster(clusterName). + lb.addInboundRouter(clusterName, port, portName). + addInboundTLS() + + b.addLocalAppCluster(clusterName). addLocalAppStaticEndpoints(clusterName, port) - break } } @@ -76,7 +77,7 @@ func (b *Builder) addInboundListener(name string, workload *pbcatalog.Workload) return b.NewListenerBuilder(listener) } -func (l *ListenerBuilder) addInboundRouter(clusterName string, port *pbcatalog.WorkloadPort) *ListenerBuilder { +func (l *ListenerBuilder) addInboundRouter(clusterName string, port *pbcatalog.WorkloadPort, portName string) *ListenerBuilder { if l.listener == nil { return l } @@ -89,12 +90,19 @@ func (l *ListenerBuilder) addInboundRouter(clusterName string, port *pbcatalog.W StatPrefix: l.listener.Name, }, }, + Match: &pbproxystate.Match{ + AlpnProtocols: []string{getAlpnProtocolFromPortName(portName)}, + }, } l.listener.Routers = append(l.listener.Routers, r) } return l } +func getAlpnProtocolFromPortName(portName string) string { + return fmt.Sprintf("consul~%s", portName) +} + func (b *Builder) addLocalAppCluster(clusterName string) *Builder { // Make cluster for this router destination. b.proxyStateTemplate.ProxyState.Clusters[clusterName] = &pbproxystate.Cluster{ diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/local_app_multiport_test.go b/internal/mesh/internal/controllers/sidecarproxy/builder/local_app_multiport_test.go new file mode 100644 index 0000000000..5637703360 --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/local_app_multiport_test.go @@ -0,0 +1,101 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package builder + +import ( + "github.com/hashicorp/consul/internal/testing/golden" + "sort" + "testing" + + "github.com/stretchr/testify/require" + + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" +) + +func TestBuildLocalApp_Multiport(t *testing.T) { + cases := map[string]struct { + workload *pbcatalog.Workload + }{ + "source/multiport-l4-single-workload-address-without-ports": { + workload: &pbcatalog.Workload{ + Addresses: []*pbcatalog.WorkloadAddress{ + { + Host: "10.0.0.1", + }, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "admin-port": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + }, + "source/multiport-l4-multiple-workload-addresses-without-ports": { + workload: &pbcatalog.Workload{ + Addresses: []*pbcatalog.WorkloadAddress{ + { + Host: "10.0.0.1", + }, + { + Host: "10.0.0.2", + }, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "admin-port": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + }, + "source/multiport-l4-multiple-workload-addresses-with-specific-ports": { + workload: &pbcatalog.Workload{ + Addresses: []*pbcatalog.WorkloadAddress{ + { + Host: "10.0.0.1", + Ports: []string{"admin-port"}, + }, + { + Host: "10.0.0.2", + Ports: []string{"api-port"}, + }, + { + Host: "10.0.0.3", + Ports: []string{"mesh"}, + }, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "admin-port": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", nil). + BuildLocalApp(c.workload). + Build() + + // sort routers because of test flakes where order was flip flopping. + actualRouters := proxyTmpl.ProxyState.Listeners[0].Routers + sort.Slice(actualRouters, func(i, j int) bool { + return actualRouters[i].String() < actualRouters[j].String() + }) + + actual := protoToJSON(t, proxyTmpl) + expected := JSONToProxyTemplate(t, golden.GetBytes(t, actual, name+".golden")) + + // sort routers on listener from golden file + expectedRouters := expected.ProxyState.Listeners[0].Routers + sort.Slice(expectedRouters, func(i, j int) bool { + return expectedRouters[i].String() < expectedRouters[j].String() + }) + + // convert back to json after sorting so that test output does not contain extraneous fields. + require.Equal(t, protoToJSON(t, expected), protoToJSON(t, proxyTmpl)) + }) + } +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/naming.go b/internal/mesh/internal/controllers/sidecarproxy/builder/naming.go index 09a9706a89..6826191bdf 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/naming.go +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/naming.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/consul/proto-public/pbresource" ) -func DestinationClusterName(serviceRef *pbresource.Reference, datacenter, trustDomain string) string { +func DestinationSNI(serviceRef *pbresource.Reference, datacenter, trustDomain string) string { return connect.ServiceSNI(serviceRef.Name, "", serviceRef.Tenancy.Namespace, @@ -19,8 +19,9 @@ func DestinationClusterName(serviceRef *pbresource.Reference, datacenter, trustD trustDomain) } -func DestinationStatPrefix(serviceRef *pbresource.Reference, datacenter string) string { - return fmt.Sprintf("upstream.%s.%s.%s.%s", +func DestinationStatPrefix(serviceRef *pbresource.Reference, portName, datacenter string) string { + return fmt.Sprintf("upstream.%s.%s.%s.%s.%s", + portName, serviceRef.Name, serviceRef.Tenancy.Namespace, serviceRef.Tenancy.Partition, diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info.go b/internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info.go new file mode 100644 index 0000000000..82e706467c --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info.go @@ -0,0 +1,80 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package builder + +import ( + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" +) + +// servicePortInfo is a struct used by the destination builder so that it can pre-process +// what is the service mesh port and what are the distinct ports across the endpoints. +// This pre-processing reduces the iterations during the BuildDestinations processing +// would need to get the ports, check if one was the mesh port, know whether it already +// has a cluster created for it and so on. + +type servicePortInfo struct { + // meshPortName is the name of the port with Mesh Protocol. + meshPortName string + // meshPort is the port with Mesh Protocol. + meshPort *pbcatalog.WorkloadPort + // servicePorts are the distinct ports that need clusters and routers for given destination. + // servicePorts do not include the mesh port and are called servicePorts because they + // belong to the service. + servicePorts map[string]*pbcatalog.WorkloadPort +} + +// newServicePortInfo builds a servicePointInfo given a serviceEndpoints struct. It pre-process +// what the service mesh port and the distinct service ports across the endpoints for a destination. +// The following occurs during pre-processing: +// - a port must be exposed to at least one workload address on every workload in +// the service to be a service port. Otherwise, the system would risk errors. +// - a Workload can optionally define ports specific to workload address. If no +// ports are specified for a workload address, then all the destination ports are +// used. +func newServicePortInfo(serviceEndpoints *pbcatalog.ServiceEndpoints) *servicePortInfo { + spInfo := &servicePortInfo{ + servicePorts: make(map[string]*pbcatalog.WorkloadPort), + } + type seenData struct { + port *pbcatalog.WorkloadPort + seenBy []*int + } + seen := make(map[string]*seenData) + for epIdx, ep := range serviceEndpoints.GetEndpoints() { + for range ep.Addresses { + // iterate through endpoint ports and set the mesh port + // as well as all endpoint ports for this workload if there + // are no specific workload ports. + for epPortName, epPort := range ep.Ports { + // look to set mesh port + if isMeshPort(epPort) { + spInfo.meshPortName = epPortName + spInfo.meshPort = epPort + continue + } + + // otherwise, add all ports for this endpoint. + portData, ok := seen[epPortName] + if ok { + portData.seenBy = append(portData.seenBy, &epIdx) + } else { + seenBy := append([]*int{}, &epIdx) + seen[epPortName] = &seenData{port: epPort, seenBy: seenBy} + } + } + } + } + + for portName, portData := range seen { + // make sure each port is seen by all endpoints + if len(portData.seenBy) == len(serviceEndpoints.GetEndpoints()) { + spInfo.servicePorts[portName] = portData.port + } + } + return spInfo +} + +func isMeshPort(port *pbcatalog.WorkloadPort) bool { + return port.Protocol == pbcatalog.Protocol_PROTOCOL_MESH +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info_test.go b/internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info_test.go new file mode 100644 index 0000000000..069be9a444 --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/service_port_info_test.go @@ -0,0 +1,49 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package builder + +import ( + "testing" + + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" + "github.com/stretchr/testify/require" +) + +// Test_newServicePortInfo test case shows: +// - endpoint 1 has one address with no specific ports. +// - endpoint 2 has one address with no specific ports. +// - the cumulative effect is then the union of endpoints 1 and 2. +func Test_newServicePortInfo(t *testing.T) { + serviceEndpoints := &pbcatalog.ServiceEndpoints{ + Endpoints: []*pbcatalog.Endpoint{ + { + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "10.0.0.1"}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "admin-port": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + { + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "10.0.0.2"}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + }, + }, + } + expectedResult := &servicePortInfo{ + meshPortName: "mesh", + meshPort: &pbcatalog.WorkloadPort{Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + servicePorts: map[string]*pbcatalog.WorkloadPort{ + "api-port": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + }, + } + require.Equal(t, expectedResult, newServicePortInfo(serviceEndpoints)) +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-implicit-and-explicit-destinations-tproxy.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-implicit-and-explicit-destinations-tproxy.golden index dbda8aebe7..afe86fa8cd 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-implicit-and-explicit-destinations-tproxy.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-implicit-and-explicit-destinations-tproxy.golden @@ -1,13 +1,16 @@ { "proxyState": { "clusters": { - "api-1.default.dc1.internal.foo.consul": { + "tcp.api-1.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-1.default.dc1.internal.foo.consul", @@ -21,13 +24,16 @@ } } }, - "api-2.default.dc1.internal.foo.consul": { + "tcp.api-2.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-2.default.dc1.internal.foo.consul", @@ -64,72 +70,11 @@ "routers": [ { "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" + "name": "tcp.api-2.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-2.default.default.dc1" }, "match": { + "destinationPort": 8080, "prefixRanges": [ { "addressPrefix": "2.2.2.2", @@ -154,8 +99,8 @@ "routers": [ { "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" + "name": "tcp.api-1.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-1.default.default.dc1" } } ] diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multi-destination.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multi-destination.golden index 24b06ad29b..993e27c619 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multi-destination.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multi-destination.golden @@ -1,13 +1,16 @@ { "proxyState": { "clusters": { - "api-1.default.dc1.internal.foo.consul": { + "tcp.api-1.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-1.default.dc1.internal.foo.consul", @@ -21,13 +24,16 @@ } } }, - "api-2.default.dc1.internal.foo.consul": { + "tcp.api-2.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-2.default.dc1.internal.foo.consul", @@ -61,8 +67,8 @@ "routers": [ { "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" + "name": "tcp.api-1.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-1.default.default.dc1" } } ] @@ -73,8 +79,8 @@ "routers": [ { "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" + "name": "tcp.api-2.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-2.default.default.dc1" } } ], diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multiple-implicit-destinations-tproxy.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multiple-implicit-destinations-tproxy.golden index 6c1bfb6a12..ed6d05b516 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multiple-implicit-destinations-tproxy.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-multiple-implicit-destinations-tproxy.golden @@ -1,13 +1,16 @@ { "proxyState": { "clusters": { - "api-1.default.dc1.internal.foo.consul": { + "tcp.api-1.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-1.default.dc1.internal.foo.consul", @@ -21,13 +24,16 @@ } } }, - "api-2.default.dc1.internal.foo.consul": { + "tcp.api-2.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-2.default.dc1.internal.foo.consul", @@ -64,10 +70,11 @@ "routers": [ { "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" + "name": "tcp.api-1.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-1.default.default.dc1" }, "match": { + "destinationPort": 8080, "prefixRanges": [ { "addressPrefix": "1.1.1.1", @@ -78,235 +85,11 @@ }, { "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" + "name": "tcp.api-2.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-2.default.default.dc1" }, "match": { + "destinationPort": 8080, "prefixRanges": [ { "addressPrefix": "2.2.2.2", diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-ip-port-bind-address.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-ip-port-bind-address.golden index b426d287e9..5eda0906e5 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-ip-port-bind-address.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-ip-port-bind-address.golden @@ -1,13 +1,16 @@ { "proxyState": { "clusters": { - "api-1.default.dc1.internal.foo.consul": { + "tcp.api-1.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-1.default.dc1.internal.foo.consul", @@ -41,8 +44,8 @@ "routers": [ { "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" + "name": "tcp.api-1.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-1.default.default.dc1" } } ] diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-unix-socket-bind-address.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-unix-socket-bind-address.golden index cc2bd0fdc5..f313ad1cad 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-unix-socket-bind-address.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-destination-unix-socket-bind-address.golden @@ -1,13 +1,16 @@ { "proxyState": { "clusters": { - "api-2.default.dc1.internal.foo.consul": { + "tcp.api-2.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-2.default.dc1.internal.foo.consul", @@ -37,8 +40,8 @@ "routers": [ { "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" + "name": "tcp.api-2.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-2.default.default.dc1" } } ], diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-implicit-destination-tproxy.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-implicit-destination-tproxy.golden index 3baaa44f7d..cc5698fee6 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-implicit-destination-tproxy.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/l4-single-implicit-destination-tproxy.golden @@ -1,13 +1,16 @@ { "proxyState": { "clusters": { - "api-1.default.dc1.internal.foo.consul": { + "tcp.api-1.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { "disablePanicThreshold": true }, "outboundTls": { + "alpnProtocols": [ + "consul~tcp" + ], "outboundMesh": { "identityKey": "test-identity", "sni": "api-1.default.dc1.internal.foo.consul", @@ -44,64 +47,11 @@ "routers": [ { "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" + "name": "tcp.api-1.default.dc1.internal.foo.consul", + "statPrefix": "upstream.tcp.api-1.default.default.dc1" }, "match": { + "destinationPort": 8080, "prefixRanges": [ { "addressPrefix": "1.1.1.1", diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-implicit-and-explicit-destinations-tproxy.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-multiple-implicit-destinations-tproxy.golden similarity index 50% rename from internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-implicit-and-explicit-destinations-tproxy.golden rename to internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-multiple-implicit-destinations-tproxy.golden index dbda8aebe7..468b47e176 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-implicit-and-explicit-destinations-tproxy.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-multiple-implicit-destinations-tproxy.golden @@ -1,72 +1,53 @@ { "proxyState": { - "clusters": { - "api-1.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-1.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api1-identity" - ] - } - } - } - } - } - }, - "api-2.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-2.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api2-identity" - ] - } - } - } - } - } - } - }, "identity": { - "name": "test-identity", "tenancy": { - "namespace": "default", "partition": "default", + "namespace": "default", "peerName": "local" - } + }, + "name": "test-identity" }, "listeners": [ { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], + "name": "outbound_listener", "direction": "DIRECTION_OUTBOUND", "hostPort": { "host": "127.0.0.1", "port": 15001 }, - "name": "outbound_listener", "routers": [ { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" + "match": { + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ], + "destinationPort": 8080 }, + "l4": { + "name": "admin-port.api-app.default.dc1.internal.foo.consul", + "statPrefix": "upstream.admin-port.api-app.default.default.dc1" + } + }, + { + "match": { + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ], + "destinationPort": 9090 + }, + "l4": { + "name": "api-port.api-app.default.dc1.internal.foo.consul", + "statPrefix": "upstream.api-port.api-app.default.default.dc1" + } + }, + { "match": { "prefixRanges": [ { @@ -77,27 +58,15 @@ "addressPrefix": "3.3.3.3", "prefixLen": 32 } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" + ], + "destinationPort": 8080 }, + "l4": { + "name": "admin-port.api-app2.default.dc1.internal.foo.consul", + "statPrefix": "upstream.admin-port.api-app2.default.default.dc1" + } + }, + { "match": { "prefixRanges": [ { @@ -108,67 +77,122 @@ "addressPrefix": "3.3.3.3", "prefixLen": 32 } - ] + ], + "destinationPort": 9090 + }, + "l4": { + "name": "api-port.api-app2.default.dc1.internal.foo.consul", + "statPrefix": "upstream.api-port.api-app2.default.default.dc1" } } - ] - }, - { + ], "capabilities": [ "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "1.1.1.1", - "port": 1234 - }, - "name": "api-1:tcp:1.1.1.1:1234", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - } - } ] } - ] + ], + "clusters": { + "admin-port.api-app.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api-app-identity" + ] + }, + "sni": "api-app.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~admin-port" + ] + } + } + } + }, + "api-port.api-app.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api-app-identity" + ] + }, + "sni": "api-app.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~api-port" + ] + } + } + } + }, + "admin-port.api-app2.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api-app2-identity" + ] + }, + "sni": "api-app2.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~admin-port" + ] + } + } + } + }, + "api-port.api-app2.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api-app2-identity" + ] + }, + "sni": "api-app2.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~api-port" + ] + } + } + } + } + } }, "requiredEndpoints": { - "api-1.default.dc1.internal.foo.consul": { + "api-app.default.dc1.internal.foo.consul": { "id": { - "name": "api-1", + "name": "api-app", "tenancy": { - "namespace": "default", "partition": "default", + "namespace": "default", "peerName": "local" }, "type": { @@ -179,12 +203,12 @@ }, "port": "mesh" }, - "api-2.default.dc1.internal.foo.consul": { + "api-app2.default.dc1.internal.foo.consul": { "id": { - "name": "api-2", + "name": "api-app2", "tenancy": { - "namespace": "default", "partition": "default", + "namespace": "default", "peerName": "local" }, "type": { diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-implicit-destination-tproxy.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-single-implicit-destination-tproxy.golden similarity index 55% rename from internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-implicit-destination-tproxy.golden rename to internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-single-implicit-destination-tproxy.golden index 3baaa44f7d..ce239c7ed3 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-implicit-destination-tproxy.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-single-implicit-destination-tproxy.golden @@ -1,7 +1,60 @@ { "proxyState": { + "identity": { + "tenancy": { + "partition": "default", + "namespace": "default", + "peerName": "local" + }, + "name": "test-identity" + }, + "listeners": [ + { + "name": "outbound_listener", + "direction": "DIRECTION_OUTBOUND", + "hostPort": { + "host": "127.0.0.1", + "port": 15001 + }, + "routers": [ + { + "match": { + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ], + "destinationPort": 8080 + }, + "l4": { + "name": "admin-port.api-app.default.dc1.internal.foo.consul", + "statPrefix": "upstream.admin-port.api-app.default.default.dc1" + } + }, + { + "match": { + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ], + "destinationPort": 9090 + }, + "l4": { + "name": "api-port.api-app.default.dc1.internal.foo.consul", + "statPrefix": "upstream.api-port.api-app.default.default.dc1" + } + } + ], + "capabilities": [ + "CAPABILITY_TRANSPARENT" + ] + } + ], "clusters": { - "api-1.default.dc1.internal.foo.consul": { + "api-port.api-app.default.dc1.internal.foo.consul": { "endpointGroup": { "dynamic": { "config": { @@ -10,117 +63,52 @@ "outboundTls": { "outboundMesh": { "identityKey": "test-identity", - "sni": "api-1.default.dc1.internal.foo.consul", "validationContext": { "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api1-identity" + "spiffe://foo.consul/ap/default/ns/default/identity/api-app-identity" ] - } - } + }, + "sni": "api-app.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~api-port" + ] + } + } + } + }, + "admin-port.api-app.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api-app-identity" + ] + }, + "sni": "api-app.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~admin-port" + ] } } } } - }, - "identity": { - "name": "test-identity", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - } - }, - "listeners": [ - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - } - ] - } - ] + } }, "requiredEndpoints": { - "api-1.default.dc1.internal.foo.consul": { + "api-app.default.dc1.internal.foo.consul": { "id": { - "name": "api-1", + "name": "api-app", "tenancy": { - "namespace": "default", "partition": "default", + "namespace": "default", "peerName": "local" }, "type": { diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-multi-destination b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-single-implicit-destination-with-multiple-workloads-tproxy.golden similarity index 50% rename from internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-multi-destination rename to internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-single-implicit-destination-with-multiple-workloads-tproxy.golden index 24b06ad29b..1161b5c973 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-multi-destination +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/destination/multiport-l4-single-implicit-destination-with-multiple-workloads-tproxy.golden @@ -1,113 +1,117 @@ { + "requiredLeafCertificates": {}, + "requiredTrustBundles": {}, "proxyState": { - "clusters": { - "api-1.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-1.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api1-identity" - ] - } - } - } - } - } - }, - "api-2.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-2.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api2-identity" - ] - } - } - } - } - } - } - }, "identity": { - "name": "test-identity", "tenancy": { - "namespace": "default", "partition": "default", + "namespace": "default", "peerName": "local" - } + }, + "name": "test-identity" }, "listeners": [ { + "name": "outbound_listener", "direction": "DIRECTION_OUTBOUND", "hostPort": { - "host": "1.1.1.1", - "port": 1234 + "host": "127.0.0.1", + "port": 15001 }, - "name": "api-1:tcp:1.1.1.1:1234", "routers": [ { + "match": { + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ], + "destinationPort": 8080 + }, "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" + "name": "admin-port.api-app.default.dc1.internal.foo.consul", + "statPrefix": "upstream.admin-port.api-app.default.default.dc1" } - } - ] - }, - { - "direction": "DIRECTION_OUTBOUND", - "name": "api-2:tcp:/path/to/socket", - "routers": [ + }, { + "match": { + "prefixRanges": [ + { + "addressPrefix": "1.1.1.1", + "prefixLen": 32 + } + ], + "destinationPort": 9090 + }, "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" + "name": "api-port.api-app.default.dc1.internal.foo.consul", + "statPrefix": "upstream.api-port.api-app.default.default.dc1" } } ], - "unixSocket": { - "mode": "0666", - "path": "/path/to/socket" - } + "capabilities": [ + "CAPABILITY_TRANSPARENT" + ] } - ] - }, - "requiredEndpoints": { - "api-1.default.dc1.internal.foo.consul": { - "id": { - "name": "api-1", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - }, - "type": { - "group": "catalog", - "groupVersion": "v1alpha1", - "kind": "ServiceEndpoints" + ], + "clusters": { + "api-port.api-app.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api-app-identity" + ] + }, + "sni": "api-app.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~api-port" + ] + } + } } }, - "port": "mesh" + "admin-port.api-app.default.dc1.internal.foo.consul": { + "endpointGroup": { + "dynamic": { + "config": { + "disablePanicThreshold": true + }, + "outboundTls": { + "outboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "spiffeIds": [ + "spiffe://foo.consul/ap/default/ns/default/identity/api-app-identity" + ] + }, + "sni": "api-app.default.dc1.internal.foo.consul" + }, + "alpnProtocols": [ + "consul~admin-port" + ] + } + } + } + } }, - "api-2.default.dc1.internal.foo.consul": { + "endpoints": {} + }, + "requiredEndpoints": { + "api-app.default.dc1.internal.foo.consul": { "id": { - "name": "api-2", + "name": "api-app", "tenancy": { - "namespace": "default", "partition": "default", + "namespace": "default", "peerName": "local" }, "type": { diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-multiple-implicit-destinations-tproxy.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-multiple-implicit-destinations-tproxy.golden deleted file mode 100644 index 6c1bfb6a12..0000000000 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-multiple-implicit-destinations-tproxy.golden +++ /dev/null @@ -1,360 +0,0 @@ -{ - "proxyState": { - "clusters": { - "api-1.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-1.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api1-identity" - ] - } - } - } - } - } - }, - "api-2.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-2.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api2-identity" - ] - } - } - } - } - } - } - }, - "identity": { - "name": "test-identity", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - } - }, - "listeners": [ - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - }, - { - "capabilities": [ - "CAPABILITY_TRANSPARENT" - ], - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "127.0.0.1", - "port": 15001 - }, - "name": "outbound_listener", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "1.1.1.1", - "prefixLen": 32 - } - ] - } - }, - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - }, - "match": { - "prefixRanges": [ - { - "addressPrefix": "2.2.2.2", - "prefixLen": 32 - }, - { - "addressPrefix": "3.3.3.3", - "prefixLen": 32 - } - ] - } - } - ] - } - ] - }, - "requiredEndpoints": { - "api-1.default.dc1.internal.foo.consul": { - "id": { - "name": "api-1", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - }, - "type": { - "group": "catalog", - "groupVersion": "v1alpha1", - "kind": "ServiceEndpoints" - } - }, - "port": "mesh" - }, - "api-2.default.dc1.internal.foo.consul": { - "id": { - "name": "api-2", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - }, - "type": { - "group": "catalog", - "groupVersion": "v1alpha1", - "kind": "ServiceEndpoints" - } - }, - "port": "mesh" - } - } -} \ No newline at end of file diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-ip-port-bind-address b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-ip-port-bind-address deleted file mode 100644 index b426d287e9..0000000000 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-ip-port-bind-address +++ /dev/null @@ -1,70 +0,0 @@ -{ - "proxyState": { - "clusters": { - "api-1.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-1.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api1-identity" - ] - } - } - } - } - } - } - }, - "identity": { - "name": "test-identity", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - } - }, - "listeners": [ - { - "direction": "DIRECTION_OUTBOUND", - "hostPort": { - "host": "1.1.1.1", - "port": 1234 - }, - "name": "api-1:tcp:1.1.1.1:1234", - "routers": [ - { - "l4": { - "name": "api-1.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-1.default.default.dc1" - } - } - ] - } - ] - }, - "requiredEndpoints": { - "api-1.default.dc1.internal.foo.consul": { - "id": { - "name": "api-1", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - }, - "type": { - "group": "catalog", - "groupVersion": "v1alpha1", - "kind": "ServiceEndpoints" - } - }, - "port": "mesh" - } - } -} \ No newline at end of file diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-unix-socket-bind-address b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-unix-socket-bind-address deleted file mode 100644 index cc2bd0fdc5..0000000000 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/l4-single-destination-unix-socket-bind-address +++ /dev/null @@ -1,70 +0,0 @@ -{ - "proxyState": { - "clusters": { - "api-2.default.dc1.internal.foo.consul": { - "endpointGroup": { - "dynamic": { - "config": { - "disablePanicThreshold": true - }, - "outboundTls": { - "outboundMesh": { - "identityKey": "test-identity", - "sni": "api-2.default.dc1.internal.foo.consul", - "validationContext": { - "spiffeIds": [ - "spiffe://foo.consul/ap/default/ns/default/identity/api2-identity" - ] - } - } - } - } - } - } - }, - "identity": { - "name": "test-identity", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - } - }, - "listeners": [ - { - "direction": "DIRECTION_OUTBOUND", - "name": "api-2:tcp:/path/to/socket", - "routers": [ - { - "l4": { - "name": "api-2.default.dc1.internal.foo.consul", - "statPrefix": "upstream.api-2.default.default.dc1" - } - } - ], - "unixSocket": { - "mode": "0666", - "path": "/path/to/socket" - } - } - ] - }, - "requiredEndpoints": { - "api-2.default.dc1.internal.foo.consul": { - "id": { - "name": "api-2", - "tenancy": { - "namespace": "default", - "partition": "default", - "peerName": "local" - }, - "type": { - "group": "catalog", - "groupVersion": "v1alpha1", - "kind": "ServiceEndpoints" - } - }, - "port": "mesh" - } - } -} \ No newline at end of file diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-with-specific-ports.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-with-specific-ports.golden index e9c3a9a18d..48285321bd 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-with-specific-ports.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-with-specific-ports.golden @@ -50,6 +50,11 @@ "l4": { "name": "local_app:port1", "statPrefix": "public_listener" + }, + "match": { + "alpnProtocols": [ + "consul~port1" + ] } } ] diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-without-ports.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-without-ports.golden index ba93466594..80eb8a8b05 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-without-ports.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-multiple-workload-addresses-without-ports.golden @@ -50,6 +50,11 @@ "l4": { "name": "local_app:port1", "statPrefix": "public_listener" + }, + "match": { + "alpnProtocols": [ + "consul~port1" + ] } } ] diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-single-workload-address-without-ports.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-single-workload-address-without-ports.golden index ba93466594..80eb8a8b05 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-single-workload-address-without-ports.golden +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/l4-single-workload-address-without-ports.golden @@ -50,6 +50,11 @@ "l4": { "name": "local_app:port1", "statPrefix": "public_listener" + }, + "match": { + "alpnProtocols": [ + "consul~port1" + ] } } ] diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-with-specific-ports.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-with-specific-ports.golden new file mode 100644 index 0000000000..0a08401fb9 --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-with-specific-ports.golden @@ -0,0 +1,113 @@ +{ + "proxyState": { + "identity": { + "tenancy": { + "partition": "default", + "namespace": "default", + "peerName": "local" + }, + "name": "test-identity" + }, + "listeners": [ + { + "name": "public_listener", + "direction": "DIRECTION_INBOUND", + "hostPort": { + "host": "10.0.0.3", + "port": 20000 + }, + "routers": [ + { + "match": { + "alpnProtocols": [ + "consul~admin-port" + ] + }, + "l4": { + "name": "local_app:admin-port", + "statPrefix": "public_listener" + }, + "inboundTls": { + "inboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "trustBundlePeerNameKeys": [ + "local" + ] + } + } + } + }, + { + "match": { + "alpnProtocols": [ + "consul~api-port" + ] + }, + "l4": { + "name": "local_app:api-port", + "statPrefix": "public_listener" + }, + "inboundTls": { + "inboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "trustBundlePeerNameKeys": [ + "local" + ] + } + } + } + } + ] + } + ], + "clusters": { + "local_app:api-port": { + "endpointGroup": { + "static": {} + } + }, + "local_app:admin-port": { + "endpointGroup": { + "static": {} + } + } + }, + "endpoints": { + "local_app:admin-port": { + "endpoints": [ + { + "hostPort": { + "host": "127.0.0.1", + "port": 8080 + } + } + ] + }, + "local_app:api-port": { + "endpoints": [ + { + "hostPort": { + "host": "127.0.0.1", + "port": 9090 + } + } + ] + } + } + }, + "requiredLeafCertificates": { + "test-identity": { + "name": "test-identity", + "namespace": "default", + "partition": "default" + } + }, + "requiredTrustBundles": { + "local": { + "peer": "local" + } + }, + "requiredEndpoints": {} +} \ No newline at end of file diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-without-ports.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-without-ports.golden new file mode 100644 index 0000000000..662eefb21c --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-multiple-workload-addresses-without-ports.golden @@ -0,0 +1,113 @@ +{ + "proxyState": { + "identity": { + "tenancy": { + "partition": "default", + "namespace": "default", + "peerName": "local" + }, + "name": "test-identity" + }, + "listeners": [ + { + "name": "public_listener", + "direction": "DIRECTION_INBOUND", + "hostPort": { + "host": "10.0.0.1", + "port": 20000 + }, + "routers": [ + { + "match": { + "alpnProtocols": [ + "consul~admin-port" + ] + }, + "l4": { + "name": "local_app:admin-port", + "statPrefix": "public_listener" + }, + "inboundTls": { + "inboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "trustBundlePeerNameKeys": [ + "local" + ] + } + } + } + }, + { + "match": { + "alpnProtocols": [ + "consul~api-port" + ] + }, + "l4": { + "name": "local_app:api-port", + "statPrefix": "public_listener" + }, + "inboundTls": { + "inboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "trustBundlePeerNameKeys": [ + "local" + ] + } + } + } + } + ] + } + ], + "clusters": { + "local_app:api-port": { + "endpointGroup": { + "static": {} + } + }, + "local_app:admin-port": { + "endpointGroup": { + "static": {} + } + } + }, + "endpoints": { + "local_app:admin-port": { + "endpoints": [ + { + "hostPort": { + "host": "127.0.0.1", + "port": 8080 + } + } + ] + }, + "local_app:api-port": { + "endpoints": [ + { + "hostPort": { + "host": "127.0.0.1", + "port": 9090 + } + } + ] + } + } + }, + "requiredLeafCertificates": { + "test-identity": { + "name": "test-identity", + "namespace": "default", + "partition": "default" + } + }, + "requiredTrustBundles": { + "local": { + "peer": "local" + } + }, + "requiredEndpoints": {} +} \ No newline at end of file diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-single-workload-address-without-ports.golden b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-single-workload-address-without-ports.golden new file mode 100644 index 0000000000..662eefb21c --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/testdata/source/multiport-l4-single-workload-address-without-ports.golden @@ -0,0 +1,113 @@ +{ + "proxyState": { + "identity": { + "tenancy": { + "partition": "default", + "namespace": "default", + "peerName": "local" + }, + "name": "test-identity" + }, + "listeners": [ + { + "name": "public_listener", + "direction": "DIRECTION_INBOUND", + "hostPort": { + "host": "10.0.0.1", + "port": 20000 + }, + "routers": [ + { + "match": { + "alpnProtocols": [ + "consul~admin-port" + ] + }, + "l4": { + "name": "local_app:admin-port", + "statPrefix": "public_listener" + }, + "inboundTls": { + "inboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "trustBundlePeerNameKeys": [ + "local" + ] + } + } + } + }, + { + "match": { + "alpnProtocols": [ + "consul~api-port" + ] + }, + "l4": { + "name": "local_app:api-port", + "statPrefix": "public_listener" + }, + "inboundTls": { + "inboundMesh": { + "identityKey": "test-identity", + "validationContext": { + "trustBundlePeerNameKeys": [ + "local" + ] + } + } + } + } + ] + } + ], + "clusters": { + "local_app:api-port": { + "endpointGroup": { + "static": {} + } + }, + "local_app:admin-port": { + "endpointGroup": { + "static": {} + } + } + }, + "endpoints": { + "local_app:admin-port": { + "endpoints": [ + { + "hostPort": { + "host": "127.0.0.1", + "port": 8080 + } + } + ] + }, + "local_app:api-port": { + "endpoints": [ + { + "hostPort": { + "host": "127.0.0.1", + "port": 9090 + } + } + ] + } + } + }, + "requiredLeafCertificates": { + "test-identity": { + "name": "test-identity", + "namespace": "default", + "partition": "default" + } + }, + "requiredTrustBundles": { + "local": { + "peer": "local" + } + }, + "requiredEndpoints": {} +} \ No newline at end of file diff --git a/internal/testing/golden/golden.go b/internal/testing/golden/golden.go index 4466ad4cbc..8145d16814 100644 --- a/internal/testing/golden/golden.go +++ b/internal/testing/golden/golden.go @@ -22,6 +22,16 @@ var update = flag.Bool("update", false, "update golden files") // to the value of actual. func Get(t *testing.T, actual, filename string) string { t.Helper() + return string(GetBytes(t, actual, filename)) +} + +// GetBytes reads the expected value from the file at filename and returns the +// value as a byte array. filename is relative to the ./testdata directory. +// +// If the `-update` flag is used with `go test`, the golden file will be updated +// to the value of actual. +func GetBytes(t *testing.T, actual, filename string) []byte { + t.Helper() path := filepath.Join("testdata", filename) if *update { @@ -34,5 +44,5 @@ func Get(t *testing.T, actual, filename string) string { expected, err := os.ReadFile(path) require.NoError(t, err) - return string(expected) + return expected } diff --git a/proto-public/pbmesh/v1alpha1/pbproxystate/listener.pb.go b/proto-public/pbmesh/v1alpha1/pbproxystate/listener.pb.go index 24c6f5fc8c..4c315baa2e 100644 --- a/proto-public/pbmesh/v1alpha1/pbproxystate/listener.pb.go +++ b/proto-public/pbmesh/v1alpha1/pbproxystate/listener.pb.go @@ -500,11 +500,12 @@ type Match struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DestinationPort *wrapperspb.UInt32Value `protobuf:"bytes,1,opt,name=destination_port,json=destinationPort,proto3" json:"destination_port,omitempty"` - PrefixRanges []*CidrRange `protobuf:"bytes,2,rep,name=prefix_ranges,json=prefixRanges,proto3" json:"prefix_ranges,omitempty"` - SourcePrefixRanges []*CidrRange `protobuf:"bytes,3,rep,name=source_prefix_ranges,json=sourcePrefixRanges,proto3" json:"source_prefix_ranges,omitempty"` + AlpnProtocols []string `protobuf:"bytes,1,rep,name=alpn_protocols,json=alpnProtocols,proto3" json:"alpn_protocols,omitempty"` + DestinationPort *wrapperspb.UInt32Value `protobuf:"bytes,2,opt,name=destination_port,json=destinationPort,proto3" json:"destination_port,omitempty"` + PrefixRanges []*CidrRange `protobuf:"bytes,3,rep,name=prefix_ranges,json=prefixRanges,proto3" json:"prefix_ranges,omitempty"` + SourcePrefixRanges []*CidrRange `protobuf:"bytes,4,rep,name=source_prefix_ranges,json=sourcePrefixRanges,proto3" json:"source_prefix_ranges,omitempty"` // server_names matches based on SNI of the incoming request. - ServerNames []string `protobuf:"bytes,4,rep,name=server_names,json=serverNames,proto3" json:"server_names,omitempty"` + ServerNames []string `protobuf:"bytes,5,rep,name=server_names,json=serverNames,proto3" json:"server_names,omitempty"` } func (x *Match) Reset() { @@ -539,6 +540,13 @@ func (*Match) Descriptor() ([]byte, []int) { return file_pbmesh_v1alpha1_pbproxystate_listener_proto_rawDescGZIP(), []int{2} } +func (x *Match) GetAlpnProtocols() []string { + if x != nil { + return x.AlpnProtocols + } + return nil +} + func (x *Match) GetDestinationPort() *wrapperspb.UInt32Value { if x != nil { return x.DestinationPort @@ -963,125 +971,128 @@ var file_pbmesh_v1alpha1_pbproxystate_listener_proto_rawDesc = []byte{ 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x6c, 0x73, 0x42, 0x0d, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xba, 0x02, 0x0a, 0x05, 0x4d, 0x61, 0x74, - 0x63, 0x68, 0x12, 0x47, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, - 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5b, 0x0a, 0x0d, 0x70, - 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x66, - 0x69, 0x78, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x68, 0x0a, 0x14, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x12, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x09, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x3b, 0x0a, 0x0a, 0x70, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x70, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x4c, 0x65, 0x6e, 0x22, 0x86, 0x02, 0x0a, 0x0d, 0x4c, 0x34, 0x44, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xe1, 0x02, 0x0a, 0x05, 0x4d, 0x61, 0x74, + 0x63, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x70, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x6c, 0x70, 0x6e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, + 0x72, 0x74, 0x12, 0x5b, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x72, 0x61, 0x6e, + 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, + 0x65, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, + 0x68, 0x0a, 0x14, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, + 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x43, 0x69, 0x64, 0x72, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x12, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x72, 0x65, + 0x66, 0x69, 0x78, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x09, + 0x43, 0x69, 0x64, 0x72, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x12, 0x3b, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x09, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x4c, 0x65, 0x6e, 0x22, 0x86, 0x02, + 0x0a, 0x0d, 0x4c, 0x34, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x50, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x12, 0x58, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x34, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, + 0x0a, 0x13, 0x61, 0x64, 0x64, 0x5f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x61, 0x64, 0x64, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, + 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x15, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa1, 0x03, 0x0a, 0x0d, 0x4c, 0x37, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x58, 0x0a, - 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, - 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, - 0x4c, 0x34, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x69, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x61, 0x64, 0x64, 0x5f, 0x65, - 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x61, 0x64, 0x64, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x49, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x69, - 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x62, - 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, - 0xa1, 0x03, 0x0a, 0x0d, 0x4c, 0x37, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x5f, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, - 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x53, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x37, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x58, 0x0a, 0x0a, 0x69, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x53, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x37, - 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x61, 0x64, 0x64, 0x5f, 0x65, 0x6d, 0x70, - 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x11, 0x61, 0x64, 0x64, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x5f, 0x78, 0x66, 0x63, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x58, 0x66, 0x63, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x6d, - 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x6d, 0x61, - 0x78, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0x31, 0x0a, 0x0e, 0x53, 0x4e, 0x49, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x5f, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, - 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x2a, 0x55, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, - 0x0a, 0x11, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x42, 0x4f, - 0x55, 0x4e, 0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x2a, 0x54, 0x0a, - 0x12, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x1b, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, - 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, - 0x4c, 0x54, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x5f, - 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x45, 0x58, 0x41, 0x43, - 0x54, 0x10, 0x01, 0x2a, 0x71, 0x0a, 0x0a, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, - 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x41, 0x52, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x25, 0x0a, - 0x21, 0x43, 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x4c, 0x37, 0x5f, 0x50, - 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x49, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x54, 0x49, - 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, - 0x54, 0x59, 0x5f, 0x4c, 0x34, 0x5f, 0x54, 0x4c, 0x53, 0x5f, 0x49, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x2a, 0x4f, 0x0a, 0x0a, 0x4c, 0x37, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x14, 0x0a, 0x10, 0x4c, 0x37, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, - 0x43, 0x4f, 0x4c, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4c, 0x37, - 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x32, 0x10, - 0x01, 0x12, 0x14, 0x0a, 0x10, 0x4c, 0x37, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, - 0x5f, 0x47, 0x52, 0x50, 0x43, 0x10, 0x02, 0x42, 0xd9, 0x02, 0x0a, 0x2f, 0x63, 0x6f, 0x6d, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, - 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x42, 0x0d, 0x4c, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, - 0x61, 0x74, 0x65, 0xa2, 0x02, 0x05, 0x48, 0x43, 0x4d, 0x56, 0x50, 0xaa, 0x02, 0x2b, 0x48, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, - 0x65, 0x73, 0x68, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x62, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0xca, 0x02, 0x2b, 0x48, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, - 0x68, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x50, 0x62, 0x70, 0x72, 0x6f, - 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0xe2, 0x02, 0x37, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, - 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x50, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x2f, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x68, 0x3a, 0x3a, 0x56, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3a, 0x3a, 0x50, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x12, 0x58, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x37, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x13, + 0x61, 0x64, 0x64, 0x5f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x61, 0x64, 0x64, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x78, 0x66, 0x63, 0x63, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x58, 0x66, 0x63, 0x63, 0x12, + 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x15, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x31, 0x0a, 0x0e, 0x53, 0x4e, + 0x49, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, + 0x73, 0x74, 0x61, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x2a, 0x55, 0x0a, + 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, + 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, 0x55, + 0x4e, 0x44, 0x10, 0x02, 0x2a, 0x54, 0x0a, 0x12, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x1b, 0x42, 0x41, + 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x53, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x42, + 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, + 0x4e, 0x53, 0x5f, 0x45, 0x58, 0x41, 0x43, 0x54, 0x10, 0x01, 0x2a, 0x71, 0x0a, 0x0a, 0x43, 0x61, + 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x41, 0x50, 0x41, + 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x41, 0x52, 0x45, + 0x4e, 0x54, 0x10, 0x00, 0x12, 0x25, 0x0a, 0x21, 0x43, 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, + 0x54, 0x59, 0x5f, 0x4c, 0x37, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x49, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x43, + 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x4c, 0x34, 0x5f, 0x54, 0x4c, 0x53, + 0x5f, 0x49, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x2a, 0x4f, 0x0a, + 0x0a, 0x4c, 0x37, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x14, 0x0a, 0x10, 0x4c, + 0x37, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x10, + 0x00, 0x12, 0x15, 0x0a, 0x11, 0x4c, 0x37, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, + 0x5f, 0x48, 0x54, 0x54, 0x50, 0x32, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x4c, 0x37, 0x5f, 0x50, + 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x47, 0x52, 0x50, 0x43, 0x10, 0x02, 0x42, 0xd9, + 0x02, 0x0a, 0x2f, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x42, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, + 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x70, 0x62, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0xa2, 0x02, 0x05, 0x48, 0x43, 0x4d, + 0x56, 0x50, 0xaa, 0x02, 0x2b, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x31, 0x2e, 0x50, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, + 0xca, 0x02, 0x2b, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, + 0x31, 0x5c, 0x50, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0xe2, 0x02, + 0x37, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, + 0x50, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x2f, 0x48, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x4d, 0x65, + 0x73, 0x68, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3a, 0x3a, 0x50, 0x62, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/proto-public/pbmesh/v1alpha1/pbproxystate/listener.proto b/proto-public/pbmesh/v1alpha1/pbproxystate/listener.proto index d4a4dcda9f..5c0f8b3718 100644 --- a/proto-public/pbmesh/v1alpha1/pbproxystate/listener.proto +++ b/proto-public/pbmesh/v1alpha1/pbproxystate/listener.proto @@ -74,11 +74,12 @@ message Router { } message Match { - google.protobuf.UInt32Value destination_port = 1; - repeated CidrRange prefix_ranges = 2; - repeated CidrRange source_prefix_ranges = 3; + repeated string alpn_protocols = 1; + google.protobuf.UInt32Value destination_port = 2; + repeated CidrRange prefix_ranges = 3; + repeated CidrRange source_prefix_ranges = 4; // server_names matches based on SNI of the incoming request. - repeated string server_names = 4; + repeated string server_names = 5; } message CidrRange {