2022-03-07 17:47:14 +00:00
|
|
|
package proxycfg
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/mitchellh/go-testing-interface"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2022-04-05 21:10:06 +00:00
|
|
|
"github.com/hashicorp/consul/acl"
|
2022-03-07 17:47:14 +00:00
|
|
|
"github.com/hashicorp/consul/agent/cache"
|
|
|
|
"github.com/hashicorp/consul/agent/connect"
|
|
|
|
"github.com/hashicorp/consul/agent/consul/discoverychain"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
|
|
"github.com/hashicorp/consul/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGateway(
|
|
|
|
t testing.T,
|
|
|
|
populateServices bool,
|
|
|
|
protocol string,
|
|
|
|
variation string,
|
|
|
|
nsFn func(ns *structs.NodeService),
|
|
|
|
configFn func(entry *structs.IngressGatewayConfigEntry),
|
|
|
|
extraUpdates []cache.UpdateEvent,
|
|
|
|
additionalEntries ...structs.ConfigEntry,
|
|
|
|
) *ConfigSnapshot {
|
|
|
|
roots, placeholderLeaf := TestCerts(t)
|
|
|
|
|
|
|
|
entry := &structs.IngressGatewayConfigEntry{
|
|
|
|
Kind: structs.IngressGateway,
|
|
|
|
Name: "ingress-gateway",
|
|
|
|
}
|
|
|
|
|
|
|
|
if populateServices {
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: protocol,
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "db"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if configFn != nil {
|
|
|
|
configFn(entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
baseEvents := []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: rootsWatchID,
|
|
|
|
Result: roots,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayConfigWatchID,
|
|
|
|
Result: &structs.ConfigEntryResponse{
|
|
|
|
Entry: entry,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: leafWatchID,
|
|
|
|
Result: placeholderLeaf, // TODO(rb): should this be generated differently?
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if populateServices {
|
|
|
|
baseEvents = testSpliceEvents(baseEvents, []cache.UpdateEvent{{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: structs.NewServiceName("db", nil),
|
|
|
|
Port: 8080,
|
|
|
|
Hosts: nil,
|
|
|
|
Protocol: protocol,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}})
|
|
|
|
|
|
|
|
upstreams := structs.TestUpstreams(t)
|
|
|
|
upstreams = structs.Upstreams{upstreams[0]} // just keep 'db'
|
|
|
|
|
|
|
|
baseEvents = testSpliceEvents(baseEvents, setupTestVariationConfigEntriesAndSnapshot(
|
|
|
|
t, variation, upstreams, additionalEntries...,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
return testConfigSnapshotFixture(t, &structs.NodeService{
|
|
|
|
Kind: structs.ServiceKindIngressGateway,
|
|
|
|
Service: "ingress-gateway",
|
|
|
|
Port: 9999,
|
|
|
|
Address: "1.2.3.4",
|
|
|
|
Meta: nil,
|
|
|
|
TaggedAddresses: nil,
|
|
|
|
}, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewaySDS_GatewayLevel_MixedTLS(t testing.T) *ConfigSnapshot {
|
|
|
|
secureUID := UpstreamIDFromString("secure")
|
|
|
|
secureChain := discoverychain.TestCompileConfigEntries(
|
|
|
|
t,
|
|
|
|
"secure",
|
|
|
|
"default",
|
|
|
|
"default",
|
|
|
|
"dc1",
|
|
|
|
connect.TestClusterID+".consul",
|
|
|
|
nil,
|
|
|
|
)
|
|
|
|
|
|
|
|
insecureUID := UpstreamIDFromString("insecure")
|
|
|
|
insecureChain := discoverychain.TestCompileConfigEntries(
|
|
|
|
t,
|
|
|
|
"insecure",
|
|
|
|
"default",
|
|
|
|
"default",
|
|
|
|
"dc1",
|
|
|
|
connect.TestClusterID+".consul",
|
|
|
|
nil,
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "tcp", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
// Disable GW-level defaults so we can mix TLS and non-TLS listeners
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
SDS: nil,
|
|
|
|
}
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
// Setup two TCP listeners, one with and one without SDS config
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "tcp",
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "listener-sds-cluster",
|
|
|
|
CertResource: "listener-cert",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "secure"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Port: 9090,
|
|
|
|
Protocol: "tcp",
|
|
|
|
TLS: nil,
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "insecure"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: structs.NewServiceName("secure", nil),
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "tcp",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: structs.NewServiceName("insecure", nil),
|
|
|
|
Port: 9090,
|
|
|
|
Protocol: "tcp",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + secureUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: secureChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + secureChain.ID() + ":" + secureUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "secure"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + insecureUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: insecureChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + insecureChain.ID() + ":" + insecureUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "insecure"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewaySDS_GatewayLevel(t testing.T) *ConfigSnapshot {
|
|
|
|
return TestConfigSnapshotIngressGateway(t, true, "tcp", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster",
|
|
|
|
CertResource: "cert-resource",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewaySDS_GatewayAndListenerLevel(t testing.T) *ConfigSnapshot {
|
|
|
|
return TestConfigSnapshotIngressGateway(t, true, "tcp", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster",
|
|
|
|
CertResource: "cert-resource",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
entry.Listeners[0].TLS = &structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
// Override the cert, fall back to the cluster at gw level. We
|
|
|
|
// don't test every possible valid combination here since we
|
|
|
|
// already did that in TestResolveListenerSDSConfig. This is
|
|
|
|
// just an extra check to make sure that data is plumbed through
|
|
|
|
// correctly.
|
|
|
|
CertResource: "listener-cert",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewaySDS_GatewayAndListenerLevel_HTTP(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
http = structs.NewServiceName("http", nil)
|
|
|
|
httpUID = NewUpstreamIDFromServiceName(http)
|
|
|
|
httpChain = discoverychain.TestCompileConfigEntries(t, "http", "default", "default", "dc1", connect.TestClusterID+".consul", nil,
|
|
|
|
&structs.ServiceConfigEntry{
|
|
|
|
Kind: structs.ServiceDefaults,
|
|
|
|
Name: "http",
|
|
|
|
Protocol: "http",
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "http", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster",
|
|
|
|
CertResource: "cert-resource",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "http"},
|
|
|
|
},
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
// Override the cert, fall back to the cluster at gw level. We
|
|
|
|
// don't test every possible valid combination here since we
|
|
|
|
// already did that in TestResolveListenerSDSConfig. This is
|
|
|
|
// just an extra check to make sure that data is plumbed through
|
|
|
|
// correctly.
|
|
|
|
CertResource: "listener-cert",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: http,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + httpUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: httpChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + httpChain.ID() + ":" + httpUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "http"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewaySDS_ServiceLevel(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
s1 = structs.NewServiceName("s1", nil)
|
|
|
|
s1UID = NewUpstreamIDFromServiceName(s1)
|
|
|
|
s1Chain = discoverychain.TestCompileConfigEntries(t, "s1", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s2 = structs.NewServiceName("s2", nil)
|
|
|
|
s2UID = NewUpstreamIDFromServiceName(s2)
|
|
|
|
s2Chain = discoverychain.TestCompileConfigEntries(t, "s2", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "tcp", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
// Disable GW-level defaults so we can test only service-level
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
SDS: nil,
|
|
|
|
}
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
// Setup http listeners, one multiple services with SDS
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
TLS: nil, // no listener-level SDS config
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{
|
|
|
|
Name: "s1",
|
|
|
|
Hosts: []string{"s1.example.com"},
|
|
|
|
TLS: &structs.GatewayServiceTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster-1",
|
|
|
|
CertResource: "s1.example.com-cert",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "s2",
|
|
|
|
Hosts: []string{"s2.example.com"},
|
|
|
|
TLS: &structs.GatewayServiceTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster-2",
|
|
|
|
CertResource: "s2.example.com-cert",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: s1,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s2,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s1UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s1Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s1Chain.ID() + ":" + s1UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s1"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s2UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s2Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s2Chain.ID() + ":" + s2UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewaySDS_ListenerAndServiceLevel(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
s1 = structs.NewServiceName("s1", nil)
|
|
|
|
s1UID = NewUpstreamIDFromServiceName(s1)
|
|
|
|
s1Chain = discoverychain.TestCompileConfigEntries(t, "s1", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s2 = structs.NewServiceName("s2", nil)
|
|
|
|
s2UID = NewUpstreamIDFromServiceName(s2)
|
|
|
|
s2Chain = discoverychain.TestCompileConfigEntries(t, "s2", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "tcp", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
// Disable GW-level defaults so we can test only service-level
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
SDS: nil,
|
|
|
|
}
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
// Setup http listeners, one multiple services with SDS
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster-2",
|
|
|
|
CertResource: "*.example.com-cert",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{
|
|
|
|
Name: "s1",
|
|
|
|
Hosts: []string{"s1.example.com"},
|
|
|
|
TLS: &structs.GatewayServiceTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster-1",
|
|
|
|
CertResource: "s1.example.com-cert",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "s2",
|
|
|
|
// s2 uses the default listener cert
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: s1,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s2,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s1UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s1Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s1Chain.ID() + ":" + s1UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s1"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s2UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s2Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s2Chain.ID() + ":" + s2UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewaySDS_MixedNoTLS(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
s1 = structs.NewServiceName("s1", nil)
|
|
|
|
s1UID = NewUpstreamIDFromServiceName(s1)
|
|
|
|
s1Chain = discoverychain.TestCompileConfigEntries(t, "s1", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s2 = structs.NewServiceName("s2", nil)
|
|
|
|
s2UID = NewUpstreamIDFromServiceName(s2)
|
|
|
|
s2Chain = discoverychain.TestCompileConfigEntries(t, "s2", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "tcp", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
// Disable GW-level defaults so we can test only service-level
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
SDS: nil,
|
|
|
|
}
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
// Setup http listeners, one multiple services with SDS
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
TLS: nil, // No listener level TLS setup either
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{
|
|
|
|
Name: "s1",
|
|
|
|
Hosts: []string{"s1.example.com"},
|
|
|
|
TLS: &structs.GatewayServiceTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "sds-cluster-1",
|
|
|
|
CertResource: "s1.example.com-cert",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "s2",
|
|
|
|
// s2 has no SDS config so should be non-TLS
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: s1,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s2,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s1UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s1Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s1Chain.ID() + ":" + s1UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s1"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s2UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s2Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s2Chain.ID() + ":" + s2UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGateway_MixedListeners(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
s1 = structs.NewServiceName("s1", nil)
|
|
|
|
s1UID = NewUpstreamIDFromServiceName(s1)
|
|
|
|
s1Chain = discoverychain.TestCompileConfigEntries(t, "s1", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s2 = structs.NewServiceName("s2", nil)
|
|
|
|
s2UID = NewUpstreamIDFromServiceName(s2)
|
|
|
|
s2Chain = discoverychain.TestCompileConfigEntries(t, "s2", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "tcp", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.TLS = structs.GatewayTLSConfig{
|
|
|
|
Enabled: false, // No Gateway-level built-in TLS
|
|
|
|
SDS: nil, // Undo gateway-level SDS
|
|
|
|
}
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
// One listener has built-in TLS, one doesn't
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
Enabled: true, // built-in TLS enabled
|
|
|
|
},
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Port: 9090,
|
|
|
|
Protocol: "http",
|
|
|
|
TLS: nil, // No TLS enabled
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s2"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: s1,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s2,
|
|
|
|
Port: 9090,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s1UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s1Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s1Chain.ID() + ":" + s1UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s1"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s2UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s2Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s2Chain.ID() + ":" + s2UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngress_HTTPMultipleServices(t testing.T) *ConfigSnapshot {
|
|
|
|
// We do not add baz/qux here so that we test the chain.IsDefault() case
|
|
|
|
entries := []structs.ConfigEntry{
|
|
|
|
&structs.ProxyConfigEntry{
|
|
|
|
Kind: structs.ProxyDefaults,
|
|
|
|
Name: structs.ProxyConfigGlobal,
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"protocol": "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
&structs.ServiceResolverConfigEntry{
|
|
|
|
Kind: structs.ServiceResolver,
|
|
|
|
Name: "foo",
|
|
|
|
ConnectTimeout: 22 * time.Second,
|
|
|
|
},
|
|
|
|
&structs.ServiceResolverConfigEntry{
|
|
|
|
Kind: structs.ServiceResolver,
|
|
|
|
Name: "bar",
|
|
|
|
ConnectTimeout: 22 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
foo = structs.NewServiceName("foo", nil)
|
|
|
|
fooUID = NewUpstreamIDFromServiceName(foo)
|
|
|
|
fooChain = discoverychain.TestCompileConfigEntries(t, "foo", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...)
|
|
|
|
|
|
|
|
bar = structs.NewServiceName("bar", nil)
|
|
|
|
barUID = NewUpstreamIDFromServiceName(bar)
|
|
|
|
barChain = discoverychain.TestCompileConfigEntries(t, "bar", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...)
|
|
|
|
|
|
|
|
baz = structs.NewServiceName("baz", nil)
|
|
|
|
bazUID = NewUpstreamIDFromServiceName(baz)
|
|
|
|
bazChain = discoverychain.TestCompileConfigEntries(t, "baz", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...)
|
|
|
|
|
|
|
|
qux = structs.NewServiceName("qux", nil)
|
|
|
|
quxUID = NewUpstreamIDFromServiceName(qux)
|
|
|
|
quxChain = discoverychain.TestCompileConfigEntries(t, "qux", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...)
|
|
|
|
)
|
|
|
|
|
2022-03-30 15:04:18 +00:00
|
|
|
require.False(t, fooChain.Default)
|
|
|
|
require.False(t, barChain.Default)
|
|
|
|
require.True(t, bazChain.Default)
|
|
|
|
require.True(t, quxChain.Default)
|
2022-03-07 17:47:14 +00:00
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "http", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{
|
|
|
|
Name: "foo",
|
|
|
|
Hosts: []string{
|
|
|
|
"test1.example.com",
|
|
|
|
"test2.example.com",
|
|
|
|
"test2.example.com:8080",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Port: 443,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "baz"},
|
|
|
|
{Name: "qux"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: foo,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Hosts: []string{
|
|
|
|
"test1.example.com",
|
|
|
|
"test2.example.com",
|
|
|
|
"test2.example.com:8080",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: bar,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: baz,
|
|
|
|
Port: 443,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: qux,
|
|
|
|
Port: 443,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + fooUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: fooChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + fooChain.ID() + ":" + fooUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "foo"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + barUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: barChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + barChain.ID() + ":" + barUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "bar"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + bazUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: bazChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + bazChain.ID() + ":" + bazUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "baz"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + quxUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: quxChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + quxChain.ID() + ":" + quxUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "qux"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngress_MultipleListenersDuplicateService(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
foo = structs.NewServiceName("foo", nil)
|
|
|
|
fooUID = NewUpstreamIDFromServiceName(foo)
|
|
|
|
fooChain = discoverychain.TestCompileConfigEntries(t, "foo", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
bar = structs.NewServiceName("bar", nil)
|
|
|
|
barUID = NewUpstreamIDFromServiceName(bar)
|
|
|
|
barChain = discoverychain.TestCompileConfigEntries(t, "bar", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, false, "http", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "foo"},
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Port: 443,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "foo"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: foo,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: bar,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: foo,
|
|
|
|
Port: 443,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + fooUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: fooChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + fooChain.ID() + ":" + fooUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "foo"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + barUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: barChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + barChain.ID() + ":" + barUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodesAlternate(t),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGatewayWithChain(
|
|
|
|
t testing.T,
|
|
|
|
variant string,
|
2022-04-05 21:10:06 +00:00
|
|
|
webEntMeta, fooEntMeta *acl.EnterpriseMeta,
|
2022-03-07 17:47:14 +00:00
|
|
|
) *ConfigSnapshot {
|
|
|
|
if webEntMeta == nil {
|
2022-04-05 21:10:06 +00:00
|
|
|
webEntMeta = &acl.EnterpriseMeta{}
|
2022-03-07 17:47:14 +00:00
|
|
|
}
|
|
|
|
if fooEntMeta == nil {
|
2022-04-05 21:10:06 +00:00
|
|
|
fooEntMeta = &acl.EnterpriseMeta{}
|
2022-03-07 17:47:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
updates []cache.UpdateEvent
|
|
|
|
configFn func(entry *structs.IngressGatewayConfigEntry)
|
|
|
|
|
|
|
|
populateServices bool
|
|
|
|
useSDS bool
|
|
|
|
listenerSDS, webSDS, fooSDS, wildcard bool
|
|
|
|
)
|
|
|
|
switch variant {
|
|
|
|
case "router-header-manip":
|
|
|
|
configFn = func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{
|
|
|
|
Name: "db",
|
|
|
|
RequestHeaders: &structs.HTTPHeaderModifiers{
|
|
|
|
Add: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
Set: map[string]string{
|
|
|
|
"bar": "baz",
|
|
|
|
},
|
|
|
|
Remove: []string{"qux"},
|
|
|
|
},
|
|
|
|
ResponseHeaders: &structs.HTTPHeaderModifiers{
|
|
|
|
Add: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
Set: map[string]string{
|
|
|
|
"bar": "baz",
|
|
|
|
},
|
|
|
|
Remove: []string{"qux"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
populateServices = true
|
|
|
|
case "sds-listener-level":
|
|
|
|
// Listener-level SDS means all services share the default route.
|
|
|
|
useSDS = true
|
|
|
|
listenerSDS = true
|
|
|
|
case "sds-listener-level-wildcard":
|
|
|
|
// Listener-level SDS means all services share the default route.
|
|
|
|
useSDS = true
|
|
|
|
listenerSDS = true
|
|
|
|
wildcard = true
|
|
|
|
case "sds-service-level":
|
|
|
|
// Services should get separate routes and no default since they all
|
|
|
|
// have custom certs.
|
|
|
|
useSDS = true
|
|
|
|
webSDS = true
|
|
|
|
fooSDS = true
|
|
|
|
case "sds-service-level-mixed-tls":
|
|
|
|
// Web needs a separate route as it has custom filter chain but foo
|
|
|
|
// should use default route for listener.
|
|
|
|
useSDS = true
|
|
|
|
webSDS = true
|
|
|
|
default:
|
|
|
|
t.Fatalf("unknown variant %q", variant)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if useSDS {
|
|
|
|
webUpstream := structs.Upstream{
|
|
|
|
DestinationName: "web",
|
|
|
|
// We use empty not default here because of the way upstream identifiers
|
|
|
|
// vary between OSS and Enterprise currently causing test conflicts. In
|
|
|
|
// real life `proxycfg` always sets ingress upstream namespaces to
|
|
|
|
// `NamespaceOrDefault` which shouldn't matter because we should be
|
|
|
|
// consistent within a single binary it's just inconvenient if OSS and
|
|
|
|
// enterprise tests generate different output.
|
|
|
|
DestinationNamespace: webEntMeta.NamespaceOrEmpty(),
|
|
|
|
DestinationPartition: webEntMeta.PartitionOrEmpty(),
|
|
|
|
LocalBindPort: 9191,
|
|
|
|
IngressHosts: []string{
|
|
|
|
"www.example.com",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fooUpstream := structs.Upstream{
|
|
|
|
DestinationName: "foo",
|
|
|
|
DestinationNamespace: fooEntMeta.NamespaceOrEmpty(),
|
|
|
|
DestinationPartition: fooEntMeta.PartitionOrEmpty(),
|
|
|
|
LocalBindPort: 9191,
|
|
|
|
IngressHosts: []string{
|
|
|
|
"foo.example.com",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
web = structs.NewServiceName("web", webEntMeta)
|
|
|
|
webUID = NewUpstreamID(&webUpstream)
|
|
|
|
|
|
|
|
foo = structs.NewServiceName("foo", fooEntMeta)
|
|
|
|
fooUID = NewUpstreamID(&fooUpstream)
|
|
|
|
)
|
|
|
|
|
|
|
|
configFn = func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.TLS.SDS = nil
|
|
|
|
il := structs.IngressListener{
|
|
|
|
Port: 9191,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{
|
|
|
|
Name: "web",
|
|
|
|
Hosts: []string{"www.example.com"},
|
|
|
|
EnterpriseMeta: *webEntMeta,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "foo",
|
|
|
|
Hosts: []string{"foo.example.com"},
|
|
|
|
EnterpriseMeta: *fooEntMeta,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now set the appropriate SDS configs
|
|
|
|
if listenerSDS {
|
|
|
|
il.TLS = &structs.GatewayTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "listener-cluster",
|
|
|
|
CertResource: "listener-cert",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if webSDS {
|
|
|
|
il.Services[0].TLS = &structs.GatewayServiceTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "web-cluster",
|
|
|
|
CertResource: "www-cert",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if fooSDS {
|
|
|
|
il.Services[1].TLS = &structs.GatewayServiceTLSConfig{
|
|
|
|
SDS: &structs.GatewayTLSSDSConfig{
|
|
|
|
ClusterName: "foo-cluster",
|
|
|
|
CertResource: "foo-cert",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if wildcard {
|
|
|
|
// undo all that and set just a single wildcard config with no TLS to test
|
|
|
|
// the lookup path where we have to compare an actual resolved upstream to
|
|
|
|
// a wildcard config.
|
|
|
|
il.Services = []structs.IngressService{
|
|
|
|
{
|
|
|
|
Name: "*",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
entry.Listeners = []structs.IngressListener{il}
|
|
|
|
}
|
|
|
|
|
|
|
|
if wildcard {
|
|
|
|
// We also don't support user-specified hosts with wildcard so remove
|
|
|
|
// those from the upstreams.
|
|
|
|
webUpstream.IngressHosts = nil
|
|
|
|
fooUpstream.IngressHosts = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
entries := []structs.ConfigEntry{
|
|
|
|
&structs.ProxyConfigEntry{
|
|
|
|
Kind: structs.ProxyDefaults,
|
|
|
|
Name: structs.ProxyConfigGlobal,
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"protocol": "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
&structs.ServiceResolverConfigEntry{
|
|
|
|
Kind: structs.ServiceResolver,
|
|
|
|
Name: "web",
|
|
|
|
EnterpriseMeta: *webEntMeta,
|
|
|
|
ConnectTimeout: 22 * time.Second,
|
|
|
|
},
|
|
|
|
&structs.ServiceResolverConfigEntry{
|
|
|
|
Kind: structs.ServiceResolver,
|
|
|
|
Name: "foo",
|
|
|
|
EnterpriseMeta: *fooEntMeta,
|
|
|
|
ConnectTimeout: 22 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
webChain := discoverychain.TestCompileConfigEntries(t, "web",
|
|
|
|
webEntMeta.NamespaceOrDefault(),
|
|
|
|
webEntMeta.PartitionOrDefault(), "dc1",
|
|
|
|
connect.TestClusterID+".consul", nil, entries...)
|
|
|
|
fooChain := discoverychain.TestCompileConfigEntries(t, "foo",
|
|
|
|
fooEntMeta.NamespaceOrDefault(),
|
|
|
|
fooEntMeta.PartitionOrDefault(), "dc1",
|
|
|
|
connect.TestClusterID+".consul", nil, entries...)
|
|
|
|
|
|
|
|
updates = []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: web,
|
|
|
|
Port: 9191,
|
|
|
|
Protocol: "http",
|
|
|
|
Hosts: webUpstream.IngressHosts,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: foo,
|
|
|
|
Port: 9191,
|
|
|
|
Protocol: "http",
|
|
|
|
Hosts: fooUpstream.IngressHosts,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + webUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: webChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + fooUID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: fooChain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + webChain.ID() + ":" + webUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "web"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + fooChain.ID() + ":" + fooUID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "foo"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, populateServices, "http", "chain-and-router", nil, configFn, updates)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGateway_TLSMinVersionListenersGatewayDefaults(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
s1 = structs.NewServiceName("s1", nil)
|
|
|
|
s1UID = NewUpstreamIDFromServiceName(s1)
|
|
|
|
s1Chain = discoverychain.TestCompileConfigEntries(t, "s1", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s2 = structs.NewServiceName("s2", nil)
|
|
|
|
s2UID = NewUpstreamIDFromServiceName(s2)
|
|
|
|
s2Chain = discoverychain.TestCompileConfigEntries(t, "s2", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s3 = structs.NewServiceName("s3", nil)
|
|
|
|
s3UID = NewUpstreamIDFromServiceName(s3)
|
|
|
|
s3Chain = discoverychain.TestCompileConfigEntries(t, "s3", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s4 = structs.NewServiceName("s4", nil)
|
|
|
|
s4UID = NewUpstreamIDFromServiceName(s4)
|
|
|
|
s4Chain = discoverychain.TestCompileConfigEntries(t, "s4", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, true, "tcp", "default", nil,
|
|
|
|
func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.TLS.Enabled = true
|
|
|
|
entry.TLS.TLSMinVersion = types.TLSv1_2
|
|
|
|
|
|
|
|
// One listener disables TLS, one inherits TLS minimum version from the gateway
|
|
|
|
// config, two others set different versions
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
// Omits listener TLS config, should default to gateway TLS config
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// Explicitly sets listener TLS config to nil, should default to gateway TLS config
|
|
|
|
{
|
|
|
|
Port: 8081,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s2"},
|
|
|
|
},
|
|
|
|
TLS: nil,
|
|
|
|
},
|
|
|
|
// Explicitly enables TLS config, but with no listener default TLS params,
|
|
|
|
// should default to gateway TLS config
|
|
|
|
{
|
|
|
|
Port: 8082,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s3"},
|
|
|
|
},
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
Enabled: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// Explicitly unset gateway default TLS min version in favor of proxy default
|
|
|
|
{
|
|
|
|
Port: 8083,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s3"},
|
|
|
|
},
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
Enabled: true,
|
|
|
|
TLSMinVersion: types.TLSVersionAuto,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// Disables listener TLS
|
|
|
|
{
|
|
|
|
Port: 8084,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s4"},
|
|
|
|
},
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
Enabled: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
// One listener disables TLS, one inherits TLS minimum version from the gateway
|
|
|
|
// config, two others set different versions
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: s1,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s2,
|
|
|
|
Port: 8081,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s3,
|
|
|
|
Port: 8082,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s4,
|
|
|
|
Port: 8083,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s4,
|
|
|
|
Port: 8084,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s1UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s1Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s2UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s2Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s3UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s3Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s4UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s4Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s1Chain.ID() + ":" + s1UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s1"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s2Chain.ID() + ":" + s2UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s3Chain.ID() + ":" + s3UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s3"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s4Chain.ID() + ":" + s4UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s4"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGateway_SingleTLSListener(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
s1 = structs.NewServiceName("s1", nil)
|
|
|
|
s1UID = NewUpstreamIDFromServiceName(s1)
|
|
|
|
s1Chain = discoverychain.TestCompileConfigEntries(t, "s1", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s2 = structs.NewServiceName("s2", nil)
|
|
|
|
s2UID = NewUpstreamIDFromServiceName(s2)
|
|
|
|
s2Chain = discoverychain.TestCompileConfigEntries(t, "s2", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
return TestConfigSnapshotIngressGateway(t, true, "tcp", "simple", nil,
|
|
|
|
func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Port: 8081,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s2"},
|
|
|
|
},
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
Enabled: true,
|
|
|
|
TLSMinVersion: types.TLSv1_2,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
// One listener should inherit non-TLS gateway config, another
|
|
|
|
// listener configures TLS with an explicit minimum version
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: s1,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s2,
|
|
|
|
Port: 8081,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s1UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s1Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s2UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s2Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s1Chain.ID() + ":" + s1UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s1"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s2Chain.ID() + ":" + s2UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfigSnapshotIngressGateway_TLSMixedMinVersionListeners(t testing.T) *ConfigSnapshot {
|
|
|
|
var (
|
|
|
|
s1 = structs.NewServiceName("s1", nil)
|
|
|
|
s1UID = NewUpstreamIDFromServiceName(s1)
|
|
|
|
s1Chain = discoverychain.TestCompileConfigEntries(t, "s1", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s2 = structs.NewServiceName("s2", nil)
|
|
|
|
s2UID = NewUpstreamIDFromServiceName(s2)
|
|
|
|
s2Chain = discoverychain.TestCompileConfigEntries(t, "s2", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
|
|
|
|
s3 = structs.NewServiceName("s3", nil)
|
|
|
|
s3UID = NewUpstreamIDFromServiceName(s3)
|
|
|
|
s3Chain = discoverychain.TestCompileConfigEntries(t, "s3", "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
return TestConfigSnapshotIngressGateway(t, true, "tcp", "default", nil,
|
|
|
|
func(entry *structs.IngressGatewayConfigEntry) {
|
|
|
|
entry.TLS.Enabled = true
|
|
|
|
entry.TLS.TLSMinVersion = types.TLSv1_2
|
|
|
|
|
|
|
|
// One listener disables TLS, one inherits TLS minimum version from the gateway
|
|
|
|
// config, two others set different versions
|
|
|
|
entry.Listeners = []structs.IngressListener{
|
|
|
|
{
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Port: 8081,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s2"},
|
|
|
|
},
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
Enabled: true,
|
|
|
|
TLSMinVersion: types.TLSv1_0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Port: 8082,
|
|
|
|
Protocol: "http",
|
|
|
|
Services: []structs.IngressService{
|
|
|
|
{Name: "s3"},
|
|
|
|
},
|
|
|
|
TLS: &structs.GatewayTLSConfig{
|
|
|
|
Enabled: true,
|
|
|
|
TLSMinVersion: types.TLSv1_3,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}, []cache.UpdateEvent{
|
|
|
|
{
|
|
|
|
CorrelationID: gatewayServicesWatchID,
|
|
|
|
Result: &structs.IndexedGatewayServices{
|
|
|
|
// One listener should inherit TLS minimum version from the gateway config,
|
|
|
|
// two others each set explicit TLS minimum versions
|
|
|
|
Services: []*structs.GatewayService{
|
|
|
|
{
|
|
|
|
Service: s1,
|
|
|
|
Port: 8080,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s2,
|
|
|
|
Port: 8081,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Service: s3,
|
|
|
|
Port: 8082,
|
|
|
|
Protocol: "http",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s1UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s1Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s2UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s2Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "discovery-chain:" + s3UID.String(),
|
|
|
|
Result: &structs.DiscoveryChainResponse{
|
|
|
|
Chain: s3Chain,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s1Chain.ID() + ":" + s1UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s1"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s2Chain.ID() + ":" + s2UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
CorrelationID: "upstream-target:" + s3Chain.ID() + ":" + s3UID.String(),
|
|
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
|
|
Nodes: TestUpstreamNodes(t, "s3"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|