mirror of https://github.com/status-im/consul.git
Add Upstream Service Targeting to Property Override Extension (#17517)
* add upstream service targeting to property override extension * Also add baseline goldens for service specific property override extension. * Refactor the extension framework to put more logic into the templates. * fix up the golden tests
This commit is contained in:
parent
44f90132e0
commit
d99312b86e
|
@ -72,16 +72,19 @@ func (a *awsLambda) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
|||
|
||||
// PatchRoute modifies the routing configuration for a service of kind TerminatingGateway. If the kind is
|
||||
// not TerminatingGateway, then it can not be modified.
|
||||
func (a *awsLambda) PatchRoute(r *extensioncommon.RuntimeConfig, route *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
if r.Kind != api.ServiceKindTerminatingGateway {
|
||||
return route, false, nil
|
||||
func (a *awsLambda) PatchRoute(p extensioncommon.RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
cfg := p.RuntimeConfig
|
||||
if cfg.Kind != api.ServiceKindTerminatingGateway {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
// Only patch outbound routes.
|
||||
if extensioncommon.IsRouteToLocalAppCluster(route) {
|
||||
return route, false, nil
|
||||
if p.IsInbound() {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
route := p.Message
|
||||
|
||||
for _, virtualHost := range route.VirtualHosts {
|
||||
for _, route := range virtualHost.Routes {
|
||||
action, ok := route.Action.(*envoy_route_v3.Route_Route)
|
||||
|
@ -101,16 +104,18 @@ func (a *awsLambda) PatchRoute(r *extensioncommon.RuntimeConfig, route *envoy_ro
|
|||
}
|
||||
|
||||
// PatchCluster patches the provided envoy cluster with data required to support an AWS lambda function
|
||||
func (a *awsLambda) PatchCluster(_ *extensioncommon.RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
func (a *awsLambda) PatchCluster(p extensioncommon.ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
// Only patch outbound clusters.
|
||||
if extensioncommon.IsLocalAppCluster(c) {
|
||||
return c, false, nil
|
||||
if p.IsInbound() {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
transportSocket, err := extensioncommon.MakeUpstreamTLSTransportSocket(&envoy_tls_v3.UpstreamTlsContext{
|
||||
Sni: "*.amazonaws.com",
|
||||
})
|
||||
|
||||
c := p.Message
|
||||
|
||||
if err != nil {
|
||||
return c, false, fmt.Errorf("failed to make transport socket: %w", err)
|
||||
}
|
||||
|
@ -168,9 +173,11 @@ func (a *awsLambda) PatchCluster(_ *extensioncommon.RuntimeConfig, c *envoy_clus
|
|||
|
||||
// PatchFilter patches the provided envoy filter with an inserted lambda filter being careful not to
|
||||
// overwrite the http filters.
|
||||
func (a *awsLambda) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error) {
|
||||
func (a *awsLambda) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||
filter := p.Message
|
||||
|
||||
// Only patch outbound filters.
|
||||
if isInboundListener {
|
||||
if p.IsInbound() {
|
||||
return filter, false, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,10 @@ func TestPatchCluster(t *testing.T) {
|
|||
|
||||
// Test patching the cluster
|
||||
rc := extensioncommon.RuntimeConfig{}
|
||||
patchedCluster, patchSuccess, err := tc.lambda.PatchCluster(&rc, tc.input)
|
||||
patchedCluster, patchSuccess, err := tc.lambda.PatchCluster(extensioncommon.ClusterPayload{
|
||||
RuntimeConfig: &rc,
|
||||
Message: tc.input,
|
||||
})
|
||||
if tc.isErrExpected {
|
||||
assert.Error(t, err)
|
||||
assert.False(t, patchSuccess)
|
||||
|
@ -307,7 +310,10 @@ func TestPatchRoute(t *testing.T) {
|
|||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
l := awsLambda{}
|
||||
r, ok, err := l.PatchRoute(tc.conf, tc.route)
|
||||
r, ok, err := l.PatchRoute(extensioncommon.RoutePayload{
|
||||
RuntimeConfig: tc.conf,
|
||||
Message: tc.route,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expectRoute, r)
|
||||
require.Equal(t, tc.expectBool, ok)
|
||||
|
@ -456,7 +462,14 @@ func TestPatchFilter(t *testing.T) {
|
|||
PayloadPassthrough: true,
|
||||
InvocationMode: "asynchronous",
|
||||
}
|
||||
f, ok, err := l.PatchFilter(nil, tc.filter, tc.isInboundFilter)
|
||||
d := extensioncommon.TrafficDirectionOutbound
|
||||
if tc.isInboundFilter {
|
||||
d = extensioncommon.TrafficDirectionInbound
|
||||
}
|
||||
f, ok, err := l.PatchFilter(extensioncommon.FilterPayload{
|
||||
Message: tc.filter,
|
||||
TrafficDirection: d,
|
||||
})
|
||||
require.Equal(t, tc.expectBool, ok)
|
||||
if tc.expectErr == "" {
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -601,7 +601,7 @@ func (t Target) clusterName(cfg *cmn.RuntimeConfig) (string, error) {
|
|||
|
||||
for service, upstream := range cfg.Upstreams {
|
||||
if service == t.Service {
|
||||
for sni := range upstream.SNI {
|
||||
for sni := range upstream.SNIs {
|
||||
return sni, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,10 +102,11 @@ func (p *ratelimit) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
|||
|
||||
// PatchFilter inserts a http local rate_limit filter at the head of
|
||||
// envoy.filters.network.http_connection_manager filters
|
||||
func (p ratelimit) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error) {
|
||||
func (r ratelimit) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||
filter := p.Message
|
||||
// rate limit is only applied to the inbound listener of the service itself
|
||||
// since the limit is aggregated from all downstream connections.
|
||||
if !isInboundListener {
|
||||
if !p.IsInbound() {
|
||||
return filter, false, nil
|
||||
}
|
||||
|
||||
|
@ -123,34 +124,34 @@ func (p ratelimit) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_l
|
|||
|
||||
tokenBucket := envoy_type_v3.TokenBucket{}
|
||||
|
||||
if p.TokensPerFill != nil {
|
||||
if r.TokensPerFill != nil {
|
||||
tokenBucket.TokensPerFill = &wrappers.UInt32Value{
|
||||
Value: uint32(*p.TokensPerFill),
|
||||
Value: uint32(*r.TokensPerFill),
|
||||
}
|
||||
}
|
||||
if p.MaxTokens != nil {
|
||||
tokenBucket.MaxTokens = uint32(*p.MaxTokens)
|
||||
if r.MaxTokens != nil {
|
||||
tokenBucket.MaxTokens = uint32(*r.MaxTokens)
|
||||
}
|
||||
|
||||
if p.FillInterval != nil {
|
||||
tokenBucket.FillInterval = durationpb.New(time.Duration(*p.FillInterval) * time.Second)
|
||||
if r.FillInterval != nil {
|
||||
tokenBucket.FillInterval = durationpb.New(time.Duration(*r.FillInterval) * time.Second)
|
||||
}
|
||||
|
||||
var FilterEnabledDefault *envoy_core_v3.RuntimeFractionalPercent
|
||||
if p.FilterEnabled != nil {
|
||||
if r.FilterEnabled != nil {
|
||||
FilterEnabledDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
||||
DefaultValue: &envoy_type_v3.FractionalPercent{
|
||||
Numerator: *p.FilterEnabled,
|
||||
Numerator: *r.FilterEnabled,
|
||||
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var FilterEnforcedDefault *envoy_core_v3.RuntimeFractionalPercent
|
||||
if p.FilterEnforced != nil {
|
||||
if r.FilterEnforced != nil {
|
||||
FilterEnforcedDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
||||
DefaultValue: &envoy_type_v3.FractionalPercent{
|
||||
Numerator: *p.FilterEnforced,
|
||||
Numerator: *r.FilterEnforced,
|
||||
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -67,14 +67,16 @@ func (l *lua) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
|||
return string(config.Kind) == l.ProxyType
|
||||
}
|
||||
|
||||
func (l *lua) matchesListenerDirection(isInboundListener bool) bool {
|
||||
func (l *lua) matchesListenerDirection(p extensioncommon.FilterPayload) bool {
|
||||
isInboundListener := p.IsInbound()
|
||||
return (!isInboundListener && l.Listener == "outbound") || (isInboundListener && l.Listener == "inbound")
|
||||
}
|
||||
|
||||
// PatchFilter inserts a lua filter directly prior to envoy.filters.http.router.
|
||||
func (l *lua) PatchFilter(_ *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error) {
|
||||
func (l *lua) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||
filter := p.Message
|
||||
// Make sure filter matches extension config.
|
||||
if !l.matchesListenerDirection(isInboundListener) {
|
||||
if !l.matchesListenerDirection(p) {
|
||||
return filter, false, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package propertyoverride
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
||||
envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||
|
@ -14,14 +13,10 @@ import (
|
|||
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||
"github.com/hashicorp/consul/lib/maps"
|
||||
)
|
||||
|
||||
type stringSet map[string]struct{}
|
||||
|
||||
type propertyOverride struct {
|
||||
extensioncommon.BasicExtensionAdapter
|
||||
|
||||
// Patches are an array of Patch operations to be applied to the target resource(s).
|
||||
Patches []Patch
|
||||
// Debug controls error messages when Path matching fails.
|
||||
|
@ -43,7 +38,42 @@ type ResourceFilter struct {
|
|||
// TrafficDirection determines whether the patch will be applied to a service's inbound
|
||||
// or outbound resources.
|
||||
// This field is required.
|
||||
TrafficDirection TrafficDirection
|
||||
TrafficDirection extensioncommon.TrafficDirection
|
||||
|
||||
// Services indicates which upstream services will have corresponding Envoy resources patched.
|
||||
// This includes directly targeted and discovery chain services. If Services is omitted or
|
||||
// empty, all resources matching the filter will be targeted (including TProxy, which
|
||||
// implicitly corresponds to any number of upstreams). Services must be omitted unless
|
||||
// TrafficDirection is set to outbound.
|
||||
Services []*ServiceName
|
||||
}
|
||||
|
||||
func matchesResourceFilter[K proto.Message](rf ResourceFilter, resourceType ResourceType, payload extensioncommon.Payload[K]) bool {
|
||||
if resourceType != rf.ResourceType {
|
||||
return false
|
||||
}
|
||||
|
||||
if payload.TrafficDirection != rf.TrafficDirection {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(rf.Services) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, s := range rf.Services {
|
||||
if payload.ServiceName == nil || s.CompoundServiceName != *payload.ServiceName {
|
||||
continue
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type ServiceName struct {
|
||||
api.CompoundServiceName
|
||||
}
|
||||
|
||||
// ResourceType is the type of Envoy resource being patched.
|
||||
|
@ -56,23 +86,13 @@ const (
|
|||
ResourceTypeRoute ResourceType = "route"
|
||||
)
|
||||
|
||||
var ResourceTypes = stringSet{
|
||||
var ResourceTypes = extensioncommon.StringSet{
|
||||
string(ResourceTypeCluster): {},
|
||||
string(ResourceTypeClusterLoadAssignment): {},
|
||||
string(ResourceTypeListener): {},
|
||||
string(ResourceTypeRoute): {},
|
||||
string(ResourceTypeListener): {},
|
||||
}
|
||||
|
||||
// TrafficDirection determines whether inbound or outbound Envoy resources will be patched.
|
||||
type TrafficDirection string
|
||||
|
||||
const (
|
||||
TrafficDirectionInbound TrafficDirection = "inbound"
|
||||
TrafficDirectionOutbound TrafficDirection = "outbound"
|
||||
)
|
||||
|
||||
var TrafficDirections = stringSet{string(TrafficDirectionInbound): {}, string(TrafficDirectionOutbound): {}}
|
||||
|
||||
// Op is the type of JSON Patch operation being applied.
|
||||
type Op string
|
||||
|
||||
|
@ -81,10 +101,10 @@ const (
|
|||
OpRemove Op = "remove"
|
||||
)
|
||||
|
||||
var Ops = stringSet{string(OpAdd): {}, string(OpRemove): {}}
|
||||
var Ops = extensioncommon.StringSet{string(OpAdd): {}, string(OpRemove): {}}
|
||||
|
||||
// validProxyTypes is the set of supported proxy types for this extension.
|
||||
var validProxyTypes = stringSet{
|
||||
var validProxyTypes = extensioncommon.StringSet{
|
||||
string(api.ServiceKindConnectProxy): struct{}{},
|
||||
string(api.ServiceKindTerminatingGateway): struct{}{},
|
||||
}
|
||||
|
@ -139,27 +159,58 @@ type Patch struct {
|
|||
|
||||
var _ extensioncommon.BasicExtension = (*propertyOverride)(nil)
|
||||
|
||||
func (c *stringSet) checkRequired(v, fieldName string) error {
|
||||
if _, ok := (*c)[v]; !ok {
|
||||
if v == "" {
|
||||
return fmt.Errorf("field %s is required", fieldName)
|
||||
}
|
||||
return fmt.Errorf("invalid %s '%q'; supported values: %s",
|
||||
fieldName, v, strings.Join(maps.SliceOfKeys(*c), ", "))
|
||||
func (f *ResourceFilter) isEmpty() bool {
|
||||
if f == nil {
|
||||
return true
|
||||
}
|
||||
return nil
|
||||
|
||||
if len(f.Services) > 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if string(f.TrafficDirection) != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if string(f.ResourceType) != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *ResourceFilter) validate() error {
|
||||
if f == nil || *f == (ResourceFilter{}) {
|
||||
if f == nil || f.isEmpty() {
|
||||
return fmt.Errorf("field ResourceFilter is required")
|
||||
}
|
||||
if err := ResourceTypes.checkRequired(string(f.ResourceType), "ResourceType"); err != nil {
|
||||
if err := ResourceTypes.CheckRequired(string(f.ResourceType), "ResourceType"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := TrafficDirections.checkRequired(string(f.TrafficDirection), "TrafficDirection"); err != nil {
|
||||
if err := extensioncommon.TrafficDirections.CheckRequired(string(f.TrafficDirection), "TrafficDirection"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range f.Services {
|
||||
sn := f.Services[i]
|
||||
sn.normalize()
|
||||
|
||||
if err := sn.validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sn *ServiceName) normalize() {
|
||||
extensioncommon.NormalizeServiceName(&sn.CompoundServiceName)
|
||||
}
|
||||
|
||||
func (sn *ServiceName) validate() error {
|
||||
if sn.Name == "" {
|
||||
return fmt.Errorf("service name is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -169,7 +220,7 @@ func (p *Patch) validate(debug bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := Ops.checkRequired(string(p.Op), "Op"); err != nil {
|
||||
if err := Ops.CheckRequired(string(p.Op), "Op"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -209,7 +260,7 @@ func (p *propertyOverride) validate() error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := validProxyTypes.checkRequired(string(p.ProxyType), "ProxyType"); err != nil {
|
||||
if err := validProxyTypes.CheckRequired(string(p.ProxyType), "ProxyType"); err != nil {
|
||||
resultErr = multierror.Append(resultErr, err)
|
||||
}
|
||||
|
||||
|
@ -243,57 +294,35 @@ func (p *propertyOverride) CanApply(config *extensioncommon.RuntimeConfig) bool
|
|||
}
|
||||
|
||||
// PatchRoute patches the provided Envoy Route with any applicable `route` ResourceType patches.
|
||||
func (p *propertyOverride) PatchRoute(_ *extensioncommon.RuntimeConfig, r *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
d := TrafficDirectionOutbound
|
||||
if extensioncommon.IsRouteToLocalAppCluster(r) {
|
||||
d = TrafficDirectionInbound
|
||||
}
|
||||
return patchResourceType[*envoy_route_v3.RouteConfiguration](r, p, ResourceTypeRoute, d, &defaultStructPatcher[*envoy_route_v3.RouteConfiguration]{})
|
||||
func (p *propertyOverride) PatchRoute(payload extensioncommon.RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
return patchResourceType[*envoy_route_v3.RouteConfiguration](p, ResourceTypeRoute, payload, &defaultStructPatcher[*envoy_route_v3.RouteConfiguration]{})
|
||||
}
|
||||
|
||||
// PatchCluster patches the provided Envoy Cluster with any applicable `cluster` ResourceType patches.
|
||||
func (p *propertyOverride) PatchCluster(_ *extensioncommon.RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
d := TrafficDirectionOutbound
|
||||
if extensioncommon.IsLocalAppCluster(c) {
|
||||
d = TrafficDirectionInbound
|
||||
}
|
||||
return patchResourceType[*envoy_cluster_v3.Cluster](c, p, ResourceTypeCluster, d, &defaultStructPatcher[*envoy_cluster_v3.Cluster]{})
|
||||
func (p *propertyOverride) PatchCluster(payload extensioncommon.ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
return patchResourceType[*envoy_cluster_v3.Cluster](p, ResourceTypeCluster, payload, &defaultStructPatcher[*envoy_cluster_v3.Cluster]{})
|
||||
}
|
||||
|
||||
// PatchClusterLoadAssignment patches the provided Envoy ClusterLoadAssignment with any applicable `cluster-load-assignment` ResourceType patches.
|
||||
func (p *propertyOverride) PatchClusterLoadAssignment(_ *extensioncommon.RuntimeConfig, c *envoy_endpoint_v3.ClusterLoadAssignment) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
||||
d := TrafficDirectionOutbound
|
||||
if extensioncommon.IsLocalAppClusterLoadAssignment(c) {
|
||||
d = TrafficDirectionInbound
|
||||
}
|
||||
return patchResourceType[*envoy_endpoint_v3.ClusterLoadAssignment](c, p, ResourceTypeClusterLoadAssignment, d, &defaultStructPatcher[*envoy_endpoint_v3.ClusterLoadAssignment]{})
|
||||
func (p *propertyOverride) PatchClusterLoadAssignment(payload extensioncommon.ClusterLoadAssignmentPayload) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
||||
return patchResourceType[*envoy_endpoint_v3.ClusterLoadAssignment](p, ResourceTypeClusterLoadAssignment, payload, &defaultStructPatcher[*envoy_endpoint_v3.ClusterLoadAssignment]{})
|
||||
}
|
||||
|
||||
// PatchListener patches the provided Envoy Listener with any applicable `listener` ResourceType patches.
|
||||
func (p *propertyOverride) PatchListener(_ *extensioncommon.RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, bool, error) {
|
||||
d := TrafficDirectionOutbound
|
||||
if extensioncommon.IsInboundPublicListener(l) {
|
||||
d = TrafficDirectionInbound
|
||||
}
|
||||
return patchResourceType[*envoy_listener_v3.Listener](l, p, ResourceTypeListener, d, &defaultStructPatcher[*envoy_listener_v3.Listener]{})
|
||||
}
|
||||
|
||||
// PatchFilter does nothing as this extension does not target Filters directly.
|
||||
func (p *propertyOverride) PatchFilter(_ *extensioncommon.RuntimeConfig, f *envoy_listener_v3.Filter, _ bool) (*envoy_listener_v3.Filter, bool, error) {
|
||||
return f, false, nil
|
||||
func (p *propertyOverride) PatchListener(payload extensioncommon.ListenerPayload) (*envoy_listener_v3.Listener, bool, error) {
|
||||
return patchResourceType[*envoy_listener_v3.Listener](p, ResourceTypeListener, payload, &defaultStructPatcher[*envoy_listener_v3.Listener]{})
|
||||
}
|
||||
|
||||
// patchResourceType applies Patches matching the given ResourceType to the target K.
|
||||
// This helper simplifies implementation of the above per-type patch methods defined by BasicExtension.
|
||||
func patchResourceType[K proto.Message](k K, p *propertyOverride, t ResourceType, d TrafficDirection, patcher structPatcher[K]) (K, bool, error) {
|
||||
func patchResourceType[K proto.Message](p *propertyOverride, resourceType ResourceType, payload extensioncommon.Payload[K], patcher structPatcher[K]) (K, bool, error) {
|
||||
resultPatched := false
|
||||
var resultErr error
|
||||
|
||||
k := payload.Message
|
||||
|
||||
for _, patch := range p.Patches {
|
||||
if patch.ResourceFilter.ResourceType != t {
|
||||
continue
|
||||
}
|
||||
if patch.ResourceFilter.TrafficDirection != d {
|
||||
if !matchesResourceFilter(patch.ResourceFilter, resourceType, payload) {
|
||||
continue
|
||||
}
|
||||
newK, err := patcher.applyPatch(k, patch, p.Debug)
|
||||
|
|
|
@ -2,11 +2,13 @@ package propertyoverride
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
||||
endpointv3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||
listenerv3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -32,7 +34,7 @@ func TestConstructor(t *testing.T) {
|
|||
makeResourceFilter := func(overrides map[string]any) map[string]any {
|
||||
f := map[string]any{
|
||||
"ResourceType": ResourceTypeRoute,
|
||||
"TrafficDirection": TrafficDirectionOutbound,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
}
|
||||
return applyOverrides(f, overrides)
|
||||
}
|
||||
|
@ -63,7 +65,7 @@ func TestConstructor(t *testing.T) {
|
|||
errMsg string
|
||||
}
|
||||
|
||||
validTestCase := func(o Op, d TrafficDirection, t ResourceType) testCase {
|
||||
validTestCase := func(o Op, d extensioncommon.TrafficDirection, t ResourceType) testCase {
|
||||
var v any = "foo"
|
||||
if o != OpAdd {
|
||||
v = nil
|
||||
|
@ -214,6 +216,19 @@ func TestConstructor(t *testing.T) {
|
|||
ok: false,
|
||||
errMsg: fmt.Sprintf("field Value is not supported for %s operation", OpRemove),
|
||||
},
|
||||
"empty service name": {
|
||||
arguments: makeArguments(map[string]any{"Patches": []map[string]any{
|
||||
makePatch(map[string]any{
|
||||
"ResourceFilter": makeResourceFilter(map[string]any{
|
||||
"Services": []ServiceName{
|
||||
{CompoundServiceName: api.CompoundServiceName{}},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}}),
|
||||
ok: false,
|
||||
errMsg: "service name is required",
|
||||
},
|
||||
// See decode.HookWeakDecodeFromSlice for more details. In practice, we can end up
|
||||
// with a "Patches" field decoded to the single "Patch" value contained in the
|
||||
// serialized slice (raised from the containing slice). Using WeakDecode solves
|
||||
|
@ -222,7 +237,7 @@ func TestConstructor(t *testing.T) {
|
|||
// by WeakDecode as it is a more-permissive version of the default behavior.
|
||||
"single value Patches decoded as map construction succeeds": {
|
||||
arguments: makeArguments(map[string]any{"Patches": makePatch(map[string]any{})}),
|
||||
expected: validTestCase(OpAdd, TrafficDirectionOutbound, ResourceTypeRoute).expected,
|
||||
expected: validTestCase(OpAdd, extensioncommon.TrafficDirectionOutbound, ResourceTypeRoute).expected,
|
||||
ok: true,
|
||||
},
|
||||
"invalid ProxyType": {
|
||||
|
@ -248,10 +263,10 @@ func TestConstructor(t *testing.T) {
|
|||
}
|
||||
|
||||
for o := range Ops {
|
||||
for d := range TrafficDirections {
|
||||
for d := range extensioncommon.TrafficDirections {
|
||||
for t := range ResourceTypes {
|
||||
cases["valid everything: "+strings.Join([]string{o, d, t}, ",")] =
|
||||
validTestCase(Op(o), TrafficDirection(d), ResourceType(t))
|
||||
validTestCase(Op(o), extensioncommon.TrafficDirection(d), ResourceType(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -294,32 +309,62 @@ func Test_patchResourceType(t *testing.T) {
|
|||
Patches: patches,
|
||||
}
|
||||
}
|
||||
makePatchWithPath := func(t ResourceType, d TrafficDirection, p string) Patch {
|
||||
makePatchWithPath := func(filter ResourceFilter, p string) Patch {
|
||||
return Patch{
|
||||
ResourceFilter: ResourceFilter{
|
||||
ResourceType: t,
|
||||
TrafficDirection: d,
|
||||
},
|
||||
Op: OpAdd,
|
||||
Path: p,
|
||||
Value: 1,
|
||||
ResourceFilter: filter,
|
||||
Op: OpAdd,
|
||||
Path: p,
|
||||
Value: 1,
|
||||
}
|
||||
}
|
||||
makePatch := func(t ResourceType, d TrafficDirection) Patch {
|
||||
return makePatchWithPath(t, d, "/foo")
|
||||
makePatch := func(filter ResourceFilter) Patch {
|
||||
return makePatchWithPath(filter, "/foo")
|
||||
}
|
||||
|
||||
clusterOutbound := makePatch(ResourceTypeCluster, TrafficDirectionOutbound)
|
||||
clusterInbound := makePatch(ResourceTypeCluster, TrafficDirectionInbound)
|
||||
routeOutbound := makePatch(ResourceTypeRoute, TrafficDirectionOutbound)
|
||||
routeOutbound2 := makePatchWithPath(ResourceTypeRoute, TrafficDirectionOutbound, "/bar")
|
||||
routeInbound := makePatch(ResourceTypeRoute, TrafficDirectionInbound)
|
||||
svc1 := ServiceName{
|
||||
CompoundServiceName: api.CompoundServiceName{Name: "svc1"},
|
||||
}
|
||||
svc2 := ServiceName{
|
||||
CompoundServiceName: api.CompoundServiceName{Name: "svc2"},
|
||||
}
|
||||
|
||||
clusterOutbound := makePatch(ResourceFilter{
|
||||
ResourceType: ResourceTypeCluster,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
})
|
||||
clusterInbound := makePatch(ResourceFilter{
|
||||
ResourceType: ResourceTypeCluster,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||
})
|
||||
listenerOutbound := makePatch(ResourceFilter{
|
||||
ResourceType: ResourceTypeListener,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
})
|
||||
listenerOutbound2 := makePatchWithPath(ResourceFilter{
|
||||
ResourceType: ResourceTypeListener,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
}, "/bar")
|
||||
listenerInbound := makePatch(ResourceFilter{
|
||||
ResourceType: ResourceTypeListener,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||
})
|
||||
routeOutbound := makePatch(ResourceFilter{
|
||||
ResourceType: ResourceTypeRoute,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
})
|
||||
routeOutbound2 := makePatchWithPath(ResourceFilter{
|
||||
ResourceType: ResourceTypeRoute,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
}, "/bar")
|
||||
routeInbound := makePatch(ResourceFilter{
|
||||
ResourceType: ResourceTypeRoute,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||
})
|
||||
|
||||
type args struct {
|
||||
d TrafficDirection
|
||||
k proto.Message
|
||||
p *propertyOverride
|
||||
t ResourceType
|
||||
resourceType ResourceType
|
||||
payload extensioncommon.Payload[proto.Message]
|
||||
p *propertyOverride
|
||||
}
|
||||
type testCase struct {
|
||||
args args
|
||||
|
@ -329,79 +374,179 @@ func Test_patchResourceType(t *testing.T) {
|
|||
cases := map[string]testCase{
|
||||
"outbound gets matching patch": {
|
||||
args: args{
|
||||
d: TrafficDirectionOutbound,
|
||||
k: &clusterv3.Cluster{},
|
||||
resourceType: ResourceTypeCluster,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
Message: &clusterv3.Cluster{},
|
||||
},
|
||||
p: makeExtension(clusterOutbound),
|
||||
t: ResourceTypeCluster,
|
||||
},
|
||||
expectPatched: true,
|
||||
wantApplied: []Patch{clusterOutbound},
|
||||
},
|
||||
"inbound gets matching patch": {
|
||||
args: args{
|
||||
d: TrafficDirectionInbound,
|
||||
k: &clusterv3.Cluster{},
|
||||
resourceType: ResourceTypeCluster,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||
Message: &clusterv3.Cluster{},
|
||||
},
|
||||
p: makeExtension(clusterInbound),
|
||||
t: ResourceTypeCluster,
|
||||
},
|
||||
expectPatched: true,
|
||||
wantApplied: []Patch{clusterInbound},
|
||||
},
|
||||
"multiple resources same direction only gets matching resource": {
|
||||
args: args{
|
||||
d: TrafficDirectionOutbound,
|
||||
k: &clusterv3.Cluster{},
|
||||
p: makeExtension(clusterOutbound, routeOutbound),
|
||||
t: ResourceTypeCluster,
|
||||
resourceType: ResourceTypeCluster,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
Message: &clusterv3.Cluster{},
|
||||
},
|
||||
p: makeExtension(clusterOutbound, listenerOutbound),
|
||||
},
|
||||
expectPatched: true,
|
||||
wantApplied: []Patch{clusterOutbound},
|
||||
},
|
||||
"multiple directions same resource only gets matching direction": {
|
||||
args: args{
|
||||
d: TrafficDirectionOutbound,
|
||||
k: &clusterv3.Cluster{},
|
||||
resourceType: ResourceTypeCluster,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
Message: &clusterv3.Cluster{},
|
||||
},
|
||||
p: makeExtension(clusterOutbound, clusterInbound),
|
||||
t: ResourceTypeCluster,
|
||||
},
|
||||
expectPatched: true,
|
||||
wantApplied: []Patch{clusterOutbound},
|
||||
},
|
||||
"multiple directions and resources only gets matching patch": {
|
||||
args: args{
|
||||
d: TrafficDirectionInbound,
|
||||
k: &routev3.RouteConfiguration{},
|
||||
p: makeExtension(clusterOutbound, clusterInbound, routeOutbound, routeInbound),
|
||||
t: ResourceTypeRoute,
|
||||
resourceType: ResourceTypeRoute,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionInbound,
|
||||
Message: &routev3.RouteConfiguration{},
|
||||
},
|
||||
p: makeExtension(clusterOutbound, clusterInbound, listenerOutbound, listenerInbound, routeOutbound, routeOutbound2, routeInbound),
|
||||
},
|
||||
expectPatched: true,
|
||||
wantApplied: []Patch{routeInbound},
|
||||
},
|
||||
"multiple directions and resources multiple matches gets all matching patches": {
|
||||
args: args{
|
||||
d: TrafficDirectionOutbound,
|
||||
k: &routev3.RouteConfiguration{},
|
||||
p: makeExtension(clusterOutbound, clusterInbound, routeOutbound, routeInbound, routeOutbound2),
|
||||
t: ResourceTypeRoute,
|
||||
resourceType: ResourceTypeRoute,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
Message: &routev3.RouteConfiguration{},
|
||||
},
|
||||
p: makeExtension(clusterOutbound, clusterInbound, listenerOutbound, listenerInbound, listenerOutbound2, routeOutbound, routeOutbound2, routeInbound),
|
||||
},
|
||||
expectPatched: true,
|
||||
wantApplied: []Patch{routeOutbound, routeOutbound2},
|
||||
},
|
||||
"multiple directions and resources no matches gets no patches": {
|
||||
args: args{
|
||||
d: TrafficDirectionOutbound,
|
||||
k: &routev3.RouteConfiguration{},
|
||||
p: makeExtension(clusterInbound, routeOutbound, routeInbound, routeOutbound2),
|
||||
t: ResourceTypeCluster,
|
||||
resourceType: ResourceTypeCluster,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
Message: &clusterv3.Cluster{},
|
||||
},
|
||||
p: makeExtension(clusterInbound, listenerOutbound, listenerInbound, listenerOutbound2, routeInbound, routeOutbound),
|
||||
},
|
||||
expectPatched: false,
|
||||
wantApplied: nil,
|
||||
},
|
||||
}
|
||||
|
||||
type resourceTypeServiceMatch struct {
|
||||
resourceType ResourceType
|
||||
message proto.Message
|
||||
}
|
||||
|
||||
resourceTypeCases := []resourceTypeServiceMatch{
|
||||
{
|
||||
resourceType: ResourceTypeCluster,
|
||||
message: &clusterv3.Cluster{},
|
||||
},
|
||||
{
|
||||
resourceType: ResourceTypeListener,
|
||||
message: &listenerv3.Listener{},
|
||||
},
|
||||
{
|
||||
resourceType: ResourceTypeRoute,
|
||||
message: &routev3.RouteConfiguration{},
|
||||
},
|
||||
{
|
||||
resourceType: ResourceTypeClusterLoadAssignment,
|
||||
message: &endpointv3.ClusterLoadAssignment{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range resourceTypeCases {
|
||||
{
|
||||
patch := makePatch(ResourceFilter{
|
||||
ResourceType: tc.resourceType,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
Services: []*ServiceName{
|
||||
{CompoundServiceName: svc2.CompoundServiceName},
|
||||
},
|
||||
})
|
||||
|
||||
cases[fmt.Sprintf("%s - no match", tc.resourceType)] = testCase{
|
||||
args: args{
|
||||
resourceType: tc.resourceType,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
ServiceName: &svc1.CompoundServiceName,
|
||||
Message: tc.message,
|
||||
RuntimeConfig: &extensioncommon.RuntimeConfig{
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
svc1.CompoundServiceName: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
p: makeExtension(patch),
|
||||
},
|
||||
expectPatched: false,
|
||||
wantApplied: nil,
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
patch := makePatch(ResourceFilter{
|
||||
ResourceType: tc.resourceType,
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
Services: []*ServiceName{
|
||||
{CompoundServiceName: svc2.CompoundServiceName},
|
||||
{CompoundServiceName: svc1.CompoundServiceName},
|
||||
},
|
||||
})
|
||||
|
||||
cases[fmt.Sprintf("%s - match", tc.resourceType)] = testCase{
|
||||
args: args{
|
||||
resourceType: tc.resourceType,
|
||||
payload: extensioncommon.Payload[proto.Message]{
|
||||
TrafficDirection: extensioncommon.TrafficDirectionOutbound,
|
||||
ServiceName: &svc1.CompoundServiceName,
|
||||
Message: tc.message,
|
||||
RuntimeConfig: &extensioncommon.RuntimeConfig{
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
svc1.CompoundServiceName: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
p: makeExtension(patch),
|
||||
},
|
||||
expectPatched: true,
|
||||
wantApplied: []Patch{patch},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for n, tc := range cases {
|
||||
t.Run(n, func(t *testing.T) {
|
||||
mockPatcher := MockPatcher[proto.Message]{}
|
||||
_, patched, err := patchResourceType[proto.Message](tc.args.k, tc.args.p, tc.args.t, tc.args.d, &mockPatcher)
|
||||
_, patched, err := patchResourceType[proto.Message](tc.args.p, tc.args.resourceType, tc.args.payload, &mockPatcher)
|
||||
|
||||
require.NoError(t, err, "unexpected error from mock")
|
||||
require.Equal(t, tc.expectPatched, patched)
|
||||
|
|
|
@ -195,7 +195,7 @@ func (p *pluginConfig) asyncDataSource(rtCfg *extensioncommon.RuntimeConfig) (*e
|
|||
clusterSNI := ""
|
||||
for service, upstream := range rtCfg.Upstreams {
|
||||
if service == remote.HttpURI.Service {
|
||||
for sni := range upstream.SNI {
|
||||
for sni := range upstream.SNIs {
|
||||
clusterSNI = sni
|
||||
break
|
||||
}
|
||||
|
|
|
@ -609,7 +609,7 @@ func makeTestRuntimeConfig(protocol string, enterprise bool) *extensioncommon.Ru
|
|||
Namespace: acl.NamespaceOrDefault(ns),
|
||||
Partition: acl.PartitionOrDefault(ap),
|
||||
}: {
|
||||
SNI: map[string]struct{}{"test-file-server": {}},
|
||||
SNIs: map[string]struct{}{"test-file-server": {}},
|
||||
EnvoyID: "test-file-server",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -34,7 +34,6 @@ import (
|
|||
|
||||
const (
|
||||
meshGatewayExportedClusterNamePrefix = "exported~"
|
||||
failoverClusterNamePrefix = "failover-target~"
|
||||
)
|
||||
|
||||
// clustersFromSnapshot returns the xDS API representation of the "clusters" in the snapshot.
|
||||
|
@ -1915,7 +1914,7 @@ func (s *ResourceGenerator) getTargetClusterName(upstreamsSnapshot *proxycfg.Con
|
|||
}
|
||||
clusterName = CustomizeClusterName(clusterName, chain)
|
||||
if failover {
|
||||
clusterName = failoverClusterNamePrefix + clusterName
|
||||
clusterName = xdscommon.FailoverClusterNamePrefix + clusterName
|
||||
}
|
||||
if forMeshGateway {
|
||||
clusterName = meshGatewayExportedClusterNamePrefix + clusterName
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/agent/xds/extensionruntime"
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
)
|
||||
|
@ -110,7 +111,7 @@ end`,
|
|||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/outlier_detection/success_rate_minimum_hosts",
|
||||
|
@ -125,7 +126,7 @@ end`,
|
|||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/outlier_detection",
|
||||
|
@ -143,7 +144,7 @@ end`,
|
|||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "remove",
|
||||
"Path": "/outlier_detection",
|
||||
|
@ -157,7 +158,7 @@ end`,
|
|||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/upstream_connection_options/tcp_keepalive/keepalive_probes",
|
||||
|
@ -172,7 +173,7 @@ end`,
|
|||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||
"TrafficDirection": propertyoverride.TrafficDirectionOutbound,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/round_robin_lb_config",
|
||||
|
@ -181,6 +182,169 @@ end`,
|
|||
},
|
||||
})
|
||||
|
||||
propertyOverrideServiceDefaultsClusterLoadAssignmentOutboundAdd := makePropOverrideNsFunc(
|
||||
map[string]interface{}{
|
||||
"Patches": []map[string]interface{}{
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeClusterLoadAssignment,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/policy/overprovisioning_factor",
|
||||
"Value": 123,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
propertyOverrideServiceDefaultsClusterLoadAssignmentInboundAdd := makePropOverrideNsFunc(
|
||||
map[string]interface{}{
|
||||
"Patches": []map[string]interface{}{
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeClusterLoadAssignment,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/policy/overprovisioning_factor",
|
||||
"Value": 123,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
propertyOverrideServiceDefaultsListenerInboundAdd := makePropOverrideNsFunc(
|
||||
map[string]interface{}{
|
||||
"Patches": []map[string]interface{}{
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/stat_prefix",
|
||||
"Value": "custom.stats",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
propertyOverrideServiceDefaultsListenerOutboundAdd := makePropOverrideNsFunc(
|
||||
map[string]interface{}{
|
||||
"Patches": []map[string]interface{}{
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/stat_prefix",
|
||||
"Value": "custom.stats",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
propertyOverrideServiceDefaultsListenerOutboundDoesntApplyToInbound := makePropOverrideNsFunc(
|
||||
map[string]interface{}{
|
||||
"Patches": []map[string]interface{}{
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/stat_prefix",
|
||||
"Value": "custom.stats.inbound.only",
|
||||
},
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/stat_prefix",
|
||||
"Value": "custom.stats.outbound.only",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Reverse order of above patches, to prove order is inconsequential
|
||||
propertyOverrideServiceDefaultsListenerInboundDoesntApplyToOutbound := makePropOverrideNsFunc(
|
||||
map[string]interface{}{
|
||||
"Patches": []map[string]interface{}{
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/stat_prefix",
|
||||
"Value": "custom.stats.outbound.only",
|
||||
},
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionInbound,
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/stat_prefix",
|
||||
"Value": "custom.stats.inbound.only",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
propertyOverridePatchSpecificUpstreamService := makePropOverrideNsFunc(
|
||||
map[string]interface{}{
|
||||
"Patches": []map[string]interface{}{
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeListener,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
"Services": []propertyoverride.ServiceName{
|
||||
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||
},
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/stat_prefix",
|
||||
"Value": "custom.stats.outbound.only",
|
||||
},
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeRoute,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
"Services": []propertyoverride.ServiceName{
|
||||
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||
},
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/most_specific_header_mutations_wins",
|
||||
"Value": true,
|
||||
},
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeCluster,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
"Services": []propertyoverride.ServiceName{
|
||||
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||
},
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/outlier_detection/success_rate_minimum_hosts",
|
||||
"Value": 1234,
|
||||
},
|
||||
{
|
||||
"ResourceFilter": map[string]interface{}{
|
||||
"ResourceType": propertyoverride.ResourceTypeClusterLoadAssignment,
|
||||
"TrafficDirection": extensioncommon.TrafficDirectionOutbound,
|
||||
"Services": []propertyoverride.ServiceName{
|
||||
{CompoundServiceName: api.CompoundServiceName{Name: "db"}},
|
||||
},
|
||||
},
|
||||
"Op": "add",
|
||||
"Path": "/policy/overprovisioning_factor",
|
||||
"Value": 1234,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
create func(t testinf.T) *proxycfg.ConfigSnapshot
|
||||
|
@ -215,6 +379,54 @@ end`,
|
|||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsRemoveOutlierDetection, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-cluster-load-assignment-outbound-add",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsClusterLoadAssignmentOutboundAdd, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-cluster-load-assignment-inbound-add",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsClusterLoadAssignmentInboundAdd, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-listener-outbound-add",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerOutboundAdd, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-listener-inbound-add",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerInboundAdd, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-outbound-doesnt-apply-to-inbound",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerOutboundDoesntApplyToInbound, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-inbound-doesnt-apply-to-outbound",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, propertyOverrideServiceDefaultsListenerInboundDoesntApplyToOutbound, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-patch-specific-upstream-service-splitter",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", false, propertyOverridePatchSpecificUpstreamService, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propertyoverride-patch-specific-upstream-service-failover",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", false, propertyOverridePatchSpecificUpstreamService, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "lambda-connect-proxy",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
|
|
|
@ -56,19 +56,27 @@ func GetRuntimeConfigurations(cfgSnap *proxycfg.ConfigSnapshot) map[api.Compound
|
|||
|
||||
// TODO(peering): consider PeerUpstreamEndpoints in addition to DiscoveryChain
|
||||
// These are the discovery chains for upstreams which have the Envoy Extensions applied to the local service.
|
||||
for uid, dc := range cfgSnap.ConnectProxy.DiscoveryChain {
|
||||
for uid, chain := range cfgSnap.ConnectProxy.DiscoveryChain {
|
||||
compoundServiceName := upstreamIDToCompoundServiceName(uid)
|
||||
extensionsMap[compoundServiceName] = convertEnvoyExtensions(dc.EnvoyExtensions)
|
||||
extensionsMap[compoundServiceName] = convertEnvoyExtensions(chain.EnvoyExtensions)
|
||||
|
||||
primarySNI := connect.ServiceSNI(uid.Name, "", chain.Namespace, chain.Partition, cfgSnap.Datacenter, trustDomain)
|
||||
snis := make(map[string]struct{})
|
||||
for _, t := range chain.Targets {
|
||||
// SNI isn't set for peered services. We don't support peered services yet.
|
||||
if t.SNI != "" {
|
||||
snis[t.SNI] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
meta := uid.EnterpriseMeta
|
||||
sni := connect.ServiceSNI(uid.Name, "", meta.NamespaceOrDefault(), meta.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain)
|
||||
outgoingKind, ok := outgoingKindByService[compoundServiceName]
|
||||
if !ok {
|
||||
outgoingKind = api.ServiceKindConnectProxy
|
||||
}
|
||||
|
||||
upstreamMap[compoundServiceName] = &extensioncommon.UpstreamData{
|
||||
SNI: map[string]struct{}{sni: {}},
|
||||
PrimarySNI: primarySNI,
|
||||
SNIs: snis,
|
||||
VIP: vipForService[compoundServiceName],
|
||||
EnvoyID: uid.EnvoyID(),
|
||||
OutgoingProxyKind: outgoingKind,
|
||||
|
@ -101,10 +109,10 @@ func GetRuntimeConfigurations(cfgSnap *proxycfg.ConfigSnapshot) map[api.Compound
|
|||
compoundServiceName := serviceNameToCompoundServiceName(svc)
|
||||
extensionsMap[compoundServiceName] = convertEnvoyExtensions(c.EnvoyExtensions)
|
||||
|
||||
sni := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain)
|
||||
primarySNI := connect.ServiceSNI(svc.Name, "", svc.NamespaceOrDefault(), svc.PartitionOrDefault(), cfgSnap.Datacenter, trustDomain)
|
||||
envoyID := proxycfg.NewUpstreamIDFromServiceName(svc)
|
||||
|
||||
snis := map[string]struct{}{sni: {}}
|
||||
snis := map[string]struct{}{primarySNI: {}}
|
||||
|
||||
resolver, hasResolver := cfgSnap.TerminatingGateway.ServiceResolvers[svc]
|
||||
if hasResolver {
|
||||
|
@ -115,7 +123,8 @@ func GetRuntimeConfigurations(cfgSnap *proxycfg.ConfigSnapshot) map[api.Compound
|
|||
}
|
||||
|
||||
upstreamMap[compoundServiceName] = &extensioncommon.UpstreamData{
|
||||
SNI: snis,
|
||||
PrimarySNI: primarySNI,
|
||||
SNIs: snis,
|
||||
EnvoyID: envoyID.EnvoyID(),
|
||||
OutgoingProxyKind: api.ServiceKindTerminatingGateway,
|
||||
}
|
||||
|
|
|
@ -58,28 +58,32 @@ func TestGetRuntimeConfigurations_TerminatingGateway(t *testing.T) {
|
|||
IsSourcedFromUpstream: true,
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
apiService: {
|
||||
SNI: map[string]struct{}{
|
||||
PrimarySNI: "api.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"api.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
},
|
||||
EnvoyID: "api",
|
||||
OutgoingProxyKind: "terminating-gateway",
|
||||
},
|
||||
cacheService: {
|
||||
SNI: map[string]struct{}{
|
||||
PrimarySNI: "cache.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"cache.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
},
|
||||
EnvoyID: "cache",
|
||||
OutgoingProxyKind: "terminating-gateway",
|
||||
},
|
||||
dbService: {
|
||||
SNI: map[string]struct{}{
|
||||
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
},
|
||||
EnvoyID: "db",
|
||||
OutgoingProxyKind: "terminating-gateway",
|
||||
},
|
||||
webService: {
|
||||
SNI: map[string]struct{}{
|
||||
PrimarySNI: "web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"canary1.web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
"canary2.web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
"web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
|
@ -134,10 +138,25 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
|||
EnvoyExtensions: envoyExtensions,
|
||||
}
|
||||
|
||||
serviceDefaultsV2 := &structs.ServiceConfigEntry{
|
||||
Kind: structs.ServiceDefaults,
|
||||
Name: "db-v2",
|
||||
Protocol: "http",
|
||||
}
|
||||
|
||||
serviceSplitter := &structs.ServiceSplitterConfigEntry{
|
||||
Kind: structs.ServiceSplitter,
|
||||
Name: "db",
|
||||
Splits: []structs.ServiceSplit{
|
||||
{Weight: 50},
|
||||
{Weight: 50, Service: "db-v2"},
|
||||
},
|
||||
}
|
||||
|
||||
// Setup a snapshot where the db upstream is on a connect proxy.
|
||||
snapConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, serviceDefaults)
|
||||
snapConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, serviceDefaults, serviceDefaultsV2, serviceSplitter)
|
||||
// Setup a snapshot where the db upstream is on a terminating gateway.
|
||||
snapTermGw := proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", false, nil, nil, serviceDefaults)
|
||||
snapTermGw := proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", false, nil, nil, serviceDefaults, serviceDefaultsV2, serviceSplitter)
|
||||
// Setup a snapshot with the local service web has extensions.
|
||||
snapWebConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, func(ns *structs.NodeService) {
|
||||
ns.Proxy.EnvoyExtensions = envoyExtensions
|
||||
|
@ -164,8 +183,10 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
|||
IsSourcedFromUpstream: true,
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
dbService: {
|
||||
SNI: map[string]struct{}{
|
||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
"db-v2.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
},
|
||||
EnvoyID: "db",
|
||||
OutgoingProxyKind: "connect-proxy",
|
||||
|
@ -193,8 +214,10 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
|||
IsSourcedFromUpstream: true,
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
dbService: {
|
||||
SNI: map[string]struct{}{
|
||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
"db-v2.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
},
|
||||
EnvoyID: "db",
|
||||
OutgoingProxyKind: "terminating-gateway",
|
||||
|
@ -224,7 +247,8 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
|||
IsSourcedFromUpstream: false,
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
dbService: {
|
||||
SNI: map[string]struct{}{
|
||||
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
},
|
||||
EnvoyID: "db",
|
||||
|
@ -245,7 +269,8 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) {
|
|||
IsSourcedFromUpstream: false,
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
dbService: {
|
||||
SNI: map[string]struct{}{
|
||||
PrimarySNI: "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
SNIs: map[string]struct{}{
|
||||
"db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul": {},
|
||||
},
|
||||
EnvoyID: "db",
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/hashicorp/consul/agent/connect"
|
||||
"github.com/hashicorp/consul/agent/proxycfg"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||
)
|
||||
|
||||
type discoChainTargets struct {
|
||||
|
@ -149,7 +150,7 @@ func (ft discoChainTargets) sequential() ([]discoChainTargetGroup, error) {
|
|||
var targetGroups []discoChainTargetGroup
|
||||
for i, t := range ft.targets {
|
||||
targetGroups = append(targetGroups, discoChainTargetGroup{
|
||||
ClusterName: fmt.Sprintf("%s%d~%s", failoverClusterNamePrefix, i, ft.baseClusterName),
|
||||
ClusterName: fmt.Sprintf("%s%d~%s", xdscommon.FailoverClusterNamePrefix, i, ft.baseClusterName),
|
||||
Targets: []targetInfo{t},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"clusterType": {
|
||||
"name": "envoy.clusters.aggregate",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.clusters.aggregate.v3.ClusterConfig",
|
||||
"clusters": [
|
||||
"failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
]
|
||||
}
|
||||
},
|
||||
"connectTimeout": "33s",
|
||||
"lbPolicy": "CLUSTER_PROVIDED",
|
||||
"outlierDetection": {
|
||||
"successRateMinimumHosts": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "33s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {
|
||||
"successRateMinimumHosts": 1234
|
||||
},
|
||||
"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/db"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "33s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {
|
||||
"successRateMinimumHosts": 1234
|
||||
},
|
||||
"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/fail"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "fail.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {},
|
||||
"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/geo-cache-target"
|
||||
},
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "local_app",
|
||||
"type": "STATIC",
|
||||
"connectTimeout": "5s",
|
||||
"loadAssignment": {
|
||||
"clusterName": "local_app",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {},
|
||||
"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/geo-cache-target"
|
||||
},
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "local_app",
|
||||
"type": "STATIC",
|
||||
"connectTimeout": "5s",
|
||||
"loadAssignment": {
|
||||
"clusterName": "local_app",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {
|
||||
"successRateMinimumHosts": 1234
|
||||
},
|
||||
"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/db"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {
|
||||
"successRateMinimumHosts": 1234
|
||||
},
|
||||
"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/dc2/svc/db"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"clusterType": {
|
||||
"name": "envoy.clusters.aggregate",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.clusters.aggregate.v3.ClusterConfig",
|
||||
"clusters": [
|
||||
"failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
]
|
||||
}
|
||||
},
|
||||
"connectTimeout": "33s",
|
||||
"lbPolicy": "CLUSTER_PROVIDED"
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "33s",
|
||||
"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/db"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "33s",
|
||||
"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/fail"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "fail.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {},
|
||||
"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/geo-cache-target"
|
||||
},
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "local_app",
|
||||
"type": "STATIC",
|
||||
"connectTimeout": "5s",
|
||||
"loadAssignment": {
|
||||
"clusterName": "local_app",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"policy": {
|
||||
"overprovisioningFactor": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"policy": {
|
||||
"overprovisioningFactor": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"policy": {
|
||||
"overprovisioningFactor": 1234
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"policy": {
|
||||
"overprovisioningFactor": 1234
|
||||
}
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "failover-target~0~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "failover-target~1~db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "db:127.0.0.1:9191",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 9191
|
||||
}
|
||||
},
|
||||
"statPrefix": "custom.stats.outbound.only",
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.db.default.default.dc1",
|
||||
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.10.10.10",
|
||||
"portValue": 8181
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@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.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "public_listener",
|
||||
"routeConfig": {
|
||||
"name": "public_listener",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "public_listener",
|
||||
"domains": [
|
||||
"*"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "local_app"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"httpFilters": [
|
||||
{
|
||||
"name": "envoy.filters.http.rbac",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
|
||||
"rules": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.header_to_metadata",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config",
|
||||
"requestRules": [
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "trust-domain",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "partition",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "namespace",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "datacenter",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "service",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\5"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.router",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tracing": {
|
||||
"randomSampling": {}
|
||||
},
|
||||
"forwardClientCertDetails": "APPEND_FORWARD",
|
||||
"setCurrentClientCertDetails": {
|
||||
"subject": true,
|
||||
"cert": true,
|
||||
"chain": true,
|
||||
"dns": true,
|
||||
"uri": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"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": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"alpnProtocols": [
|
||||
"http/1.1"
|
||||
]
|
||||
},
|
||||
"requireClientCertificate": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"trafficDirection": "INBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "db:127.0.0.1:9191",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 9191
|
||||
}
|
||||
},
|
||||
"statPrefix": "custom.stats.outbound.only",
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "upstream.db.default.default.dc1",
|
||||
"rds": {
|
||||
"configSource": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
},
|
||||
"routeConfigName": "db"
|
||||
},
|
||||
"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": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.10.10.10",
|
||||
"portValue": 8181
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@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.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "public_listener",
|
||||
"routeConfig": {
|
||||
"name": "public_listener",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "public_listener",
|
||||
"domains": [
|
||||
"*"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "local_app"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"httpFilters": [
|
||||
{
|
||||
"name": "envoy.filters.http.rbac",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
|
||||
"rules": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.header_to_metadata",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config",
|
||||
"requestRules": [
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "trust-domain",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "partition",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "namespace",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "datacenter",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "service",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\5"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.router",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tracing": {
|
||||
"randomSampling": {}
|
||||
},
|
||||
"forwardClientCertDetails": "APPEND_FORWARD",
|
||||
"setCurrentClientCertDetails": {
|
||||
"subject": true,
|
||||
"cert": true,
|
||||
"chain": true,
|
||||
"dns": true,
|
||||
"uri": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"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": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"alpnProtocols": [
|
||||
"http/1.1"
|
||||
]
|
||||
},
|
||||
"requireClientCertificate": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"trafficDirection": "INBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "db:127.0.0.1:9191",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 9191
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.db.default.default.dc1",
|
||||
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.10.10.10",
|
||||
"portValue": 8181
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@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.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "public_listener",
|
||||
"routeConfig": {
|
||||
"name": "public_listener",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "public_listener",
|
||||
"domains": [
|
||||
"*"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "local_app"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"httpFilters": [
|
||||
{
|
||||
"name": "envoy.filters.http.rbac",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC",
|
||||
"rules": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.header_to_metadata",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config",
|
||||
"requestRules": [
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "trust-domain",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "partition",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "namespace",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "datacenter",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"header": "x-forwarded-client-cert",
|
||||
"onHeaderPresent": {
|
||||
"metadataNamespace": "consul",
|
||||
"key": "service",
|
||||
"regexValueRewrite": {
|
||||
"pattern": {
|
||||
"googleRe2": {},
|
||||
"regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*"
|
||||
},
|
||||
"substitution": "\\5"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.router",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tracing": {
|
||||
"randomSampling": {}
|
||||
},
|
||||
"forwardClientCertDetails": "APPEND_FORWARD",
|
||||
"setCurrentClientCertDetails": {
|
||||
"subject": true,
|
||||
"cert": true,
|
||||
"chain": true,
|
||||
"dns": true,
|
||||
"uri": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"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": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"alpnProtocols": [
|
||||
"http/1.1"
|
||||
]
|
||||
},
|
||||
"requireClientCertificate": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"trafficDirection": "INBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"name": "db",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "db",
|
||||
"domains": [
|
||||
"*"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"timeout": "33s"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mostSpecificHeaderMutationsWins": true,
|
||||
"validateClusters": true
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"name": "db",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "db",
|
||||
"domains": [
|
||||
"*"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"weightedClusters": {
|
||||
"clusters": [
|
||||
{
|
||||
"name": "v1.db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"weight": 5000
|
||||
},
|
||||
{
|
||||
"name": "v2.db.default.dc2.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"weight": 5000
|
||||
}
|
||||
],
|
||||
"totalWeight": 10000
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mostSpecificHeaderMutationsWins": true,
|
||||
"validateClusters": true
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"name": "db",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "db",
|
||||
"domains": [
|
||||
"*"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"timeout": "33s"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"validateClusters": true
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -38,7 +38,7 @@ type BasicExtension interface {
|
|||
// PatchRoute patches a route to include the custom Envoy configuration
|
||||
// required to integrate with the built in extension template.
|
||||
// See also PatchRoutes.
|
||||
PatchRoute(*RuntimeConfig, *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error)
|
||||
PatchRoute(RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error)
|
||||
|
||||
// PatchRoutes patches routes to include the custom Envoy configuration
|
||||
// required to integrate with the built in extension template.
|
||||
|
@ -51,7 +51,7 @@ type BasicExtension interface {
|
|||
// PatchCluster patches a cluster to include the custom Envoy configuration
|
||||
// required to integrate with the built in extension template.
|
||||
// See also PatchClusters.
|
||||
PatchCluster(*RuntimeConfig, *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error)
|
||||
PatchCluster(ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error)
|
||||
|
||||
// PatchClusters patches clusters to include the custom Envoy configuration
|
||||
// required to integrate with the built in extension template.
|
||||
|
@ -63,12 +63,12 @@ type BasicExtension interface {
|
|||
|
||||
// PatchClusterLoadAssignment patches a cluster load assignment to include the custom Envoy configuration
|
||||
// required to integrate with the built in extension template.
|
||||
PatchClusterLoadAssignment(*RuntimeConfig, *envoy_endpoint_v3.ClusterLoadAssignment) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error)
|
||||
PatchClusterLoadAssignment(ClusterLoadAssignmentPayload) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error)
|
||||
|
||||
// PatchListener patches a listener to include the custom Envoy configuration
|
||||
// required to integrate with the built in extension template.
|
||||
// See also PatchListeners.
|
||||
PatchListener(*RuntimeConfig, *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, bool, error)
|
||||
PatchListener(ListenerPayload) (*envoy_listener_v3.Listener, bool, error)
|
||||
|
||||
// PatchListeners patches listeners to include the custom Envoy configuration
|
||||
// required to integrate with the built in extension template.
|
||||
|
@ -81,7 +81,7 @@ type BasicExtension interface {
|
|||
// PatchFilter patches an Envoy filter to include the custom Envoy
|
||||
// configuration required to integrate with the built in extension template.
|
||||
// See also PatchFilters.
|
||||
PatchFilter(cfg *RuntimeConfig, f *envoy_listener_v3.Filter, isInboundListener bool) (*envoy_listener_v3.Filter, bool, error)
|
||||
PatchFilter(FilterPayload) (*envoy_listener_v3.Filter, bool, error)
|
||||
|
||||
// PatchFilters patches Envoy filters to include the custom Envoy
|
||||
// configuration required to integrate with the built in extension template.
|
||||
|
@ -197,7 +197,7 @@ func (b *BasicEnvoyExtender) patchClusters(config *RuntimeConfig, clusters Clust
|
|||
return clusters, fmt.Errorf("error patching clusters: %w", err)
|
||||
}
|
||||
for nameOrSNI, cluster := range clusters {
|
||||
patchedCluster, patched, err := b.Extension.PatchCluster(config, cluster)
|
||||
patchedCluster, patched, err := b.Extension.PatchCluster(config.GetClusterPayload(cluster))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster %q: %w", nameOrSNI, err))
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ func (b *BasicEnvoyExtender) patchClusters(config *RuntimeConfig, clusters Clust
|
|||
// We patch cluster load assignments directly above for EDS, but also here for CDS,
|
||||
// since updates can come from either.
|
||||
if patchedCluster.LoadAssignment != nil {
|
||||
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config, patchedCluster.LoadAssignment)
|
||||
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config.GetClusterLoadAssignmentPayload(patchedCluster.LoadAssignment))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching load assignment for cluster %q: %w", nameOrSNI, err))
|
||||
} else if patched {
|
||||
|
@ -225,7 +225,7 @@ func (b *BasicEnvoyExtender) patchClusterLoadAssignments(config *RuntimeConfig,
|
|||
var resultErr error
|
||||
|
||||
for nameOrSNI, clusterLoadAssignment := range clusterLoadAssignments {
|
||||
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config, clusterLoadAssignment)
|
||||
patchedClusterLoadAssignment, patched, err := b.Extension.PatchClusterLoadAssignment(config.GetClusterLoadAssignmentPayload(clusterLoadAssignment))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster load assignment %q: %w", nameOrSNI, err))
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ func (b *BasicEnvoyExtender) patchRoutes(config *RuntimeConfig, routes RouteMap)
|
|||
return routes, fmt.Errorf("error patching routes: %w", err)
|
||||
}
|
||||
for nameOrSNI, route := range patchedRoutes {
|
||||
patchedRoute, patched, err := b.Extension.PatchRoute(config, route)
|
||||
patchedRoute, patched, err := b.Extension.PatchRoute(config.GetRoutePayload(route))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching route %q: %w", nameOrSNI, err))
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ func (b *BasicEnvoyExtender) patchListeners(config *RuntimeConfig, listeners Lis
|
|||
return listeners, fmt.Errorf("error patching listeners: %w", err)
|
||||
}
|
||||
for nameOrSNI, listener := range listeners {
|
||||
patchedListener, patched, err := b.Extension.PatchListener(config, listener)
|
||||
patchedListener, patched, err := b.Extension.PatchListener(config.GetListenerPayload(listener))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener %q: %w", nameOrSNI, err))
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ func (b *BasicEnvoyExtender) patchListenerFilterChains(config *RuntimeConfig, l
|
|||
func (b *BasicEnvoyExtender) patchTerminatingGatewayListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener, nameOrSNI string) (*envoy_listener_v3.Listener, error) {
|
||||
var resultErr error
|
||||
for idx, filterChain := range l.FilterChains {
|
||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, IsInboundPublicListener(l)); err == nil {
|
||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, l); err == nil {
|
||||
l.FilterChains[idx] = patchedFilterChain
|
||||
} else {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain of terminating gateway listener %q: %w", nameOrSNI, err))
|
||||
|
@ -330,10 +330,8 @@ func (b *BasicEnvoyExtender) patchConnectProxyListenerFilterChains(config *Runti
|
|||
func (b *BasicEnvoyExtender) patchNonTProxyConnectProxyListenerFilterChains(config *RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, error) {
|
||||
var resultErr error
|
||||
|
||||
inbound := IsInboundPublicListener(l)
|
||||
|
||||
for idx, filterChain := range l.FilterChains {
|
||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, inbound); err == nil {
|
||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, l); err == nil {
|
||||
l.FilterChains[idx] = patchedFilterChain
|
||||
} else {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain: %w", err))
|
||||
|
@ -346,7 +344,6 @@ func (b *BasicEnvoyExtender) patchTProxyListenerFilterChains(config *RuntimeConf
|
|||
var resultErr error
|
||||
|
||||
vip := config.Upstreams[config.ServiceName].VIP
|
||||
inbound := IsInboundPublicListener(l)
|
||||
|
||||
for idx, filterChain := range l.FilterChains {
|
||||
match := filterChainTProxyMatch(vip, filterChain)
|
||||
|
@ -354,7 +351,7 @@ func (b *BasicEnvoyExtender) patchTProxyListenerFilterChains(config *RuntimeConf
|
|||
continue
|
||||
}
|
||||
|
||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, inbound); err == nil {
|
||||
if patchedFilterChain, err := b.patchFilterChain(config, filterChain, l); err == nil {
|
||||
l.FilterChains[idx] = patchedFilterChain
|
||||
} else {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter chain for %q: %w", vip, err))
|
||||
|
@ -364,14 +361,15 @@ func (b *BasicEnvoyExtender) patchTProxyListenerFilterChains(config *RuntimeConf
|
|||
return l, resultErr
|
||||
}
|
||||
|
||||
func (b *BasicEnvoyExtender) patchFilterChain(config *RuntimeConfig, filterChain *envoy_listener_v3.FilterChain, isInboundListener bool) (*envoy_listener_v3.FilterChain, error) {
|
||||
func (b *BasicEnvoyExtender) patchFilterChain(config *RuntimeConfig, filterChain *envoy_listener_v3.FilterChain, l *envoy_listener_v3.Listener) (*envoy_listener_v3.FilterChain, error) {
|
||||
var resultErr error
|
||||
patchedFilters, err := b.Extension.PatchFilters(config, filterChain.Filters, isInboundListener)
|
||||
inbound := IsInboundPublicListener(l)
|
||||
patchedFilters, err := b.Extension.PatchFilters(config, filterChain.Filters, inbound)
|
||||
if err != nil {
|
||||
return filterChain, fmt.Errorf("error patching filters: %w", err)
|
||||
}
|
||||
for idx, filter := range patchedFilters {
|
||||
patchedFilter, patched, err := b.Extension.PatchFilter(config, filter, isInboundListener)
|
||||
patchedFilter, patched, err := b.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching filter: %w", err))
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ type BasicExtensionAdapter struct{}
|
|||
func (BasicExtensionAdapter) CanApply(_ *RuntimeConfig) bool { return false }
|
||||
|
||||
// PatchCluster provides a default implementation of the PatchCluster interface that does nothing.
|
||||
func (BasicExtensionAdapter) PatchCluster(_ *RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
return c, false, nil
|
||||
func (BasicExtensionAdapter) PatchCluster(p ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
// PatchClusters provides a default implementation of the PatchClusters interface that does nothing.
|
||||
|
@ -30,13 +30,13 @@ func (BasicExtensionAdapter) PatchClusters(_ *RuntimeConfig, c ClusterMap) (Clus
|
|||
}
|
||||
|
||||
// PatchClusterLoadAssignment provides a default implementation of the PatchClusterLoadAssignment interface that does nothing.
|
||||
func (BasicExtensionAdapter) PatchClusterLoadAssignment(_ *RuntimeConfig, c *envoy_endpoint_v3.ClusterLoadAssignment) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
||||
return c, false, nil
|
||||
func (BasicExtensionAdapter) PatchClusterLoadAssignment(p ClusterLoadAssignmentPayload) (*envoy_endpoint_v3.ClusterLoadAssignment, bool, error) {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
// PatchListener provides a default implementation of the PatchListener interface that does nothing.
|
||||
func (BasicExtensionAdapter) PatchListener(_ *RuntimeConfig, l *envoy_listener_v3.Listener) (*envoy_listener_v3.Listener, bool, error) {
|
||||
return l, false, nil
|
||||
func (BasicExtensionAdapter) PatchListener(p ListenerPayload) (*envoy_listener_v3.Listener, bool, error) {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
// PatchListeners provides a default implementation of the PatchListeners interface that does nothing.
|
||||
|
@ -45,8 +45,8 @@ func (BasicExtensionAdapter) PatchListeners(_ *RuntimeConfig, l ListenerMap) (Li
|
|||
}
|
||||
|
||||
// PatchFilter provides a default implementation of the PatchFilter interface that does nothing.
|
||||
func (BasicExtensionAdapter) PatchFilter(_ *RuntimeConfig, f *envoy_listener_v3.Filter, _ bool) (*envoy_listener_v3.Filter, bool, error) {
|
||||
return f, false, nil
|
||||
func (BasicExtensionAdapter) PatchFilter(p FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
// PatchFilters provides a default implementation of the PatchFilters interface that does nothing.
|
||||
|
@ -55,8 +55,8 @@ func (BasicExtensionAdapter) PatchFilters(_ *RuntimeConfig, f []*envoy_listener_
|
|||
}
|
||||
|
||||
// PatchRoute provides a default implementation of the PatchRoute interface that does nothing.
|
||||
func (BasicExtensionAdapter) PatchRoute(_ *RuntimeConfig, r *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
return r, false, nil
|
||||
func (BasicExtensionAdapter) PatchRoute(p RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
return p.Message, false, nil
|
||||
}
|
||||
|
||||
// PatchRoutes provides a default implementation of the PatchRoutes interface that does nothing.
|
||||
|
|
|
@ -17,9 +17,11 @@ import (
|
|||
envoy_tcp_proxy_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
|
||||
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||
envoy_resource_v3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
|
||||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||
)
|
||||
|
||||
// MakeUpstreamTLSTransportSocket generates an Envoy transport socket for the given TLS context.
|
||||
|
@ -70,6 +72,206 @@ func MakeFilter(name string, cfg proto.Message) (*envoy_listener_v3.Filter, erro
|
|||
}, nil
|
||||
}
|
||||
|
||||
// TrafficDirection determines whether inbound or outbound Envoy resources will be patched.
|
||||
type TrafficDirection string
|
||||
|
||||
const (
|
||||
TrafficDirectionInbound TrafficDirection = "inbound"
|
||||
TrafficDirectionOutbound TrafficDirection = "outbound"
|
||||
)
|
||||
|
||||
var TrafficDirections = StringSet{string(TrafficDirectionInbound): {}, string(TrafficDirectionOutbound): {}}
|
||||
|
||||
type StringSet map[string]struct{}
|
||||
|
||||
func (c *StringSet) CheckRequired(v, fieldName string) error {
|
||||
if _, ok := (*c)[v]; !ok {
|
||||
if v == "" {
|
||||
return fmt.Errorf("field %s is required", fieldName)
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for k := range *c {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid %s '%q'; supported values: %s",
|
||||
fieldName, v, strings.Join(keys, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NormalizeEmptyToDefault(s string) string {
|
||||
if s == "" {
|
||||
return "default"
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func NormalizeServiceName(sn *api.CompoundServiceName) {
|
||||
sn.Namespace = NormalizeEmptyToDefault(sn.Namespace)
|
||||
sn.Partition = NormalizeEmptyToDefault(sn.Partition)
|
||||
}
|
||||
|
||||
// Payload represents a single Envoy resource to be modified by extensions.
|
||||
// It associates the RuntimeConfig of the local proxy, the TrafficDirection
|
||||
// of the resource, and the CompoundServiceName and UpstreamData (if outbound)
|
||||
// of a service the Envoy resource corresponds to.
|
||||
type Payload[K proto.Message] struct {
|
||||
RuntimeConfig *RuntimeConfig
|
||||
ServiceName *api.CompoundServiceName
|
||||
Upstream *UpstreamData
|
||||
TrafficDirection TrafficDirection
|
||||
Message K
|
||||
}
|
||||
|
||||
func (p Payload[K]) IsInbound() bool {
|
||||
return p.TrafficDirection == TrafficDirectionInbound
|
||||
}
|
||||
|
||||
type ClusterPayload = Payload[*envoy_cluster_v3.Cluster]
|
||||
type ClusterLoadAssignmentPayload = Payload[*envoy_endpoint_v3.ClusterLoadAssignment]
|
||||
type ListenerPayload = Payload[*envoy_listener_v3.Listener]
|
||||
type FilterPayload = Payload[*envoy_listener_v3.Filter]
|
||||
type RoutePayload = Payload[*envoy_route_v3.RouteConfiguration]
|
||||
|
||||
func (cfg *RuntimeConfig) GetClusterPayload(c *envoy_cluster_v3.Cluster) ClusterPayload {
|
||||
d := TrafficDirectionOutbound
|
||||
var u *UpstreamData
|
||||
var sn *api.CompoundServiceName
|
||||
|
||||
if IsLocalAppCluster(c) {
|
||||
d = TrafficDirectionInbound
|
||||
} else {
|
||||
u, sn = cfg.findUpstreamBySNI(c.Name)
|
||||
}
|
||||
|
||||
return ClusterPayload{
|
||||
RuntimeConfig: cfg,
|
||||
ServiceName: sn,
|
||||
Upstream: u,
|
||||
TrafficDirection: d,
|
||||
Message: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RuntimeConfig) GetListenerPayload(l *envoy_listener_v3.Listener) ListenerPayload {
|
||||
d := TrafficDirectionOutbound
|
||||
var u *UpstreamData
|
||||
var sn *api.CompoundServiceName
|
||||
|
||||
if IsInboundPublicListener(l) {
|
||||
d = TrafficDirectionInbound
|
||||
} else {
|
||||
u, sn = c.findUpstreamByEnvoyID(GetListenerEnvoyID(l))
|
||||
}
|
||||
|
||||
return ListenerPayload{
|
||||
RuntimeConfig: c,
|
||||
ServiceName: sn,
|
||||
Upstream: u,
|
||||
TrafficDirection: d,
|
||||
Message: l,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RuntimeConfig) GetFilterPayload(f *envoy_listener_v3.Filter, l *envoy_listener_v3.Listener) FilterPayload {
|
||||
d := TrafficDirectionOutbound
|
||||
var u *UpstreamData
|
||||
var sn *api.CompoundServiceName
|
||||
|
||||
if IsInboundPublicListener(l) {
|
||||
d = TrafficDirectionInbound
|
||||
} else {
|
||||
u, sn = c.findUpstreamByEnvoyID(GetListenerEnvoyID(l))
|
||||
}
|
||||
|
||||
return FilterPayload{
|
||||
RuntimeConfig: c,
|
||||
ServiceName: sn,
|
||||
Upstream: u,
|
||||
TrafficDirection: d,
|
||||
Message: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RuntimeConfig) GetRoutePayload(r *envoy_route_v3.RouteConfiguration) RoutePayload {
|
||||
d := TrafficDirectionOutbound
|
||||
var u *UpstreamData
|
||||
var sn *api.CompoundServiceName
|
||||
|
||||
if IsRouteToLocalAppCluster(r) {
|
||||
d = TrafficDirectionInbound
|
||||
} else {
|
||||
u, sn = c.findUpstreamByEnvoyID(r.Name)
|
||||
}
|
||||
|
||||
return RoutePayload{
|
||||
RuntimeConfig: c,
|
||||
ServiceName: sn,
|
||||
Upstream: u,
|
||||
TrafficDirection: d,
|
||||
Message: r,
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *RuntimeConfig) GetClusterLoadAssignmentPayload(c *envoy_endpoint_v3.ClusterLoadAssignment) ClusterLoadAssignmentPayload {
|
||||
d := TrafficDirectionOutbound
|
||||
var u *UpstreamData
|
||||
var sn *api.CompoundServiceName
|
||||
|
||||
if IsLocalAppClusterLoadAssignment(c) {
|
||||
d = TrafficDirectionInbound
|
||||
} else {
|
||||
u, sn = cfg.findUpstreamBySNI(c.ClusterName)
|
||||
|
||||
}
|
||||
|
||||
return ClusterLoadAssignmentPayload{
|
||||
RuntimeConfig: cfg,
|
||||
ServiceName: sn,
|
||||
Upstream: u,
|
||||
TrafficDirection: d,
|
||||
Message: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RuntimeConfig) findUpstreamByEnvoyID(envoyID string) (*UpstreamData, *api.CompoundServiceName) {
|
||||
for sn, u := range c.Upstreams {
|
||||
if u.EnvoyID == envoyID {
|
||||
return u, &sn
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *RuntimeConfig) findUpstreamBySNI(sni string) (*UpstreamData, *api.CompoundServiceName) {
|
||||
for sn, u := range c.Upstreams {
|
||||
_, ok := u.SNIs[sni]
|
||||
if ok {
|
||||
return u, &sn
|
||||
}
|
||||
|
||||
if strings.HasPrefix(sni, xdscommon.FailoverClusterNamePrefix) {
|
||||
parts := strings.Split(sni, "~")
|
||||
|
||||
if len(parts) != 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
id := parts[2]
|
||||
_, ok := u.SNIs[id]
|
||||
if ok {
|
||||
return u, &sn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetListenerEnvoyID returns the Envoy ID string parsed from the name of the given Listener. If none is found, it
|
||||
// returns the empty string.
|
||||
func GetListenerEnvoyID(l *envoy_listener_v3.Listener) string {
|
||||
|
|
|
@ -8,8 +8,11 @@ import "github.com/hashicorp/consul/api"
|
|||
// UpstreamData has the SNI, EnvoyID, and OutgoingProxyKind of the upstream services for the local proxy and this data
|
||||
// is used to choose which Envoy resources to patch.
|
||||
type UpstreamData struct {
|
||||
// SNI is the SNI header used to reach an upstream service.
|
||||
SNI map[string]struct{}
|
||||
// This is the SNI for the upstream service without accounting for any discovery chain magic.
|
||||
PrimarySNI string
|
||||
|
||||
// SNIs is the SNIs header used to reach an upstream service.
|
||||
SNIs map[string]struct{}
|
||||
|
||||
// EnvoyID is the envoy ID of an upstream service, structured <service> or <partition>/<ns>/<service> when using a
|
||||
// non-default namespace or partition.
|
||||
|
@ -68,7 +71,7 @@ type RuntimeConfig struct {
|
|||
// Only used when IsSourcedFromUpstream is true.
|
||||
func (c RuntimeConfig) MatchesUpstreamServiceSNI(sni string) bool {
|
||||
u := c.Upstreams[c.ServiceName]
|
||||
_, match := u.SNI[sni]
|
||||
_, match := u.SNIs[sni]
|
||||
return match
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ func makeTestRuntimeConfig() RuntimeConfig {
|
|||
sn: {
|
||||
EnvoyID: "eid",
|
||||
OutgoingProxyKind: api.ServiceKindTerminatingGateway,
|
||||
SNI: map[string]struct{}{
|
||||
SNIs: map[string]struct{}{
|
||||
"sni1": {},
|
||||
"sni2": {},
|
||||
},
|
||||
|
|
|
@ -74,7 +74,7 @@ func (ext *UpstreamEnvoyExtender) Extend(resources *xdscommon.IndexedResources,
|
|||
continue
|
||||
}
|
||||
|
||||
newCluster, patched, err := ext.Extension.PatchCluster(config, resource)
|
||||
newCluster, patched, err := ext.Extension.PatchCluster(config.GetClusterPayload(resource))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching cluster: %w", err))
|
||||
continue
|
||||
|
@ -101,7 +101,7 @@ func (ext *UpstreamEnvoyExtender) Extend(resources *xdscommon.IndexedResources,
|
|||
continue
|
||||
}
|
||||
|
||||
newRoute, patched, err := ext.Extension.PatchRoute(config, resource)
|
||||
newRoute, patched, err := ext.Extension.PatchRoute(config.GetRoutePayload(resource))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching route: %w", err))
|
||||
continue
|
||||
|
@ -146,7 +146,7 @@ func (ext *UpstreamEnvoyExtender) patchTerminatingGatewayListener(config *Runtim
|
|||
var filters []*envoy_listener_v3.Filter
|
||||
|
||||
for _, filter := range filterChain.Filters {
|
||||
newFilter, ok, err := ext.Extension.PatchFilter(config, filter, IsInboundPublicListener(l))
|
||||
newFilter, ok, err := ext.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
||||
|
@ -190,7 +190,7 @@ func (ext *UpstreamEnvoyExtender) patchConnectProxyListener(config *RuntimeConfi
|
|||
var filters []*envoy_listener_v3.Filter
|
||||
|
||||
for _, filter := range filterChain.Filters {
|
||||
newFilter, ok, err := ext.Extension.PatchFilter(config, filter, IsInboundPublicListener(l))
|
||||
newFilter, ok, err := ext.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
||||
filters = append(filters, filter)
|
||||
|
@ -225,7 +225,7 @@ func (ext *UpstreamEnvoyExtender) patchTProxyListener(config *RuntimeConfig, l *
|
|||
}
|
||||
|
||||
for _, filter := range filterChain.Filters {
|
||||
newFilter, ok, err := ext.Extension.PatchFilter(config, filter, IsInboundPublicListener(l))
|
||||
newFilter, ok, err := ext.Extension.PatchFilter(config.GetFilterPayload(filter, l))
|
||||
if err != nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
|
||||
filters = append(filters, filter)
|
||||
|
|
|
@ -52,6 +52,8 @@ const (
|
|||
|
||||
// SecretType is the TypeURL for Secret discovery responses.
|
||||
SecretType = apiTypePrefix + "envoy.extensions.transport_sockets.tls.v3.Secret"
|
||||
|
||||
FailoverClusterNamePrefix = "failover-target~"
|
||||
)
|
||||
|
||||
type IndexedResources struct {
|
||||
|
|
|
@ -87,7 +87,7 @@ func Validate(indexedResources *xdscommon.IndexedResources, envoyID string, vip
|
|||
// the cluster SNIs configured on this proxy, not just the upstream being validated. This means the
|
||||
// PatchCluster function in the Validate plugin will be run on all clusters, but errors will only
|
||||
// surface for clusters related to the upstream being validated.
|
||||
SNI: snis,
|
||||
SNIs: snis,
|
||||
EnvoyID: envoyID,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -92,10 +92,10 @@ func MakeValidate(ext extensioncommon.RuntimeConfig) (extensioncommon.BasicExten
|
|||
upstream, ok := ext.Upstreams[ext.ServiceName]
|
||||
if ok {
|
||||
vip = upstream.VIP
|
||||
if upstream.SNI == nil || len(upstream.SNI) == 0 {
|
||||
if upstream.SNIs == nil || len(upstream.SNIs) == 0 {
|
||||
return nil, fmt.Errorf("no SNIs were set, unable to validate Envoy clusters")
|
||||
}
|
||||
snis = upstream.SNI
|
||||
snis = upstream.SNIs
|
||||
}
|
||||
if mainEnvoyID == "" && vip == "" {
|
||||
return nil, fmt.Errorf("envoyID or virtual IP is required")
|
||||
|
@ -306,84 +306,87 @@ func (p *Validate) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (p *Validate) PatchRoute(config *extensioncommon.RuntimeConfig, route *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
func (v *Validate) PatchRoute(p extensioncommon.RoutePayload) (*envoy_route_v3.RouteConfiguration, bool, error) {
|
||||
route := p.Message
|
||||
// Route name on connect proxies will be the envoy ID. We are only validating routes for the specific upstream with
|
||||
// the envoyID configured.
|
||||
if route.Name != p.envoyID {
|
||||
if route.Name != p.Upstream.EnvoyID {
|
||||
return route, false, nil
|
||||
}
|
||||
p.route = true
|
||||
v.route = true
|
||||
for sni := range extensioncommon.RouteClusterNames(route) {
|
||||
if _, ok := p.resources[sni]; ok {
|
||||
if _, ok := v.resources[sni]; ok {
|
||||
continue
|
||||
}
|
||||
p.resources[sni] = &resource{required: true}
|
||||
v.resources[sni] = &resource{required: true}
|
||||
}
|
||||
return route, false, nil
|
||||
}
|
||||
|
||||
func (p *Validate) PatchCluster(config *extensioncommon.RuntimeConfig, c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
v, ok := p.resources[c.Name]
|
||||
func (v *Validate) PatchCluster(p extensioncommon.ClusterPayload) (*envoy_cluster_v3.Cluster, bool, error) {
|
||||
c := p.Message
|
||||
val, ok := v.resources[c.Name]
|
||||
if !ok {
|
||||
v = &resource{}
|
||||
p.resources[c.Name] = v
|
||||
val = &resource{}
|
||||
v.resources[c.Name] = val
|
||||
}
|
||||
v.cluster = true
|
||||
val.cluster = true
|
||||
|
||||
// If it's an aggregate cluster, add the child clusters to p.resources if they are not already there.
|
||||
aggregateCluster, ok := isAggregateCluster(c)
|
||||
if ok {
|
||||
// Mark this as an aggregate cluster, so we know we do not need to validate its endpoints directly.
|
||||
v.aggregateCluster = true
|
||||
val.aggregateCluster = true
|
||||
for _, clusterName := range aggregateCluster.Clusters {
|
||||
r, ok := p.resources[clusterName]
|
||||
r, ok := v.resources[clusterName]
|
||||
if !ok {
|
||||
r = &resource{}
|
||||
p.resources[clusterName] = r
|
||||
v.resources[clusterName] = r
|
||||
}
|
||||
if v.aggregateClusterChildren == nil {
|
||||
v.aggregateClusterChildren = []string{}
|
||||
if val.aggregateClusterChildren == nil {
|
||||
val.aggregateClusterChildren = []string{}
|
||||
}
|
||||
// On the parent cluster, add the children.
|
||||
v.aggregateClusterChildren = append(v.aggregateClusterChildren, clusterName)
|
||||
val.aggregateClusterChildren = append(val.aggregateClusterChildren, clusterName)
|
||||
// On the child cluster, set the parent.
|
||||
r.parentCluster = c.Name
|
||||
// The child clusters of an aggregate cluster will be required if the parent cluster is.
|
||||
r.required = v.required
|
||||
r.required = val.required
|
||||
}
|
||||
return c, false, nil
|
||||
}
|
||||
|
||||
if c.EdsClusterConfig != nil {
|
||||
v.usesEDS = true
|
||||
val.usesEDS = true
|
||||
} else {
|
||||
la := c.LoadAssignment
|
||||
if la == nil {
|
||||
return c, false, nil
|
||||
}
|
||||
v.endpoints = len(la.Endpoints) + len(la.NamedEndpoints)
|
||||
val.endpoints = len(la.Endpoints) + len(la.NamedEndpoints)
|
||||
}
|
||||
return c, false, nil
|
||||
}
|
||||
|
||||
func (p *Validate) PatchFilter(config *extensioncommon.RuntimeConfig, filter *envoy_listener_v3.Filter, _ bool) (*envoy_listener_v3.Filter, bool, error) {
|
||||
func (v *Validate) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener_v3.Filter, bool, error) {
|
||||
filter := p.Message
|
||||
// If a single filter exists for a listener we say it exists.
|
||||
p.listener = true
|
||||
v.listener = true
|
||||
|
||||
if httpConfig := envoy_resource_v3.GetHTTPConnectionManager(filter); httpConfig != nil {
|
||||
// If the http filter uses RDS, then the clusters we need to validate exist in the route, and there's nothing
|
||||
// else we need to do with the filter.
|
||||
if httpConfig.GetRds() != nil {
|
||||
p.usesRDS = true
|
||||
v.usesRDS = true
|
||||
|
||||
// Edit the runtime configuration to add an envoy ID based on the route name in the filter. This is because
|
||||
// routes are matched by envoyID and in the transparent proxy case, we only have the VIP set in the
|
||||
// RuntimeConfig.
|
||||
p.envoyID = httpConfig.GetRds().RouteConfigName
|
||||
v.envoyID = httpConfig.GetRds().RouteConfigName
|
||||
emptyServiceKey := api.CompoundServiceName{}
|
||||
upstream, ok := config.Upstreams[emptyServiceKey]
|
||||
upstream, ok := p.RuntimeConfig.Upstreams[emptyServiceKey]
|
||||
if ok {
|
||||
upstream.EnvoyID = p.envoyID
|
||||
upstream.EnvoyID = v.envoyID
|
||||
}
|
||||
return filter, true, nil
|
||||
}
|
||||
|
@ -392,10 +395,10 @@ func (p *Validate) PatchFilter(config *extensioncommon.RuntimeConfig, filter *en
|
|||
// FilterClusterNames handles the filter being an http or tcp filter.
|
||||
for sni := range extensioncommon.FilterClusterNames(filter) {
|
||||
// Mark any clusters we see as required resources.
|
||||
if r, ok := p.resources[sni]; ok {
|
||||
if r, ok := v.resources[sni]; ok {
|
||||
r.required = true
|
||||
} else {
|
||||
p.resources[sni] = &resource{required: true}
|
||||
v.resources[sni] = &resource{required: true}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ func TestMakeValidate(t *testing.T) {
|
|||
},
|
||||
Upstreams: map[api.CompoundServiceName]*extensioncommon.UpstreamData{
|
||||
svc: {
|
||||
SNI: tc.snis,
|
||||
SNIs: tc.snis,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue