mirror of https://github.com/hashicorp/consul
Backport of Inline API Gateway TLS cert code into release/1.15.x (#16306)
* Inline API Gateway TLS cert code (#16295) * Include secret type when building resources from config snapshot * First pass at generating envoy secrets from api-gateway snapshot * Update comments for xDS update order * Add secret type + corresponding golden files to existing tests * Initialize test helpers for testing api-gateway resource generation * Generate golden files for new api-gateway xDS resource test * Support ADS for TLS certificates on api-gateway * Configure TLS on api-gateway listeners * Inline TLS cert code * update tests * Add SNI support so we can have multiple certificates * Remove commented out section from helper * regen deep-copy * Add tcp tls test --------- Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com> * Fix bad merge --------- Co-authored-by: Andrew Stucki <andrew.stucki@hashicorp.com> Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com>pull/16308/head^2
parent
3cba165d78
commit
4920cb4a77
|
@ -310,6 +310,23 @@ func (o *configSnapshotAPIGateway) DeepCopy() *configSnapshotAPIGateway {
|
|||
cp.Listeners[k2] = cp_Listeners_v2
|
||||
}
|
||||
}
|
||||
if o.ListenerCertificates != nil {
|
||||
cp.ListenerCertificates = make(map[IngressListenerKey][]structs.InlineCertificateConfigEntry, len(o.ListenerCertificates))
|
||||
for k2, v2 := range o.ListenerCertificates {
|
||||
var cp_ListenerCertificates_v2 []structs.InlineCertificateConfigEntry
|
||||
if v2 != nil {
|
||||
cp_ListenerCertificates_v2 = make([]structs.InlineCertificateConfigEntry, len(v2))
|
||||
copy(cp_ListenerCertificates_v2, v2)
|
||||
for i3 := range v2 {
|
||||
{
|
||||
retV := v2[i3].DeepCopy()
|
||||
cp_ListenerCertificates_v2[i3] = *retV
|
||||
}
|
||||
}
|
||||
}
|
||||
cp.ListenerCertificates[k2] = cp_ListenerCertificates_v2
|
||||
}
|
||||
}
|
||||
if o.BoundListeners != nil {
|
||||
cp.BoundListeners = make(map[string]structs.BoundAPIGatewayListener, len(o.BoundListeners))
|
||||
for k2, v2 := range o.BoundListeners {
|
||||
|
|
|
@ -734,6 +734,8 @@ type configSnapshotAPIGateway struct {
|
|||
// Listeners is the original listener config from the api-gateway config
|
||||
// entry to save us trying to pass fields through Upstreams
|
||||
Listeners map[string]structs.APIGatewayListener
|
||||
// this acts as an intermediary for inlining certificates
|
||||
ListenerCertificates map[IngressListenerKey][]structs.InlineCertificateConfigEntry
|
||||
|
||||
BoundListeners map[string]structs.BoundAPIGatewayListener
|
||||
}
|
||||
|
@ -751,6 +753,9 @@ func (c *configSnapshotAPIGateway) ToIngress(datacenter string) (configSnapshotI
|
|||
watchedUpstreamEndpoints := make(map[UpstreamID]map[string]structs.CheckServiceNodes)
|
||||
watchedGatewayEndpoints := make(map[UpstreamID]map[string]structs.CheckServiceNodes)
|
||||
|
||||
// reset the cached certificates
|
||||
c.ListenerCertificates = make(map[IngressListenerKey][]structs.InlineCertificateConfigEntry)
|
||||
|
||||
for name, listener := range c.Listeners {
|
||||
boundListener, ok := c.BoundListeners[name]
|
||||
if !ok {
|
||||
|
@ -802,17 +807,18 @@ func (c *configSnapshotAPIGateway) ToIngress(datacenter string) (configSnapshotI
|
|||
watchedGatewayEndpoints[id] = gatewayEndpoints
|
||||
}
|
||||
|
||||
// Configure TLS for the ingress listener
|
||||
tls, err := c.toIngressTLS()
|
||||
if err != nil {
|
||||
return configSnapshotIngressGateway{}, err
|
||||
}
|
||||
ingressListener.TLS = tls
|
||||
|
||||
key := IngressListenerKey{
|
||||
Port: listener.Port,
|
||||
Protocol: string(listener.Protocol),
|
||||
}
|
||||
|
||||
// Configure TLS for the ingress listener
|
||||
tls, err := c.toIngressTLS(key, listener, boundListener)
|
||||
if err != nil {
|
||||
return configSnapshotIngressGateway{}, err
|
||||
}
|
||||
|
||||
ingressListener.TLS = tls
|
||||
ingressListeners[key] = ingressListener
|
||||
ingressUpstreams[key] = upstreams
|
||||
}
|
||||
|
@ -905,9 +911,25 @@ DOMAIN_LOOP:
|
|||
return services, upstreams, compiled, err
|
||||
}
|
||||
|
||||
func (c *configSnapshotAPIGateway) toIngressTLS() (*structs.GatewayTLSConfig, error) {
|
||||
// TODO (t-eckert) this is dependent on future SDS work.
|
||||
return &structs.GatewayTLSConfig{}, nil
|
||||
func (c *configSnapshotAPIGateway) toIngressTLS(key IngressListenerKey, listener structs.APIGatewayListener, bound structs.BoundAPIGatewayListener) (*structs.GatewayTLSConfig, error) {
|
||||
if len(listener.TLS.Certificates) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, certRef := range bound.Certificates {
|
||||
cert, ok := c.Certificates.Get(certRef)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
c.ListenerCertificates[key] = append(c.ListenerCertificates[key], *cert)
|
||||
}
|
||||
|
||||
return &structs.GatewayTLSConfig{
|
||||
Enabled: true,
|
||||
TLSMinVersion: listener.TLS.MinVersion,
|
||||
TLSMaxVersion: listener.TLS.MaxVersion,
|
||||
CipherSuites: listener.TLS.CipherSuites,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type configSnapshotIngressGateway struct {
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
package proxycfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/consul/agent/connect"
|
||||
"github.com/hashicorp/consul/agent/consul/discoverychain"
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
)
|
||||
|
||||
func TestConfigSnapshotAPIGateway(
|
||||
t testing.T,
|
||||
variation string,
|
||||
nsFn func(ns *structs.NodeService),
|
||||
configFn func(entry *structs.APIGatewayConfigEntry, boundEntry *structs.BoundAPIGatewayConfigEntry),
|
||||
routes []structs.BoundRoute,
|
||||
certificates []structs.InlineCertificateConfigEntry,
|
||||
extraUpdates []UpdateEvent,
|
||||
additionalEntries ...structs.ConfigEntry,
|
||||
) *ConfigSnapshot {
|
||||
roots, placeholderLeaf := TestCerts(t)
|
||||
|
||||
entry := &structs.APIGatewayConfigEntry{
|
||||
Kind: structs.APIGateway,
|
||||
Name: "api-gateway",
|
||||
}
|
||||
boundEntry := &structs.BoundAPIGatewayConfigEntry{
|
||||
Kind: structs.BoundAPIGateway,
|
||||
Name: "api-gateway",
|
||||
}
|
||||
|
||||
if configFn != nil {
|
||||
configFn(entry, boundEntry)
|
||||
}
|
||||
|
||||
baseEvents := []UpdateEvent{
|
||||
{
|
||||
CorrelationID: rootsWatchID,
|
||||
Result: roots,
|
||||
},
|
||||
{
|
||||
CorrelationID: leafWatchID,
|
||||
Result: placeholderLeaf,
|
||||
},
|
||||
{
|
||||
CorrelationID: gatewayConfigWatchID,
|
||||
Result: &structs.ConfigEntryResponse{
|
||||
Entry: entry,
|
||||
},
|
||||
},
|
||||
{
|
||||
CorrelationID: gatewayConfigWatchID,
|
||||
Result: &structs.ConfigEntryResponse{
|
||||
Entry: boundEntry,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
// Add the watch event for the route.
|
||||
watch := UpdateEvent{
|
||||
CorrelationID: routeConfigWatchID,
|
||||
Result: &structs.ConfigEntryResponse{
|
||||
Entry: route,
|
||||
},
|
||||
}
|
||||
baseEvents = append(baseEvents, watch)
|
||||
|
||||
// Add the watch event for the discovery chain.
|
||||
entries := []structs.ConfigEntry{
|
||||
&structs.ProxyConfigEntry{
|
||||
Kind: structs.ProxyDefaults,
|
||||
Name: structs.ProxyConfigGlobal,
|
||||
Config: map[string]interface{}{
|
||||
"protocol": route.GetProtocol(),
|
||||
},
|
||||
},
|
||||
&structs.ServiceResolverConfigEntry{
|
||||
Kind: structs.ServiceResolver,
|
||||
Name: "api-gateway",
|
||||
},
|
||||
}
|
||||
|
||||
// Add a discovery chain watch event for each service.
|
||||
for _, serviceName := range route.GetServiceNames() {
|
||||
discoChain := UpdateEvent{
|
||||
CorrelationID: fmt.Sprintf("discovery-chain:%s", UpstreamIDString("", "", serviceName.Name, &serviceName.EnterpriseMeta, "")),
|
||||
Result: &structs.DiscoveryChainResponse{
|
||||
Chain: discoverychain.TestCompileConfigEntries(t, serviceName.Name, "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...),
|
||||
},
|
||||
}
|
||||
baseEvents = append(baseEvents, discoChain)
|
||||
}
|
||||
}
|
||||
|
||||
for _, certificate := range certificates {
|
||||
inlineCertificate := certificate
|
||||
baseEvents = append(baseEvents, UpdateEvent{
|
||||
CorrelationID: inlineCertificateConfigWatchID,
|
||||
Result: &structs.ConfigEntryResponse{
|
||||
Entry: &inlineCertificate,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
upstreams := structs.TestUpstreams(t)
|
||||
|
||||
baseEvents = testSpliceEvents(baseEvents, setupTestVariationConfigEntriesAndSnapshot(
|
||||
t, variation, upstreams, additionalEntries...,
|
||||
))
|
||||
|
||||
return testConfigSnapshotFixture(t, &structs.NodeService{
|
||||
Kind: structs.ServiceKindAPIGateway,
|
||||
Service: "api-gateway",
|
||||
Address: "1.2.3.4",
|
||||
Meta: nil,
|
||||
TaggedAddresses: nil,
|
||||
}, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates))
|
||||
}
|
||||
|
||||
// TestConfigSnapshotAPIGateway_NilConfigEntry is used to test when
|
||||
// the update event for the config entry returns nil
|
||||
// since this always happens on the first watch if it doesn't exist.
|
||||
func TestConfigSnapshotAPIGateway_NilConfigEntry(
|
||||
t testing.T,
|
||||
) *ConfigSnapshot {
|
||||
roots, _ := TestCerts(t)
|
||||
|
||||
baseEvents := []UpdateEvent{
|
||||
{
|
||||
CorrelationID: rootsWatchID,
|
||||
Result: roots,
|
||||
},
|
||||
{
|
||||
CorrelationID: gatewayConfigWatchID,
|
||||
Result: &structs.ConfigEntryResponse{
|
||||
Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist.
|
||||
},
|
||||
},
|
||||
{
|
||||
CorrelationID: gatewayConfigWatchID,
|
||||
Result: &structs.ConfigEntryResponse{
|
||||
Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist.
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return testConfigSnapshotFixture(t, &structs.NodeService{
|
||||
Kind: structs.ServiceKindAPIGateway,
|
||||
Service: "api-gateway",
|
||||
Address: "1.2.3.4",
|
||||
Meta: nil,
|
||||
TaggedAddresses: nil,
|
||||
}, nil, nil, testSpliceEvents(baseEvents, nil))
|
||||
}
|
|
@ -64,6 +64,30 @@ func (e *InlineCertificateConfigEntry) Validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (e *InlineCertificateConfigEntry) Hosts() ([]string, error) {
|
||||
certificateBlock, _ := pem.Decode([]byte(e.Certificate))
|
||||
if certificateBlock == nil {
|
||||
return nil, errors.New("failed to parse certificate PEM")
|
||||
}
|
||||
|
||||
certificate, err := x509.ParseCertificate(certificateBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse certificate: %w", err)
|
||||
}
|
||||
|
||||
hosts := []string{certificate.Subject.CommonName}
|
||||
|
||||
for _, name := range certificate.DNSNames {
|
||||
hosts = append(hosts, name)
|
||||
}
|
||||
|
||||
for _, ip := range certificate.IPAddresses {
|
||||
hosts = append(hosts, ip.String())
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func (e *InlineCertificateConfigEntry) CanRead(authz acl.Authorizer) error {
|
||||
var authzContext acl.AuthorizerContext
|
||||
e.FillAuthzContext(&authzContext)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package structs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
|
@ -24,6 +25,10 @@ type ResourceReference struct {
|
|||
acl.EnterpriseMeta
|
||||
}
|
||||
|
||||
func (r *ResourceReference) String() string {
|
||||
return fmt.Sprintf("%s:%s/%s/%s/%s", r.Kind, r.PartitionOrDefault(), r.NamespaceOrDefault(), r.Name, r.SectionName)
|
||||
}
|
||||
|
||||
func (r *ResourceReference) IsSame(other *ResourceReference) bool {
|
||||
if r == nil && other == nil {
|
||||
return true
|
||||
|
|
|
@ -466,20 +466,21 @@ func (s *Server) applyEnvoyExtensions(resources *xdscommon.IndexedResources, cfg
|
|||
return nil
|
||||
}
|
||||
|
||||
// https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#eventual-consistency-considerations
|
||||
var xDSUpdateOrder = []xDSUpdateOperation{
|
||||
// TODO Update comments
|
||||
// 1. SDS updates (if any) can be pushed here with no harm.
|
||||
{TypeUrl: xdscommon.SecretType, Upsert: true},
|
||||
// 1. CDS updates (if any) must always be pushed first.
|
||||
// 2. CDS updates (if any) must always be pushed before the following types.
|
||||
{TypeUrl: xdscommon.ClusterType, Upsert: true},
|
||||
// 2. EDS updates (if any) must arrive after CDS updates for the respective clusters.
|
||||
// 3. EDS updates (if any) must arrive after CDS updates for the respective clusters.
|
||||
{TypeUrl: xdscommon.EndpointType, Upsert: true},
|
||||
// 3. LDS updates must arrive after corresponding CDS/EDS updates.
|
||||
// 4. LDS updates must arrive after corresponding CDS/EDS updates.
|
||||
{TypeUrl: xdscommon.ListenerType, Upsert: true, Remove: true},
|
||||
// 4. RDS updates related to the newly added listeners must arrive after CDS/EDS/LDS updates.
|
||||
// 5. RDS updates related to the newly added listeners must arrive after CDS/EDS/LDS updates.
|
||||
{TypeUrl: xdscommon.RouteType, Upsert: true, Remove: true},
|
||||
// 5. (NOT IMPLEMENTED YET IN CONSUL) VHDS updates (if any) related to the newly added RouteConfigurations must arrive after RDS updates.
|
||||
// 6. (NOT IMPLEMENTED YET IN CONSUL) VHDS updates (if any) related to the newly added RouteConfigurations must arrive after RDS updates.
|
||||
// {},
|
||||
// 6. Stale CDS clusters, related EDS endpoints (ones no longer being referenced) and SDS secrets can then be removed.
|
||||
// 7. Stale CDS clusters, related EDS endpoints (ones no longer being referenced) and SDS secrets can then be removed.
|
||||
{TypeUrl: xdscommon.ClusterType, Remove: true},
|
||||
{TypeUrl: xdscommon.EndpointType, Remove: true},
|
||||
{TypeUrl: xdscommon.SecretType, Remove: true},
|
||||
|
|
|
@ -2328,6 +2328,9 @@ func makeHTTPInspectorListenerFilter() (*envoy_listener_v3.ListenerFilter, error
|
|||
}
|
||||
|
||||
func makeSNIFilterChainMatch(sniMatches ...string) *envoy_listener_v3.FilterChainMatch {
|
||||
if sniMatches == nil {
|
||||
return nil
|
||||
}
|
||||
return &envoy_listener_v3.FilterChainMatch{
|
||||
ServerNames: sniMatches,
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/consul/agent/proxycfg"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/consul/types"
|
||||
)
|
||||
|
||||
|
@ -25,6 +26,15 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
|
|||
return nil, fmt.Errorf("no listener config found for listener on proto/port %s/%d", listenerKey.Protocol, listenerKey.Port)
|
||||
}
|
||||
|
||||
var isAPIGatewayWithTLS bool
|
||||
var certs []structs.InlineCertificateConfigEntry
|
||||
if cfgSnap.APIGateway.ListenerCertificates != nil {
|
||||
certs = cfgSnap.APIGateway.ListenerCertificates[listenerKey]
|
||||
}
|
||||
if certs != nil {
|
||||
isAPIGatewayWithTLS = true
|
||||
}
|
||||
|
||||
tlsContext, err := makeDownstreamTLSContextFromSnapshotListenerConfig(cfgSnap, listenerCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -72,6 +82,7 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
|
|||
logger: s.Logger,
|
||||
}
|
||||
l := makeListener(opts)
|
||||
|
||||
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||
accessLogs: &cfgSnap.Proxy.AccessLogs,
|
||||
routeName: uid.EnvoyID(),
|
||||
|
@ -87,8 +98,30 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
|
|||
l.FilterChains = []*envoy_listener_v3.FilterChain{
|
||||
filterChain,
|
||||
}
|
||||
resources = append(resources, l)
|
||||
|
||||
if isAPIGatewayWithTLS {
|
||||
// construct SNI filter chains
|
||||
l.FilterChains, err = makeInlineOverrideFilterChains(cfgSnap, cfgSnap.IngressGateway.TLSConfig, listenerKey, listenerFilterOpts{
|
||||
useRDS: useRDS,
|
||||
protocol: listenerKey.Protocol,
|
||||
routeName: listenerKey.RouteName(),
|
||||
cluster: clusterName,
|
||||
statPrefix: "ingress_upstream_",
|
||||
accessLogs: &cfgSnap.Proxy.AccessLogs,
|
||||
logger: s.Logger,
|
||||
}, certs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// add the tls inspector to do SNI introspection
|
||||
tlsInspector, err := makeTLSInspectorListenerFilter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.ListenerFilters = []*envoy_listener_v3.ListenerFilter{tlsInspector}
|
||||
}
|
||||
|
||||
resources = append(resources, l)
|
||||
} else {
|
||||
// If multiple upstreams share this port, make a special listener for the protocol.
|
||||
listenerOpts := makeListenerOpts{
|
||||
|
@ -121,6 +154,13 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if isAPIGatewayWithTLS {
|
||||
sniFilterChains, err = makeInlineOverrideFilterChains(cfgSnap, cfgSnap.IngressGateway.TLSConfig, listenerKey, filterOpts, certs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any sni filter chains, we need a TLS inspector filter!
|
||||
if len(sniFilterChains) > 0 {
|
||||
tlsInspector, err := makeTLSInspectorListenerFilter()
|
||||
|
@ -134,7 +174,7 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
|
|||
|
||||
// See if there are other services that didn't have specific SNI-matching
|
||||
// filter chains. If so add a default filterchain to serve them.
|
||||
if len(sniFilterChains) < len(upstreams) {
|
||||
if len(sniFilterChains) < len(upstreams) && !isAPIGatewayWithTLS {
|
||||
defaultFilter, err := makeListenerFilter(filterOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -379,10 +419,133 @@ func makeSDSOverrideFilterChains(cfgSnap *proxycfg.ConfigSnapshot,
|
|||
return chains, nil
|
||||
}
|
||||
|
||||
// when we have multiple certificates on a single listener, we need
|
||||
// to duplicate the filter chains with multiple TLS contexts
|
||||
func makeInlineOverrideFilterChains(cfgSnap *proxycfg.ConfigSnapshot,
|
||||
tlsCfg structs.GatewayTLSConfig,
|
||||
listenerKey proxycfg.IngressListenerKey,
|
||||
filterOpts listenerFilterOpts,
|
||||
certs []structs.InlineCertificateConfigEntry) ([]*envoy_listener_v3.FilterChain, error) {
|
||||
|
||||
listenerCfg, ok := cfgSnap.IngressGateway.Listeners[listenerKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no listener config found for listener on port %d", listenerKey.Port)
|
||||
}
|
||||
|
||||
var chains []*envoy_listener_v3.FilterChain
|
||||
|
||||
constructChain := func(name string, hosts []string, tlsContext *envoy_tls_v3.CommonTlsContext) error {
|
||||
filterOpts.filterName = name
|
||||
filter, err := makeListenerFilter(filterOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Configure alpn protocols on TLSContext
|
||||
tlsContext.AlpnProtocols = getAlpnProtocols(listenerCfg.Protocol)
|
||||
transportSocket, err := makeDownstreamTLSTransportSocket(&envoy_tls_v3.DownstreamTlsContext{
|
||||
CommonTlsContext: tlsContext,
|
||||
RequireClientCertificate: &wrapperspb.BoolValue{Value: false},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chains = append(chains, &envoy_listener_v3.FilterChain{
|
||||
FilterChainMatch: makeSNIFilterChainMatch(hosts...),
|
||||
Filters: []*envoy_listener_v3.Filter{
|
||||
filter,
|
||||
},
|
||||
TransportSocket: transportSocket,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
multipleCerts := len(certs) > 1
|
||||
|
||||
allCertHosts := map[string]struct{}{}
|
||||
overlappingHosts := map[string]struct{}{}
|
||||
|
||||
if multipleCerts {
|
||||
// we only need to prune out overlapping hosts if we have more than
|
||||
// one certificate
|
||||
for _, cert := range certs {
|
||||
hosts, err := cert.Hosts()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse hosts from x509 certificate: %v", hosts)
|
||||
}
|
||||
for _, host := range hosts {
|
||||
if _, ok := allCertHosts[host]; ok {
|
||||
overlappingHosts[host] = struct{}{}
|
||||
}
|
||||
allCertHosts[host] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, cert := range certs {
|
||||
var hosts []string
|
||||
|
||||
// if we only have one cert, we just use it for all ingress
|
||||
if multipleCerts {
|
||||
// otherwise, we need an SNI per cert and to fallback to our ingress
|
||||
// gateway certificate signed by our Consul CA
|
||||
certHosts, err := cert.Hosts()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse hosts from x509 certificate: %v", hosts)
|
||||
}
|
||||
// filter out any overlapping hosts so we don't have collisions in our filter chains
|
||||
for _, host := range certHosts {
|
||||
if _, ok := overlappingHosts[host]; !ok {
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
}
|
||||
|
||||
if len(hosts) == 0 {
|
||||
// all of our hosts are overlapping, so we just skip this filter and it'll be
|
||||
// handled by the default filter chain
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := constructChain(cert.Name, hosts, makeInlineTLSContextFromGatewayTLSConfig(tlsCfg, cert)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if multipleCerts {
|
||||
// if we have more than one cert, add a default handler that uses the leaf cert from connect
|
||||
if err := constructChain("default", nil, makeCommonTLSContext(cfgSnap.Leaf(), cfgSnap.RootPEMs(), makeTLSParametersFromGatewayTLSConfig(tlsCfg))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return chains, nil
|
||||
}
|
||||
|
||||
func makeTLSParametersFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.TlsParameters {
|
||||
return makeTLSParametersFromTLSConfig(tlsCfg.TLSMinVersion, tlsCfg.TLSMaxVersion, tlsCfg.CipherSuites)
|
||||
}
|
||||
|
||||
func makeInlineTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig, cert structs.InlineCertificateConfigEntry) *envoy_tls_v3.CommonTlsContext {
|
||||
return &envoy_tls_v3.CommonTlsContext{
|
||||
TlsParams: makeTLSParametersFromGatewayTLSConfig(tlsCfg),
|
||||
TlsCertificates: []*envoy_tls_v3.TlsCertificate{{
|
||||
CertificateChain: &envoy_core_v3.DataSource{
|
||||
Specifier: &envoy_core_v3.DataSource_InlineString{
|
||||
InlineString: lib.EnsureTrailingNewline(cert.Certificate),
|
||||
},
|
||||
},
|
||||
PrivateKey: &envoy_core_v3.DataSource{
|
||||
Specifier: &envoy_core_v3.DataSource_InlineString{
|
||||
InlineString: lib.EnsureTrailingNewline(cert.PrivateKey),
|
||||
},
|
||||
},
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
func makeCommonTLSContextFromGatewayTLSConfig(tlsCfg structs.GatewayTLSConfig) *envoy_tls_v3.CommonTlsContext {
|
||||
return &envoy_tls_v3.CommonTlsContext{
|
||||
TlsParams: makeTLSParametersFromGatewayTLSConfig(tlsCfg),
|
||||
|
@ -396,6 +559,7 @@ func makeCommonTLSContextFromGatewayServiceTLSConfig(tlsCfg structs.GatewayServi
|
|||
TlsCertificateSdsSecretConfigs: makeTLSCertificateSdsSecretConfigsFromSDS(*tlsCfg.SDS),
|
||||
}
|
||||
}
|
||||
|
||||
func makeTLSCertificateSdsSecretConfigsFromSDS(sdsCfg structs.GatewayTLSSDSConfig) []*envoy_tls_v3.SdsSecretConfig {
|
||||
return []*envoy_tls_v3.SdsSecretConfig{
|
||||
{
|
||||
|
|
|
@ -527,6 +527,210 @@ func TestListenersFromSnapshot(t *testing.T) {
|
|||
}, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "api-gateway",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, nil, nil, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "api-gateway-nil-config-entry",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway_NilConfigEntry(t)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "api-gateway-tcp-listener",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) {
|
||||
entry.Listeners = []structs.APIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Protocol: structs.ListenerProtocolTCP,
|
||||
Port: 8080,
|
||||
},
|
||||
}
|
||||
bound.Listeners = []structs.BoundAPIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
},
|
||||
}
|
||||
}, nil, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "api-gateway-tcp-listener-with-tcp-route",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) {
|
||||
entry.Listeners = []structs.APIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Protocol: structs.ListenerProtocolTCP,
|
||||
Port: 8080,
|
||||
},
|
||||
}
|
||||
bound.Listeners = []structs.BoundAPIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Routes: []structs.ResourceReference{
|
||||
{
|
||||
Name: "tcp-route",
|
||||
Kind: structs.TCPRoute,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
}, []structs.BoundRoute{
|
||||
&structs.TCPRouteConfigEntry{
|
||||
Name: "tcp-route",
|
||||
Kind: structs.TCPRoute,
|
||||
Parents: []structs.ResourceReference{
|
||||
{
|
||||
Kind: structs.APIGateway,
|
||||
Name: "api-gateway",
|
||||
},
|
||||
},
|
||||
Services: []structs.TCPService{
|
||||
{Name: "tcp-service"},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "api-gateway-http-listener",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) {
|
||||
entry.Listeners = []structs.APIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Protocol: structs.ListenerProtocolHTTP,
|
||||
Port: 8080,
|
||||
},
|
||||
}
|
||||
bound.Listeners = []structs.BoundAPIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Routes: []structs.ResourceReference{},
|
||||
},
|
||||
}
|
||||
}, nil, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "api-gateway-http-listener-with-http-route",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) {
|
||||
entry.Listeners = []structs.APIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Protocol: structs.ListenerProtocolHTTP,
|
||||
Port: 8080,
|
||||
},
|
||||
}
|
||||
bound.Listeners = []structs.BoundAPIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Routes: []structs.ResourceReference{
|
||||
{
|
||||
Name: "http-route",
|
||||
Kind: structs.HTTPRoute,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}, []structs.BoundRoute{
|
||||
&structs.HTTPRouteConfigEntry{
|
||||
Name: "http-route",
|
||||
Kind: structs.HTTPRoute,
|
||||
Parents: []structs.ResourceReference{
|
||||
{
|
||||
Kind: structs.APIGateway,
|
||||
Name: "api-gateway",
|
||||
},
|
||||
},
|
||||
Rules: []structs.HTTPRouteRule{
|
||||
{
|
||||
Services: []structs.HTTPService{
|
||||
{Name: "http-service"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "api-gateway-tcp-listener-with-tcp-and-http-route",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) {
|
||||
entry.Listeners = []structs.APIGatewayListener{
|
||||
{
|
||||
Name: "listener-tcp",
|
||||
Protocol: structs.ListenerProtocolTCP,
|
||||
Port: 8080,
|
||||
},
|
||||
{
|
||||
Name: "listener-http",
|
||||
Protocol: structs.ListenerProtocolHTTP,
|
||||
Port: 8081,
|
||||
},
|
||||
}
|
||||
bound.Listeners = []structs.BoundAPIGatewayListener{
|
||||
{
|
||||
Name: "listener-tcp",
|
||||
Routes: []structs.ResourceReference{
|
||||
{
|
||||
Name: "tcp-route",
|
||||
Kind: structs.TCPRoute,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "listener-http",
|
||||
Routes: []structs.ResourceReference{
|
||||
{
|
||||
Name: "http-route",
|
||||
Kind: structs.HTTPRoute,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}, []structs.BoundRoute{
|
||||
&structs.TCPRouteConfigEntry{
|
||||
Name: "tcp-route",
|
||||
Kind: structs.TCPRoute,
|
||||
Parents: []structs.ResourceReference{
|
||||
{
|
||||
Kind: structs.APIGateway,
|
||||
Name: "api-gateway",
|
||||
},
|
||||
},
|
||||
Services: []structs.TCPService{
|
||||
{Name: "tcp-service"},
|
||||
},
|
||||
},
|
||||
&structs.HTTPRouteConfigEntry{
|
||||
Name: "http-route",
|
||||
Kind: structs.HTTPRoute,
|
||||
Parents: []structs.ResourceReference{
|
||||
{
|
||||
Kind: structs.APIGateway,
|
||||
Name: "api-gateway",
|
||||
},
|
||||
},
|
||||
Rules: []structs.HTTPRouteRule{
|
||||
{
|
||||
Services: []structs.HTTPService{
|
||||
{Name: "http-service"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ingress-gateway",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
|
|
|
@ -35,8 +35,7 @@ func NewResourceGenerator(
|
|||
|
||||
func (g *ResourceGenerator) AllResourcesFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) (map[string][]proto.Message, error) {
|
||||
all := make(map[string][]proto.Message)
|
||||
// TODO Add xdscommon.SecretType
|
||||
for _, typeUrl := range []string{xdscommon.ListenerType, xdscommon.RouteType, xdscommon.ClusterType, xdscommon.EndpointType} {
|
||||
for _, typeUrl := range []string{xdscommon.ListenerType, xdscommon.RouteType, xdscommon.ClusterType, xdscommon.EndpointType, xdscommon.SecretType} {
|
||||
res, err := g.resourcesFromSnapshot(typeUrl, cfgSnap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate xDS resources for %q: %v", typeUrl, err)
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||
|
||||
"github.com/hashicorp/consul/agent/xds/testcommon"
|
||||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||
|
||||
|
@ -25,6 +27,7 @@ var testTypeUrlToPrettyName = map[string]string{
|
|||
xdscommon.RouteType: "routes",
|
||||
xdscommon.ClusterType: "clusters",
|
||||
xdscommon.EndpointType: "endpoints",
|
||||
xdscommon.SecretType: "secrets",
|
||||
}
|
||||
|
||||
type goldenTestCase struct {
|
||||
|
@ -60,7 +63,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) {
|
|||
|
||||
// We need to replace the TLS certs with deterministic ones to make golden
|
||||
// files workable. Note we don't update these otherwise they'd change
|
||||
// golder files for every test case and so not be any use!
|
||||
// golden files for every test case and so not be any use!
|
||||
testcommon.SetupTLSRootsAndLeaf(t, snap)
|
||||
|
||||
if tt.setup != nil {
|
||||
|
@ -82,6 +85,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) {
|
|||
xdscommon.RouteType,
|
||||
xdscommon.ClusterType,
|
||||
xdscommon.EndpointType,
|
||||
xdscommon.SecretType,
|
||||
}
|
||||
require.Len(t, resources, len(typeUrls))
|
||||
|
||||
|
@ -101,6 +105,8 @@ func TestAllResourcesFromSnapshot(t *testing.T) {
|
|||
return items[i].(*envoy_cluster_v3.Cluster).Name < items[j].(*envoy_cluster_v3.Cluster).Name
|
||||
case xdscommon.EndpointType:
|
||||
return items[i].(*envoy_endpoint_v3.ClusterLoadAssignment).ClusterName < items[j].(*envoy_endpoint_v3.ClusterLoadAssignment).ClusterName
|
||||
case xdscommon.SecretType:
|
||||
return items[i].(*envoy_tls_v3.Secret).Name < items[j].(*envoy_tls_v3.Secret).Name
|
||||
default:
|
||||
panic("not possible")
|
||||
}
|
||||
|
@ -165,6 +171,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) {
|
|||
tests = append(tests, getMeshGatewayPeeringGoldenTestCases()...)
|
||||
tests = append(tests, getTrafficControlPeeringGoldenTestCases()...)
|
||||
tests = append(tests, getEnterpriseGoldenTestCases()...)
|
||||
tests = append(tests, getAPIGatewayGoldenTestCases()...)
|
||||
|
||||
latestEnvoyVersion := xdscommon.EnvoyVersions[0]
|
||||
for _, envoyVersion := range xdscommon.EnvoyVersions {
|
||||
|
@ -256,3 +263,100 @@ func getTrafficControlPeeringGoldenTestCases() []goldenTestCase {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
gatewayTestPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAx95Opa6t4lGEpiTUogEBptqOdam2ch4BHQGhNhX/MrDwwuZQ
|
||||
httBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2jQlhqTodElkbsd5vWY8R/bxJWQSo
|
||||
NvVE12TlzECxGpJEiHt4W0r8pGffk+rvpljiUyCfnT1kGF3znOSjK1hRMTn6RKWC
|
||||
yYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409g9X5VU88/Bmmrz4cMyxce86Kc2ug
|
||||
5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftrXOvuCbO5IBRHMOBHiHTZ4rtGuhMa
|
||||
Ir21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+WmQIDAQABAoIBACYvceUzp2MK4gYA
|
||||
GWPOP2uKbBdM0l+hHeNV0WAM+dHMfmMuL4pkT36ucqt0ySOLjw6rQyOZG5nmA6t9
|
||||
sv0g4ae2eCMlyDIeNi1Yavu4Wt6YX4cTXbQKThm83C6W2X9THKbauBbxD621bsDK
|
||||
7PhiGPN60yPue7YwFQAPqqD4YaK+s22HFIzk9gwM/rkvAUNwRv7SyHMiFe4Igc1C
|
||||
Eev7iHWzvj5Heoz6XfF+XNF9DU+TieSUAdjd56VyUb8XL4+uBTOhHwLiXvAmfaMR
|
||||
HvpcxeKnYZusS6NaOxcUHiJnsLNWrxmJj9WEGgQzuLxcLjTe4vVmELVZD8t3QUKj
|
||||
PAxu8tUCgYEA7KIWVn9dfVpokReorFym+J8FzLwSktP9RZYEMonJo00i8aii3K9s
|
||||
u/aSwRWQSCzmON1ZcxZzWhwQF9usz6kGCk//9+4hlVW90GtNK0RD+j7sp4aT2JI8
|
||||
9eLEjTG+xSXa7XWe98QncjjL9lu/yrRncSTxHs13q/XP198nn2aYuQ8CgYEA2Dnt
|
||||
sRBzv0fFEvzzFv7G/5f85mouN38TUYvxNRTjBLCXl9DeKjDkOVZ2b6qlfQnYXIru
|
||||
H+W+v+AZEb6fySXc8FRab7lkgTMrwE+aeI4rkW7asVwtclv01QJ5wMnyT84AgDD/
|
||||
Dgt/RThFaHgtU9TW5GOZveL+l9fVPn7vKFdTJdcCgYEArJ99zjHxwJ1whNAOk1av
|
||||
09UmRPm6TvRo4heTDk8oEoIWCNatoHI0z1YMLuENNSnT9Q280FFDayvnrY/qnD7A
|
||||
kktT/sjwJOG8q8trKzIMqQS4XWm2dxoPcIyyOBJfCbEY6XuRsUuePxwh5qF942EB
|
||||
yS9a2s6nC4Ix0lgPrqAIr48CgYBgS/Q6riwOXSU8nqCYdiEkBYlhCJrKpnJxF9T1
|
||||
ofa0yPzKZP/8ZEfP7VzTwHjxJehQ1qLUW9pG08P2biH1UEKEWdzo8vT6wVJT1F/k
|
||||
HtTycR8+a+Hlk2SHVRHqNUYQGpuIe8mrdJ1as4Pd0d/F/P0zO9Rlh+mAsGPM8HUM
|
||||
T0+9gwKBgHDoerX7NTskg0H0t8O+iSMevdxpEWp34ZYa9gHiftTQGyrRgERCa7Gj
|
||||
nZPAxKb2JoWyfnu3v7G5gZ8fhDFsiOxLbZv6UZJBbUIh1MjJISpXrForDrC2QNLX
|
||||
kHrHfwBFDB3KMudhQknsJzEJKCL/KmFH6o0MvsoaT9yzEl3K+ah/
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
gatewayTestCertificate = `-----BEGIN CERTIFICATE-----
|
||||
MIICljCCAX4CCQCQMDsYO8FrPjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJV
|
||||
UzAeFw0yMjEyMjAxNzUwMjVaFw0yNzEyMTkxNzUwMjVaMA0xCzAJBgNVBAYTAlVT
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx95Opa6t4lGEpiTUogEB
|
||||
ptqOdam2ch4BHQGhNhX/MrDwwuZQhttBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2
|
||||
jQlhqTodElkbsd5vWY8R/bxJWQSoNvVE12TlzECxGpJEiHt4W0r8pGffk+rvplji
|
||||
UyCfnT1kGF3znOSjK1hRMTn6RKWCyYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409
|
||||
g9X5VU88/Bmmrz4cMyxce86Kc2ug5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftr
|
||||
XOvuCbO5IBRHMOBHiHTZ4rtGuhMaIr21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+W
|
||||
mQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfCqoUIdPf/HGSbOorPyZWbyizNtHJ
|
||||
GL7x9cAeIYxpI5Y/WcO1o5v94lvrgm3FNfJoGKbV66+JxOge731FrfMpHplhar1Z
|
||||
RahYIzNLRBTLrwadLAZkApUpZvB8qDK4knsTWFYujNsylCww2A6ajzIMFNU4GkUK
|
||||
NtyHRuD+KYRmjXtyX1yHNqfGN3vOQmwavHq2R8wHYuBSc6LAHHV9vG+j0VsgMELO
|
||||
qwxn8SmLkSKbf2+MsQVzLCXXN5u+D8Yv+4py+oKP4EQ5aFZuDEx+r/G/31rTthww
|
||||
AAJAMaoXmoYVdgXV+CPuBb2M4XCpuzLu3bcA2PXm5ipSyIgntMKwXV7r
|
||||
-----END CERTIFICATE-----`
|
||||
)
|
||||
|
||||
func getAPIGatewayGoldenTestCases() []goldenTestCase {
|
||||
return []goldenTestCase{
|
||||
{
|
||||
name: "api-gateway-with-tcp-route-and-inline-certificate",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotAPIGateway(t, "default", nil, func(entry *structs.APIGatewayConfigEntry, bound *structs.BoundAPIGatewayConfigEntry) {
|
||||
entry.Listeners = []structs.APIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Protocol: structs.ListenerProtocolTCP,
|
||||
Port: 8080,
|
||||
TLS: structs.APIGatewayTLSConfiguration{
|
||||
Certificates: []structs.ResourceReference{{
|
||||
Kind: structs.InlineCertificate,
|
||||
Name: "certificate",
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
bound.Listeners = []structs.BoundAPIGatewayListener{
|
||||
{
|
||||
Name: "listener",
|
||||
Certificates: []structs.ResourceReference{{
|
||||
Kind: structs.InlineCertificate,
|
||||
Name: "certificate",
|
||||
}},
|
||||
Routes: []structs.ResourceReference{{
|
||||
Kind: structs.TCPRoute,
|
||||
Name: "route",
|
||||
}},
|
||||
},
|
||||
}
|
||||
}, []structs.BoundRoute{
|
||||
&structs.TCPRouteConfigEntry{
|
||||
Kind: structs.TCPRoute,
|
||||
Name: "route",
|
||||
Services: []structs.TCPService{{
|
||||
Name: "service",
|
||||
}},
|
||||
},
|
||||
}, []structs.InlineCertificateConfigEntry{{
|
||||
Kind: structs.InlineCertificate,
|
||||
Name: "certificate",
|
||||
PrivateKey: gatewayTestPrivateKey,
|
||||
Certificate: gatewayTestCertificate,
|
||||
}}, nil)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,18 +21,10 @@ func (s *ResourceGenerator) secretsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot
|
|||
case structs.ServiceKindConnectProxy,
|
||||
structs.ServiceKindTerminatingGateway,
|
||||
structs.ServiceKindMeshGateway,
|
||||
structs.ServiceKindIngressGateway:
|
||||
structs.ServiceKindIngressGateway,
|
||||
structs.ServiceKindAPIGateway:
|
||||
return nil, nil
|
||||
// Only API gateways utilize secrets
|
||||
case structs.ServiceKindAPIGateway:
|
||||
return s.secretsFromSnapshotAPIGateway(cfgSnap)
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ResourceGenerator) secretsFromSnapshotAPIGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
|
||||
var res []proto.Message
|
||||
// TODO
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ func SetupTLSRootsAndLeaf(t *testing.T, snap *proxycfg.ConfigSnapshot) {
|
|||
case structs.ServiceKindMeshGateway:
|
||||
snap.MeshGateway.Leaf.CertPEM = loadTestResource(t, "test-leaf-cert")
|
||||
snap.MeshGateway.Leaf.PrivateKeyPEM = loadTestResource(t, "test-leaf-key")
|
||||
case structs.ServiceKindAPIGateway:
|
||||
snap.APIGateway.Leaf.CertPEM = loadTestResource(t, "test-leaf-cert")
|
||||
snap.APIGateway.Leaf.PrivateKeyPEM = loadTestResource(t, "test-leaf-key")
|
||||
}
|
||||
}
|
||||
if snap.Roots != nil {
|
||||
|
|
55
agent/xds/testdata/clusters/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
55
agent/xds/testdata/clusters/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {},
|
||||
"commonLbConfig": {
|
||||
"healthyPanicThreshold": {}
|
||||
},
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"tlsParams": {},
|
||||
"tlsCertificates": [
|
||||
{
|
||||
"certificateChain": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"privateKey": {
|
||||
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"validationContext": {
|
||||
"trustedCa": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"matchSubjectAltNames": [
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/service"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/endpoints/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
5
agent/xds/testdata/endpoints/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"nonce": "00000001"
|
||||
}
|
49
agent/xds/testdata/listeners/api-gateway-http-listener-with-http-route.latest.golden
vendored
Normal file
49
agent/xds/testdata/listeners/api-gateway-http-listener-with-http-route.latest.golden
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "http:1.2.3.4:8080",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "1.2.3.4",
|
||||
"portValue": 8080
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "ingress_upstream_8080",
|
||||
"rds": {
|
||||
"configSource": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
},
|
||||
"routeConfigName": "8080"
|
||||
},
|
||||
"httpFilters": [
|
||||
{
|
||||
"name": "envoy.filters.http.router",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tracing": {
|
||||
"randomSampling": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
74
agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-and-http-route.latest.golden
vendored
Normal file
74
agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-and-http-route.latest.golden
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "http:1.2.3.4:8081",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "1.2.3.4",
|
||||
"portValue": 8081
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "ingress_upstream_8081",
|
||||
"rds": {
|
||||
"configSource": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
},
|
||||
"routeConfigName": "8081"
|
||||
},
|
||||
"httpFilters": [
|
||||
{
|
||||
"name": "envoy.filters.http.router",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tracing": {
|
||||
"randomSampling": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "tcp-service:1.2.3.4:8080",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "1.2.3.4",
|
||||
"portValue": 8080
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.tcp-service.default.default.dc1",
|
||||
"cluster": "tcp-service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
32
agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-route.latest.golden
vendored
Normal file
32
agent/xds/testdata/listeners/api-gateway-tcp-listener-with-tcp-route.latest.golden
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "tcp-service:1.2.3.4:8080",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "1.2.3.4",
|
||||
"portValue": 8080
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.tcp-service.default.default.dc1",
|
||||
"cluster": "tcp-service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
60
agent/xds/testdata/listeners/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
60
agent/xds/testdata/listeners/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "service:1.2.3.4:8080",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "1.2.3.4",
|
||||
"portValue": 8080
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "ingress_upstream_certificate",
|
||||
"cluster": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
],
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"tlsParams": {},
|
||||
"tlsCertificates": [
|
||||
{
|
||||
"certificateChain": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICljCCAX4CCQCQMDsYO8FrPjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJV\nUzAeFw0yMjEyMjAxNzUwMjVaFw0yNzEyMTkxNzUwMjVaMA0xCzAJBgNVBAYTAlVT\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx95Opa6t4lGEpiTUogEB\nptqOdam2ch4BHQGhNhX/MrDwwuZQhttBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2\njQlhqTodElkbsd5vWY8R/bxJWQSoNvVE12TlzECxGpJEiHt4W0r8pGffk+rvplji\nUyCfnT1kGF3znOSjK1hRMTn6RKWCyYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409\ng9X5VU88/Bmmrz4cMyxce86Kc2ug5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftr\nXOvuCbO5IBRHMOBHiHTZ4rtGuhMaIr21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+W\nmQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBfCqoUIdPf/HGSbOorPyZWbyizNtHJ\nGL7x9cAeIYxpI5Y/WcO1o5v94lvrgm3FNfJoGKbV66+JxOge731FrfMpHplhar1Z\nRahYIzNLRBTLrwadLAZkApUpZvB8qDK4knsTWFYujNsylCww2A6ajzIMFNU4GkUK\nNtyHRuD+KYRmjXtyX1yHNqfGN3vOQmwavHq2R8wHYuBSc6LAHHV9vG+j0VsgMELO\nqwxn8SmLkSKbf2+MsQVzLCXXN5u+D8Yv+4py+oKP4EQ5aFZuDEx+r/G/31rTthww\nAAJAMaoXmoYVdgXV+CPuBb2M4XCpuzLu3bcA2PXm5ipSyIgntMKwXV7r\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"privateKey": {
|
||||
"inlineString": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAx95Opa6t4lGEpiTUogEBptqOdam2ch4BHQGhNhX/MrDwwuZQ\nhttBwMfngQ/wd9NmYEPAwj0dumUoAITIq6i2jQlhqTodElkbsd5vWY8R/bxJWQSo\nNvVE12TlzECxGpJEiHt4W0r8pGffk+rvpljiUyCfnT1kGF3znOSjK1hRMTn6RKWC\nyYaBvXQiB4SGilfLgJcEpOJKtISIxmZ+S409g9X5VU88/Bmmrz4cMyxce86Kc2ug\n5/MOv0CjWDJwlrv8njneV2zvraQ61DDwQftrXOvuCbO5IBRHMOBHiHTZ4rtGuhMa\nIr21V4vb6n8c4YzXiFvhUYcyX7rltGZzVd+WmQIDAQABAoIBACYvceUzp2MK4gYA\nGWPOP2uKbBdM0l+hHeNV0WAM+dHMfmMuL4pkT36ucqt0ySOLjw6rQyOZG5nmA6t9\nsv0g4ae2eCMlyDIeNi1Yavu4Wt6YX4cTXbQKThm83C6W2X9THKbauBbxD621bsDK\n7PhiGPN60yPue7YwFQAPqqD4YaK+s22HFIzk9gwM/rkvAUNwRv7SyHMiFe4Igc1C\nEev7iHWzvj5Heoz6XfF+XNF9DU+TieSUAdjd56VyUb8XL4+uBTOhHwLiXvAmfaMR\nHvpcxeKnYZusS6NaOxcUHiJnsLNWrxmJj9WEGgQzuLxcLjTe4vVmELVZD8t3QUKj\nPAxu8tUCgYEA7KIWVn9dfVpokReorFym+J8FzLwSktP9RZYEMonJo00i8aii3K9s\nu/aSwRWQSCzmON1ZcxZzWhwQF9usz6kGCk//9+4hlVW90GtNK0RD+j7sp4aT2JI8\n9eLEjTG+xSXa7XWe98QncjjL9lu/yrRncSTxHs13q/XP198nn2aYuQ8CgYEA2Dnt\nsRBzv0fFEvzzFv7G/5f85mouN38TUYvxNRTjBLCXl9DeKjDkOVZ2b6qlfQnYXIru\nH+W+v+AZEb6fySXc8FRab7lkgTMrwE+aeI4rkW7asVwtclv01QJ5wMnyT84AgDD/\nDgt/RThFaHgtU9TW5GOZveL+l9fVPn7vKFdTJdcCgYEArJ99zjHxwJ1whNAOk1av\n09UmRPm6TvRo4heTDk8oEoIWCNatoHI0z1YMLuENNSnT9Q280FFDayvnrY/qnD7A\nkktT/sjwJOG8q8trKzIMqQS4XWm2dxoPcIyyOBJfCbEY6XuRsUuePxwh5qF942EB\nyS9a2s6nC4Ix0lgPrqAIr48CgYBgS/Q6riwOXSU8nqCYdiEkBYlhCJrKpnJxF9T1\nofa0yPzKZP/8ZEfP7VzTwHjxJehQ1qLUW9pG08P2biH1UEKEWdzo8vT6wVJT1F/k\nHtTycR8+a+Hlk2SHVRHqNUYQGpuIe8mrdJ1as4Pd0d/F/P0zO9Rlh+mAsGPM8HUM\nT0+9gwKBgHDoerX7NTskg0H0t8O+iSMevdxpEWp34ZYa9gHiftTQGyrRgERCa7Gj\nnZPAxKb2JoWyfnu3v7G5gZ8fhDFsiOxLbZv6UZJBbUIh1MjJISpXrForDrC2QNLX\nkHrHfwBFDB3KMudhQknsJzEJKCL/KmFH6o0MvsoaT9yzEl3K+ah/\n-----END RSA PRIVATE KEY-----\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"requireClientCertificate": false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"listenerFilters": [
|
||||
{
|
||||
"name": "envoy.filters.listener.tls_inspector",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector"
|
||||
}
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/routes/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
5
agent/xds/testdata/routes/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/secrets/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
5
agent/xds/testdata/secrets/api-gateway-with-tcp-route-and-inline-certificate.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/secrets/local-mesh-gateway-with-peered-upstreams.latest.golden
vendored
Normal file
5
agent/xds/testdata/secrets/local-mesh-gateway-with-peered-upstreams.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http.latest.golden
vendored
Normal file
5
agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services-http.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services.latest.golden
vendored
Normal file
5
agent/xds/testdata/secrets/mesh-gateway-with-exported-peered-services.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/secrets/mesh-gateway-with-imported-peered-services.latest.golden
vendored
Normal file
5
agent/xds/testdata/secrets/mesh-gateway-with-imported-peered-services.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/secrets/mesh-gateway-with-peer-through-mesh-gateway-enabled.latest.golden
vendored
Normal file
5
agent/xds/testdata/secrets/mesh-gateway-with-peer-through-mesh-gateway-enabled.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
5
agent/xds/testdata/secrets/transparent-proxy-with-peered-upstreams.latest.golden
vendored
Normal file
5
agent/xds/testdata/secrets/transparent-proxy-with-peered-upstreams.latest.golden
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
snapshot_envoy_admin localhost:20000 api-gateway primary || true
|
|
@ -0,0 +1,4 @@
|
|||
services {
|
||||
name = "api-gateway"
|
||||
kind = "api-gateway"
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "api-gateway"
|
||||
name = "api-gateway"
|
||||
listeners = [
|
||||
{
|
||||
name = "listener-one"
|
||||
port = 9999
|
||||
protocol = "http"
|
||||
tls = {
|
||||
certificates = [
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "host-consul-example"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "listener-two"
|
||||
port = 9998
|
||||
protocol = "http"
|
||||
tls = {
|
||||
certificates = [
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "host-consul-example"
|
||||
},
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "also-host-consul-example"
|
||||
},
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "other-consul-example"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "inline-certificate"
|
||||
name = "host-consul-example"
|
||||
private_key = <<EOF
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA0wzZeonUklhOvJ0AxcdDdCTiMwR9tsm/6IGcw9Jm50xVY+qg
|
||||
5GFg1RWrQaODq7Gjqd/JDUAwtTBnQMs1yt6nbsHe2QhbD4XeqtZ+6fTv1ZpG3k8F
|
||||
eB/M01xFqovczRV/ie77wd4vqoPD+AcfD8NDAFJt3htwUgGIqkQHP329Sh3TtLga
|
||||
9ZMCs1MoTT+POYGUPL8bwt9R6ClNrucbH4Bs6OnX2ZFbKF75O9OHKNxWTmpDSodv
|
||||
OFbFyKps3BfnPuF0Z6mj5M5yZeCjmtfS25PrsM3pMBGK5YHb0MlFfZIrIGboMbrz
|
||||
9F/BMQJ64pMe43KwqHvTnbKWhp6PzLhEkPGLnwIDAQABAoIBADBEJAiONPszDu67
|
||||
yU1yAM8zEDgysr127liyK7PtDnOfVXgAVMNmMcsJpZzhVF+TxKY487YAFCOb6kE7
|
||||
OBYpTYla9SgVbR3js8TGQUgoKCFlowd8cvfB7gn4dEZIrjqIzB4zdYgk1Cne8JZs
|
||||
qoHkWhJcx5ugEtPuXd7yp+WxT/T+6uOro06scp67NhP5t9yoAGFv5Vdb577RuzRo
|
||||
Wkd9higQ9A20+GtjCY0EYxdgRviWvW7mM5/F+Lzcaui86ME+ga754gX8zgW3+NJ5
|
||||
LMsz5OLSnh291Uyjmr77HWBv/xvpq01Fls0LyJcgxFVZuJs5GQz+l3otSqv4FTP6
|
||||
Ua9w/YECgYEA8To3dgUK1QhzX5rwhWtlst3pItGTvmEdNzXmjgSylu7uKM13i+xg
|
||||
llhp2uXrOEtuL+xtBZdeFNaijusbyqjg0xj6e4o31c19okuuDkJD5/sfQq22bvrn
|
||||
gVJMGuESprIiPePrEyrXCHOdxH6eDgR2dIzAeO5vz0nnKGFAWrJJbvECgYEA3/mJ
|
||||
eacXOJznw4Sa8jGWS2FtZLKxDHph7uDKMJmuG0ukb3aHJ9dMHrPleCLo8mhpoObA
|
||||
hueoIbIP7swGrQx79+nZbnQpF6rMp6FAU5bF3gSrj1eWbaeh8pn9mrv4hal9USmn
|
||||
orTbXMxDp3XSh7voR8Fqy5tMQqwZ+Lz74ccbw48CgYEA5cEhGdNrocPOv3x/IVRN
|
||||
JLOfXX5nTaiJfxBja1imEIO5ajtoZWjaBdhn2gmqo4+UfyicHfsxrH9RjPX5HmkC
|
||||
2Yys5gWbcJOr2Wxjd0k+DDFucL+rRsDKxq1vtxov/X0kh/YQ68ydynr0BTbjq04s
|
||||
1I1KtOPEspYdCKS3+qpcrsECgYBtvYeVesBO9do9G0kMKC26y4bdEwzaz1ASykNn
|
||||
IrWDHEH6dznr1HqwhHaHsZsvwucWdlmZAAKKWAOkfoU63uYS55qomvPTa9WQwNqS
|
||||
2koi6Wjh+Al1uvAHvVncKgOwAgar8Nv5ReJBirgPYhSAexpppiRclL/93vNuw7Iq
|
||||
wvMgkwKBgQC5wnb6SUUrzzKKSRgyusHM/XrjiKgVKq7lvFE9/iJkcw+BEXpjjbEe
|
||||
RyD0a7PRtCfR39SMVrZp4KXVNNK5ln0WhuLvraMDwOpH9JDWHQiAhuJ3ooSwBylK
|
||||
+QCLjyOtWAGZAIBRJyb1txfTXZ++dldkOjBi3bmEiadOa48ksvDsNQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
EOF
|
||||
|
||||
certificate = <<EOF
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDQjCCAioCCQC6cMRYsE+ahDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAkxBMQ0wCwYDVQQKDARUZXN0MQ0wCwYD
|
||||
VQQLDARTdHViMRwwGgYDVQQDDBNob3N0LmNvbnN1bC5leGFtcGxlMB4XDTIzMDIx
|
||||
NzAyMTA1MloXDTI4MDIxNjAyMTA1MlowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
|
||||
AkNBMQswCQYDVQQHDAJMQTENMAsGA1UECgwEVGVzdDENMAsGA1UECwwEU3R1YjEc
|
||||
MBoGA1UEAwwTaG9zdC5jb25zdWwuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBANMM2XqJ1JJYTrydAMXHQ3Qk4jMEfbbJv+iBnMPSZudMVWPq
|
||||
oORhYNUVq0Gjg6uxo6nfyQ1AMLUwZ0DLNcrep27B3tkIWw+F3qrWfun079WaRt5P
|
||||
BXgfzNNcRaqL3M0Vf4nu+8HeL6qDw/gHHw/DQwBSbd4bcFIBiKpEBz99vUod07S4
|
||||
GvWTArNTKE0/jzmBlDy/G8LfUegpTa7nGx+AbOjp19mRWyhe+TvThyjcVk5qQ0qH
|
||||
bzhWxciqbNwX5z7hdGepo+TOcmXgo5rX0tuT67DN6TARiuWB29DJRX2SKyBm6DG6
|
||||
8/RfwTECeuKTHuNysKh7052yloaej8y4RJDxi58CAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAHF10odRNJ7TKvcD2JPtR8wMacfldSiPcQnn+rhMUyBaKOoSrALxOev+N
|
||||
L8N+RtEV+KXkyBkvT71OZzEpY9ROwqOQ/acnMdbfG0IBPbg3c/7WDD2sjcdr1zvc
|
||||
U3T7WJ7G3guZ5aWCuAGgOyT6ZW8nrDa4yFbKZ1PCJkvUQ2ttO1lXmyGPM533Y2pi
|
||||
SeXP6LL7z5VNqYO3oz5IJEstt10IKxdmb2gKFhHjgEmHN2gFL0jaPi4mjjaINrxq
|
||||
MdqcM9IzLr26AjZ45NuI9BCcZWO1mraaQTOIb3QL5LyqaC7CRJXLYPSGARthyDhq
|
||||
J3TrQE3YVrL4D9xnklT86WDnZKApJg==
|
||||
-----END CERTIFICATE-----
|
||||
EOF
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "inline-certificate"
|
||||
name = "also-host-consul-example"
|
||||
private_key = <<EOF
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA0wzZeonUklhOvJ0AxcdDdCTiMwR9tsm/6IGcw9Jm50xVY+qg
|
||||
5GFg1RWrQaODq7Gjqd/JDUAwtTBnQMs1yt6nbsHe2QhbD4XeqtZ+6fTv1ZpG3k8F
|
||||
eB/M01xFqovczRV/ie77wd4vqoPD+AcfD8NDAFJt3htwUgGIqkQHP329Sh3TtLga
|
||||
9ZMCs1MoTT+POYGUPL8bwt9R6ClNrucbH4Bs6OnX2ZFbKF75O9OHKNxWTmpDSodv
|
||||
OFbFyKps3BfnPuF0Z6mj5M5yZeCjmtfS25PrsM3pMBGK5YHb0MlFfZIrIGboMbrz
|
||||
9F/BMQJ64pMe43KwqHvTnbKWhp6PzLhEkPGLnwIDAQABAoIBADBEJAiONPszDu67
|
||||
yU1yAM8zEDgysr127liyK7PtDnOfVXgAVMNmMcsJpZzhVF+TxKY487YAFCOb6kE7
|
||||
OBYpTYla9SgVbR3js8TGQUgoKCFlowd8cvfB7gn4dEZIrjqIzB4zdYgk1Cne8JZs
|
||||
qoHkWhJcx5ugEtPuXd7yp+WxT/T+6uOro06scp67NhP5t9yoAGFv5Vdb577RuzRo
|
||||
Wkd9higQ9A20+GtjCY0EYxdgRviWvW7mM5/F+Lzcaui86ME+ga754gX8zgW3+NJ5
|
||||
LMsz5OLSnh291Uyjmr77HWBv/xvpq01Fls0LyJcgxFVZuJs5GQz+l3otSqv4FTP6
|
||||
Ua9w/YECgYEA8To3dgUK1QhzX5rwhWtlst3pItGTvmEdNzXmjgSylu7uKM13i+xg
|
||||
llhp2uXrOEtuL+xtBZdeFNaijusbyqjg0xj6e4o31c19okuuDkJD5/sfQq22bvrn
|
||||
gVJMGuESprIiPePrEyrXCHOdxH6eDgR2dIzAeO5vz0nnKGFAWrJJbvECgYEA3/mJ
|
||||
eacXOJznw4Sa8jGWS2FtZLKxDHph7uDKMJmuG0ukb3aHJ9dMHrPleCLo8mhpoObA
|
||||
hueoIbIP7swGrQx79+nZbnQpF6rMp6FAU5bF3gSrj1eWbaeh8pn9mrv4hal9USmn
|
||||
orTbXMxDp3XSh7voR8Fqy5tMQqwZ+Lz74ccbw48CgYEA5cEhGdNrocPOv3x/IVRN
|
||||
JLOfXX5nTaiJfxBja1imEIO5ajtoZWjaBdhn2gmqo4+UfyicHfsxrH9RjPX5HmkC
|
||||
2Yys5gWbcJOr2Wxjd0k+DDFucL+rRsDKxq1vtxov/X0kh/YQ68ydynr0BTbjq04s
|
||||
1I1KtOPEspYdCKS3+qpcrsECgYBtvYeVesBO9do9G0kMKC26y4bdEwzaz1ASykNn
|
||||
IrWDHEH6dznr1HqwhHaHsZsvwucWdlmZAAKKWAOkfoU63uYS55qomvPTa9WQwNqS
|
||||
2koi6Wjh+Al1uvAHvVncKgOwAgar8Nv5ReJBirgPYhSAexpppiRclL/93vNuw7Iq
|
||||
wvMgkwKBgQC5wnb6SUUrzzKKSRgyusHM/XrjiKgVKq7lvFE9/iJkcw+BEXpjjbEe
|
||||
RyD0a7PRtCfR39SMVrZp4KXVNNK5ln0WhuLvraMDwOpH9JDWHQiAhuJ3ooSwBylK
|
||||
+QCLjyOtWAGZAIBRJyb1txfTXZ++dldkOjBi3bmEiadOa48ksvDsNQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
EOF
|
||||
|
||||
certificate = <<EOF
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDQjCCAioCCQC6cMRYsE+ahDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAkxBMQ0wCwYDVQQKDARUZXN0MQ0wCwYD
|
||||
VQQLDARTdHViMRwwGgYDVQQDDBNob3N0LmNvbnN1bC5leGFtcGxlMB4XDTIzMDIx
|
||||
NzAyMTA1MloXDTI4MDIxNjAyMTA1MlowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
|
||||
AkNBMQswCQYDVQQHDAJMQTENMAsGA1UECgwEVGVzdDENMAsGA1UECwwEU3R1YjEc
|
||||
MBoGA1UEAwwTaG9zdC5jb25zdWwuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBANMM2XqJ1JJYTrydAMXHQ3Qk4jMEfbbJv+iBnMPSZudMVWPq
|
||||
oORhYNUVq0Gjg6uxo6nfyQ1AMLUwZ0DLNcrep27B3tkIWw+F3qrWfun079WaRt5P
|
||||
BXgfzNNcRaqL3M0Vf4nu+8HeL6qDw/gHHw/DQwBSbd4bcFIBiKpEBz99vUod07S4
|
||||
GvWTArNTKE0/jzmBlDy/G8LfUegpTa7nGx+AbOjp19mRWyhe+TvThyjcVk5qQ0qH
|
||||
bzhWxciqbNwX5z7hdGepo+TOcmXgo5rX0tuT67DN6TARiuWB29DJRX2SKyBm6DG6
|
||||
8/RfwTECeuKTHuNysKh7052yloaej8y4RJDxi58CAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAHF10odRNJ7TKvcD2JPtR8wMacfldSiPcQnn+rhMUyBaKOoSrALxOev+N
|
||||
L8N+RtEV+KXkyBkvT71OZzEpY9ROwqOQ/acnMdbfG0IBPbg3c/7WDD2sjcdr1zvc
|
||||
U3T7WJ7G3guZ5aWCuAGgOyT6ZW8nrDa4yFbKZ1PCJkvUQ2ttO1lXmyGPM533Y2pi
|
||||
SeXP6LL7z5VNqYO3oz5IJEstt10IKxdmb2gKFhHjgEmHN2gFL0jaPi4mjjaINrxq
|
||||
MdqcM9IzLr26AjZ45NuI9BCcZWO1mraaQTOIb3QL5LyqaC7CRJXLYPSGARthyDhq
|
||||
J3TrQE3YVrL4D9xnklT86WDnZKApJg==
|
||||
-----END CERTIFICATE-----
|
||||
EOF
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "inline-certificate"
|
||||
name = "other-consul-example"
|
||||
private_key = <<EOF
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA7Qgf93OZYlpM9UvfbFBUeK+udCTfy+yRbTKYgti5qKyZQwnT
|
||||
7GtxpNxWWNT7ecqGZJb3BxhIVjTYZwZYB1zDzHzE7zTVydrTbRP4MhaJhqWNdPdq
|
||||
Ctth9QsX2r6KFPogvUPaYVrQBbXHoGTVcCZlFJOlEGGnuIU2cJcZEryxJKv3mB4P
|
||||
FpHKP/YXy3qQb4A0+REGI93atGCxhCO5Mu5lgG+x54nKCdIXy3LVAyDqSjPuR01s
|
||||
+ifdDkYUfvVY3DOb0bcNaMwi752GkfPuuxsKeHAsHmWHWOxkFiQAy3eSLJjSDghF
|
||||
66JVZ6wx74Awb8NBm9nmYTbnZAUn3Z0tN6jlFwIDAQABAoIBAGh8EWNJ8M4bEht7
|
||||
A5TCYEoG3zbRXlmNAZoKGJJtKIIC+1hCx8lKn4DVo7ZqxCOus8k5htD40kI170KS
|
||||
2FD+gkzsnv724lqlfFdz2w9xQdQ5u/5YZcU9aZPT/QLuxP10OORVObl6h4JM3B+G
|
||||
81MJibslTjjHY2CCUDoXUPUiek+4KTI6BYn9PL+ReCaH9qv85hIWvkgbwU2f9i3n
|
||||
T8MysgDBNoKbVAqsH5Hq/zFkW5iad/zpgW+REgYK/gjBfUNEsRusm1GYim4XJtZf
|
||||
SmXBtdYhk8kDBrMk1mNdZeMXMfl0VwZaHca8QmqrgDm//grUYKLWZO/PbDoI5c+w
|
||||
/MTN6tkCgYEA956LZJ+Ts9g9k+jLcUV1hOAmR6cAL5tjEkBPVC5FC+5o42qOgI58
|
||||
5NQjmVCM+mD9w+deAXkT/IDXzV28Y02lZ1pyOXTN+ChE2ZBym+yu2zyLj45lJzx5
|
||||
h+lC7aeCBIGyjP/t6wFoFdCaluAsWpU4SY1DWtExcCLvXs0+zDiYjZMCgYEA9Q3Y
|
||||
mlrAvdzb61x8BAEPpBTMSu0a+jo8mkJoUFS4ndFXEl5yPzqf6IUrFgzqgVruQg7k
|
||||
dIZK5uDqNI7sXDXulpPFHbJdpAZq3Dlkv0VOvcgRycuWgDAyOngCSRN8JC7u4P5j
|
||||
54xgAYQSCC/kPolFMHntXQLjzPevJNrkKnJfXO0CgYEAyCf5ByJSs0o1JE1Fvc7m
|
||||
mrzRVJPye4kAQS2IskQgfe9+C24DuHj1DcdI61IIUw95sRRhkZE8jZvcVN3TPPXz
|
||||
oKKkuDrpjxGF7dNsQQvFn+PF8AmrTFb+6dSszAvd9iScnor110OwzglsHE8iqyn5
|
||||
cMLmUg/NBZbHpPsFKvEIp08CgYAmQ1Az4cHAo5CvMlSm52eCzkCL3nPc6GT4DTBu
|
||||
gpwFAF/hHWAnYUcArnJo0gF3yzPympKvYxyk6i+Hn11mlIE5f79CgMxARURAOLHz
|
||||
b6X42hl08dYBFAVzvbNVp7Y1jCJ+fRoqWG/RLMcIAjpYTWTBSfh3EnFxWqc9UPRZ
|
||||
cFxVjQKBgQDUXDww+jXXTFlYkbhgNOtQS57M8jKWHnUxEc7IXOjF/0WGEEBAc2uc
|
||||
fFW5dnPyS3D6vecWA8KB8LKcXey3ZcDZnVkahSgYhYHrGJrANzhfM3yli+lSFWsT
|
||||
r295+0za3P3LVL4aKS+ok9oYZaVyMe/vlCMrIS+sh6SEc4+v0qNa3g==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
EOF
|
||||
|
||||
certificate = <<EOF
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDQjCCAioCCQC2H6+PYz23xDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAkxBMQ0wCwYDVQQKDARUZXN0MQwwCgYD
|
||||
VQQLDANGb28xHTAbBgNVBAMMFG90aGVyLmNvbnN1bC5leGFtcGxlMB4XDTIzMDIx
|
||||
NzAyMTM0OVoXDTI4MDIxNjAyMTM0OVowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
|
||||
AkNBMQswCQYDVQQHDAJMQTENMAsGA1UECgwEVGVzdDEMMAoGA1UECwwDRm9vMR0w
|
||||
GwYDVQQDDBRvdGhlci5jb25zdWwuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAO0IH/dzmWJaTPVL32xQVHivrnQk38vskW0ymILYuaismUMJ
|
||||
0+xrcaTcVljU+3nKhmSW9wcYSFY02GcGWAdcw8x8xO801cna020T+DIWiYaljXT3
|
||||
agrbYfULF9q+ihT6IL1D2mFa0AW1x6Bk1XAmZRSTpRBhp7iFNnCXGRK8sSSr95ge
|
||||
DxaRyj/2F8t6kG+ANPkRBiPd2rRgsYQjuTLuZYBvseeJygnSF8ty1QMg6koz7kdN
|
||||
bPon3Q5GFH71WNwzm9G3DWjMIu+dhpHz7rsbCnhwLB5lh1jsZBYkAMt3kiyY0g4I
|
||||
ReuiVWesMe+AMG/DQZvZ5mE252QFJ92dLTeo5RcCAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAijm6blixjl+pMRAj7EajoPjU+GqhooZayJrvdwvofwcPxQYpkPuh7Uc6
|
||||
l2z494b75cRzMw7wS+iW/ad8NYrfw1JwHMsUfncxs5LDO5GsKl9Krg/39goDl3wC
|
||||
ywTcl00y+FMYfldNPjKDLunENmn+yPa2pKuBVQ0yOKALp+oUeJFVzRNPV5fohlBi
|
||||
HjypkO0KaVmCG6P01cqCgVkNzxnX9qQYP3YXX1yt5iOcI7QcoOa5WnRhOuD8WqJ1
|
||||
v3AZGYNvKyXf9E5nD0y2Cmz6t1awjFjzMlXMx6AdHrjWqxtHhYQ1xz4P4NfzK27m
|
||||
cCtURSzXMgcrSeZLepBfdICf+0/0+Q==
|
||||
-----END CERTIFICATE-----
|
||||
EOF
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
Kind = "proxy-defaults"
|
||||
Name = "global"
|
||||
Config {
|
||||
protocol = "http"
|
||||
}
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "http-route"
|
||||
name = "api-gateway-route-one"
|
||||
rules = [
|
||||
{
|
||||
services = [
|
||||
{
|
||||
name = "s1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
parents = [
|
||||
{
|
||||
name = "api-gateway"
|
||||
sectionName = "listener-one"
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "http-route"
|
||||
name = "api-gateway-route-two"
|
||||
rules = [
|
||||
{
|
||||
services = [
|
||||
{
|
||||
name = "s2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
parents = [
|
||||
{
|
||||
name = "api-gateway"
|
||||
sectionName = "listener-two"
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "service-intentions"
|
||||
name = "s1"
|
||||
sources {
|
||||
name = "api-gateway"
|
||||
action = "allow"
|
||||
}
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "service-intentions"
|
||||
name = "s2"
|
||||
sources {
|
||||
name = "api-gateway"
|
||||
action = "deny"
|
||||
}
|
||||
'
|
||||
|
||||
register_services primary
|
||||
|
||||
gen_envoy_bootstrap api-gateway 20000 primary true
|
||||
gen_envoy_bootstrap s1 19000
|
||||
gen_envoy_bootstrap s2 19001
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
export REQUIRED_SERVICES="$DEFAULT_REQUIRED_SERVICES api-gateway-primary"
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
@test "api gateway proxy admin is up on :20000" {
|
||||
retry_default curl -f -s localhost:20000/stats -o /dev/null
|
||||
}
|
||||
|
||||
@test "api gateway should have be accepted and not conflicted" {
|
||||
assert_config_entry_status Accepted True Accepted primary api-gateway api-gateway
|
||||
assert_config_entry_status Conflicted False NoConflict primary api-gateway api-gateway
|
||||
}
|
||||
|
||||
@test "api gateway should have healthy endpoints for s1" {
|
||||
assert_config_entry_status Bound True Bound primary http-route api-gateway-route-one
|
||||
assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s1 HEALTHY 1
|
||||
}
|
||||
|
||||
@test "api gateway should have healthy endpoints for s2" {
|
||||
assert_config_entry_status Bound True Bound primary http-route api-gateway-route-two
|
||||
assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s2 HEALTHY 1
|
||||
}
|
||||
|
||||
@test "api gateway should be able to connect to s1 via configured port" {
|
||||
run retry_long curl -sk -f -d hello https://localhost:9999
|
||||
[[ "$output" == *"hello"* ]]
|
||||
}
|
||||
|
||||
@test "api gateway should be able to serve host.consul.example traffic on listener 1" {
|
||||
assert_cert_has_cn localhost:9999 host.consul.example host.consul.example
|
||||
}
|
||||
|
||||
@test "api gateway should be able to serve all other traffic with the host.consul.example certificate on listener 1" {
|
||||
assert_cert_has_cn localhost:9999 host.consul.example other.consul.example
|
||||
}
|
||||
|
||||
@test "api gateway should get an intentions error connecting to s2 via configured port" {
|
||||
run retry_default sh -c "curl -sk https://localhost:9998 | grep RBAC"
|
||||
[[ "$output" == "RBAC: access denied" ]]
|
||||
}
|
||||
|
||||
@test "api gateway should be able to serve listener 2 with the other.consul.example certificate" {
|
||||
assert_cert_has_cn localhost:9998 other.consul.example other.consul.example
|
||||
}
|
||||
|
||||
@test "api gateway should fall back to a connect certificate on conflicted SNI on listener 2" {
|
||||
assert_cert_has_cn localhost:9998 pri host.consul.example
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
snapshot_envoy_admin localhost:20000 api-gateway primary || true
|
|
@ -0,0 +1,4 @@
|
|||
services {
|
||||
name = "api-gateway"
|
||||
kind = "api-gateway"
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "api-gateway"
|
||||
name = "api-gateway"
|
||||
listeners = [
|
||||
{
|
||||
name = "listener-one"
|
||||
port = 9999
|
||||
protocol = "tcp"
|
||||
tls = {
|
||||
certificates = [
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "host-consul-example"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "listener-two"
|
||||
port = 9998
|
||||
protocol = "tcp"
|
||||
tls = {
|
||||
certificates = [
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "host-consul-example"
|
||||
},
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "also-host-consul-example"
|
||||
},
|
||||
{
|
||||
kind = "inline-certificate"
|
||||
name = "other-consul-example"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "inline-certificate"
|
||||
name = "host-consul-example"
|
||||
private_key = <<EOF
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA0wzZeonUklhOvJ0AxcdDdCTiMwR9tsm/6IGcw9Jm50xVY+qg
|
||||
5GFg1RWrQaODq7Gjqd/JDUAwtTBnQMs1yt6nbsHe2QhbD4XeqtZ+6fTv1ZpG3k8F
|
||||
eB/M01xFqovczRV/ie77wd4vqoPD+AcfD8NDAFJt3htwUgGIqkQHP329Sh3TtLga
|
||||
9ZMCs1MoTT+POYGUPL8bwt9R6ClNrucbH4Bs6OnX2ZFbKF75O9OHKNxWTmpDSodv
|
||||
OFbFyKps3BfnPuF0Z6mj5M5yZeCjmtfS25PrsM3pMBGK5YHb0MlFfZIrIGboMbrz
|
||||
9F/BMQJ64pMe43KwqHvTnbKWhp6PzLhEkPGLnwIDAQABAoIBADBEJAiONPszDu67
|
||||
yU1yAM8zEDgysr127liyK7PtDnOfVXgAVMNmMcsJpZzhVF+TxKY487YAFCOb6kE7
|
||||
OBYpTYla9SgVbR3js8TGQUgoKCFlowd8cvfB7gn4dEZIrjqIzB4zdYgk1Cne8JZs
|
||||
qoHkWhJcx5ugEtPuXd7yp+WxT/T+6uOro06scp67NhP5t9yoAGFv5Vdb577RuzRo
|
||||
Wkd9higQ9A20+GtjCY0EYxdgRviWvW7mM5/F+Lzcaui86ME+ga754gX8zgW3+NJ5
|
||||
LMsz5OLSnh291Uyjmr77HWBv/xvpq01Fls0LyJcgxFVZuJs5GQz+l3otSqv4FTP6
|
||||
Ua9w/YECgYEA8To3dgUK1QhzX5rwhWtlst3pItGTvmEdNzXmjgSylu7uKM13i+xg
|
||||
llhp2uXrOEtuL+xtBZdeFNaijusbyqjg0xj6e4o31c19okuuDkJD5/sfQq22bvrn
|
||||
gVJMGuESprIiPePrEyrXCHOdxH6eDgR2dIzAeO5vz0nnKGFAWrJJbvECgYEA3/mJ
|
||||
eacXOJznw4Sa8jGWS2FtZLKxDHph7uDKMJmuG0ukb3aHJ9dMHrPleCLo8mhpoObA
|
||||
hueoIbIP7swGrQx79+nZbnQpF6rMp6FAU5bF3gSrj1eWbaeh8pn9mrv4hal9USmn
|
||||
orTbXMxDp3XSh7voR8Fqy5tMQqwZ+Lz74ccbw48CgYEA5cEhGdNrocPOv3x/IVRN
|
||||
JLOfXX5nTaiJfxBja1imEIO5ajtoZWjaBdhn2gmqo4+UfyicHfsxrH9RjPX5HmkC
|
||||
2Yys5gWbcJOr2Wxjd0k+DDFucL+rRsDKxq1vtxov/X0kh/YQ68ydynr0BTbjq04s
|
||||
1I1KtOPEspYdCKS3+qpcrsECgYBtvYeVesBO9do9G0kMKC26y4bdEwzaz1ASykNn
|
||||
IrWDHEH6dznr1HqwhHaHsZsvwucWdlmZAAKKWAOkfoU63uYS55qomvPTa9WQwNqS
|
||||
2koi6Wjh+Al1uvAHvVncKgOwAgar8Nv5ReJBirgPYhSAexpppiRclL/93vNuw7Iq
|
||||
wvMgkwKBgQC5wnb6SUUrzzKKSRgyusHM/XrjiKgVKq7lvFE9/iJkcw+BEXpjjbEe
|
||||
RyD0a7PRtCfR39SMVrZp4KXVNNK5ln0WhuLvraMDwOpH9JDWHQiAhuJ3ooSwBylK
|
||||
+QCLjyOtWAGZAIBRJyb1txfTXZ++dldkOjBi3bmEiadOa48ksvDsNQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
EOF
|
||||
|
||||
certificate = <<EOF
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDQjCCAioCCQC6cMRYsE+ahDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAkxBMQ0wCwYDVQQKDARUZXN0MQ0wCwYD
|
||||
VQQLDARTdHViMRwwGgYDVQQDDBNob3N0LmNvbnN1bC5leGFtcGxlMB4XDTIzMDIx
|
||||
NzAyMTA1MloXDTI4MDIxNjAyMTA1MlowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
|
||||
AkNBMQswCQYDVQQHDAJMQTENMAsGA1UECgwEVGVzdDENMAsGA1UECwwEU3R1YjEc
|
||||
MBoGA1UEAwwTaG9zdC5jb25zdWwuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBANMM2XqJ1JJYTrydAMXHQ3Qk4jMEfbbJv+iBnMPSZudMVWPq
|
||||
oORhYNUVq0Gjg6uxo6nfyQ1AMLUwZ0DLNcrep27B3tkIWw+F3qrWfun079WaRt5P
|
||||
BXgfzNNcRaqL3M0Vf4nu+8HeL6qDw/gHHw/DQwBSbd4bcFIBiKpEBz99vUod07S4
|
||||
GvWTArNTKE0/jzmBlDy/G8LfUegpTa7nGx+AbOjp19mRWyhe+TvThyjcVk5qQ0qH
|
||||
bzhWxciqbNwX5z7hdGepo+TOcmXgo5rX0tuT67DN6TARiuWB29DJRX2SKyBm6DG6
|
||||
8/RfwTECeuKTHuNysKh7052yloaej8y4RJDxi58CAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAHF10odRNJ7TKvcD2JPtR8wMacfldSiPcQnn+rhMUyBaKOoSrALxOev+N
|
||||
L8N+RtEV+KXkyBkvT71OZzEpY9ROwqOQ/acnMdbfG0IBPbg3c/7WDD2sjcdr1zvc
|
||||
U3T7WJ7G3guZ5aWCuAGgOyT6ZW8nrDa4yFbKZ1PCJkvUQ2ttO1lXmyGPM533Y2pi
|
||||
SeXP6LL7z5VNqYO3oz5IJEstt10IKxdmb2gKFhHjgEmHN2gFL0jaPi4mjjaINrxq
|
||||
MdqcM9IzLr26AjZ45NuI9BCcZWO1mraaQTOIb3QL5LyqaC7CRJXLYPSGARthyDhq
|
||||
J3TrQE3YVrL4D9xnklT86WDnZKApJg==
|
||||
-----END CERTIFICATE-----
|
||||
EOF
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "inline-certificate"
|
||||
name = "also-host-consul-example"
|
||||
private_key = <<EOF
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA0wzZeonUklhOvJ0AxcdDdCTiMwR9tsm/6IGcw9Jm50xVY+qg
|
||||
5GFg1RWrQaODq7Gjqd/JDUAwtTBnQMs1yt6nbsHe2QhbD4XeqtZ+6fTv1ZpG3k8F
|
||||
eB/M01xFqovczRV/ie77wd4vqoPD+AcfD8NDAFJt3htwUgGIqkQHP329Sh3TtLga
|
||||
9ZMCs1MoTT+POYGUPL8bwt9R6ClNrucbH4Bs6OnX2ZFbKF75O9OHKNxWTmpDSodv
|
||||
OFbFyKps3BfnPuF0Z6mj5M5yZeCjmtfS25PrsM3pMBGK5YHb0MlFfZIrIGboMbrz
|
||||
9F/BMQJ64pMe43KwqHvTnbKWhp6PzLhEkPGLnwIDAQABAoIBADBEJAiONPszDu67
|
||||
yU1yAM8zEDgysr127liyK7PtDnOfVXgAVMNmMcsJpZzhVF+TxKY487YAFCOb6kE7
|
||||
OBYpTYla9SgVbR3js8TGQUgoKCFlowd8cvfB7gn4dEZIrjqIzB4zdYgk1Cne8JZs
|
||||
qoHkWhJcx5ugEtPuXd7yp+WxT/T+6uOro06scp67NhP5t9yoAGFv5Vdb577RuzRo
|
||||
Wkd9higQ9A20+GtjCY0EYxdgRviWvW7mM5/F+Lzcaui86ME+ga754gX8zgW3+NJ5
|
||||
LMsz5OLSnh291Uyjmr77HWBv/xvpq01Fls0LyJcgxFVZuJs5GQz+l3otSqv4FTP6
|
||||
Ua9w/YECgYEA8To3dgUK1QhzX5rwhWtlst3pItGTvmEdNzXmjgSylu7uKM13i+xg
|
||||
llhp2uXrOEtuL+xtBZdeFNaijusbyqjg0xj6e4o31c19okuuDkJD5/sfQq22bvrn
|
||||
gVJMGuESprIiPePrEyrXCHOdxH6eDgR2dIzAeO5vz0nnKGFAWrJJbvECgYEA3/mJ
|
||||
eacXOJznw4Sa8jGWS2FtZLKxDHph7uDKMJmuG0ukb3aHJ9dMHrPleCLo8mhpoObA
|
||||
hueoIbIP7swGrQx79+nZbnQpF6rMp6FAU5bF3gSrj1eWbaeh8pn9mrv4hal9USmn
|
||||
orTbXMxDp3XSh7voR8Fqy5tMQqwZ+Lz74ccbw48CgYEA5cEhGdNrocPOv3x/IVRN
|
||||
JLOfXX5nTaiJfxBja1imEIO5ajtoZWjaBdhn2gmqo4+UfyicHfsxrH9RjPX5HmkC
|
||||
2Yys5gWbcJOr2Wxjd0k+DDFucL+rRsDKxq1vtxov/X0kh/YQ68ydynr0BTbjq04s
|
||||
1I1KtOPEspYdCKS3+qpcrsECgYBtvYeVesBO9do9G0kMKC26y4bdEwzaz1ASykNn
|
||||
IrWDHEH6dznr1HqwhHaHsZsvwucWdlmZAAKKWAOkfoU63uYS55qomvPTa9WQwNqS
|
||||
2koi6Wjh+Al1uvAHvVncKgOwAgar8Nv5ReJBirgPYhSAexpppiRclL/93vNuw7Iq
|
||||
wvMgkwKBgQC5wnb6SUUrzzKKSRgyusHM/XrjiKgVKq7lvFE9/iJkcw+BEXpjjbEe
|
||||
RyD0a7PRtCfR39SMVrZp4KXVNNK5ln0WhuLvraMDwOpH9JDWHQiAhuJ3ooSwBylK
|
||||
+QCLjyOtWAGZAIBRJyb1txfTXZ++dldkOjBi3bmEiadOa48ksvDsNQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
EOF
|
||||
|
||||
certificate = <<EOF
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDQjCCAioCCQC6cMRYsE+ahDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAkxBMQ0wCwYDVQQKDARUZXN0MQ0wCwYD
|
||||
VQQLDARTdHViMRwwGgYDVQQDDBNob3N0LmNvbnN1bC5leGFtcGxlMB4XDTIzMDIx
|
||||
NzAyMTA1MloXDTI4MDIxNjAyMTA1MlowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
|
||||
AkNBMQswCQYDVQQHDAJMQTENMAsGA1UECgwEVGVzdDENMAsGA1UECwwEU3R1YjEc
|
||||
MBoGA1UEAwwTaG9zdC5jb25zdWwuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBANMM2XqJ1JJYTrydAMXHQ3Qk4jMEfbbJv+iBnMPSZudMVWPq
|
||||
oORhYNUVq0Gjg6uxo6nfyQ1AMLUwZ0DLNcrep27B3tkIWw+F3qrWfun079WaRt5P
|
||||
BXgfzNNcRaqL3M0Vf4nu+8HeL6qDw/gHHw/DQwBSbd4bcFIBiKpEBz99vUod07S4
|
||||
GvWTArNTKE0/jzmBlDy/G8LfUegpTa7nGx+AbOjp19mRWyhe+TvThyjcVk5qQ0qH
|
||||
bzhWxciqbNwX5z7hdGepo+TOcmXgo5rX0tuT67DN6TARiuWB29DJRX2SKyBm6DG6
|
||||
8/RfwTECeuKTHuNysKh7052yloaej8y4RJDxi58CAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAHF10odRNJ7TKvcD2JPtR8wMacfldSiPcQnn+rhMUyBaKOoSrALxOev+N
|
||||
L8N+RtEV+KXkyBkvT71OZzEpY9ROwqOQ/acnMdbfG0IBPbg3c/7WDD2sjcdr1zvc
|
||||
U3T7WJ7G3guZ5aWCuAGgOyT6ZW8nrDa4yFbKZ1PCJkvUQ2ttO1lXmyGPM533Y2pi
|
||||
SeXP6LL7z5VNqYO3oz5IJEstt10IKxdmb2gKFhHjgEmHN2gFL0jaPi4mjjaINrxq
|
||||
MdqcM9IzLr26AjZ45NuI9BCcZWO1mraaQTOIb3QL5LyqaC7CRJXLYPSGARthyDhq
|
||||
J3TrQE3YVrL4D9xnklT86WDnZKApJg==
|
||||
-----END CERTIFICATE-----
|
||||
EOF
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "inline-certificate"
|
||||
name = "other-consul-example"
|
||||
private_key = <<EOF
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA7Qgf93OZYlpM9UvfbFBUeK+udCTfy+yRbTKYgti5qKyZQwnT
|
||||
7GtxpNxWWNT7ecqGZJb3BxhIVjTYZwZYB1zDzHzE7zTVydrTbRP4MhaJhqWNdPdq
|
||||
Ctth9QsX2r6KFPogvUPaYVrQBbXHoGTVcCZlFJOlEGGnuIU2cJcZEryxJKv3mB4P
|
||||
FpHKP/YXy3qQb4A0+REGI93atGCxhCO5Mu5lgG+x54nKCdIXy3LVAyDqSjPuR01s
|
||||
+ifdDkYUfvVY3DOb0bcNaMwi752GkfPuuxsKeHAsHmWHWOxkFiQAy3eSLJjSDghF
|
||||
66JVZ6wx74Awb8NBm9nmYTbnZAUn3Z0tN6jlFwIDAQABAoIBAGh8EWNJ8M4bEht7
|
||||
A5TCYEoG3zbRXlmNAZoKGJJtKIIC+1hCx8lKn4DVo7ZqxCOus8k5htD40kI170KS
|
||||
2FD+gkzsnv724lqlfFdz2w9xQdQ5u/5YZcU9aZPT/QLuxP10OORVObl6h4JM3B+G
|
||||
81MJibslTjjHY2CCUDoXUPUiek+4KTI6BYn9PL+ReCaH9qv85hIWvkgbwU2f9i3n
|
||||
T8MysgDBNoKbVAqsH5Hq/zFkW5iad/zpgW+REgYK/gjBfUNEsRusm1GYim4XJtZf
|
||||
SmXBtdYhk8kDBrMk1mNdZeMXMfl0VwZaHca8QmqrgDm//grUYKLWZO/PbDoI5c+w
|
||||
/MTN6tkCgYEA956LZJ+Ts9g9k+jLcUV1hOAmR6cAL5tjEkBPVC5FC+5o42qOgI58
|
||||
5NQjmVCM+mD9w+deAXkT/IDXzV28Y02lZ1pyOXTN+ChE2ZBym+yu2zyLj45lJzx5
|
||||
h+lC7aeCBIGyjP/t6wFoFdCaluAsWpU4SY1DWtExcCLvXs0+zDiYjZMCgYEA9Q3Y
|
||||
mlrAvdzb61x8BAEPpBTMSu0a+jo8mkJoUFS4ndFXEl5yPzqf6IUrFgzqgVruQg7k
|
||||
dIZK5uDqNI7sXDXulpPFHbJdpAZq3Dlkv0VOvcgRycuWgDAyOngCSRN8JC7u4P5j
|
||||
54xgAYQSCC/kPolFMHntXQLjzPevJNrkKnJfXO0CgYEAyCf5ByJSs0o1JE1Fvc7m
|
||||
mrzRVJPye4kAQS2IskQgfe9+C24DuHj1DcdI61IIUw95sRRhkZE8jZvcVN3TPPXz
|
||||
oKKkuDrpjxGF7dNsQQvFn+PF8AmrTFb+6dSszAvd9iScnor110OwzglsHE8iqyn5
|
||||
cMLmUg/NBZbHpPsFKvEIp08CgYAmQ1Az4cHAo5CvMlSm52eCzkCL3nPc6GT4DTBu
|
||||
gpwFAF/hHWAnYUcArnJo0gF3yzPympKvYxyk6i+Hn11mlIE5f79CgMxARURAOLHz
|
||||
b6X42hl08dYBFAVzvbNVp7Y1jCJ+fRoqWG/RLMcIAjpYTWTBSfh3EnFxWqc9UPRZ
|
||||
cFxVjQKBgQDUXDww+jXXTFlYkbhgNOtQS57M8jKWHnUxEc7IXOjF/0WGEEBAc2uc
|
||||
fFW5dnPyS3D6vecWA8KB8LKcXey3ZcDZnVkahSgYhYHrGJrANzhfM3yli+lSFWsT
|
||||
r295+0za3P3LVL4aKS+ok9oYZaVyMe/vlCMrIS+sh6SEc4+v0qNa3g==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
EOF
|
||||
|
||||
certificate = <<EOF
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDQjCCAioCCQC2H6+PYz23xDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAkxBMQ0wCwYDVQQKDARUZXN0MQwwCgYD
|
||||
VQQLDANGb28xHTAbBgNVBAMMFG90aGVyLmNvbnN1bC5leGFtcGxlMB4XDTIzMDIx
|
||||
NzAyMTM0OVoXDTI4MDIxNjAyMTM0OVowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
|
||||
AkNBMQswCQYDVQQHDAJMQTENMAsGA1UECgwEVGVzdDEMMAoGA1UECwwDRm9vMR0w
|
||||
GwYDVQQDDBRvdGhlci5jb25zdWwuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAO0IH/dzmWJaTPVL32xQVHivrnQk38vskW0ymILYuaismUMJ
|
||||
0+xrcaTcVljU+3nKhmSW9wcYSFY02GcGWAdcw8x8xO801cna020T+DIWiYaljXT3
|
||||
agrbYfULF9q+ihT6IL1D2mFa0AW1x6Bk1XAmZRSTpRBhp7iFNnCXGRK8sSSr95ge
|
||||
DxaRyj/2F8t6kG+ANPkRBiPd2rRgsYQjuTLuZYBvseeJygnSF8ty1QMg6koz7kdN
|
||||
bPon3Q5GFH71WNwzm9G3DWjMIu+dhpHz7rsbCnhwLB5lh1jsZBYkAMt3kiyY0g4I
|
||||
ReuiVWesMe+AMG/DQZvZ5mE252QFJ92dLTeo5RcCAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAijm6blixjl+pMRAj7EajoPjU+GqhooZayJrvdwvofwcPxQYpkPuh7Uc6
|
||||
l2z494b75cRzMw7wS+iW/ad8NYrfw1JwHMsUfncxs5LDO5GsKl9Krg/39goDl3wC
|
||||
ywTcl00y+FMYfldNPjKDLunENmn+yPa2pKuBVQ0yOKALp+oUeJFVzRNPV5fohlBi
|
||||
HjypkO0KaVmCG6P01cqCgVkNzxnX9qQYP3YXX1yt5iOcI7QcoOa5WnRhOuD8WqJ1
|
||||
v3AZGYNvKyXf9E5nD0y2Cmz6t1awjFjzMlXMx6AdHrjWqxtHhYQ1xz4P4NfzK27m
|
||||
cCtURSzXMgcrSeZLepBfdICf+0/0+Q==
|
||||
-----END CERTIFICATE-----
|
||||
EOF
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
Kind = "proxy-defaults"
|
||||
Name = "global"
|
||||
Config {
|
||||
protocol = "tcp"
|
||||
}
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "tcp-route"
|
||||
name = "api-gateway-route-one"
|
||||
services = [
|
||||
{
|
||||
name = "s1"
|
||||
}
|
||||
]
|
||||
parents = [
|
||||
{
|
||||
name = "api-gateway"
|
||||
sectionName = "listener-one"
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "tcp-route"
|
||||
name = "api-gateway-route-two"
|
||||
services = [
|
||||
{
|
||||
name = "s2"
|
||||
}
|
||||
]
|
||||
parents = [
|
||||
{
|
||||
name = "api-gateway"
|
||||
sectionName = "listener-two"
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "service-intentions"
|
||||
name = "s1"
|
||||
sources {
|
||||
name = "api-gateway"
|
||||
action = "allow"
|
||||
}
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
kind = "service-intentions"
|
||||
name = "s2"
|
||||
sources {
|
||||
name = "api-gateway"
|
||||
action = "deny"
|
||||
}
|
||||
'
|
||||
|
||||
register_services primary
|
||||
|
||||
gen_envoy_bootstrap api-gateway 20000 primary true
|
||||
gen_envoy_bootstrap s1 19000
|
||||
gen_envoy_bootstrap s2 19001
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
export REQUIRED_SERVICES="$DEFAULT_REQUIRED_SERVICES api-gateway-primary"
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
@test "api gateway proxy admin is up on :20000" {
|
||||
retry_default curl -f -s localhost:20000/stats -o /dev/null
|
||||
}
|
||||
|
||||
@test "api gateway should have be accepted and not conflicted" {
|
||||
assert_config_entry_status Accepted True Accepted primary api-gateway api-gateway
|
||||
assert_config_entry_status Conflicted False NoConflict primary api-gateway api-gateway
|
||||
}
|
||||
|
||||
@test "api gateway should have healthy endpoints for s1" {
|
||||
assert_config_entry_status Bound True Bound primary tcp-route api-gateway-route-one
|
||||
assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s1 HEALTHY 1
|
||||
}
|
||||
|
||||
@test "api gateway should have healthy endpoints for s2" {
|
||||
assert_config_entry_status Bound True Bound primary tcp-route api-gateway-route-two
|
||||
assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s2 HEALTHY 1
|
||||
}
|
||||
|
||||
@test "api gateway should be able to connect to s1 via configured port" {
|
||||
run retry_long curl -sk -f -d hello https://localhost:9999
|
||||
[[ "$output" == *"hello"* ]]
|
||||
}
|
||||
|
||||
@test "api gateway should be able to serve host.consul.example traffic on listener 1" {
|
||||
assert_cert_has_cn localhost:9999 host.consul.example host.consul.example
|
||||
}
|
||||
|
||||
@test "api gateway should be able to serve all other traffic with the host.consul.example certificate on listener 1" {
|
||||
assert_cert_has_cn localhost:9999 host.consul.example other.consul.example
|
||||
}
|
||||
|
||||
@test "api gateway should be able to serve listener 2 with the other.consul.example certificate" {
|
||||
assert_cert_has_cn localhost:9998 other.consul.example other.consul.example
|
||||
}
|
||||
|
||||
@test "api gateway should fall back to a connect certificate on conflicted SNI on listener 2" {
|
||||
assert_cert_has_cn localhost:9998 pri host.consul.example
|
||||
}
|
|
@ -147,6 +147,20 @@ function assert_cert_signed_by_ca {
|
|||
echo "$CERT" | grep 'Verify return code: 0 (ok)'
|
||||
}
|
||||
|
||||
function assert_cert_has_cn {
|
||||
local HOSTPORT=$1
|
||||
local CN=$2
|
||||
local SERVER_NAME=${3:-$CN}
|
||||
|
||||
CERT=$(openssl s_client -connect $HOSTPORT -servername $SERVER_NAME -showcerts </dev/null 2>/dev/null)
|
||||
|
||||
echo "WANT CN: ${CN} (SNI: ${SERVER_NAME})"
|
||||
echo "GOT CERT:"
|
||||
echo "$CERT"
|
||||
|
||||
echo "$CERT" | grep "CN = ${CN}"
|
||||
}
|
||||
|
||||
function assert_envoy_version {
|
||||
local ADMINPORT=$1
|
||||
run retry_default curl -f -s localhost:$ADMINPORT/server_info
|
||||
|
|
Loading…
Reference in New Issue