Update public listener with SPIFFE Validator
Envoy's SPIFFE certificate validation extension allows for us to validate against different root certificates depending on the trust domain of the dialing proxy. If there are any trust bundles from peers in the config snapshot then we use the SPIFFE validator as the validation context, rather than the usual TrustedCA. The injected validation config includes the local root certificates as well.
This commit is contained in:
parent
ad6dbe081a
commit
137bfbb02b
|
@ -646,6 +646,7 @@ func (a *Agent) Start(ctx context.Context) error {
|
|||
ResolvedServiceConfig: proxycfgglue.CacheResolvedServiceConfig(a.cache),
|
||||
ServiceList: proxycfgglue.CacheServiceList(a.cache),
|
||||
TrustBundle: proxycfgglue.CacheTrustBundle(a.cache),
|
||||
TrustBundleList: proxycfgglue.CacheTrustBundleList(a.cache),
|
||||
}
|
||||
a.fillEnterpriseProxyDataSources(&proxyDataSources)
|
||||
a.proxyConfig, err = proxycfg.NewManager(proxycfg.ManagerConfig{
|
||||
|
|
|
@ -101,10 +101,18 @@ func CacheServiceList(c *cache.Cache) proxycfg.ServiceList {
|
|||
return &cacheProxyDataSource[*structs.DCSpecificRequest]{c, cachetype.CatalogServiceListName}
|
||||
}
|
||||
|
||||
// CacheTrustBundle satisfies the proxycfg.TrustBundle interface by sourcing
|
||||
// data from the agent cache.
|
||||
func CacheTrustBundle(c *cache.Cache) proxycfg.TrustBundle {
|
||||
return &cacheProxyDataSource[*pbpeering.TrustBundleReadRequest]{c, cachetype.TrustBundleReadName}
|
||||
}
|
||||
|
||||
// CacheTrustBundleList satisfies the proxycfg.TrustBundleList interface by sourcing
|
||||
// data from the agent cache.
|
||||
func CacheTrustBundleList(c *cache.Cache) proxycfg.TrustBundleList {
|
||||
return &cacheProxyDataSource[*pbpeering.TrustBundleListByServiceRequest]{c, cachetype.TrustBundleListName}
|
||||
}
|
||||
|
||||
// cacheProxyDataSource implements a generic wrapper around the agent cache to
|
||||
// provide data to the proxycfg.Manager.
|
||||
type cacheProxyDataSource[ReqType cache.Request] struct {
|
||||
|
|
|
@ -44,6 +44,16 @@ func (s *handlerConnectProxy) initialize(ctx context.Context) (ConfigSnapshot, e
|
|||
return snap, err
|
||||
}
|
||||
|
||||
err = s.dataSources.TrustBundleList.Notify(ctx, &pbpeering.TrustBundleListByServiceRequest{
|
||||
// TODO(peering): Pass ACL token
|
||||
ServiceName: s.proxyCfg.DestinationServiceName,
|
||||
Namespace: s.proxyID.NamespaceOrDefault(),
|
||||
Partition: s.proxyID.PartitionOrDefault(),
|
||||
}, peeringTrustBundlesWatchID, s.ch)
|
||||
if err != nil {
|
||||
return snap, err
|
||||
}
|
||||
|
||||
// Watch the leaf cert
|
||||
err = s.dataSources.LeafCertificate.Notify(ctx, &cachetype.ConnectCALeafRequest{
|
||||
Datacenter: s.source.Datacenter,
|
||||
|
@ -259,6 +269,16 @@ func (s *handlerConnectProxy) handleUpdate(ctx context.Context, u UpdateEvent, s
|
|||
snap.ConnectProxy.PeerTrustBundles[peer] = resp.Bundle
|
||||
}
|
||||
|
||||
case u.CorrelationID == peeringTrustBundlesWatchID:
|
||||
resp, ok := u.Result.(*pbpeering.TrustBundleListByServiceResponse)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type for response: %T", u.Result)
|
||||
}
|
||||
if len(resp.Bundles) > 0 {
|
||||
snap.ConnectProxy.PeeringTrustBundles = resp.Bundles
|
||||
}
|
||||
snap.ConnectProxy.PeeringTrustBundlesSet = true
|
||||
|
||||
case u.CorrelationID == intentionsWatchID:
|
||||
resp, ok := u.Result.(*structs.IndexedIntentionMatches)
|
||||
if !ok {
|
||||
|
|
|
@ -82,6 +82,10 @@ type DataSources struct {
|
|||
// TrustBundle provides updates about the trust bundle for a single peer.
|
||||
TrustBundle TrustBundle
|
||||
|
||||
// TrustBundleList provides updates about the list of trust bundles for
|
||||
// peered clusters that the given proxy is exported to.
|
||||
TrustBundleList TrustBundleList
|
||||
|
||||
DataSourcesEnterprise
|
||||
}
|
||||
|
||||
|
@ -185,3 +189,9 @@ type ServiceList interface {
|
|||
type TrustBundle interface {
|
||||
Notify(ctx context.Context, req *pbpeering.TrustBundleReadRequest, correlationID string, ch chan<- UpdateEvent) error
|
||||
}
|
||||
|
||||
// TrustBundleList is the interface used to consume updates about trust bundles
|
||||
// for peered clusters that the given proxy is exported to.
|
||||
type TrustBundleList interface {
|
||||
Notify(ctx context.Context, req *pbpeering.TrustBundleListByServiceRequest, correlationID string, ch chan<- UpdateEvent) error
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/consul/proto/pbpeering"
|
||||
"github.com/mitchellh/copystructure"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/consul/proto/pbpeering"
|
||||
)
|
||||
|
||||
// TODO(ingress): Can we think of a better for this bag of data?
|
||||
|
@ -122,6 +122,9 @@ func gatewayKeyFromString(s string) GatewayKey {
|
|||
type configSnapshotConnectProxy struct {
|
||||
ConfigSnapshotUpstreams
|
||||
|
||||
PeeringTrustBundlesSet bool
|
||||
PeeringTrustBundles []*pbpeering.PeeringTrustBundle
|
||||
|
||||
WatchedServiceChecks map[structs.ServiceID][]structs.CheckType // TODO: missing garbage collection
|
||||
PreparedQueryEndpoints map[UpstreamID]structs.CheckServiceNodes // DEPRECATED:see:WatchedUpstreamEndpoints
|
||||
|
||||
|
@ -152,6 +155,7 @@ func (c *configSnapshotConnectProxy) isEmpty() bool {
|
|||
len(c.UpstreamConfig) == 0 &&
|
||||
len(c.PassthroughUpstreams) == 0 &&
|
||||
len(c.IntentionUpstreams) == 0 &&
|
||||
!c.PeeringTrustBundlesSet &&
|
||||
!c.MeshConfigSet
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
const (
|
||||
coalesceTimeout = 200 * time.Millisecond
|
||||
rootsWatchID = "roots"
|
||||
peeringTrustBundlesWatchID = "peering-trust-bundles"
|
||||
leafWatchID = "leaf"
|
||||
peerTrustBundleIDPrefix = "peer-trust-bundle:"
|
||||
intentionsWatchID = "intentions"
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/proto/pbpeering"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
@ -15,6 +14,8 @@ import (
|
|||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||
"github.com/hashicorp/consul/agent/consul/discoverychain"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/proto/pbpeering"
|
||||
"github.com/hashicorp/consul/proto/prototest"
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
)
|
||||
|
||||
|
@ -134,6 +135,7 @@ func recordWatches(sc *stateConfig) *watchRecorder {
|
|||
ResolvedServiceConfig: typedWatchRecorder[*structs.ServiceConfigRequest]{wr},
|
||||
ServiceList: typedWatchRecorder[*structs.DCSpecificRequest]{wr},
|
||||
TrustBundle: typedWatchRecorder[*pbpeering.TrustBundleReadRequest]{wr},
|
||||
TrustBundleList: typedWatchRecorder[*pbpeering.TrustBundleListByServiceRequest]{wr},
|
||||
}
|
||||
recordWatchesEnterprise(sc, wr)
|
||||
|
||||
|
@ -217,6 +219,14 @@ func genVerifyLeafWatch(expectedService string, expectedDatacenter string) verif
|
|||
return genVerifyLeafWatchWithDNSSANs(expectedService, expectedDatacenter, nil)
|
||||
}
|
||||
|
||||
func genVerifyTrustBundleListWatch(service string) verifyWatchRequest {
|
||||
return func(t testing.TB, request any) {
|
||||
reqReal, ok := request.(*pbpeering.TrustBundleListByServiceRequest)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, service, reqReal.ServiceName)
|
||||
}
|
||||
}
|
||||
|
||||
func genVerifyResolverWatch(expectedService, expectedDatacenter, expectedKind string) verifyWatchRequest {
|
||||
return func(t testing.TB, request any) {
|
||||
reqReal, ok := request.(*structs.ConfigEntryQuery)
|
||||
|
@ -2492,6 +2502,7 @@ func TestState_WatchesAndUpdates(t *testing.T) {
|
|||
}),
|
||||
rootsWatchID: genVerifyDCSpecificWatch("dc1"),
|
||||
leafWatchID: genVerifyLeafWatch("web", "dc1"),
|
||||
peeringTrustBundlesWatchID: genVerifyTrustBundleListWatch("web"),
|
||||
peerTrustBundleIDPrefix + "peer-a": genVerifyTrustBundleReadWatch("peer-a"),
|
||||
// No Peering watch
|
||||
},
|
||||
|
@ -2514,12 +2525,18 @@ func TestState_WatchesAndUpdates(t *testing.T) {
|
|||
|
||||
require.Len(t, snap.ConnectProxy.WatchedServiceChecks, 0, "%+v", snap.ConnectProxy.WatchedServiceChecks)
|
||||
require.Len(t, snap.ConnectProxy.PreparedQueryEndpoints, 0, "%+v", snap.ConnectProxy.PreparedQueryEndpoints)
|
||||
require.Len(t, snap.ConnectProxy.PeeringTrustBundles, 0, "%+v", snap.ConnectProxy.PeeringTrustBundles)
|
||||
require.False(t, snap.ConnectProxy.PeeringTrustBundlesSet)
|
||||
},
|
||||
},
|
||||
{
|
||||
// This time add the events
|
||||
events: []UpdateEvent{
|
||||
rootWatchEvent(),
|
||||
{
|
||||
CorrelationID: peeringTrustBundlesWatchID,
|
||||
Result: peerTrustBundles,
|
||||
},
|
||||
{
|
||||
CorrelationID: leafWatchID,
|
||||
Result: issuedCert,
|
||||
|
@ -2551,8 +2568,10 @@ func TestState_WatchesAndUpdates(t *testing.T) {
|
|||
verifySnapshot: func(t testing.TB, snap *ConfigSnapshot) {
|
||||
require.True(t, snap.Valid())
|
||||
require.True(t, snap.MeshGateway.isEmpty())
|
||||
|
||||
require.Equal(t, indexedRoots, snap.Roots)
|
||||
require.Equal(t, issuedCert, snap.ConnectProxy.Leaf)
|
||||
prototest.AssertDeepEqual(t, peerTrustBundles.Bundles, snap.ConnectProxy.PeeringTrustBundles)
|
||||
|
||||
require.Len(t, snap.ConnectProxy.DiscoveryChain, 2, "%+v", snap.ConnectProxy.DiscoveryChain)
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreams, 2, "%+v", snap.ConnectProxy.WatchedUpstreams)
|
||||
|
|
|
@ -24,8 +24,6 @@ import (
|
|||
)
|
||||
|
||||
func TestPeerTrustBundles(t testing.T) *pbpeering.TrustBundleListByServiceResponse {
|
||||
t.Helper()
|
||||
|
||||
return &pbpeering.TrustBundleListByServiceResponse{
|
||||
Bundles: []*pbpeering.PeeringTrustBundle{
|
||||
{
|
||||
|
@ -722,6 +720,7 @@ func testConfigSnapshotFixture(
|
|||
ResolvedServiceConfig: &noopDataSource[*structs.ServiceConfigRequest]{},
|
||||
ServiceList: &noopDataSource[*structs.DCSpecificRequest]{},
|
||||
TrustBundle: &noopDataSource[*pbpeering.TrustBundleReadRequest]{},
|
||||
TrustBundleList: &noopDataSource[*pbpeering.TrustBundleListByServiceRequest]{},
|
||||
},
|
||||
dnsConfig: DNSConfig{ // TODO: make configurable
|
||||
Domain: "consul",
|
||||
|
@ -922,6 +921,7 @@ func NewTestDataSources() *TestDataSources {
|
|||
ResolvedServiceConfig: NewTestDataSource[*structs.ServiceConfigRequest, *structs.ServiceConfigResponse](),
|
||||
ServiceList: NewTestDataSource[*structs.DCSpecificRequest, *structs.IndexedServiceList](),
|
||||
TrustBundle: NewTestDataSource[*pbpeering.TrustBundleReadRequest, *pbpeering.TrustBundleReadResponse](),
|
||||
TrustBundleList: NewTestDataSource[*pbpeering.TrustBundleListByServiceRequest, *pbpeering.TrustBundleListByServiceResponse](),
|
||||
}
|
||||
srcs.buildEnterpriseSources()
|
||||
return srcs
|
||||
|
@ -945,6 +945,9 @@ type TestDataSources struct {
|
|||
ResolvedServiceConfig *TestDataSource[*structs.ServiceConfigRequest, *structs.ServiceConfigResponse]
|
||||
ServiceList *TestDataSource[*structs.DCSpecificRequest, *structs.IndexedServiceList]
|
||||
TrustBundle *TestDataSource[*pbpeering.TrustBundleReadRequest, *pbpeering.TrustBundleReadResponse]
|
||||
TrustBundleList *TestDataSource[*pbpeering.TrustBundleListByServiceRequest, *pbpeering.TrustBundleListByServiceResponse]
|
||||
|
||||
TestDataSourcesEnterprise
|
||||
}
|
||||
|
||||
func (t *TestDataSources) ToDataSources() DataSources {
|
||||
|
@ -965,6 +968,7 @@ func (t *TestDataSources) ToDataSources() DataSources {
|
|||
ResolvedServiceConfig: t.ResolvedServiceConfig,
|
||||
ServiceList: t.ServiceList,
|
||||
TrustBundle: t.TrustBundle,
|
||||
TrustBundleList: t.TrustBundleList,
|
||||
}
|
||||
t.fillEnterpriseDataSources(&ds)
|
||||
return ds
|
||||
|
|
|
@ -11,9 +11,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/consul/types"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
|
@ -39,10 +36,14 @@ import (
|
|||
"github.com/golang/protobuf/ptypes/any"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/connect"
|
||||
"github.com/hashicorp/consul/agent/proxycfg"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/consul/proto/pbpeering"
|
||||
"github.com/hashicorp/consul/sdk/iptables"
|
||||
"github.com/hashicorp/consul/types"
|
||||
)
|
||||
|
||||
const virtualIPTag = "virtual"
|
||||
|
@ -777,6 +778,100 @@ func (s *ResourceGenerator) injectConnectTLSOnFilterChains(cfgSnap *proxycfg.Con
|
|||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// NOTE: This method MUST only be used for connect proxy public listeners,
|
||||
// since TLS validation will be done against root certs for all peers
|
||||
// that might dial this proxy.
|
||||
func (s *ResourceGenerator) injectConnectTLSForPublicListener(cfgSnap *proxycfg.ConfigSnapshot, listener *envoy_listener_v3.Listener) error {
|
||||
if cfgSnap.Kind != structs.ServiceKindConnectProxy {
|
||||
return fmt.Errorf("cannot inject peering trust bundles for kind %q", cfgSnap.Kind)
|
||||
}
|
||||
|
||||
// Create TLS validation context for mTLS with leaf certificate and root certs.
|
||||
tlsContext := makeCommonTLSContext(
|
||||
cfgSnap.Leaf(),
|
||||
cfgSnap.RootPEMs(),
|
||||
makeTLSParametersFromProxyTLSConfig(cfgSnap.MeshConfigTLSIncoming()),
|
||||
)
|
||||
|
||||
// Inject peering trust bundles if this service is exported to peered clusters.
|
||||
if len(cfgSnap.ConnectProxy.PeeringTrustBundles) > 0 {
|
||||
spiffeConfig, err := makeSpiffeValidatorConfig(cfgSnap.Roots.TrustDomain, cfgSnap.RootPEMs(), cfgSnap.ConnectProxy.PeeringTrustBundles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typ, ok := tlsContext.ValidationContextType.(*envoy_tls_v3.CommonTlsContext_ValidationContext)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type for TLS context validation: %T", tlsContext.ValidationContextType)
|
||||
}
|
||||
|
||||
// makeCommonTLSFromLead injects the local trust domain's CA root certs as the TrustedCA.
|
||||
// We nil it out here since the local roots are included in the SPIFFE validator config.
|
||||
typ.ValidationContext.TrustedCa = nil
|
||||
typ.ValidationContext.CustomValidatorConfig = &envoy_core_v3.TypedExtensionConfig{
|
||||
// The typed config name is hard-coded because it is not available as a wellknown var in the control plane lib.
|
||||
Name: "envoy.tls.cert_validator.spiffe",
|
||||
TypedConfig: spiffeConfig,
|
||||
}
|
||||
}
|
||||
|
||||
transportSocket, err := makeDownstreamTLSTransportSocket(&envoy_tls_v3.DownstreamTlsContext{
|
||||
CommonTlsContext: tlsContext,
|
||||
RequireClientCertificate: &wrappers.BoolValue{Value: true},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for idx := range listener.FilterChains {
|
||||
listener.FilterChains[idx].TransportSocket = transportSocket
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SPIFFECertValidatorConfig is used to validate certificates from trust domains other than our own.
|
||||
// With cluster peering we expect peered clusters to have independent certificate authorities.
|
||||
// This means that we cannot use a single set of root CA certificates to validate client certificates for mTLS,
|
||||
// but rather we need to validate against different roots depending on the trust domain of the certificate presented.
|
||||
func makeSpiffeValidatorConfig(trustDomain, roots string, peerBundles []*pbpeering.PeeringTrustBundle) (*any.Any, error) {
|
||||
// Store the trust bundle for the local trust domain.
|
||||
bundles := map[string]string{trustDomain: roots}
|
||||
|
||||
// Store the trust bundle for each trust domain of the peers this proxy is exported to.
|
||||
// This allows us to validate traffic from other trust domains.
|
||||
for _, b := range peerBundles {
|
||||
var pems string
|
||||
for _, pem := range b.RootPEMs {
|
||||
pems += lib.EnsureTrailingNewline(pem)
|
||||
}
|
||||
bundles[b.TrustDomain] = pems
|
||||
}
|
||||
|
||||
cfg := &envoy_tls_v3.SPIFFECertValidatorConfig{
|
||||
TrustDomains: make([]*envoy_tls_v3.SPIFFECertValidatorConfig_TrustDomain, 0, len(bundles)),
|
||||
}
|
||||
|
||||
for domain, bundle := range bundles {
|
||||
cfg.TrustDomains = append(cfg.TrustDomains, &envoy_tls_v3.SPIFFECertValidatorConfig_TrustDomain{
|
||||
Name: domain,
|
||||
TrustBundle: &envoy_core_v3.DataSource{
|
||||
Specifier: &envoy_core_v3.DataSource_InlineString{
|
||||
InlineString: bundle,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Sort the trust domains so that the output is stable.
|
||||
// This benefits tests but also prevents Envoy from mistakenly thinking the listener
|
||||
// changed and needs to be drained only because this ordering is different.
|
||||
sort.Slice(cfg.TrustDomains, func(i int, j int) bool {
|
||||
return cfg.TrustDomains[i].Name < cfg.TrustDomains[j].Name
|
||||
})
|
||||
return ptypes.MarshalAny(cfg)
|
||||
}
|
||||
|
||||
func (s *ResourceGenerator) makeInboundListener(cfgSnap *proxycfg.ConfigSnapshot, name string) (proto.Message, error) {
|
||||
var l *envoy_listener_v3.Listener
|
||||
var err error
|
||||
|
@ -899,7 +994,7 @@ func (s *ResourceGenerator) finalizePublicListenerFromConfig(l *envoy_listener_v
|
|||
}
|
||||
|
||||
// Always apply TLS certificates
|
||||
if err := s.injectConnectTLSOnFilterChains(cfgSnap, l); err != nil {
|
||||
if err := s.injectConnectTLSForPublicListener(cfgSnap, l); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"time"
|
||||
|
||||
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
|
||||
testinf "github.com/mitchellh/go-testing-interface"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
@ -42,6 +41,21 @@ func TestListenersFromSnapshot(t *testing.T) {
|
|||
return proxycfg.TestConfigSnapshot(t, nil, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "connect-proxy-exported-to-peers",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) {
|
||||
// This test is only concerned about the SPIFFE cert validator config in the public listener
|
||||
// so we empty out the upstreams to avoid generating unnecessary upstream listeners.
|
||||
ns.Proxy.Upstreams = structs.Upstreams{}
|
||||
}, []proxycfg.UpdateEvent{
|
||||
{
|
||||
CorrelationID: "peering-trust-bundles",
|
||||
Result: proxycfg.TestPeerTrustBundles(t),
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "connect-proxy-with-tls-outgoing-min-version-auto",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "public_listener:0.0.0.0:9999",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "0.0.0.0",
|
||||
"portValue": 9999
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.rbac",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC",
|
||||
"rules": {
|
||||
|
||||
},
|
||||
"statPrefix": "connect_authz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "public_listener",
|
||||
"cluster": "local_app"
|
||||
}
|
||||
}
|
||||
],
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||
"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": {
|
||||
"customValidatorConfig": {
|
||||
"name": "envoy.tls.cert_validator.spiffe",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig",
|
||||
"trustDomains": [
|
||||
{
|
||||
"name": "11111111-2222-3333-4444-555555555555.consul",
|
||||
"trustBundle": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1c053652-8512-4373-90cf-5a7f6263a994.consul",
|
||||
"trustBundle": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICczCCAdwCCQC3BLnEmLCrSjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQVoxEjAQBgNVBAcMCUZsYWdzdGFmZjEMMAoGA1UECgwDRm9v\nMRAwDgYDVQQLDAdleGFtcGxlMQ8wDQYDVQQDDAZwZWVyLWExHTAbBgkqhkiG9w0B\nCQEWDmZvb0BwZWVyLWEuY29tMB4XDTIyMDUyNjAxMDQ0NFoXDTIzMDUyNjAxMDQ0\nNFowfjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkFaMRIwEAYDVQQHDAlGbGFnc3Rh\nZmYxDDAKBgNVBAoMA0ZvbzEQMA4GA1UECwwHZXhhbXBsZTEPMA0GA1UEAwwGcGVl\nci1hMR0wGwYJKoZIhvcNAQkBFg5mb29AcGVlci1hLmNvbTCBnzANBgkqhkiG9w0B\nAQEFAAOBjQAwgYkCgYEA2zFYGTbXDAntT5pLTpZ2+VTiqx4J63VRJH1kdu11f0FV\nc2jl1pqCuYDbQXknDU0Pv1Q5y0+nSAihD2KqGS571r+vHQiPtKYPYRqPEe9FzAhR\n2KhWH6v/tk5DG1HqOjV9/zWRKB12gdFNZZqnw/e7NjLNq3wZ2UAwxXip5uJ8uwMC\nAwEAATANBgkqhkiG9w0BAQsFAAOBgQC/CJ9Syf4aL91wZizKTejwouRYoWv4gRAk\nyto45ZcNMHfJ0G2z+XAMl9ZbQsLgXmzAx4IM6y5Jckq8pKC4PEijCjlKTktLHlEy\n0ggmFxtNB1tid2NC8dOzcQ3l45+gDjDqdILhAvLDjlAIebdkqVqb2CfFNW/I2CQH\nZAuKN1aoKA==\n-----END CERTIFICATE-----\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "d89ac423-e95a-475d-94f2-1c557c57bf31.consul",
|
||||
"trustBundle": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICcTCCAdoCCQDyGxC08cD0BDANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCENhcmxzYmFkMQwwCgYDVQQKDANGb28x\nEDAOBgNVBAsMB2V4YW1wbGUxDzANBgNVBAMMBnBlZXItYjEdMBsGCSqGSIb3DQEJ\nARYOZm9vQHBlZXItYi5jb20wHhcNMjIwNTI2MDExNjE2WhcNMjMwNTI2MDExNjE2\nWjB9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCENhcmxzYmFk\nMQwwCgYDVQQKDANGb28xEDAOBgNVBAsMB2V4YW1wbGUxDzANBgNVBAMMBnBlZXIt\nYjEdMBsGCSqGSIb3DQEJARYOZm9vQHBlZXItYi5jb20wgZ8wDQYJKoZIhvcNAQEB\nBQADgY0AMIGJAoGBAL4i5erdZ5vKk3mzW9Qt6Wvw/WN/IpMDlL0a28wz9oDCtMLN\ncD/XQB9yT5jUwb2s4mD1lCDZtee8MHeD8zygICozufWVB+u2KvMaoA50T9GMQD0E\nz/0nz/Z703I4q13VHeTpltmEpYcfxw/7nJ3leKA34+Nj3zteJ70iqvD/TNBBAgMB\nAAEwDQYJKoZIhvcNAQELBQADgYEAbL04gicH+EIznDNhZJEb1guMBtBBJ8kujPyU\nao8xhlUuorDTLwhLpkKsOhD8619oSS8KynjEBichidQRkwxIaze0a2mrGT+tGBMf\npVz6UeCkqpde6bSJ/ozEe/2seQzKqYvRT1oUjLwYvY7OIh2DzYibOAxh6fewYAmU\n5j5qNLc=\n-----END CERTIFICATE-----\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requireClientCertificate": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"trafficDirection": "INBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -7,7 +7,7 @@ import (
|
|||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
func AssertDeepEqual(t *testing.T, x, y interface{}, opts ...cmp.Option) {
|
||||
func AssertDeepEqual(t testing.TB, x, y interface{}, opts ...cmp.Option) {
|
||||
t.Helper()
|
||||
|
||||
opts = append(opts, protocmp.Transform())
|
||||
|
|
Loading…
Reference in New Issue