add partition to SNI when partition is non default (#10917)

This commit is contained in:
Dhia Ayachi 2021-09-01 10:35:39 -04:00 committed by GitHub
parent 3254308fd3
commit 09197c989c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 65 additions and 28 deletions

View File

@ -2,10 +2,17 @@ package connect
import ( import (
"fmt" "fmt"
"strings"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
) )
const (
internal = "internal"
version = "v1"
internalVersion = internal + "-" + version
)
func UpstreamSNI(u *structs.Upstream, subset string, dc string, trustDomain string) string { func UpstreamSNI(u *structs.Upstream, subset string, dc string, trustDomain string) string {
if u.Datacenter != "" { if u.Datacenter != "" {
dc = u.Datacenter dc = u.Datacenter
@ -14,23 +21,39 @@ func UpstreamSNI(u *structs.Upstream, subset string, dc string, trustDomain stri
if u.DestinationType == structs.UpstreamDestTypePreparedQuery { if u.DestinationType == structs.UpstreamDestTypePreparedQuery {
return QuerySNI(u.DestinationName, dc, trustDomain) return QuerySNI(u.DestinationName, dc, trustDomain)
} }
return ServiceSNI(u.DestinationName, subset, u.DestinationNamespace, dc, trustDomain) return ServiceSNI(u.DestinationName, subset, u.DestinationNamespace, u.DestinationPartition, dc, trustDomain)
} }
func DatacenterSNI(dc string, trustDomain string) string { func DatacenterSNI(dc string, trustDomain string) string {
return fmt.Sprintf("%s.internal.%s", dc, trustDomain) return fmt.Sprintf("%s.internal.%s", dc, trustDomain)
} }
func ServiceSNI(service string, subset string, namespace string, datacenter string, trustDomain string) string { func ServiceSNI(service string, subset string, namespace string, partition string, datacenter string, trustDomain string) string {
if namespace == "" { if namespace == "" {
namespace = "default" namespace = "default"
} }
if partition == "" {
if subset == "" { partition = "default"
return fmt.Sprintf("%s.%s.%s.internal.%s", service, namespace, datacenter, trustDomain)
} else {
return fmt.Sprintf("%s.%s.%s.%s.internal.%s", subset, service, namespace, datacenter, trustDomain)
} }
switch partition {
case "default":
if subset == "" {
return dotJoin(service, namespace, datacenter, internal, trustDomain)
} else {
return dotJoin(subset, service, namespace, datacenter, internal, trustDomain)
}
default:
if subset == "" {
return dotJoin(service, namespace, partition, datacenter, internalVersion, trustDomain)
} else {
return dotJoin(subset, service, namespace, partition, datacenter, internalVersion, trustDomain)
}
}
}
func dotJoin(parts ...string) string {
return strings.Join(parts, ".")
} }
func QuerySNI(service string, datacenter string, trustDomain string) string { func QuerySNI(service string, datacenter string, trustDomain string) string {
@ -38,5 +61,5 @@ func QuerySNI(service string, datacenter string, trustDomain string) string {
} }
func TargetSNI(target *structs.DiscoveryTarget, trustDomain string) string { func TargetSNI(target *structs.DiscoveryTarget, trustDomain string) string {
return ServiceSNI(target.Service, target.ServiceSubset, target.Namespace, target.Datacenter, trustDomain) return ServiceSNI(target.Service, target.ServiceSubset, target.Namespace, target.Partition, target.Datacenter, trustDomain)
} }

View File

@ -11,8 +11,10 @@ const (
testTrustDomain1 = "5fcd4b81-a2ca-405a-ac62-0fac602c1949.consul" testTrustDomain1 = "5fcd4b81-a2ca-405a-ac62-0fac602c1949.consul"
testTrustDomain2 = "d2e1a32e-5733-47f2-a9dd-6cf271aab5b7.consul" testTrustDomain2 = "d2e1a32e-5733-47f2-a9dd-6cf271aab5b7.consul"
testTrustDomainSuffix1 = "internal.5fcd4b81-a2ca-405a-ac62-0fac602c1949.consul" testTrustDomainSuffix1 = internal + ".5fcd4b81-a2ca-405a-ac62-0fac602c1949.consul"
testTrustDomainSuffix2 = "internal.d2e1a32e-5733-47f2-a9dd-6cf271aab5b7.consul" testTrustDomainSuffix1WithPart = internalVersion + ".5fcd4b81-a2ca-405a-ac62-0fac602c1949.consul"
testTrustDomainSuffix2 = internal + ".d2e1a32e-5733-47f2-a9dd-6cf271aab5b7.consul"
testTrustDomainSuffix2WithPart = internalVersion + ".d2e1a32e-5733-47f2-a9dd-6cf271aab5b7.consul"
) )
func TestUpstreamSNI(t *testing.T) { func TestUpstreamSNI(t *testing.T) {
@ -101,19 +103,35 @@ func TestDatacenterSNI(t *testing.T) {
func TestServiceSNI(t *testing.T) { func TestServiceSNI(t *testing.T) {
// empty namespace, empty subset // empty namespace, empty subset
require.Equal(t, "api.default.foo."+testTrustDomainSuffix1, require.Equal(t, "api.default.foo."+testTrustDomainSuffix1,
ServiceSNI("api", "", "", "foo", testTrustDomain1)) ServiceSNI("api", "", "", "", "foo", testTrustDomain1))
// set namespace, empty subset // set namespace, empty subset
require.Equal(t, "api.neighbor.foo."+testTrustDomainSuffix2, require.Equal(t, "api.neighbor.foo."+testTrustDomainSuffix2,
ServiceSNI("api", "", "neighbor", "foo", testTrustDomain2)) ServiceSNI("api", "", "neighbor", "", "foo", testTrustDomain2))
// empty namespace, set subset // empty namespace, set subset
require.Equal(t, "v2.api.default.foo."+testTrustDomainSuffix1, require.Equal(t, "v2.api.default.foo."+testTrustDomainSuffix1,
ServiceSNI("api", "v2", "", "foo", testTrustDomain1)) ServiceSNI("api", "v2", "", "", "foo", testTrustDomain1))
// set namespace, set subset // set namespace, set subset
require.Equal(t, "canary.api.neighbor.foo."+testTrustDomainSuffix2, require.Equal(t, "canary.api.neighbor.foo."+testTrustDomainSuffix2,
ServiceSNI("api", "canary", "neighbor", "foo", testTrustDomain2)) ServiceSNI("api", "canary", "neighbor", "", "foo", testTrustDomain2))
// empty namespace, empty subset, set partition
require.Equal(t, "api.default.part1.foo."+testTrustDomainSuffix1WithPart,
ServiceSNI("api", "", "", "part1", "foo", testTrustDomain1))
// set namespace, empty subset, set partition
require.Equal(t, "api.neighbor.part1.foo."+testTrustDomainSuffix2WithPart,
ServiceSNI("api", "", "neighbor", "part1", "foo", testTrustDomain2))
// empty namespace, set subset, set partition
require.Equal(t, "v2.api.default.part1.foo."+testTrustDomainSuffix1WithPart,
ServiceSNI("api", "v2", "", "part1", "foo", testTrustDomain1))
// set namespace, set subset, set partition
require.Equal(t, "canary.api.neighbor.part1.foo."+testTrustDomainSuffix2WithPart,
ServiceSNI("api", "canary", "neighbor", "part1", "foo", testTrustDomain2))
} }
func TestQuerySNI(t *testing.T) { func TestQuerySNI(t *testing.T) {

View File

@ -1868,7 +1868,7 @@ func TestState_WatchesAndUpdates(t *testing.T) {
// should not be used in DC-local calls. // should not be used in DC-local calls.
require.Equal(t, snap.ConnectProxy.PassthroughUpstreams, map[string]ServicePassthroughAddrs{ require.Equal(t, snap.ConnectProxy.PassthroughUpstreams, map[string]ServicePassthroughAddrs{
db.String(): { db.String(): {
SNI: connect.ServiceSNI("db", "", structs.IntentionDefaultNamespace, snap.Datacenter, snap.Roots.TrustDomain), SNI: connect.ServiceSNI("db", "", structs.IntentionDefaultNamespace, "", snap.Datacenter, snap.Roots.TrustDomain),
SpiffeID: connect.SpiffeIDService{ SpiffeID: connect.SpiffeIDService{
Host: snap.Roots.TrustDomain, Host: snap.Roots.TrustDomain,
Namespace: db.NamespaceOrDefault(), Namespace: db.NamespaceOrDefault(),

View File

@ -87,12 +87,7 @@ func (s *handlerUpstreams) handleUpdateUpstreams(ctx context.Context, u cache.Up
svc.Name = dst svc.Name = dst
} }
sni := connect.ServiceSNI( sni := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), snap.Datacenter, snap.Roots.TrustDomain)
svc.Name,
"",
svc.NamespaceOrDefault(),
snap.Datacenter,
snap.Roots.TrustDomain)
spiffeID := connect.SpiffeIDService{ spiffeID := connect.SpiffeIDService{
Host: snap.Roots.TrustDomain, Host: snap.Roots.TrustDomain,

View File

@ -211,6 +211,7 @@ type DiscoveryTarget struct {
Service string `json:",omitempty"` Service string `json:",omitempty"`
ServiceSubset string `json:",omitempty"` ServiceSubset string `json:",omitempty"`
Namespace string `json:",omitempty"` Namespace string `json:",omitempty"`
Partition string `json:",omitempty"`
Datacenter string `json:",omitempty"` Datacenter string `json:",omitempty"`
MeshGateway MeshGatewayConfig `json:",omitempty"` MeshGateway MeshGatewayConfig `json:",omitempty"`

View File

@ -306,7 +306,7 @@ func (s *ResourceGenerator) makeGatewayServiceClusters(
clusters := make([]proto.Message, 0, len(services)) clusters := make([]proto.Message, 0, len(services))
for svc := range services { for svc := range services {
clusterName := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) clusterName := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
resolver, hasResolver := resolvers[svc] resolver, hasResolver := resolvers[svc]
var loadBalancer *structs.LoadBalancer var loadBalancer *structs.LoadBalancer
@ -345,7 +345,7 @@ func (s *ResourceGenerator) makeGatewayServiceClusters(
} }
opts := gatewayClusterOpts{ opts := gatewayClusterOpts{
name: connect.ServiceSNI(svc.Name, name, svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain), name: connect.ServiceSNI(svc.Name, name, svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain),
hostnameEndpoints: subsetHostnameEndpoints, hostnameEndpoints: subsetHostnameEndpoints,
onlyPassing: subset.OnlyPassing, onlyPassing: subset.OnlyPassing,
connectTimeout: resolver.ConnectTimeout, connectTimeout: resolver.ConnectTimeout,

View File

@ -246,7 +246,7 @@ func (s *ResourceGenerator) endpointsFromServicesAndResolvers(
// now generate the load assignment for all subsets // now generate the load assignment for all subsets
for subsetName, groups := range clusterEndpoints { for subsetName, groups := range clusterEndpoints {
clusterName := connect.ServiceSNI(svc.Name, subsetName, svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) clusterName := connect.ServiceSNI(svc.Name, subsetName, svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
la := makeLoadAssignment( la := makeLoadAssignment(
clusterName, clusterName,
groups, groups,

View File

@ -1013,7 +1013,7 @@ func (s *ResourceGenerator) makeTerminatingGatewayListener(
// Make a FilterChain for each linked service // Make a FilterChain for each linked service
// Match on the cluster name, // Match on the cluster name,
for _, svc := range cfgSnap.TerminatingGateway.ValidServices() { for _, svc := range cfgSnap.TerminatingGateway.ValidServices() {
clusterName := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) clusterName := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
// Resolvers are optional. // Resolvers are optional.
resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc] resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc]
@ -1048,7 +1048,7 @@ func (s *ResourceGenerator) makeTerminatingGatewayListener(
if hasResolver { if hasResolver {
// generate 1 filter chain for each service subset // generate 1 filter chain for each service subset
for subsetName := range resolver.Subsets { for subsetName := range resolver.Subsets {
subsetClusterName := connect.ServiceSNI(svc.Name, subsetName, svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) subsetClusterName := connect.ServiceSNI(svc.Name, subsetName, svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
subsetClusterChain, err := s.makeFilterChainTerminatingGateway( subsetClusterChain, err := s.makeFilterChainTerminatingGateway(
cfgSnap, cfgSnap,

View File

@ -77,7 +77,7 @@ func (s *ResourceGenerator) routesFromSnapshotTerminatingGateway(cfgSnap *proxyc
var resources []proto.Message var resources []proto.Message
for _, svc := range cfgSnap.TerminatingGateway.ValidServices() { for _, svc := range cfgSnap.TerminatingGateway.ValidServices() {
clusterName := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) clusterName := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc] resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc]
svcConfig := cfgSnap.TerminatingGateway.ServiceConfigs[svc] svcConfig := cfgSnap.TerminatingGateway.ServiceConfigs[svc]
@ -109,7 +109,7 @@ func (s *ResourceGenerator) routesFromSnapshotTerminatingGateway(cfgSnap *proxyc
// If there is a service-resolver for this service then also setup routes for each subset // If there is a service-resolver for this service then also setup routes for each subset
for name := range resolver.Subsets { for name := range resolver.Subsets {
clusterName = connect.ServiceSNI(svc.Name, name, svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) clusterName = connect.ServiceSNI(svc.Name, name, svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
route, err := makeNamedDefaultRouteWithLB(clusterName, lb, true) route, err := makeNamedDefaultRouteWithLB(clusterName, lb, true)
if err != nil { if err != nil {
s.Logger.Error("failed to make route", "cluster", clusterName, "error", err) s.Logger.Error("failed to make route", "cluster", clusterName, "error", err)