mirror of https://github.com/hashicorp/consul
commit
74de240902
@ -0,0 +1,3 @@
|
||||
```release-note:feature
|
||||
reloadable config: Made enable_debug config reloadable and enable pprof command to work when config toggles to true
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
connect/ca: Fixes a bug preventing CA configuration updates in secondary datacenters
|
||||
```
|
@ -1,199 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package localratelimit
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||
envoy_ratelimit "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/local_ratelimit/v3"
|
||||
envoy_http_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||
envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
|
||||
envoy_resource_v3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||
)
|
||||
|
||||
type ratelimit struct {
|
||||
extensioncommon.BasicExtensionAdapter
|
||||
|
||||
ProxyType string
|
||||
|
||||
// Token bucket of the rate limit
|
||||
MaxTokens *int
|
||||
TokensPerFill *int
|
||||
FillInterval *int
|
||||
|
||||
// Percent of requests to be rate limited
|
||||
FilterEnabled *uint32
|
||||
FilterEnforced *uint32
|
||||
}
|
||||
|
||||
var _ extensioncommon.BasicExtension = (*ratelimit)(nil)
|
||||
|
||||
// Constructor follows a specific function signature required for the extension registration.
|
||||
func Constructor(ext api.EnvoyExtension) (extensioncommon.EnvoyExtender, error) {
|
||||
var r ratelimit
|
||||
if name := ext.Name; name != api.BuiltinLocalRatelimitExtension {
|
||||
return nil, fmt.Errorf("expected extension name 'ratelimit' but got %q", name)
|
||||
}
|
||||
|
||||
if err := r.fromArguments(ext.Arguments); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &extensioncommon.BasicEnvoyExtender{
|
||||
Extension: &r,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *ratelimit) fromArguments(args map[string]interface{}) error {
|
||||
if err := mapstructure.Decode(args, r); err != nil {
|
||||
return fmt.Errorf("error decoding extension arguments: %v", err)
|
||||
}
|
||||
if r.ProxyType == "" {
|
||||
r.ProxyType = string(api.ServiceKindConnectProxy)
|
||||
}
|
||||
return r.validate()
|
||||
}
|
||||
|
||||
func (r *ratelimit) validate() error {
|
||||
var resultErr error
|
||||
|
||||
// NOTE: Envoy requires FillInterval value must be greater than 0.
|
||||
// If unset, it is considered as 0.
|
||||
if r.FillInterval == nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("FillInterval(in second) is missing"))
|
||||
} else if *r.FillInterval <= 0 {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("FillInterval(in second) must be greater than 0, got %d", *r.FillInterval))
|
||||
}
|
||||
|
||||
// NOTE: Envoy requires MaxToken value must be greater than 0.
|
||||
// If unset, it is considered as 0.
|
||||
if r.MaxTokens == nil {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("MaxTokens is missing"))
|
||||
} else if *r.MaxTokens <= 0 {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("MaxTokens must be greater than 0, got %d", r.MaxTokens))
|
||||
}
|
||||
|
||||
// TokensPerFill is allowed to unset. In this case, envoy
|
||||
// uses its default value, which is 1.
|
||||
if r.TokensPerFill != nil && *r.TokensPerFill <= 0 {
|
||||
resultErr = multierror.Append(resultErr, fmt.Errorf("TokensPerFill must be greater than 0, got %d", *r.TokensPerFill))
|
||||
}
|
||||
|
||||
if err := validateProxyType(r.ProxyType); err != nil {
|
||||
resultErr = multierror.Append(resultErr, err)
|
||||
}
|
||||
|
||||
return resultErr
|
||||
}
|
||||
|
||||
// CanApply determines if the extension can apply to the given extension configuration.
|
||||
func (p *ratelimit) CanApply(config *extensioncommon.RuntimeConfig) bool {
|
||||
return string(config.Kind) == p.ProxyType
|
||||
}
|
||||
|
||||
// PatchFilter inserts a http local rate_limit filter at the head of
|
||||
// envoy.filters.network.http_connection_manager filters
|
||||
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 !p.IsInbound() {
|
||||
return filter, false, nil
|
||||
}
|
||||
|
||||
if filter.Name != "envoy.filters.network.http_connection_manager" {
|
||||
return filter, false, nil
|
||||
}
|
||||
if typedConfig := filter.GetTypedConfig(); typedConfig == nil {
|
||||
return filter, false, errors.New("error getting typed config for http filter")
|
||||
}
|
||||
|
||||
config := envoy_resource_v3.GetHTTPConnectionManager(filter)
|
||||
if config == nil {
|
||||
return filter, false, errors.New("error unmarshalling filter")
|
||||
}
|
||||
|
||||
tokenBucket := envoy_type_v3.TokenBucket{}
|
||||
|
||||
if r.TokensPerFill != nil {
|
||||
tokenBucket.TokensPerFill = &wrapperspb.UInt32Value{
|
||||
Value: uint32(*r.TokensPerFill),
|
||||
}
|
||||
}
|
||||
if r.MaxTokens != nil {
|
||||
tokenBucket.MaxTokens = uint32(*r.MaxTokens)
|
||||
}
|
||||
|
||||
if r.FillInterval != nil {
|
||||
tokenBucket.FillInterval = durationpb.New(time.Duration(*r.FillInterval) * time.Second)
|
||||
}
|
||||
|
||||
var FilterEnabledDefault *envoy_core_v3.RuntimeFractionalPercent
|
||||
if r.FilterEnabled != nil {
|
||||
FilterEnabledDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
||||
DefaultValue: &envoy_type_v3.FractionalPercent{
|
||||
Numerator: *r.FilterEnabled,
|
||||
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var FilterEnforcedDefault *envoy_core_v3.RuntimeFractionalPercent
|
||||
if r.FilterEnforced != nil {
|
||||
FilterEnforcedDefault = &envoy_core_v3.RuntimeFractionalPercent{
|
||||
DefaultValue: &envoy_type_v3.FractionalPercent{
|
||||
Numerator: *r.FilterEnforced,
|
||||
Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
ratelimitHttpFilter, err := extensioncommon.MakeEnvoyHTTPFilter(
|
||||
"envoy.filters.http.local_ratelimit",
|
||||
&envoy_ratelimit.LocalRateLimit{
|
||||
TokenBucket: &tokenBucket,
|
||||
StatPrefix: "local_ratelimit",
|
||||
FilterEnabled: FilterEnabledDefault,
|
||||
FilterEnforced: FilterEnforcedDefault,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return filter, false, err
|
||||
}
|
||||
|
||||
changedFilters := make([]*envoy_http_v3.HttpFilter, 0, len(config.HttpFilters)+1)
|
||||
|
||||
// The ratelimitHttpFilter is inserted as the first element of the http
|
||||
// filter chain.
|
||||
changedFilters = append(changedFilters, ratelimitHttpFilter)
|
||||
changedFilters = append(changedFilters, config.HttpFilters...)
|
||||
config.HttpFilters = changedFilters
|
||||
|
||||
newFilter, err := extensioncommon.MakeFilter("envoy.filters.network.http_connection_manager", config)
|
||||
if err != nil {
|
||||
return filter, false, errors.New("error making new filter")
|
||||
}
|
||||
|
||||
return newFilter, true, nil
|
||||
}
|
||||
|
||||
func validateProxyType(t string) error {
|
||||
if t != string(api.ServiceKindConnectProxy) {
|
||||
return fmt.Errorf("unexpected ProxyType %q", t)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package localratelimit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/envoyextensions/extensioncommon"
|
||||
)
|
||||
|
||||
func TestConstructor(t *testing.T) {
|
||||
makeArguments := func(overrides map[string]interface{}) map[string]interface{} {
|
||||
m := map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
}
|
||||
|
||||
for k, v := range overrides {
|
||||
m[k] = v
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
extensionName string
|
||||
arguments map[string]interface{}
|
||||
expected ratelimit
|
||||
ok bool
|
||||
expectedErrMsg string
|
||||
}{
|
||||
"with no arguments": {
|
||||
arguments: nil,
|
||||
ok: false,
|
||||
},
|
||||
"with an invalid name": {
|
||||
arguments: makeArguments(map[string]interface{}{}),
|
||||
extensionName: "bad",
|
||||
ok: false,
|
||||
},
|
||||
"MaxToken is missing": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"FillInterval": 30,
|
||||
"TokensPerFill": 5,
|
||||
}),
|
||||
expectedErrMsg: "MaxTokens is missing",
|
||||
ok: false,
|
||||
},
|
||||
"MaxTokens <= 0": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"FillInterval": 30,
|
||||
"TokensPerFill": 5,
|
||||
"MaxTokens": 0,
|
||||
}),
|
||||
expectedErrMsg: "MaxTokens must be greater than 0",
|
||||
ok: false,
|
||||
},
|
||||
"FillInterval is missing": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"TokensPerFill": 5,
|
||||
"MaxTokens": 10,
|
||||
}),
|
||||
expectedErrMsg: "FillInterval(in second) is missing",
|
||||
ok: false,
|
||||
},
|
||||
"FillInterval <= 0": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"FillInterval": 0,
|
||||
"TokensPerFill": 5,
|
||||
"MaxTokens": 10,
|
||||
}),
|
||||
expectedErrMsg: "FillInterval(in second) must be greater than 0",
|
||||
ok: false,
|
||||
},
|
||||
"TokensPerFill <= 0": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"FillInterval": 30,
|
||||
"TokensPerFill": 0,
|
||||
"MaxTokens": 10,
|
||||
}),
|
||||
expectedErrMsg: "TokensPerFill must be greater than 0",
|
||||
ok: false,
|
||||
},
|
||||
"FilterEnabled < 0": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"FillInterval": 30,
|
||||
"TokensPerFill": 5,
|
||||
"MaxTokens": 10,
|
||||
"FilterEnabled": -1,
|
||||
}),
|
||||
expectedErrMsg: "cannot parse 'FilterEnabled', -1 overflows uint",
|
||||
ok: false,
|
||||
},
|
||||
"FilterEnforced < 0": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"FillInterval": 30,
|
||||
"TokensPerFill": 5,
|
||||
"MaxTokens": 10,
|
||||
"FilterEnforced": -1,
|
||||
}),
|
||||
expectedErrMsg: "cannot parse 'FilterEnforced', -1 overflows uint",
|
||||
ok: false,
|
||||
},
|
||||
"invalid proxy type": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "invalid",
|
||||
"FillInterval": 30,
|
||||
"MaxTokens": 20,
|
||||
"TokensPerFill": 5,
|
||||
}),
|
||||
expectedErrMsg: `unexpected ProxyType "invalid"`,
|
||||
ok: false,
|
||||
},
|
||||
"default proxy type": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"FillInterval": 30,
|
||||
"MaxTokens": 20,
|
||||
"TokensPerFill": 5,
|
||||
}),
|
||||
expected: ratelimit{
|
||||
ProxyType: "connect-proxy",
|
||||
MaxTokens: intPointer(20),
|
||||
FillInterval: intPointer(30),
|
||||
TokensPerFill: intPointer(5),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
"valid everything": {
|
||||
arguments: makeArguments(map[string]interface{}{
|
||||
"ProxyType": "connect-proxy",
|
||||
"FillInterval": 30,
|
||||
"MaxTokens": 20,
|
||||
"TokensPerFill": 5,
|
||||
}),
|
||||
expected: ratelimit{
|
||||
ProxyType: "connect-proxy",
|
||||
MaxTokens: intPointer(20),
|
||||
FillInterval: intPointer(30),
|
||||
TokensPerFill: intPointer(5),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
}
|
||||
|
||||
for n, tc := range cases {
|
||||
t.Run(n, func(t *testing.T) {
|
||||
|
||||
extensionName := api.BuiltinLocalRatelimitExtension
|
||||
if tc.extensionName != "" {
|
||||
extensionName = tc.extensionName
|
||||
}
|
||||
|
||||
svc := api.CompoundServiceName{Name: "svc"}
|
||||
ext := extensioncommon.RuntimeConfig{
|
||||
ServiceName: svc,
|
||||
EnvoyExtension: api.EnvoyExtension{
|
||||
Name: extensionName,
|
||||
Arguments: tc.arguments,
|
||||
},
|
||||
}
|
||||
|
||||
e, err := Constructor(ext.EnvoyExtension)
|
||||
|
||||
if tc.ok {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &extensioncommon.BasicEnvoyExtender{Extension: &tc.expected}, e)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tc.expectedErrMsg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func intPointer(i int) *int {
|
||||
return &i
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
{
|
||||
"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",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {},
|
||||
"commonLbConfig": {
|
||||
"healthyPanicThreshold": {}
|
||||
},
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"tlsParams": {},
|
||||
"tlsCertificates": [
|
||||
{
|
||||
"certificateChain": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"privateKey": {
|
||||
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"validationContext": {
|
||||
"trustedCa": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"matchSubjectAltNames": [
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/db"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "db.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"
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "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": "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"
|
||||
}
|
@ -1,256 +0,0 @@
|
||||
{
|
||||
"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.local_ratelimit",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit",
|
||||
"statPrefix": "local_ratelimit",
|
||||
"tokenBucket": {
|
||||
"maxTokens": 3,
|
||||
"tokensPerFill": 2,
|
||||
"fillInterval": "10s"
|
||||
},
|
||||
"filterEnabled": {
|
||||
"defaultValue": {
|
||||
"numerator": 100
|
||||
}
|
||||
},
|
||||
"filterEnforced": {
|
||||
"defaultValue": {
|
||||
"numerator": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"nonce": "00000001"
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "example-okta.com",
|
||||
"portValue": 90
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "example-okta.com",
|
||||
"portValue": 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 9091
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "example-okta.com",
|
||||
"portValue": 90
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"validationContext": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "example-okta.com",
|
||||
"portValue": 443
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"validationContext": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 9091
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"validationContext": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"loadAssignment": {
|
||||
"clusterName": "jwks_cluster_okta",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 443
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "jwks_cluster_okta",
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"validationContext": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "STRICT_DNS"
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
|
||||
snapshot_envoy_admin localhost:19000 s1 primary || true
|
||||
snapshot_envoy_admin localhost:19001 s2 primary || true
|
@ -1,19 +0,0 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
services {
|
||||
name = "s1"
|
||||
port = 8080
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
upstreams = [
|
||||
{
|
||||
destination_name = "s2"
|
||||
local_bind_port = 5000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
services {
|
||||
name = "s2"
|
||||
port = 8181
|
||||
connect { sidecar_service {} }
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
|
||||
set -eEuo pipefail
|
||||
|
||||
upsert_config_entry primary '
|
||||
Kind = "service-defaults"
|
||||
Name = "s2"
|
||||
Protocol = "http"
|
||||
EnvoyExtensions = [
|
||||
{
|
||||
Name = "builtin/http/localratelimit",
|
||||
Arguments = {
|
||||
ProxyType = "connect-proxy"
|
||||
MaxTokens = 1,
|
||||
TokensPerFill = 1,
|
||||
FillInterval = 120,
|
||||
FilterEnabled = 100,
|
||||
FilterEnforced = 100,
|
||||
}
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
upsert_config_entry primary '
|
||||
Kind = "service-defaults"
|
||||
Name = "s1"
|
||||
Protocol = "tcp"
|
||||
EnvoyExtensions = [
|
||||
{
|
||||
Name = "builtin/http/localratelimit",
|
||||
Arguments = {
|
||||
ProxyType = "connect-proxy"
|
||||
MaxTokens = 1,
|
||||
TokensPerFill = 1,
|
||||
FillInterval = 120,
|
||||
FilterEnabled = 100,
|
||||
FilterEnforced = 100,
|
||||
}
|
||||
}
|
||||
]
|
||||
'
|
||||
|
||||
register_services primary
|
||||
|
||||
gen_envoy_bootstrap s1 19000 primary
|
||||
gen_envoy_bootstrap s2 19001 primary
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
|
||||
export REQUIRED_SERVICES="s1 s1-sidecar-proxy s2 s2-sidecar-proxy"
|
@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
@test "s1 proxy admin is up on :19000" {
|
||||
retry_default curl -f -s localhost:19000/stats -o /dev/null
|
||||
}
|
||||
|
||||
@test "s2 proxy admin is up on :19001" {
|
||||
retry_default curl -f -s localhost:19001/stats -o /dev/null
|
||||
}
|
||||
|
||||
@test "s1 proxy listener should be up and have right cert" {
|
||||
assert_proxy_presents_cert_uri localhost:21000 s1
|
||||
}
|
||||
|
||||
@test "s2 proxy listener should be up and have right cert" {
|
||||
assert_proxy_presents_cert_uri localhost:21001 s2
|
||||
}
|
||||
|
||||
@test "s2 proxy should be healthy" {
|
||||
assert_service_has_healthy_instances s2 1
|
||||
}
|
||||
|
||||
@test "s1 upstream should have healthy endpoints for s2" {
|
||||
assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary HEALTHY 1
|
||||
}
|
||||
|
||||
@test "s2 proxy should have been configured with http local ratelimit filters" {
|
||||
HTTP_FILTERS=$(get_envoy_http_filters localhost:19001)
|
||||
PUB=$(echo "$HTTP_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ')
|
||||
|
||||
echo "HTTP_FILTERS = $HTTP_FILTERS"
|
||||
echo "PUB = $PUB"
|
||||
|
||||
[ "$PUB" = "envoy.filters.http.local_ratelimit,envoy.filters.http.rbac,envoy.filters.http.header_to_metadata,envoy.filters.http.router" ]
|
||||
}
|
||||
|
||||
@test "s1(tcp) proxy should not be changed by http/localratelimit extension" {
|
||||
TCP_FILTERS=$(get_envoy_listener_filters localhost:19000)
|
||||
PUB=$(echo "$TCP_FILTERS" | grep -E "^public_listener:" | cut -f 2 -d ' ')
|
||||
|
||||
echo "TCP_FILTERS = $TCP_FILTERS"
|
||||
echo "PUB = $PUB"
|
||||
|
||||
[ "$PUB" = "envoy.filters.network.rbac,envoy.filters.network.tcp_proxy" ]
|
||||
}
|
||||
|
||||
@test "first connection to s2 - success" {
|
||||
run retry_default curl -s -f -d hello localhost:5000
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"hello"* ]]
|
||||
}
|
||||
|
||||
@test "ratelimit to s2 is in effect - return code 429" {
|
||||
retry_default must_fail_http_connection localhost:5000 429
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
---
|
||||
layout: docs
|
||||
page_title: Legacy RPC Protocol
|
||||
description: >-
|
||||
Consul agents originally could be controlled through the RPC protocol. This feature was deprecated in version 0.8 in favor of the HTTP API. Learn about agent RPC interactions and how they worked.
|
||||
---
|
||||
|
||||
# RPC Protocol
|
||||
|
||||
~> The RPC Protocol is deprecated and support was removed in Consul
|
||||
0.8. Please use the [HTTP API](/consul/api-docs), which has
|
||||
support for all features of the RPC Protocol.
|
||||
|
||||
The Consul agent provides a complete RPC mechanism that can
|
||||
be used to control the agent programmatically. This RPC
|
||||
mechanism is the same one used by the CLI but can be
|
||||
used by other applications to easily leverage the power
|
||||
of Consul without directly embedding.
|
||||
|
||||
It is important to note that the RPC protocol does not support
|
||||
all the same operations as the [HTTP API](/consul/api-docs).
|
||||
|
||||
## Implementation Details
|
||||
|
||||
The RPC protocol is implemented using [MsgPack](http://msgpack.org/)
|
||||
over TCP. This choice was driven by the fact that all operating
|
||||
systems support TCP, and MsgPack provides a fast serialization format
|
||||
that is broadly available across languages.
|
||||
|
||||
All RPC requests have a request header, and some requests have
|
||||
a request body. The request header looks like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Command": "Handshake",
|
||||
"Seq": 0
|
||||
}
|
||||
```
|
||||
|
||||
All responses have a response header, and some may contain
|
||||
a response body. The response header looks like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Seq": 0,
|
||||
"Error": ""
|
||||
}
|
||||
```
|
||||
|
||||
The `Command` in the request is used to specify what command the server should
|
||||
run, and the `Seq` is used to track the request. Responses are
|
||||
tagged with the same `Seq` as the request. This allows for some
|
||||
concurrency on the server side as requests are not purely FIFO.
|
||||
Thus, the `Seq` value should not be re-used between commands.
|
||||
All responses may be accompanied by an error.
|
||||
|
||||
Possible commands include:
|
||||
|
||||
- handshake - Initializes the connection and sets the version
|
||||
- force-leave - Removes a failed node from the cluster
|
||||
- join - Requests Consul join another node
|
||||
- members-lan - Returns the list of LAN members
|
||||
- members-wan - Returns the list of WAN members
|
||||
- monitor - Starts streaming logs over the connection
|
||||
- stop - Stops streaming logs
|
||||
- leave - Instructs the Consul agent to perform a graceful leave and shutdown
|
||||
- stats - Provides various debugging statistics
|
||||
- reload - Triggers a configuration reload
|
||||
|
||||
Each command is documented below along with any request or
|
||||
response body that is applicable.
|
||||
|
||||
### handshake
|
||||
|
||||
This command is used to initialize an RPC connection. As it informs
|
||||
the server which version the client is using, handshake MUST be the
|
||||
first command sent.
|
||||
|
||||
The request header must be followed by a handshake body, like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Version": 1
|
||||
}
|
||||
```
|
||||
|
||||
The body specifies the IPC version being used; however, only version
|
||||
1 is currently supported. This is to ensure backwards compatibility
|
||||
in the future.
|
||||
|
||||
There is no special response body, but the client should wait for the
|
||||
response and check for an error.
|
||||
|
||||
### force-leave
|
||||
|
||||
This command is used to remove failed nodes from a cluster. It takes
|
||||
the following body:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Node": "failed-node-name"
|
||||
}
|
||||
```
|
||||
|
||||
There is no special response body.
|
||||
|
||||
### join
|
||||
|
||||
This command is used to join an existing cluster using one or more known nodes.
|
||||
It takes the following body:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Existing": [
|
||||
"192.168.0.1:6000",
|
||||
"192.168.0.2:6000"
|
||||
],
|
||||
"WAN": false
|
||||
}
|
||||
```
|
||||
|
||||
The `Existing` nodes are each contacted, and `WAN` controls if we are adding a
|
||||
WAN member or LAN member. LAN members are expected to be in the same datacenter
|
||||
and should be accessible at relatively low latencies. WAN members are expected to
|
||||
be operating in different datacenters with relatively high access latencies. It is
|
||||
important that only agents running in "server" mode are able to join nodes over the
|
||||
WAN.
|
||||
|
||||
The response contains both a header and body. The body looks like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Num": 2
|
||||
}
|
||||
```
|
||||
|
||||
'Num' indicates the number of nodes successfully joined.
|
||||
|
||||
### members-lan
|
||||
|
||||
This command is used to return all the known LAN members and associated
|
||||
information. All agents will respond to this command.
|
||||
|
||||
There is no request body, but the response looks like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Members": [
|
||||
{
|
||||
"Name": "TestNode"
|
||||
"Addr": [127, 0, 0, 1],
|
||||
"Port": 5000,
|
||||
"Tags": {
|
||||
"role": "test"
|
||||
},
|
||||
"Status": "alive",
|
||||
"ProtocolMin": 0,
|
||||
"ProtocolMax": 3,
|
||||
"ProtocolCur": 2,
|
||||
"DelegateMin": 0,
|
||||
"DelegateMax": 1,
|
||||
"DelegateCur": 1,
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### members-wan
|
||||
|
||||
This command is used to return all the known WAN members and associated
|
||||
information. Only agents in server mode will respond to this command.
|
||||
|
||||
There is no request body, and the response is the same as `members-lan`
|
||||
|
||||
### monitor
|
||||
|
||||
The monitor command subscribes the channel to log messages from the Agent.
|
||||
|
||||
The request looks like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"LogLevel": "DEBUG"
|
||||
}
|
||||
```
|
||||
|
||||
This subscribes the client to all messages of at least DEBUG level.
|
||||
|
||||
The server will respond with a standard response header indicating if the monitor
|
||||
was successful. If so, any future logs will be sent and tagged with
|
||||
the same `Seq` as in the `monitor` request.
|
||||
|
||||
Assume we issued the previous monitor command with `"Seq": 50`. We may start
|
||||
getting messages like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Seq": 50,
|
||||
"Error": ""
|
||||
}
|
||||
|
||||
{
|
||||
"Log": "2013/12/03 13:06:53 [INFO] agent: Received event: member-join"
|
||||
}
|
||||
```
|
||||
|
||||
It is important to realize that these messages are sent asynchronously
|
||||
and not in response to any command. If a client is streaming
|
||||
commands, there may be logs streamed while a client is waiting for a
|
||||
response to a command. This is why the `Seq` must be used to pair requests
|
||||
with their corresponding responses.
|
||||
|
||||
The client can only be subscribed to at most a single monitor instance.
|
||||
To stop streaming, the `stop` command is used.
|
||||
|
||||
### stop
|
||||
|
||||
This command stops a monitor.
|
||||
|
||||
The request looks like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Stop": 50
|
||||
}
|
||||
```
|
||||
|
||||
This unsubscribes the client from the monitor with `Seq` value of 50.
|
||||
|
||||
There is no response body.
|
||||
|
||||
### leave
|
||||
|
||||
This command is used to trigger a graceful leave and shutdown.
|
||||
There is no request body or response body.
|
||||
|
||||
### stats
|
||||
|
||||
This command provides debug information. There is no request body, and the
|
||||
response body looks like:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"agent": {
|
||||
"check_monitors": 0,
|
||||
...
|
||||
},
|
||||
"consul: {
|
||||
"server": "true",
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### reload
|
||||
|
||||
This command is used to trigger a reload of configurations.
|
||||
There is no request body or response body.
|
Loading…
Reference in new issue