Merge branch 'main' into southworks/qa-consul

pull/17694/head
Ashesh Vidyut 1 year ago committed by GitHub
commit 74de240902
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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,3 +1,76 @@
## 1.16.0 (June 26, 2023)
BREAKING CHANGES:
* api: The `/v1/health/connect/` and `/v1/health/ingress/` endpoints now immediately return 403 "Permission Denied" errors whenever a token with insufficient `service:read` permissions is provided. Prior to this change, the endpoints returned a success code with an empty result list when a token with insufficient permissions was provided. [[GH-17424](https://github.com/hashicorp/consul/issues/17424)]
* peering: Removed deprecated backward-compatibility behavior.
Upstream overrides in service-defaults will now only apply to peer upstreams when the `peer` field is provided.
Visit the 1.16.x [upgrade instructions](https://developer.hashicorp.com/consul/docs/upgrading/upgrade-specific) for more information. [[GH-16957](https://github.com/hashicorp/consul/issues/16957)]
SECURITY:
* Bump Dockerfile base image to `alpine:3.18`. [[GH-17719](https://github.com/hashicorp/consul/issues/17719)]
* audit-logging: **(Enterprise only)** limit `v1/operator/audit-hash` endpoint to ACL token with `operator:read` privileges.
FEATURES:
* api: (Enterprise only) Add `POST /v1/operator/audit-hash` endpoint to calculate the hash of the data used by the audit log hash function and salt.
* cli: (Enterprise only) Add a new `consul operator audit hash` command to retrieve and compare the hash of the data used by the audit log hash function and salt.
* cli: Adds new command - `consul services export` - for exporting a service to a peer or partition [[GH-15654](https://github.com/hashicorp/consul/issues/15654)]
* connect: **(Consul Enterprise only)** Implement order-by-locality failover.
* mesh: Add new permissive mTLS mode that allows sidecar proxies to forward incoming traffic unmodified to the application. This adds `AllowEnablingPermissiveMutualTLS` setting to the mesh config entry and the `MutualTLSMode` setting to proxy-defaults and service-defaults. [[GH-17035](https://github.com/hashicorp/consul/issues/17035)]
* mesh: Support configuring JWT authentication in Envoy. [[GH-17452](https://github.com/hashicorp/consul/issues/17452)]
* server: **(Enterprise Only)** added server side RPC requests IP based read/write rate-limiter. [[GH-4633](https://github.com/hashicorp/consul/issues/4633)]
* server: **(Enterprise Only)** allow automatic license utilization reporting. [[GH-5102](https://github.com/hashicorp/consul/issues/5102)]
* server: added server side RPC requests global read/write rate-limiter. [[GH-16292](https://github.com/hashicorp/consul/issues/16292)]
* xds: Add `property-override` built-in Envoy extension that directly patches Envoy resources. [[GH-17487](https://github.com/hashicorp/consul/issues/17487)]
* xds: Add a built-in Envoy extension that inserts External Authorization (ext_authz) network and HTTP filters. [[GH-17495](https://github.com/hashicorp/consul/issues/17495)]
* xds: Add a built-in Envoy extension that inserts Wasm HTTP filters. [[GH-16877](https://github.com/hashicorp/consul/issues/16877)]
* xds: Add a built-in Envoy extension that inserts Wasm network filters. [[GH-17505](https://github.com/hashicorp/consul/issues/17505)]
IMPROVEMENTS:
* * api: Support filtering for config entries. [[GH-17183](https://github.com/hashicorp/consul/issues/17183)]
* * cli: Add `-filter` option to `consul config list` for filtering config entries. [[GH-17183](https://github.com/hashicorp/consul/issues/17183)]
* agent: remove agent cache dependency from service mesh leaf certificate management [[GH-17075](https://github.com/hashicorp/consul/issues/17075)]
* api: Enable setting query options on agent force-leave endpoint. [[GH-15987](https://github.com/hashicorp/consul/issues/15987)]
* audit-logging: **(Enterprise only)** enable error response and request body logging
* ca: automatically set up Vault's auto-tidy setting for tidy_expired_issuers when using Vault as a CA provider. [[GH-17138](https://github.com/hashicorp/consul/issues/17138)]
* ca: support Vault agent auto-auth config for Vault CA provider using AliCloud authentication. [[GH-16224](https://github.com/hashicorp/consul/issues/16224)]
* ca: support Vault agent auto-auth config for Vault CA provider using AppRole authentication. [[GH-16259](https://github.com/hashicorp/consul/issues/16259)]
* ca: support Vault agent auto-auth config for Vault CA provider using Azure MSI authentication. [[GH-16298](https://github.com/hashicorp/consul/issues/16298)]
* ca: support Vault agent auto-auth config for Vault CA provider using JWT authentication. [[GH-16266](https://github.com/hashicorp/consul/issues/16266)]
* ca: support Vault agent auto-auth config for Vault CA provider using Kubernetes authentication. [[GH-16262](https://github.com/hashicorp/consul/issues/16262)]
* command: Adds ACL enabled to status output on agent startup. [[GH-17086](https://github.com/hashicorp/consul/issues/17086)]
* command: Allow creating ACL Token TTL with greater than 24 hours with the -expires-ttl flag. [[GH-17066](https://github.com/hashicorp/consul/issues/17066)]
* connect: **(Enterprise Only)** Add support for specifying "Partition" and "Namespace" in Prepared Queries failover rules.
* connect: update supported envoy versions to 1.23.10, 1.24.8, 1.25.7, 1.26.2 [[GH-17546](https://github.com/hashicorp/consul/issues/17546)]
* connect: update supported envoy versions to 1.23.8, 1.24.6, 1.25.4, 1.26.0 [[GH-5200](https://github.com/hashicorp/consul/issues/5200)]
* fix metric names in /docs/agent/telemetry [[GH-17577](https://github.com/hashicorp/consul/issues/17577)]
* gateway: Change status condition reason for invalid certificate on a listener from "Accepted" to "ResolvedRefs". [[GH-17115](https://github.com/hashicorp/consul/issues/17115)]
* http: accept query parameters `datacenter`, `ap` (enterprise-only), and `namespace` (enterprise-only). Both short-hand and long-hand forms of these query params are now supported via the HTTP API (dc/datacenter, ap/partition, ns/namespace). [[GH-17525](https://github.com/hashicorp/consul/issues/17525)]
* systemd: set service type to notify. [[GH-16845](https://github.com/hashicorp/consul/issues/16845)]
* ui: Update alerts to Hds::Alert component [[GH-16412](https://github.com/hashicorp/consul/issues/16412)]
* ui: Update to use Hds::Toast component to show notifications [[GH-16519](https://github.com/hashicorp/consul/issues/16519)]
* ui: update from <button> and <a> to design-system-components button <Hds::Button> [[GH-16251](https://github.com/hashicorp/consul/issues/16251)]
* ui: update typography to styles from hds [[GH-16577](https://github.com/hashicorp/consul/issues/16577)]
BUG FIXES:
* Fix a race condition where an event is published before the data associated is commited to memdb. [[GH-16871](https://github.com/hashicorp/consul/issues/16871)]
* connect: Fix issue where changes to service exports were not reflected in proxies. [[GH-17775](https://github.com/hashicorp/consul/issues/17775)]
* gateways: **(Enterprise only)** Fixed a bug in API gateways where gateway configuration objects in non-default partitions did not reconcile properly. [[GH-17581](https://github.com/hashicorp/consul/issues/17581)]
* gateways: Fixed a bug in API gateways where binding a route that only targets a service imported from a peer results
in the programmed gateway having no routes. [[GH-17609](https://github.com/hashicorp/consul/issues/17609)]
* gateways: Fixed a bug where API gateways were not being taken into account in determining xDS rate limits. [[GH-17631](https://github.com/hashicorp/consul/issues/17631)]
* namespaces: **(Enterprise only)** fixes a bug where agent health checks stop syncing for all services on a node if the namespace of any service has been removed from the server.
* namespaces: **(Enterprise only)** fixes a bug where namespaces are stuck in a deferred deletion state indefinitely under some conditions.
Also fixes the Consul query metadata present in the HTTP headers of the namespace read and list endpoints.
* peering: Fix a bug that caused server agents to continue cleaning up peering resources even after loss of leadership. [[GH-17483](https://github.com/hashicorp/consul/issues/17483)]
* peering: Fixes a bug where the importing partition was not added to peered failover targets, which causes issues when the importing partition is a non-default partition. [[GH-16673](https://github.com/hashicorp/consul/issues/16673)]
* ui: fixes ui tests run on CI [[GH-16428](https://github.com/hashicorp/consul/issues/16428)]
* xds: Fixed a bug where modifying ACLs on a token being actively used for an xDS connection caused all xDS updates to fail. [[GH-17566](https://github.com/hashicorp/consul/issues/17566)]
## 1.15.4 (June 26, 2023) ## 1.15.4 (June 26, 2023)
FEATURES: FEATURES:

@ -19,6 +19,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/armon/go-metrics" "github.com/armon/go-metrics"
@ -415,6 +416,8 @@ type Agent struct {
// enterpriseAgent embeds fields that we only access in consul-enterprise builds // enterpriseAgent embeds fields that we only access in consul-enterprise builds
enterpriseAgent enterpriseAgent
enableDebug atomic.Bool
} }
// New process the desired options and creates a new Agent. // New process the desired options and creates a new Agent.
@ -597,6 +600,8 @@ func (a *Agent) Start(ctx context.Context) error {
// Overwrite the configuration. // Overwrite the configuration.
a.config = c a.config = c
a.enableDebug.Store(c.EnableDebug)
if err := a.tlsConfigurator.Update(a.config.TLS); err != nil { if err := a.tlsConfigurator.Update(a.config.TLS); err != nil {
return fmt.Errorf("Failed to load TLS configurations after applying auto-config settings: %w", err) return fmt.Errorf("Failed to load TLS configurations after applying auto-config settings: %w", err)
} }
@ -1126,13 +1131,13 @@ func (a *Agent) listenHTTP() ([]apiServer, error) {
httpServer := &http.Server{ httpServer := &http.Server{
Addr: l.Addr().String(), Addr: l.Addr().String(),
TLSConfig: tlscfg, TLSConfig: tlscfg,
Handler: srv.handler(a.config.EnableDebug), Handler: srv.handler(),
MaxHeaderBytes: a.config.HTTPMaxHeaderBytes, MaxHeaderBytes: a.config.HTTPMaxHeaderBytes,
} }
if scada.IsCapability(l.Addr()) { if scada.IsCapability(l.Addr()) {
// wrap in http2 server handler // wrap in http2 server handler
httpServer.Handler = h2c.NewHandler(srv.handler(a.config.EnableDebug), &http2.Server{}) httpServer.Handler = h2c.NewHandler(srv.handler(), &http2.Server{})
} }
// Load the connlimit helper into the server // Load the connlimit helper into the server
@ -4290,6 +4295,9 @@ func (a *Agent) reloadConfigInternal(newCfg *config.RuntimeConfig) error {
a.proxyConfig.SetUpdateRateLimit(newCfg.XDSUpdateRateLimit) a.proxyConfig.SetUpdateRateLimit(newCfg.XDSUpdateRateLimit)
a.enableDebug.Store(newCfg.EnableDebug)
a.config.EnableDebug = newCfg.EnableDebug
return nil return nil
} }

@ -1623,7 +1623,7 @@ func TestHTTPHandlers_AgentMetricsStream_ACLDeny(t *testing.T) {
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil)
require.NoError(t, err) require.NoError(t, err)
handle := h.handler(false) handle := h.handler()
handle.ServeHTTP(resp, req) handle.ServeHTTP(resp, req)
require.Equal(t, http.StatusForbidden, resp.Code) require.Equal(t, http.StatusForbidden, resp.Code)
require.Contains(t, resp.Body.String(), "Permission denied") require.Contains(t, resp.Body.String(), "Permission denied")
@ -1660,7 +1660,7 @@ func TestHTTPHandlers_AgentMetricsStream(t *testing.T) {
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil)
require.NoError(t, err) require.NoError(t, err)
handle := h.handler(false) handle := h.handler()
handle.ServeHTTP(resp, req) handle.ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code) require.Equal(t, http.StatusOK, resp.Code)
@ -6008,8 +6008,10 @@ func TestAgent_Monitor(t *testing.T) {
cancelCtx, cancelFunc := context.WithCancel(context.Background()) cancelCtx, cancelFunc := context.WithCancel(context.Background())
req = req.WithContext(cancelCtx) req = req.WithContext(cancelCtx)
a.enableDebug.Store(true)
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
handler := a.srv.handler(true) handler := a.srv.handler()
go handler.ServeHTTP(resp, req) go handler.ServeHTTP(resp, req)
args := &structs.ServiceDefinition{ args := &structs.ServiceDefinition{

@ -4193,6 +4193,39 @@ func TestAgent_ReloadConfig_XDSUpdateRateLimit(t *testing.T) {
require.Equal(t, rate.Limit(1000), a.proxyConfig.UpdateRateLimit()) require.Equal(t, rate.Limit(1000), a.proxyConfig.UpdateRateLimit())
} }
func TestAgent_ReloadConfig_EnableDebug(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
cfg := fmt.Sprintf(`data_dir = %q`, testutil.TempDir(t, "agent"))
a := NewTestAgent(t, cfg)
defer a.Shutdown()
c := TestConfig(
testutil.Logger(t),
config.FileSource{
Name: t.Name(),
Format: "hcl",
Data: cfg + ` enable_debug = true`,
},
)
require.NoError(t, a.reloadConfigInternal(c))
require.Equal(t, true, a.enableDebug.Load())
c = TestConfig(
testutil.Logger(t),
config.FileSource{
Name: t.Name(),
Format: "hcl",
Data: cfg + ` enable_debug = false`,
},
)
require.NoError(t, a.reloadConfigInternal(c))
require.Equal(t, false, a.enableDebug.Load())
}
func TestAgent_consulConfig_AutoEncryptAllowTLS(t *testing.T) { func TestAgent_consulConfig_AutoEncryptAllowTLS(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("too slow for testing.Short") t.Skip("too slow for testing.Short")

@ -324,8 +324,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
rt.DevMode = true rt.DevMode = true
rt.DisableAnonymousSignature = true rt.DisableAnonymousSignature = true
rt.DisableKeyringFile = true rt.DisableKeyringFile = true
rt.EnableDebug = true
rt.Experiments = []string{"resource-apis"} rt.Experiments = []string{"resource-apis"}
rt.EnableDebug = true
rt.UIConfig.Enabled = true rt.UIConfig.Enabled = true
rt.LeaveOnTerm = false rt.LeaveOnTerm = false
rt.Logging.LogLevel = "DEBUG" rt.Logging.LogLevel = "DEBUG"

@ -735,7 +735,9 @@ func shouldPersistNewRootAndConfig(newActiveRoot *structs.CARoot, oldConfig, new
if newConfig == nil { if newConfig == nil {
return false return false
} }
return newConfig.Provider == oldConfig.Provider && reflect.DeepEqual(newConfig.Config, oldConfig.Config)
// Do not persist if the new provider and config are the same as the old
return !(newConfig.Provider == oldConfig.Provider && reflect.DeepEqual(newConfig.Config, oldConfig.Config))
} }
func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error) { func (c *CAManager) UpdateConfiguration(args *structs.CARequest) (reterr error) {

@ -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
}

@ -11,7 +11,6 @@ import (
awslambda "github.com/hashicorp/consul/agent/envoyextensions/builtin/aws-lambda" awslambda "github.com/hashicorp/consul/agent/envoyextensions/builtin/aws-lambda"
extauthz "github.com/hashicorp/consul/agent/envoyextensions/builtin/ext-authz" extauthz "github.com/hashicorp/consul/agent/envoyextensions/builtin/ext-authz"
"github.com/hashicorp/consul/agent/envoyextensions/builtin/http/localratelimit"
"github.com/hashicorp/consul/agent/envoyextensions/builtin/lua" "github.com/hashicorp/consul/agent/envoyextensions/builtin/lua"
propertyoverride "github.com/hashicorp/consul/agent/envoyextensions/builtin/property-override" propertyoverride "github.com/hashicorp/consul/agent/envoyextensions/builtin/property-override"
"github.com/hashicorp/consul/agent/envoyextensions/builtin/wasm" "github.com/hashicorp/consul/agent/envoyextensions/builtin/wasm"
@ -24,7 +23,6 @@ type extensionConstructor func(api.EnvoyExtension) (extensioncommon.EnvoyExtende
var extensionConstructors = map[string]extensionConstructor{ var extensionConstructors = map[string]extensionConstructor{
api.BuiltinLuaExtension: lua.Constructor, api.BuiltinLuaExtension: lua.Constructor,
api.BuiltinAWSLambdaExtension: awslambda.Constructor, api.BuiltinAWSLambdaExtension: awslambda.Constructor,
api.BuiltinLocalRatelimitExtension: localratelimit.Constructor,
api.BuiltinPropertyOverrideExtension: propertyoverride.Constructor, api.BuiltinPropertyOverrideExtension: propertyoverride.Constructor,
api.BuiltinWasmExtension: wasm.Constructor, api.BuiltinWasmExtension: wasm.Constructor,
api.BuiltinExtAuthzExtension: extauthz.Constructor, api.BuiltinExtAuthzExtension: extauthz.Constructor,

@ -167,7 +167,7 @@ func (s *HTTPHandlers) ReloadConfig(newCfg *config.RuntimeConfig) error {
// //
// The first call must not be concurrent with any other call. Subsequent calls // The first call must not be concurrent with any other call. Subsequent calls
// may be concurrent with HTTP requests since no state is modified. // may be concurrent with HTTP requests since no state is modified.
func (s *HTTPHandlers) handler(enableDebug bool) http.Handler { func (s *HTTPHandlers) handler() http.Handler {
// Memoize multiple calls. // Memoize multiple calls.
if s.h != nil { if s.h != nil {
return s.h return s.h
@ -210,7 +210,15 @@ func (s *HTTPHandlers) handler(enableDebug bool) http.Handler {
// handlePProf takes the given pattern and pprof handler // handlePProf takes the given pattern and pprof handler
// and wraps it to add authorization and metrics // and wraps it to add authorization and metrics
handlePProf := func(pattern string, handler http.HandlerFunc) { handlePProf := func(pattern string, handler http.HandlerFunc) {
wrapper := func(resp http.ResponseWriter, req *http.Request) { wrapper := func(resp http.ResponseWriter, req *http.Request) {
// If enableDebug register wrapped pprof handlers
if !s.agent.enableDebug.Load() && s.checkACLDisabled() {
resp.WriteHeader(http.StatusNotFound)
return
}
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
@ -245,14 +253,11 @@ func (s *HTTPHandlers) handler(enableDebug bool) http.Handler {
handleFuncMetrics(pattern, s.wrap(bound, methods)) handleFuncMetrics(pattern, s.wrap(bound, methods))
} }
// If enableDebug or ACL enabled, register wrapped pprof handlers handlePProf("/debug/pprof/", pprof.Index)
if enableDebug || !s.checkACLDisabled() { handlePProf("/debug/pprof/cmdline", pprof.Cmdline)
handlePProf("/debug/pprof/", pprof.Index) handlePProf("/debug/pprof/profile", pprof.Profile)
handlePProf("/debug/pprof/cmdline", pprof.Cmdline) handlePProf("/debug/pprof/symbol", pprof.Symbol)
handlePProf("/debug/pprof/profile", pprof.Profile) handlePProf("/debug/pprof/trace", pprof.Trace)
handlePProf("/debug/pprof/symbol", pprof.Symbol)
handlePProf("/debug/pprof/trace", pprof.Trace)
}
if s.IsUIEnabled() { if s.IsUIEnabled() {
// Note that we _don't_ support reloading ui_config.{enabled, content_dir, // Note that we _don't_ support reloading ui_config.{enabled, content_dir,

@ -144,7 +144,8 @@ func TestHTTPAPI_OptionMethod_OSS(t *testing.T) {
uri := fmt.Sprintf("http://%s%s", a.HTTPAddr(), path) uri := fmt.Sprintf("http://%s%s", a.HTTPAddr(), path)
req, _ := http.NewRequest("OPTIONS", uri, nil) req, _ := http.NewRequest("OPTIONS", uri, nil)
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
allMethods := append([]string{"OPTIONS"}, methods...) allMethods := append([]string{"OPTIONS"}, methods...)
if resp.Code != http.StatusOK { if resp.Code != http.StatusOK {
@ -190,7 +191,9 @@ func TestHTTPAPI_AllowedNets_OSS(t *testing.T) {
req, _ := http.NewRequest(method, uri, nil) req, _ := http.NewRequest(method, uri, nil)
req.RemoteAddr = "192.168.1.2:5555" req.RemoteAddr = "192.168.1.2:5555"
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
require.Equal(t, http.StatusForbidden, resp.Code, "%s %s", method, path) require.Equal(t, http.StatusForbidden, resp.Code, "%s %s", method, path)
}) })

@ -288,7 +288,9 @@ func TestSetupHTTPServer_HTTP2(t *testing.T) {
err = setupHTTPS(httpServer, noopConnState, time.Second) err = setupHTTPS(httpServer, noopConnState, time.Second)
require.NoError(t, err) require.NoError(t, err)
srvHandler := a.srv.handler(true) a.enableDebug.Store(true)
srvHandler := a.srv.handler()
mux, ok := srvHandler.(*wrappedMux) mux, ok := srvHandler.(*wrappedMux)
require.True(t, ok, "expected a *wrappedMux, got %T", handler) require.True(t, ok, "expected a *wrappedMux, got %T", handler)
mux.mux.HandleFunc("/echo", handler) mux.mux.HandleFunc("/echo", handler)
@ -483,7 +485,9 @@ func TestHTTPAPI_Ban_Nonprintable_Characters(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
if got, want := resp.Code, http.StatusBadRequest; got != want { if got, want := resp.Code, http.StatusBadRequest; got != want {
t.Fatalf("bad response code got %d want %d", got, want) t.Fatalf("bad response code got %d want %d", got, want)
} }
@ -506,7 +510,9 @@ func TestHTTPAPI_Allow_Nonprintable_Characters_With_Flag(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
// Key doesn't actually exist so we should get 404 // Key doesn't actually exist so we should get 404
if got, want := resp.Code, http.StatusNotFound; got != want { if got, want := resp.Code, http.StatusNotFound; got != want {
t.Fatalf("bad response code got %d want %d", got, want) t.Fatalf("bad response code got %d want %d", got, want)
@ -645,7 +651,9 @@ func requireHasHeadersSet(t *testing.T, a *TestAgent, path string) {
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
req, _ := http.NewRequest("GET", path, nil) req, _ := http.NewRequest("GET", path, nil)
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
hdrs := resp.Header() hdrs := resp.Header()
require.Equal(t, "*", hdrs.Get("Access-Control-Allow-Origin"), require.Equal(t, "*", hdrs.Get("Access-Control-Allow-Origin"),
@ -706,14 +714,18 @@ func TestAcceptEncodingGzip(t *testing.T) {
// negotiation, but since this call doesn't go through a real // negotiation, but since this call doesn't go through a real
// transport, the header has to be set manually // transport, the header has to be set manually
req.Header["Accept-Encoding"] = []string{"gzip"} req.Header["Accept-Encoding"] = []string{"gzip"}
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
require.Equal(t, 200, resp.Code) require.Equal(t, 200, resp.Code)
require.Equal(t, "", resp.Header().Get("Content-Encoding")) require.Equal(t, "", resp.Header().Get("Content-Encoding"))
resp = httptest.NewRecorder() resp = httptest.NewRecorder()
req, _ = http.NewRequest("GET", "/v1/kv/long", nil) req, _ = http.NewRequest("GET", "/v1/kv/long", nil)
req.Header["Accept-Encoding"] = []string{"gzip"} req.Header["Accept-Encoding"] = []string{"gzip"}
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
require.Equal(t, 200, resp.Code) require.Equal(t, 200, resp.Code)
require.Equal(t, "gzip", resp.Header().Get("Content-Encoding")) require.Equal(t, "gzip", resp.Header().Get("Content-Encoding"))
} }
@ -1068,8 +1080,9 @@ func TestHTTPServer_PProfHandlers_EnableDebug(t *testing.T) {
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/debug/pprof/profile?seconds=1", nil) req, _ := http.NewRequest("GET", "/debug/pprof/profile?seconds=1", nil)
a.enableDebug.Store(true)
httpServer := &HTTPHandlers{agent: a.Agent} httpServer := &HTTPHandlers{agent: a.Agent}
httpServer.handler(true).ServeHTTP(resp, req) httpServer.handler().ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code) require.Equal(t, http.StatusOK, resp.Code)
} }
@ -1087,7 +1100,7 @@ func TestHTTPServer_PProfHandlers_DisableDebugNoACLs(t *testing.T) {
req, _ := http.NewRequest("GET", "/debug/pprof/profile", nil) req, _ := http.NewRequest("GET", "/debug/pprof/profile", nil)
httpServer := &HTTPHandlers{agent: a.Agent} httpServer := &HTTPHandlers{agent: a.Agent}
httpServer.handler(false).ServeHTTP(resp, req) httpServer.handler().ServeHTTP(resp, req)
require.Equal(t, http.StatusNotFound, resp.Code) require.Equal(t, http.StatusNotFound, resp.Code)
} }
@ -1168,7 +1181,9 @@ func TestHTTPServer_PProfHandlers_ACLs(t *testing.T) {
t.Run(fmt.Sprintf("case %d (%#v)", i, c), func(t *testing.T) { t.Run(fmt.Sprintf("case %d (%#v)", i, c), func(t *testing.T) {
req, _ := http.NewRequest("GET", fmt.Sprintf("%s?token=%s", c.endpoint, c.token), nil) req, _ := http.NewRequest("GET", fmt.Sprintf("%s?token=%s", c.endpoint, c.token), nil)
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
assert.Equal(t, c.code, resp.Code) assert.Equal(t, c.code, resp.Code)
}) })
} }
@ -1478,7 +1493,9 @@ func TestEnableWebUI(t *testing.T) {
req, _ := http.NewRequest("GET", "/ui/", nil) req, _ := http.NewRequest("GET", "/ui/", nil)
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code) require.Equal(t, http.StatusOK, resp.Code)
// Validate that it actually sent the index page we expect since an error // Validate that it actually sent the index page we expect since an error
@ -1507,7 +1524,9 @@ func TestEnableWebUI(t *testing.T) {
{ {
req, _ := http.NewRequest("GET", "/ui/", nil) req, _ := http.NewRequest("GET", "/ui/", nil)
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
a.srv.handler(true).ServeHTTP(resp, req) a.enableDebug.Store(true)
a.srv.handler().ServeHTTP(resp, req)
require.Equal(t, http.StatusOK, resp.Code) require.Equal(t, http.StatusOK, resp.Code)
require.Contains(t, resp.Body.String(), `<!-- CONSUL_VERSION:`) require.Contains(t, resp.Body.String(), `<!-- CONSUL_VERSION:`)
require.Contains(t, resp.Body.String(), `valid-but-unlikely-metrics-provider-name`) require.Contains(t, resp.Body.String(), `valid-but-unlikely-metrics-provider-name`)

@ -574,7 +574,7 @@ func (e *ProxyConfigEntry) UnmarshalBinary(data []byte) error {
// into a concrete type. // into a concrete type.
// //
// There is an 'api' variation of this in // There is an 'api' variation of this in
// command/config/write/config_write.go:newDecodeConfigEntry // command/helpers/helpers.go:newDecodeConfigEntry
func DecodeConfigEntry(raw map[string]interface{}) (ConfigEntry, error) { func DecodeConfigEntry(raw map[string]interface{}) (ConfigEntry, error) {
var entry ConfigEntry var entry ConfigEntry

@ -58,7 +58,9 @@ func TestUIEndpoint_MetricsProxy_ACLDeny(t *testing.T) {
`, backendURL)) `, backendURL))
defer a.Shutdown() defer a.Shutdown()
h := a.srv.handler(true) a.enableDebug.Store(true)
h := a.srv.handler()
testrpc.WaitForLeader(t, a.RPC, "dc1") testrpc.WaitForLeader(t, a.RPC, "dc1")

@ -2620,7 +2620,9 @@ func TestUIEndpoint_MetricsProxy(t *testing.T) {
require.NoError(t, a.Agent.reloadConfigInternal(&cfg)) require.NoError(t, a.Agent.reloadConfigInternal(&cfg))
// Now fetch the API handler to run requests against // Now fetch the API handler to run requests against
h := a.srv.handler(true) a.enableDebug.Store(true)
h := a.srv.handler()
req := httptest.NewRequest("GET", tc.path, nil) req := httptest.NewRequest("GET", tc.path, nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()

@ -6,6 +6,8 @@ package xds
import ( import (
"errors" "errors"
"fmt" "fmt"
"net/url"
"strconv"
"strings" "strings"
"time" "time"
@ -141,6 +143,22 @@ func (s *ResourceGenerator) clustersFromSnapshotConnectProxy(cfgSnap *proxycfg.C
clusters = append(clusters, upstreamCluster) clusters = append(clusters, upstreamCluster)
} }
// add clusters for jwt-providers
for _, prov := range cfgSnap.JWTProviders {
//skip cluster creation for local providers
if prov.JSONWebKeySet == nil || prov.JSONWebKeySet.Remote == nil {
continue
}
cluster, err := makeJWTProviderCluster(prov)
if err != nil {
s.Logger.Warn("failed to make jwt-provider cluster", "provider name", prov.Name, "error", err)
continue
}
clusters = append(clusters, cluster)
}
for _, u := range cfgSnap.Proxy.Upstreams { for _, u := range cfgSnap.Proxy.Upstreams {
if u.DestinationType != structs.UpstreamDestTypePreparedQuery { if u.DestinationType != structs.UpstreamDestTypePreparedQuery {
continue continue
@ -184,6 +202,82 @@ func (s *ResourceGenerator) clustersFromSnapshotConnectProxy(cfgSnap *proxycfg.C
return clusters, nil return clusters, nil
} }
func makeJWTProviderCluster(p *structs.JWTProviderConfigEntry) (*envoy_cluster_v3.Cluster, error) {
if p.JSONWebKeySet == nil || p.JSONWebKeySet.Remote == nil {
return nil, fmt.Errorf("cannot create JWKS cluster for non-remote JWKS. Provider Name: %s", p.Name)
}
hostname, scheme, port, err := parseJWTRemoteURL(p.JSONWebKeySet.Remote.URI)
if err != nil {
return nil, err
}
// TODO: expose additional fields: eg. ConnectTimeout, through
// JWTProviderConfigEntry to allow user to configure cluster
cluster := &envoy_cluster_v3.Cluster{
Name: makeJWKSClusterName(p.Name),
ClusterDiscoveryType: &envoy_cluster_v3.Cluster_Type{
Type: envoy_cluster_v3.Cluster_STRICT_DNS,
},
LoadAssignment: &envoy_endpoint_v3.ClusterLoadAssignment{
ClusterName: makeJWKSClusterName(p.Name),
Endpoints: []*envoy_endpoint_v3.LocalityLbEndpoints{
{
LbEndpoints: []*envoy_endpoint_v3.LbEndpoint{
makeEndpoint(hostname, port),
},
},
},
},
}
if scheme == "https" {
// TODO: expose this configuration through JWTProviderConfigEntry to allow
// user to configure certs
jwksTLSContext, err := makeUpstreamTLSTransportSocket(
&envoy_tls_v3.UpstreamTlsContext{
CommonTlsContext: &envoy_tls_v3.CommonTlsContext{
ValidationContextType: &envoy_tls_v3.CommonTlsContext_ValidationContext{
ValidationContext: &envoy_tls_v3.CertificateValidationContext{},
},
},
},
)
if err != nil {
return nil, err
}
cluster.TransportSocket = jwksTLSContext
}
return cluster, nil
}
// parseJWTRemoteURL splits the URI into domain, scheme and port.
// It will default to port 80 for http and 443 for https for any
// URI that does not specify a port.
func parseJWTRemoteURL(uri string) (string, string, int, error) {
u, err := url.ParseRequestURI(uri)
if err != nil {
return "", "", 0, err
}
var port int
if u.Port() != "" {
port, err = strconv.Atoi(u.Port())
if err != nil {
return "", "", port, err
}
}
if port == 0 {
port = 80
if u.Scheme == "https" {
port = 443
}
}
return u.Hostname(), u.Scheme, port, nil
}
func makeExposeClusterName(destinationPort int) string { func makeExposeClusterName(destinationPort int) string {
return fmt.Sprintf("exposed_cluster_%d", destinationPort) return fmt.Sprintf("exposed_cluster_%d", destinationPort)
} }

@ -959,6 +959,185 @@ func TestEnvoyLBConfig_InjectToCluster(t *testing.T) {
} }
} }
func TestMakeJWTProviderCluster(t *testing.T) {
// All tests here depend on golden files located under: agent/xds/testdata/jwt_authn_cluster/*
tests := map[string]struct {
provider *structs.JWTProviderConfigEntry
expectedError string
}{
"remote-jwks-not-configured": {
provider: &structs.JWTProviderConfigEntry{
Kind: "jwt-provider",
Name: "okta",
JSONWebKeySet: &structs.JSONWebKeySet{},
},
expectedError: "cannot create JWKS cluster for non remote JWKS. Provider Name: okta",
},
"local-jwks-configured": {
provider: &structs.JWTProviderConfigEntry{
Kind: "jwt-provider",
Name: "okta",
JSONWebKeySet: &structs.JSONWebKeySet{
Local: &structs.LocalJWKS{
Filename: "filename",
},
},
},
expectedError: "cannot create JWKS cluster for non remote JWKS. Provider Name: okta",
},
"https-provider-with-hostname-no-port": {
provider: makeTestProviderWithJWKS("https://example-okta.com/.well-known/jwks.json"),
},
"http-provider-with-hostname-no-port": {
provider: makeTestProviderWithJWKS("http://example-okta.com/.well-known/jwks.json"),
},
"https-provider-with-hostname-and-port": {
provider: makeTestProviderWithJWKS("https://example-okta.com:90/.well-known/jwks.json"),
},
"http-provider-with-hostname-and-port": {
provider: makeTestProviderWithJWKS("http://example-okta.com:90/.well-known/jwks.json"),
},
"https-provider-with-ip-no-port": {
provider: makeTestProviderWithJWKS("https://127.0.0.1"),
},
"http-provider-with-ip-no-port": {
provider: makeTestProviderWithJWKS("http://127.0.0.1"),
},
"https-provider-with-ip-and-port": {
provider: makeTestProviderWithJWKS("https://127.0.0.1:9091"),
},
"http-provider-with-ip-and-port": {
provider: makeTestProviderWithJWKS("http://127.0.0.1:9091"),
},
}
for name, tt := range tests {
tt := tt
t.Run(name, func(t *testing.T) {
cluster, err := makeJWTProviderCluster(tt.provider)
if tt.expectedError != "" {
require.Error(t, err, tt.expectedError)
} else {
require.NoError(t, err)
gotJSON := protoToJSON(t, cluster)
require.JSONEq(t, goldenSimple(t, filepath.Join("jwt_authn_clusters", name), gotJSON), gotJSON)
}
})
}
}
func makeTestProviderWithJWKS(uri string) *structs.JWTProviderConfigEntry {
return &structs.JWTProviderConfigEntry{
Kind: "jwt-provider",
Name: "okta",
Issuer: "test-issuer",
JSONWebKeySet: &structs.JSONWebKeySet{
Remote: &structs.RemoteJWKS{
RequestTimeoutMs: 1000,
FetchAsynchronously: true,
URI: uri,
},
},
}
}
func TestParseJWTRemoteURL(t *testing.T) {
tests := map[string]struct {
uri string
expectedHost string
expectedPort int
expectedScheme string
expectError bool
}{
"invalid-url": {
uri: ".com",
expectError: true,
},
"https-hostname-no-port": {
uri: "https://test.test.com",
expectedHost: "test.test.com",
expectedPort: 443,
expectedScheme: "https",
},
"https-hostname-with-port": {
uri: "https://test.test.com:4545",
expectedHost: "test.test.com",
expectedPort: 4545,
expectedScheme: "https",
},
"https-hostname-with-port-and-path": {
uri: "https://test.test.com:4545/test",
expectedHost: "test.test.com",
expectedPort: 4545,
expectedScheme: "https",
},
"http-hostname-no-port": {
uri: "http://test.test.com",
expectedHost: "test.test.com",
expectedPort: 80,
expectedScheme: "http",
},
"http-hostname-with-port": {
uri: "http://test.test.com:4636",
expectedHost: "test.test.com",
expectedPort: 4636,
expectedScheme: "http",
},
"https-ip-no-port": {
uri: "https://127.0.0.1",
expectedHost: "127.0.0.1",
expectedPort: 443,
expectedScheme: "https",
},
"https-ip-with-port": {
uri: "https://127.0.0.1:3434",
expectedHost: "127.0.0.1",
expectedPort: 3434,
expectedScheme: "https",
},
"http-ip-no-port": {
uri: "http://127.0.0.1",
expectedHost: "127.0.0.1",
expectedPort: 80,
expectedScheme: "http",
},
"http-ip-with-port": {
uri: "http://127.0.0.1:9190",
expectedHost: "127.0.0.1",
expectedPort: 9190,
expectedScheme: "http",
},
"http-ip-with-port-and-path": {
uri: "http://127.0.0.1:9190/some/where",
expectedHost: "127.0.0.1",
expectedPort: 9190,
expectedScheme: "http",
},
"http-ip-no-port-with-path": {
uri: "http://127.0.0.1/test/path",
expectedHost: "127.0.0.1",
expectedPort: 80,
expectedScheme: "http",
},
}
for name, tt := range tests {
tt := tt
t.Run(name, func(t *testing.T) {
host, scheme, port, err := parseJWTRemoteURL(tt.uri)
if tt.expectError {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, host, tt.expectedHost)
require.Equal(t, scheme, tt.expectedScheme)
require.Equal(t, port, tt.expectedPort)
}
})
}
}
// UID is just a convenience function to aid in writing tests less verbosely. // UID is just a convenience function to aid in writing tests less verbosely.
func UID(input string) proxycfg.UpstreamID { func UID(input string) proxycfg.UpstreamID {
return proxycfg.UpstreamIDFromString(input) return proxycfg.UpstreamIDFromString(input)

@ -15,13 +15,14 @@ import (
envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
"github.com/hashicorp/consul/agent/xds/testcommon"
"github.com/hashicorp/go-hclog" "github.com/hashicorp/go-hclog"
goversion "github.com/hashicorp/go-version" goversion "github.com/hashicorp/go-version"
testinf "github.com/mitchellh/go-testing-interface" testinf "github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"github.com/hashicorp/consul/agent/xds/testcommon"
propertyoverride "github.com/hashicorp/consul/agent/envoyextensions/builtin/property-override" propertyoverride "github.com/hashicorp/consul/agent/envoyextensions/builtin/property-override"
"github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
@ -579,27 +580,6 @@ end`,
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nsFunc, nil, makeLambdaServiceDefaults(true)) return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nsFunc, nil, makeLambdaServiceDefaults(true))
}, },
}, },
{
name: "http-local-ratelimit-applyto-filter",
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) {
ns.Proxy.Config["protocol"] = "http"
ns.Proxy.EnvoyExtensions = []structs.EnvoyExtension{
{
Name: api.BuiltinLocalRatelimitExtension,
Arguments: map[string]interface{}{
"ProxyType": "connect-proxy",
"MaxTokens": 3,
"TokensPerFill": 2,
"FillInterval": 10,
"FilterEnabled": 100,
"FilterEnforced": 100,
},
},
}
}, nil)
},
},
{ {
name: "wasm-http-local-file", name: "wasm-http-local-file",
create: func(t testinf.T) *proxycfg.ConfigSnapshot { create: func(t testinf.T) *proxycfg.ConfigSnapshot {

@ -19,6 +19,7 @@ import (
const ( const (
jwtEnvoyFilter = "envoy.filters.http.jwt_authn" jwtEnvoyFilter = "envoy.filters.http.jwt_authn"
jwtMetadataKeyPrefix = "jwt_payload" jwtMetadataKeyPrefix = "jwt_payload"
jwksClusterPrefix = "jwks_cluster"
) )
// This is an intermediate JWTProvider form used to associate // This is an intermediate JWTProvider form used to associate
@ -158,7 +159,7 @@ func buildJWTProviderConfig(p *structs.JWTProviderConfigEntry, metadataKeySuffix
} }
envoyCfg.JwksSourceSpecifier = specifier envoyCfg.JwksSourceSpecifier = specifier
} else if remote := p.JSONWebKeySet.Remote; remote != nil && remote.URI != "" { } else if remote := p.JSONWebKeySet.Remote; remote != nil && remote.URI != "" {
envoyCfg.JwksSourceSpecifier = makeRemoteJWKS(remote) envoyCfg.JwksSourceSpecifier = makeRemoteJWKS(remote, p.Name)
} else { } else {
return nil, fmt.Errorf("invalid jwt provider config; missing JSONWebKeySet for provider: %s", p.Name) return nil, fmt.Errorf("invalid jwt provider config; missing JSONWebKeySet for provider: %s", p.Name)
} }
@ -210,14 +211,12 @@ func makeLocalJWKS(l *structs.LocalJWKS, pName string) (*envoy_http_jwt_authn_v3
return specifier, nil return specifier, nil
} }
func makeRemoteJWKS(r *structs.RemoteJWKS) *envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks { func makeRemoteJWKS(r *structs.RemoteJWKS, providerName string) *envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks {
remote_specifier := envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks{ remote_specifier := envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks{
RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{ RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{
HttpUri: &envoy_core_v3.HttpUri{ HttpUri: &envoy_core_v3.HttpUri{
Uri: r.URI, Uri: r.URI,
// TODO(roncodingenthusiast): An explicit cluster is required. HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: makeJWKSClusterName(providerName)},
// Need to figure out replacing `jwks_cluster` will an actual cluster
HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: "jwks_cluster"},
}, },
AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{ AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{
FastListener: r.FetchAsynchronously, FastListener: r.FetchAsynchronously,
@ -239,6 +238,10 @@ func makeRemoteJWKS(r *structs.RemoteJWKS) *envoy_http_jwt_authn_v3.JwtProvider_
return &remote_specifier return &remote_specifier
} }
func makeJWKSClusterName(providerName string) string {
return fmt.Sprintf("%s_%s", jwksClusterPrefix, providerName)
}
func buildJWTRetryPolicy(r *structs.JWKSRetryPolicy) *envoy_core_v3.RetryPolicy { func buildJWTRetryPolicy(r *structs.JWKSRetryPolicy) *envoy_core_v3.RetryPolicy {
var pol envoy_core_v3.RetryPolicy var pol envoy_core_v3.RetryPolicy
if r == nil { if r == nil {

@ -438,7 +438,7 @@ func TestBuildJWTProviderConfig(t *testing.T) {
RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{ RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{
HttpUri: &envoy_core_v3.HttpUri{ HttpUri: &envoy_core_v3.HttpUri{
Uri: oktaRemoteJWKS.URI, Uri: oktaRemoteJWKS.URI,
HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: "jwks_cluster"}, HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: makeJWKSClusterName(ceRemoteJWKS.Name)},
Timeout: &durationpb.Duration{Seconds: 1}, Timeout: &durationpb.Duration{Seconds: 1},
}, },
AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{ AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{
@ -520,16 +520,18 @@ func TestMakeLocalJWKS(t *testing.T) {
func TestMakeRemoteJWKS(t *testing.T) { func TestMakeRemoteJWKS(t *testing.T) {
tests := map[string]struct { tests := map[string]struct {
jwks *structs.RemoteJWKS jwks *structs.RemoteJWKS
expected *envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks providerName string
expected *envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks
}{ }{
"with-no-cache-duration": { "with-no-cache-duration": {
jwks: oktaRemoteJWKS, jwks: oktaRemoteJWKS,
providerName: "auth0",
expected: &envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks{ expected: &envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks{
RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{ RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{
HttpUri: &envoy_core_v3.HttpUri{ HttpUri: &envoy_core_v3.HttpUri{
Uri: oktaRemoteJWKS.URI, Uri: oktaRemoteJWKS.URI,
HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: "jwks_cluster"}, HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: makeJWKSClusterName("auth0")},
Timeout: &durationpb.Duration{Seconds: 1}, Timeout: &durationpb.Duration{Seconds: 1},
}, },
AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{ AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{
@ -539,12 +541,13 @@ func TestMakeRemoteJWKS(t *testing.T) {
}, },
}, },
"with-retry-policy": { "with-retry-policy": {
jwks: extendedRemoteJWKS, jwks: extendedRemoteJWKS,
providerName: "okta",
expected: &envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks{ expected: &envoy_http_jwt_authn_v3.JwtProvider_RemoteJwks{
RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{ RemoteJwks: &envoy_http_jwt_authn_v3.RemoteJwks{
HttpUri: &envoy_core_v3.HttpUri{ HttpUri: &envoy_core_v3.HttpUri{
Uri: oktaRemoteJWKS.URI, Uri: oktaRemoteJWKS.URI,
HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: "jwks_cluster"}, HttpUpstreamType: &envoy_core_v3.HttpUri_Cluster{Cluster: makeJWKSClusterName("okta")},
Timeout: &durationpb.Duration{Seconds: 1}, Timeout: &durationpb.Duration{Seconds: 1},
}, },
AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{ AsyncFetch: &envoy_http_jwt_authn_v3.JwksAsyncFetch{
@ -560,7 +563,7 @@ func TestMakeRemoteJWKS(t *testing.T) {
for name, tt := range tests { for name, tt := range tests {
tt := tt tt := tt
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
res := makeRemoteJWKS(tt.jwks) res := makeRemoteJWKS(tt.jwks, tt.providerName)
require.Equal(t, res, tt.expected) require.Equal(t, res, tt.expected)
}) })
} }

@ -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"
}

@ -9,7 +9,7 @@
"remoteJwks": { "remoteJwks": {
"httpUri": { "httpUri": {
"uri": "https://example-okta.com/.well-known/jwks.json", "uri": "https://example-okta.com/.well-known/jwks.json",
"cluster": "jwks_cluster", "cluster": "jwks_cluster_okta",
"timeout": "1s" "timeout": "1s"
}, },
"asyncFetch": { "asyncFetch": {

@ -9,7 +9,7 @@
"remoteJwks": { "remoteJwks": {
"httpUri": { "httpUri": {
"uri": "https://example-okta.com/.well-known/jwks.json", "uri": "https://example-okta.com/.well-known/jwks.json",
"cluster": "jwks_cluster", "cluster": "jwks_cluster_okta",
"timeout": "1s" "timeout": "1s"
}, },
"asyncFetch": { "asyncFetch": {
@ -23,7 +23,7 @@
"remoteJwks": { "remoteJwks": {
"httpUri": { "httpUri": {
"uri": "https://example-okta.com/.well-known/jwks.json", "uri": "https://example-okta.com/.well-known/jwks.json",
"cluster": "jwks_cluster", "cluster": "jwks_cluster_okta",
"timeout": "1s" "timeout": "1s"
}, },
"asyncFetch": { "asyncFetch": {
@ -37,7 +37,7 @@
"remoteJwks": { "remoteJwks": {
"httpUri": { "httpUri": {
"uri": "https://example-auth0.com/.well-known/jwks.json", "uri": "https://example-auth0.com/.well-known/jwks.json",
"cluster": "jwks_cluster", "cluster": "jwks_cluster_auth0",
"timeout": "1s" "timeout": "1s"
}, },
"asyncFetch": { "asyncFetch": {

@ -9,7 +9,7 @@
"remoteJwks": { "remoteJwks": {
"httpUri": { "httpUri": {
"uri": "https://example-okta.com/.well-known/jwks.json", "uri": "https://example-okta.com/.well-known/jwks.json",
"cluster": "jwks_cluster", "cluster": "jwks_cluster_okta",
"timeout": "1s" "timeout": "1s"
}, },
"asyncFetch": { "asyncFetch": {

@ -9,7 +9,7 @@
"remoteJwks": { "remoteJwks": {
"httpUri": { "httpUri": {
"uri": "https://example-okta.com/.well-known/jwks.json", "uri": "https://example-okta.com/.well-known/jwks.json",
"cluster": "jwks_cluster", "cluster": "jwks_cluster_okta",
"timeout": "1s" "timeout": "1s"
}, },
"asyncFetch": { "asyncFetch": {
@ -23,7 +23,7 @@
"remoteJwks": { "remoteJwks": {
"httpUri": { "httpUri": {
"uri": "https://example-okta.com/.well-known/jwks.json", "uri": "https://example-okta.com/.well-known/jwks.json",
"cluster": "jwks_cluster", "cluster": "jwks_cluster_okta",
"timeout": "1s" "timeout": "1s"
}, },
"asyncFetch": { "asyncFetch": {

@ -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"
}

@ -42,7 +42,6 @@ const (
BuiltinAWSLambdaExtension string = "builtin/aws/lambda" BuiltinAWSLambdaExtension string = "builtin/aws/lambda"
BuiltinExtAuthzExtension string = "builtin/ext-authz" BuiltinExtAuthzExtension string = "builtin/ext-authz"
BuiltinLuaExtension string = "builtin/lua" BuiltinLuaExtension string = "builtin/lua"
BuiltinLocalRatelimitExtension string = "builtin/http/localratelimit"
BuiltinPropertyOverrideExtension string = "builtin/property-override" BuiltinPropertyOverrideExtension string = "builtin/property-override"
BuiltinWasmExtension string = "builtin/wasm" BuiltinWasmExtension string = "builtin/wasm"
// BuiltinValidateExtension should not be exposed directly or accepted as a valid configured // BuiltinValidateExtension should not be exposed directly or accepted as a valid configured

@ -7,17 +7,12 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
"time"
"github.com/hashicorp/go-multierror"
"github.com/mitchellh/cli" "github.com/mitchellh/cli"
"github.com/mitchellh/mapstructure"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/command/config" "github.com/hashicorp/consul/command/config"
"github.com/hashicorp/consul/command/flags" "github.com/hashicorp/consul/command/flags"
"github.com/hashicorp/consul/command/helpers" "github.com/hashicorp/consul/command/helpers"
"github.com/hashicorp/consul/lib/decode"
) )
func New(ui cli.Ui) *cmd { func New(ui cli.Ui) *cmd {
@ -109,67 +104,6 @@ func (c *cmd) Run(args []string) int {
return 0 return 0
} }
// There is a 'structs' variation of this in
// agent/structs/config_entry.go:DecodeConfigEntry
func newDecodeConfigEntry(raw map[string]interface{}) (api.ConfigEntry, error) {
var entry api.ConfigEntry
kindVal, ok := raw["Kind"]
if !ok {
kindVal, ok = raw["kind"]
}
if !ok {
return nil, fmt.Errorf("Payload does not contain a kind/Kind key at the top level")
}
if kindStr, ok := kindVal.(string); ok {
newEntry, err := api.MakeConfigEntry(kindStr, "")
if err != nil {
return nil, err
}
entry = newEntry
} else {
return nil, fmt.Errorf("Kind value in payload is not a string")
}
var md mapstructure.Metadata
decodeConf := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.ComposeDecodeHookFunc(
decode.HookWeakDecodeFromSlice,
decode.HookTranslateKeys,
mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToTimeHookFunc(time.RFC3339),
),
Metadata: &md,
Result: &entry,
WeaklyTypedInput: true,
}
decoder, err := mapstructure.NewDecoder(decodeConf)
if err != nil {
return nil, err
}
if err := decoder.Decode(raw); err != nil {
return nil, err
}
for _, k := range md.Unused {
switch k {
case "kind", "Kind":
// The kind field is used to determine the target, but doesn't need
// to exist on the target.
continue
}
err = multierror.Append(err, fmt.Errorf("invalid config key %q", k))
}
if err != nil {
return nil, err
}
return entry, nil
}
func (c *cmd) Synopsis() string { func (c *cmd) Synopsis() string {
return synopsis return synopsis
} }

@ -23,50 +23,50 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
) )
type BalanceInboundConnections int32 type BalanceConnections int32
const ( const (
// buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX
BalanceInboundConnections_BALANCE_INBOUND_CONNECTIONS_DEFAULT BalanceInboundConnections = 0 BalanceConnections_BALANCE_CONNECTIONS_DEFAULT BalanceConnections = 0
BalanceInboundConnections_BALANCE_INBOUND_CONNECTIONS_EXACT BalanceInboundConnections = 1 BalanceConnections_BALANCE_CONNECTIONS_EXACT BalanceConnections = 1
) )
// Enum value maps for BalanceInboundConnections. // Enum value maps for BalanceConnections.
var ( var (
BalanceInboundConnections_name = map[int32]string{ BalanceConnections_name = map[int32]string{
0: "BALANCE_INBOUND_CONNECTIONS_DEFAULT", 0: "BALANCE_CONNECTIONS_DEFAULT",
1: "BALANCE_INBOUND_CONNECTIONS_EXACT", 1: "BALANCE_CONNECTIONS_EXACT",
} }
BalanceInboundConnections_value = map[string]int32{ BalanceConnections_value = map[string]int32{
"BALANCE_INBOUND_CONNECTIONS_DEFAULT": 0, "BALANCE_CONNECTIONS_DEFAULT": 0,
"BALANCE_INBOUND_CONNECTIONS_EXACT": 1, "BALANCE_CONNECTIONS_EXACT": 1,
} }
) )
func (x BalanceInboundConnections) Enum() *BalanceInboundConnections { func (x BalanceConnections) Enum() *BalanceConnections {
p := new(BalanceInboundConnections) p := new(BalanceConnections)
*p = x *p = x
return p return p
} }
func (x BalanceInboundConnections) String() string { func (x BalanceConnections) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
} }
func (BalanceInboundConnections) Descriptor() protoreflect.EnumDescriptor { func (BalanceConnections) Descriptor() protoreflect.EnumDescriptor {
return file_pbmesh_v1alpha1_connection_proto_enumTypes[0].Descriptor() return file_pbmesh_v1alpha1_connection_proto_enumTypes[0].Descriptor()
} }
func (BalanceInboundConnections) Type() protoreflect.EnumType { func (BalanceConnections) Type() protoreflect.EnumType {
return &file_pbmesh_v1alpha1_connection_proto_enumTypes[0] return &file_pbmesh_v1alpha1_connection_proto_enumTypes[0]
} }
func (x BalanceInboundConnections) Number() protoreflect.EnumNumber { func (x BalanceConnections) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x) return protoreflect.EnumNumber(x)
} }
// Deprecated: Use BalanceInboundConnections.Descriptor instead. // Deprecated: Use BalanceConnections.Descriptor instead.
func (BalanceInboundConnections) EnumDescriptor() ([]byte, []int) { func (BalanceConnections) EnumDescriptor() ([]byte, []int) {
return file_pbmesh_v1alpha1_connection_proto_rawDescGZIP(), []int{0} return file_pbmesh_v1alpha1_connection_proto_rawDescGZIP(), []int{0}
} }
@ -130,8 +130,8 @@ type InboundConnectionsConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
MaxInboundConnections uint64 `protobuf:"varint,12,opt,name=max_inbound_connections,json=maxInboundConnections,proto3" json:"max_inbound_connections,omitempty"` MaxInboundConnections uint64 `protobuf:"varint,12,opt,name=max_inbound_connections,json=maxInboundConnections,proto3" json:"max_inbound_connections,omitempty"`
BalanceInboundConnections BalanceInboundConnections `protobuf:"varint,13,opt,name=balance_inbound_connections,json=balanceInboundConnections,proto3,enum=hashicorp.consul.mesh.v1alpha1.BalanceInboundConnections" json:"balance_inbound_connections,omitempty"` BalanceInboundConnections BalanceConnections `protobuf:"varint,13,opt,name=balance_inbound_connections,json=balanceInboundConnections,proto3,enum=hashicorp.consul.mesh.v1alpha1.BalanceConnections" json:"balance_inbound_connections,omitempty"`
} }
func (x *InboundConnectionsConfig) Reset() { func (x *InboundConnectionsConfig) Reset() {
@ -173,11 +173,11 @@ func (x *InboundConnectionsConfig) GetMaxInboundConnections() uint64 {
return 0 return 0
} }
func (x *InboundConnectionsConfig) GetBalanceInboundConnections() BalanceInboundConnections { func (x *InboundConnectionsConfig) GetBalanceInboundConnections() BalanceConnections {
if x != nil { if x != nil {
return x.BalanceInboundConnections return x.BalanceInboundConnections
} }
return BalanceInboundConnections_BALANCE_INBOUND_CONNECTIONS_DEFAULT return BalanceConnections_BALANCE_CONNECTIONS_DEFAULT
} }
var File_pbmesh_v1alpha1_connection_proto protoreflect.FileDescriptor var File_pbmesh_v1alpha1_connection_proto protoreflect.FileDescriptor
@ -194,45 +194,43 @@ var file_pbmesh_v1alpha1_connection_proto_rawDesc = []byte{
0x75, 0x74, 0x4d, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x75, 0x74, 0x4d, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f,
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
0x4d, 0x73, 0x22, 0xcd, 0x01, 0x0a, 0x18, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x4d, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x18, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x36, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x36, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04,
0x52, 0x15, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x52, 0x15, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x79, 0x0a, 0x1b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x72, 0x0a, 0x1b, 0x62, 0x61, 0x6c, 0x61, 0x6e,
0x63, 0x65, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x68, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x68,
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e,
0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x61, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x61,
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x19, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x19, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2a, 0x54, 0x0a, 0x12, 0x42,
0x6e, 0x73, 0x2a, 0x6b, 0x0a, 0x19, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x73, 0x12, 0x1f, 0x0a, 0x1b, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e,
0x27, 0x0a, 0x23, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x49, 0x4e, 0x42, 0x4f, 0x55, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54,
0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, 0x4f,
0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x25, 0x0a, 0x21, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x45, 0x58, 0x41, 0x43, 0x54, 0x10,
0x4e, 0x43, 0x45, 0x5f, 0x49, 0x4e, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x01, 0x42, 0x97, 0x02, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x45, 0x58, 0x41, 0x43, 0x54, 0x10, 0x01, 0x42, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e,
0x97, 0x02, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x67, 0x69, 0x74,
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x6d, 0x65, 0x73, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,
0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x4d, 0xaa, 0x02, 0x1e, 0x48, 0x61, 0x73, 0x68, 0x69,
0x68, 0x61, 0x31, 0x3b, 0x6d, 0x65, 0x73, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, 0x65, 0x73, 0x68,
0xa2, 0x02, 0x03, 0x48, 0x43, 0x4d, 0xaa, 0x02, 0x1e, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x1e, 0x48, 0x61, 0x73, 0x68,
0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x2e, 0x56, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73,
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x1e, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x68, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x2a, 0x48, 0x61, 0x73,
0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65,
0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x2a, 0x48, 0x61, 0x73, 0x68, 0x69, 0x73, 0x68, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d,
0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x21, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63,
0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x4d, 0x65, 0x73,
0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x21, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x68, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x68, 0x3a, 0x74, 0x6f, 0x33,
0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
} }
var ( var (
@ -250,12 +248,12 @@ func file_pbmesh_v1alpha1_connection_proto_rawDescGZIP() []byte {
var file_pbmesh_v1alpha1_connection_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_pbmesh_v1alpha1_connection_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_pbmesh_v1alpha1_connection_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_pbmesh_v1alpha1_connection_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_pbmesh_v1alpha1_connection_proto_goTypes = []interface{}{ var file_pbmesh_v1alpha1_connection_proto_goTypes = []interface{}{
(BalanceInboundConnections)(0), // 0: hashicorp.consul.mesh.v1alpha1.BalanceInboundConnections (BalanceConnections)(0), // 0: hashicorp.consul.mesh.v1alpha1.BalanceConnections
(*ConnectionConfig)(nil), // 1: hashicorp.consul.mesh.v1alpha1.ConnectionConfig (*ConnectionConfig)(nil), // 1: hashicorp.consul.mesh.v1alpha1.ConnectionConfig
(*InboundConnectionsConfig)(nil), // 2: hashicorp.consul.mesh.v1alpha1.InboundConnectionsConfig (*InboundConnectionsConfig)(nil), // 2: hashicorp.consul.mesh.v1alpha1.InboundConnectionsConfig
} }
var file_pbmesh_v1alpha1_connection_proto_depIdxs = []int32{ var file_pbmesh_v1alpha1_connection_proto_depIdxs = []int32{
0, // 0: hashicorp.consul.mesh.v1alpha1.InboundConnectionsConfig.balance_inbound_connections:type_name -> hashicorp.consul.mesh.v1alpha1.BalanceInboundConnections 0, // 0: hashicorp.consul.mesh.v1alpha1.InboundConnectionsConfig.balance_inbound_connections:type_name -> hashicorp.consul.mesh.v1alpha1.BalanceConnections
1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension type_name

@ -12,11 +12,11 @@ message ConnectionConfig {
message InboundConnectionsConfig { message InboundConnectionsConfig {
uint64 max_inbound_connections = 12; uint64 max_inbound_connections = 12;
BalanceInboundConnections balance_inbound_connections = 13; BalanceConnections balance_inbound_connections = 13;
} }
enum BalanceInboundConnections { enum BalanceConnections {
// buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX // buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX
BALANCE_INBOUND_CONNECTIONS_DEFAULT = 0; BALANCE_CONNECTIONS_DEFAULT = 0;
BALANCE_INBOUND_CONNECTIONS_EXACT = 1; BALANCE_CONNECTIONS_EXACT = 1;
} }

@ -432,11 +432,11 @@ type UpstreamConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
ConnectTimeoutMs uint64 `protobuf:"varint,2,opt,name=connect_timeout_ms,json=connectTimeoutMs,proto3" json:"connect_timeout_ms,omitempty"` ConnectTimeoutMs uint64 `protobuf:"varint,2,opt,name=connect_timeout_ms,json=connectTimeoutMs,proto3" json:"connect_timeout_ms,omitempty"`
Limits *UpstreamLimits `protobuf:"bytes,3,opt,name=limits,proto3" json:"limits,omitempty"` Limits *UpstreamLimits `protobuf:"bytes,3,opt,name=limits,proto3" json:"limits,omitempty"`
PassiveHealthCheck *PassiveHealthCheck `protobuf:"bytes,4,opt,name=passive_health_check,json=passiveHealthCheck,proto3" json:"passive_health_check,omitempty"` PassiveHealthCheck *PassiveHealthCheck `protobuf:"bytes,4,opt,name=passive_health_check,json=passiveHealthCheck,proto3" json:"passive_health_check,omitempty"`
BalanceInboundConnections BalanceInboundConnections `protobuf:"varint,5,opt,name=balance_inbound_connections,json=balanceInboundConnections,proto3,enum=hashicorp.consul.mesh.v1alpha1.BalanceInboundConnections" json:"balance_inbound_connections,omitempty"` BalanceOutboundConnections BalanceConnections `protobuf:"varint,5,opt,name=balance_outbound_connections,json=balanceOutboundConnections,proto3,enum=hashicorp.consul.mesh.v1alpha1.BalanceConnections" json:"balance_outbound_connections,omitempty"`
MeshGatewayMode MeshGatewayMode `protobuf:"varint,6,opt,name=mesh_gateway_mode,json=meshGatewayMode,proto3,enum=hashicorp.consul.mesh.v1alpha1.MeshGatewayMode" json:"mesh_gateway_mode,omitempty"` MeshGatewayMode MeshGatewayMode `protobuf:"varint,6,opt,name=mesh_gateway_mode,json=meshGatewayMode,proto3,enum=hashicorp.consul.mesh.v1alpha1.MeshGatewayMode" json:"mesh_gateway_mode,omitempty"`
} }
func (x *UpstreamConfig) Reset() { func (x *UpstreamConfig) Reset() {
@ -492,11 +492,11 @@ func (x *UpstreamConfig) GetPassiveHealthCheck() *PassiveHealthCheck {
return nil return nil
} }
func (x *UpstreamConfig) GetBalanceInboundConnections() BalanceInboundConnections { func (x *UpstreamConfig) GetBalanceOutboundConnections() BalanceConnections {
if x != nil { if x != nil {
return x.BalanceInboundConnections return x.BalanceOutboundConnections
} }
return BalanceInboundConnections_BALANCE_INBOUND_CONNECTIONS_DEFAULT return BalanceConnections_BALANCE_CONNECTIONS_DEFAULT
} }
func (x *UpstreamConfig) GetMeshGatewayMode() MeshGatewayMode { func (x *UpstreamConfig) GetMeshGatewayMode() MeshGatewayMode {
@ -740,7 +740,7 @@ var file_pbmesh_v1alpha1_upstreams_proto_rawDesc = []byte{
0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x70,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x75, 0x70,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x0d, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x0d, 0x0a, 0x0b,
0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x22, 0xc4, 0x03, 0x0a, 0x0e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x22, 0xbf, 0x03, 0x0a, 0x0e,
0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c,
0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e,
@ -755,60 +755,60 @@ var file_pbmesh_v1alpha1_upstreams_proto_rawDesc = []byte{
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70,
0x68, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74,
0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x12, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x12, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48,
0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x79, 0x0a, 0x1b, 0x62, 0x61, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x74, 0x0a, 0x1c, 0x62, 0x61,
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e,
0x39, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x32, 0x32, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x19, 0x62, 0x61, 0x6c, 0x61,
0x6e, 0x63, 0x65, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5b, 0x0a, 0x11, 0x6d, 0x65, 0x73, 0x68, 0x5f, 0x67, 0x61,
0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x2f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
0x31, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x31, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
0x65, 0x52, 0x0f, 0x6d, 0x65, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x1a, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x4f, 0x75, 0x74,
0x64, 0x65, 0x22, 0xa3, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x12, 0x5b, 0x0a, 0x11, 0x6d, 0x65, 0x73, 0x68, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x68, 0x61,
0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30,
0x0a, 0x14, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x6d, 0x61,
0x78, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73,
0x12, 0x36, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65,
0x6e, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x05, 0x52, 0x15, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0xaa, 0x01, 0x0a, 0x12, 0x50, 0x61, 0x73,
0x73, 0x69, 0x76, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12,
0x35, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x61,
0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6d, 0x61,
0x78, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x65, 0x6e, 0x66,
0x6f, 0x72, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69,
0x76, 0x65, 0x5f, 0x35, 0x78, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x65, 0x6e,
0x66, 0x6f, 0x72, 0x63, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69,
0x76, 0x65, 0x35, 0x78, 0x78, 0x42, 0x96, 0x02, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d,
0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0e, 0x55, 0x70, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4d, 0x65, 0x73,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0f, 0x6d, 0x65,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x73, 0x68, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0xa3, 0x01,
0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x0a, 0x0e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73,
0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x6d, 0x65, 0x73, 0x68, 0x76, 0x31, 0x61, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x6f,
0x6c, 0x70, 0x68, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x4d, 0xaa, 0x02, 0x1e, 0x48, 0x61, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x6d, 0x61, 0x78,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x65, 0x73, 0x68, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x1e, 0x48, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x6d, 0x61, 0x78, 0x50, 0x65, 0x6e, 0x64,
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x6d,
0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x2a, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65,
0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x6d, 0x61,
0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x21, 0x48, 0x61, 0x73, 0x73, 0x74, 0x73, 0x22, 0xaa, 0x01, 0x0a, 0x12, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x48,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x08, 0x69, 0x6e,
0x4d, 0x65, 0x73, 0x68, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x46, 0x61, 0x69, 0x6c,
0x75, 0x72, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x69, 0x6e,
0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x35, 0x78,
0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x69,
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x35, 0x78, 0x78,
0x42, 0x96, 0x02, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76,
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70,
0x68, 0x61, 0x31, 0x3b, 0x6d, 0x65, 0x73, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
0xa2, 0x02, 0x03, 0x48, 0x43, 0x4d, 0xaa, 0x02, 0x1e, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x2e, 0x56,
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x1e, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c,
0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x2a, 0x48, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68,
0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x21, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x68, 0x3a,
0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
} }
var ( var (
@ -835,7 +835,7 @@ var file_pbmesh_v1alpha1_upstreams_proto_goTypes = []interface{}{
(*PassiveHealthCheck)(nil), // 7: hashicorp.consul.mesh.v1alpha1.PassiveHealthCheck (*PassiveHealthCheck)(nil), // 7: hashicorp.consul.mesh.v1alpha1.PassiveHealthCheck
(*v1alpha1.WorkloadSelector)(nil), // 8: hashicorp.consul.catalog.v1alpha1.WorkloadSelector (*v1alpha1.WorkloadSelector)(nil), // 8: hashicorp.consul.catalog.v1alpha1.WorkloadSelector
(*pbresource.ID)(nil), // 9: hashicorp.consul.resource.ID (*pbresource.ID)(nil), // 9: hashicorp.consul.resource.ID
(BalanceInboundConnections)(0), // 10: hashicorp.consul.mesh.v1alpha1.BalanceInboundConnections (BalanceConnections)(0), // 10: hashicorp.consul.mesh.v1alpha1.BalanceConnections
(MeshGatewayMode)(0), // 11: hashicorp.consul.mesh.v1alpha1.MeshGatewayMode (MeshGatewayMode)(0), // 11: hashicorp.consul.mesh.v1alpha1.MeshGatewayMode
(*durationpb.Duration)(nil), // 12: google.protobuf.Duration (*durationpb.Duration)(nil), // 12: google.protobuf.Duration
} }
@ -853,7 +853,7 @@ var file_pbmesh_v1alpha1_upstreams_proto_depIdxs = []int32{
5, // 10: hashicorp.consul.mesh.v1alpha1.PreparedQueryUpstream.upstream_config:type_name -> hashicorp.consul.mesh.v1alpha1.UpstreamConfig 5, // 10: hashicorp.consul.mesh.v1alpha1.PreparedQueryUpstream.upstream_config:type_name -> hashicorp.consul.mesh.v1alpha1.UpstreamConfig
6, // 11: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.limits:type_name -> hashicorp.consul.mesh.v1alpha1.UpstreamLimits 6, // 11: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.limits:type_name -> hashicorp.consul.mesh.v1alpha1.UpstreamLimits
7, // 12: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.passive_health_check:type_name -> hashicorp.consul.mesh.v1alpha1.PassiveHealthCheck 7, // 12: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.passive_health_check:type_name -> hashicorp.consul.mesh.v1alpha1.PassiveHealthCheck
10, // 13: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.balance_inbound_connections:type_name -> hashicorp.consul.mesh.v1alpha1.BalanceInboundConnections 10, // 13: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.balance_outbound_connections:type_name -> hashicorp.consul.mesh.v1alpha1.BalanceConnections
11, // 14: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.mesh_gateway_mode:type_name -> hashicorp.consul.mesh.v1alpha1.MeshGatewayMode 11, // 14: hashicorp.consul.mesh.v1alpha1.UpstreamConfig.mesh_gateway_mode:type_name -> hashicorp.consul.mesh.v1alpha1.MeshGatewayMode
12, // 15: hashicorp.consul.mesh.v1alpha1.PassiveHealthCheck.interval:type_name -> google.protobuf.Duration 12, // 15: hashicorp.consul.mesh.v1alpha1.PassiveHealthCheck.interval:type_name -> google.protobuf.Duration
16, // [16:16] is the sub-list for method output_type 16, // [16:16] is the sub-list for method output_type

@ -61,7 +61,7 @@ message UpstreamConfig {
uint64 connect_timeout_ms = 2; uint64 connect_timeout_ms = 2;
UpstreamLimits limits = 3; UpstreamLimits limits = 3;
PassiveHealthCheck passive_health_check = 4; PassiveHealthCheck passive_health_check = 4;
BalanceInboundConnections balance_inbound_connections = 5; BalanceConnections balance_outbound_connections = 5;
MeshGatewayMode mesh_gateway_mode = 6; MeshGatewayMode mesh_gateway_mode = 6;
} }

@ -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
}

@ -222,8 +222,7 @@ The table below shows this endpoint's support for
| `YES` <sup>1</sup> | `all` | `background refresh` | `node:read,service:read` | | `YES` <sup>1</sup> | `all` | `background refresh` | `node:read,service:read` |
<p> <p>
<sup>1</sup>some query parameters will use the <sup>1</sup>some query parameters will use the <a href="/consul/api-docs/features/blocking#streaming-backend">streaming backend</a> for blocking queries.
<a href="/api/features/blocking#streaming-backend">streaming backend</a>
</p> </p>
### Path Parameters ### Path Parameters

@ -22,8 +22,13 @@ For nodes in server mode, the node is removed from the Raft peer set
in a graceful manner. This is critical, as in certain situations a in a graceful manner. This is critical, as in certain situations a
non-graceful leave can affect cluster availability. non-graceful leave can affect cluster availability.
Running `consul leave` on a server explicitly will reduce the quorum size. Even if the cluster used `bootstrap_expect` to set a quorum size initially, issuing `consul leave` on a server will reconfigure the cluster to have fewer servers. Depending on how many Consul servers are running, running `consul leave` on a server explicitly can reduce the quorum
This means you could end up with just one server that is still able to commit writes because quorum is only 1, but those writes might be lost if that server fails before more are added. size (which is derived from the number of Consul servers, see
[deployment_table](/consul/docs/architecture/consensus#deployment_table)).
Even if the cluster used `bootstrap_expect` to set a number of servers and thus quorum size initially,
issuing `consul leave` on a server will reconfigure the cluster to have fewer servers.
This means you could end up with just one server that is still able to commit writes because the quorum size for
1-server setup is only 1, but those writes might be lost if that server fails before more are added.
The table below shows this command's [required ACLs](/consul/api-docs/api-structure#authentication). Configuration of The table below shows this command's [required ACLs](/consul/api-docs/api-structure#authentication). Configuration of
[blocking queries](/consul/api-docs/features/blocking) and [agent caching](/consul/api-docs/features/caching) [blocking queries](/consul/api-docs/features/blocking) and [agent caching](/consul/api-docs/features/caching)

@ -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.

@ -22,11 +22,11 @@ Configure your [`Gateway`](/consul/docs/api-gateway/configuration/gateway) and [
<CodeBlockConfig hideClipboard filename="values.yaml"> <CodeBlockConfig hideClipboard filename="values.yaml">
```yaml ```yaml
apiGateway: apiGateway:
enabled: true enabled: true
managedGatewayClass: managedGatewayClass:
``` ```
</CodeBlockConfig> </CodeBlockConfig>
@ -34,9 +34,9 @@ Configure your [`Gateway`](/consul/docs/api-gateway/configuration/gateway) and [
Issue the `kubectl apply` command to implement the configurations: Issue the `kubectl apply` command to implement the configurations:
```shell-session ```shell-session
$ kubectl apply -f gateway.yaml routes.yaml $ kubectl apply -f gateway.yaml routes.yaml
``` ```
<!--- Commented out per https://github.com/hashicorp/consul/pull/11951/files#r791204596 <!--- Commented out per https://github.com/hashicorp/consul/pull/11951/files#r791204596

@ -182,6 +182,60 @@ spec:
] ]
``` ```
</CodeTabs>
</Tab>
<Tab heading="Consul Enterprise (Sameness Group)">
<CodeTabs heading="Exported services configuration syntax" tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
```hcl
Kind = "exported-services"
Partition = "<partition containing services to export>"
Name = "<partition containing services to export>"
Services = [
{
Name = "<name of service to export>"
Namespace = "<namespace in the partition containing the service to export>"
Consumers = [
{
SamenessGroup = "<name of the sameness group that dials the exported service>"
}
]
}
]
```
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ExportedServices
metadata:
name: <partition containing services to export>
spec:
services:
- name: <name of service to export>
namespace: <namespace in the partition containing the service to export>
consumers:
- samenessGroup: <name of the sameness group that dials the exported service>
```
```json
"Kind": "exported-services",
"Partition": "<partition containing services to export>",
"Name": "<partition containing services to export>",
"Services": [
{
"Name": "<name of service to export>",
"Namespace": "<namespace in the partition containing the service to export>"
"Consumers": [
{
"SamenessGroup": "<name of the sameness group that dials the exported service>"
}
]
}
]
```
</CodeTabs> </CodeTabs>
</Tab> </Tab>
</Tabs> </Tabs>
@ -456,6 +510,57 @@ spec:
</Tab> </Tab>
</Tabs> </Tabs>
### Exporting a service to a sameness group
The following example configures Consul to export a service named `api` to a defined group of partitions that belong to a separately defined [sameness group](/consul/docs/connect/config-entries/sameness-group) named `monitoring`.
<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>
```hcl
Kind = "exported-services"
Name = "default"
Services = [
{
Name = "api"
Consumers = [
{
SamenessGroup = "monitoring"
}
]
}
]
```
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
Kind: ExportedServices
metadata:
name: default
spec:
services:
- name: api
consumers:
- samenessGroup: monitoring
```
```json
"Kind": "exported-services",
"Name": "default",
"Services": [
{
"Name": "api",
"Consumers": [
{
"SamenessGroup": "monitoring"
}
]
}
]
```
</CodeTabs>
### Exporting all services ### Exporting all services
<Tabs> <Tabs>

@ -92,7 +92,7 @@ JWT = {
} }
``` ```
You can include additional configuration information to require the token to match specific claims. You can also configure the `JWT` field to apply only to requests that come from certain HTTP paths. Refer to [JWT validations with intentions](/consul/docs/conntect/config-entries/service-intentions#jwt-validations-with-intentions) for an example configuration. You can include additional configuration information to require the token to match specific claims. You can also configure the `JWT` field to apply only to requests that come from certain HTTP paths. Refer to [JWT validations with intentions](/consul/docs/connect/config-entries/service-intentions#jwt-validations-with-intentions) for an example configuration.
After you update the service intention, write the configuration to Consul so that it takes effect: After you update the service intention, write the configuration to Consul so that it takes effect:

@ -404,7 +404,7 @@ String value that specifies the namespace in which to register the service. Refe
## Multiple service definitions ## Multiple service definitions
You can define multiple services in a single definition file in the `servcies` block. This enables you register multiple services in a single command. Note that the HTTP API does not support the `services` block. You can define multiple services in a single definition file in the `services` block. This enables you register multiple services in a single command. Note that the HTTP API does not support the `services` block.
<CodeTabs tabs={[ "HCL", "JSON" ]}> <CodeTabs tabs={[ "HCL", "JSON" ]}>

@ -1071,11 +1071,6 @@
"title": "Sentinel", "title": "Sentinel",
"path": "agent/sentinel" "path": "agent/sentinel"
}, },
{
"title": "RPC",
"path": "agent/rpc",
"hidden": true
},
{ {
"title": "Experimental WAL LogStore", "title": "Experimental WAL LogStore",
"routes": [ "routes": [

Loading…
Cancel
Save