From 1e920a7f016f41479a1a09887a1ac6512a2e0575 Mon Sep 17 00:00:00 2001 From: Michael Zalimeni Date: Wed, 7 Jun 2023 17:46:49 -0400 Subject: [PATCH 001/359] [OSS] Post Consul 1.16 updates (#17606) * chore: update dev build to 1.17 * chore(ci): add nightly 1.16 test Drop the oldest and add the newest running release branch to nightly builds. --- .../{nightly-test-1.12.x.yaml => nightly-test-1.16.x.yaml} | 6 +++--- version/VERSION | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename .github/workflows/{nightly-test-1.12.x.yaml => nightly-test-1.16.x.yaml} (98%) diff --git a/.github/workflows/nightly-test-1.12.x.yaml b/.github/workflows/nightly-test-1.16.x.yaml similarity index 98% rename from .github/workflows/nightly-test-1.12.x.yaml rename to .github/workflows/nightly-test-1.16.x.yaml index 0f016075e261..c30ed6811c2b 100644 --- a/.github/workflows/nightly-test-1.12.x.yaml +++ b/.github/workflows/nightly-test-1.16.x.yaml @@ -1,7 +1,7 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 -name: Nightly Test 1.12.x +name: Nightly Test 1.16.x on: schedule: - cron: '0 4 * * *' @@ -9,8 +9,8 @@ on: env: EMBER_PARTITION_TOTAL: 4 # Has to be changed in tandem with the matrix.partition - BRANCH: "release/1.12.x" - BRANCH_NAME: "release-1.12.x" # Used for naming artifacts + BRANCH: "release/1.16.x" + BRANCH_NAME: "release-1.16.x" # Used for naming artifacts jobs: frontend-test-workspace-node: diff --git a/version/VERSION b/version/VERSION index 1f0d2f335194..ee8855caa4a7 100644 --- a/version/VERSION +++ b/version/VERSION @@ -1 +1 @@ -1.16.0-dev +1.17.0-dev From 8118aae5c14e26c3c0bc2c2fd2687da2e091e0f3 Mon Sep 17 00:00:00 2001 From: Ronald Date: Wed, 7 Jun 2023 18:35:48 -0400 Subject: [PATCH 002/359] Add writeAuditRPCEvent to agent_oss (#17607) * Add writeAuditRPCEvent to agent_oss * fix the other diffs * backport change log --- .changelog/_5740.txt | 3 +++ .changelog/_5750.txt | 3 +++ agent/agent.go | 11 +++++++++++ agent/agent_oss.go | 4 ++++ agent/config/config.go | 5 +++-- 5 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 .changelog/_5740.txt create mode 100644 .changelog/_5750.txt diff --git a/.changelog/_5740.txt b/.changelog/_5740.txt new file mode 100644 index 000000000000..4f1d6f6448f3 --- /dev/null +++ b/.changelog/_5740.txt @@ -0,0 +1,3 @@ +```release-note:feature +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. +``` \ No newline at end of file diff --git a/.changelog/_5750.txt b/.changelog/_5750.txt new file mode 100644 index 000000000000..027753c72156 --- /dev/null +++ b/.changelog/_5750.txt @@ -0,0 +1,3 @@ +```release-note:feature +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. +``` \ No newline at end of file diff --git a/agent/agent.go b/agent/agent.go index 678d110d534c..0b06688c483b 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -1621,7 +1621,18 @@ func (a *Agent) RPC(ctx context.Context, method string, args interface{}, reply method = e + "." + p[1] } } + + // audit log only on consul clients + _, ok := a.delegate.(*consul.Client) + if ok { + a.writeAuditRPCEvent(method, "OperationStart") + } + a.endpointsLock.RUnlock() + + defer func() { + a.writeAuditRPCEvent(method, "OperationComplete") + }() return a.delegate.RPC(ctx, method, args, reply) } diff --git a/agent/agent_oss.go b/agent/agent_oss.go index 93e633cc656f..e8cfea681b3c 100644 --- a/agent/agent_oss.go +++ b/agent/agent_oss.go @@ -69,3 +69,7 @@ func (a *Agent) AgentEnterpriseMeta() *acl.EnterpriseMeta { func (a *Agent) registerEntCache() {} func (*Agent) fillEnterpriseProxyDataSources(*proxycfg.DataSources) {} + +func (a *Agent) writeAuditRPCEvent(_ string, _ string) interface{} { + return nil +} diff --git a/agent/config/config.go b/agent/config/config.go index e26d6edc4d95..d8d7149afebf 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -807,8 +807,9 @@ type ConfigEntries struct { // Audit allows us to enable and define destinations for auditing type Audit struct { - Enabled *bool `mapstructure:"enabled"` - Sinks map[string]AuditSink `mapstructure:"sink"` + Enabled *bool `mapstructure:"enabled"` + Sinks map[string]AuditSink `mapstructure:"sink"` + RPCEnabled *bool `mapstructure:"rpc_enabled"` } // AuditSink can be provided multiple times to define pipelines for auditing From 779647b9486e239de1f868854ac6f367f3e5af4e Mon Sep 17 00:00:00 2001 From: Eric Haberkorn Date: Thu, 8 Jun 2023 10:26:11 -0400 Subject: [PATCH 003/359] Add Envoy and Consul version constraints to Envoy extensions (#17612) --- .../envoyextensions/registered_extensions.go | 21 +- .../registered_extensions_test.go | 24 ++ agent/structs/envoy_extension.go | 16 +- agent/structs/structs_filtering_test.go | 10 + agent/xds/delta.go | 158 +++++++---- agent/xds/delta_envoy_extender_oss_test.go | 59 +++- agent/xds/delta_test.go | 108 +++++++ ...-consul-constraint-violation.latest.golden | 127 +++++++++ ...h-envoy-constraint-violation.latest.golden | 127 +++++++++ ...-consul-constraint-violation.latest.golden | 75 +++++ ...h-envoy-constraint-violation.latest.golden | 75 +++++ ...-consul-constraint-violation.latest.golden | 265 ++++++++++++++++++ ...h-envoy-constraint-violation.latest.golden | 265 ++++++++++++++++++ ...-consul-constraint-violation.latest.golden | 5 + ...h-envoy-constraint-violation.latest.golden | 5 + api/config_entry.go | 8 +- envoyextensions/xdscommon/envoy_versioning.go | 4 +- .../xdscommon/envoy_versioning_test.go | 2 +- proto/private/pbcommon/common.gen.go | 4 + proto/private/pbcommon/common.pb.go | 82 ++++-- proto/private/pbcommon/common.proto | 2 + proto/private/pbcommon/convert_pbstruct.go | 16 +- 22 files changed, 1344 insertions(+), 114 deletions(-) create mode 100644 agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden create mode 100644 agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden create mode 100644 agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden create mode 100644 agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden create mode 100644 agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden create mode 100644 agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden create mode 100644 agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden create mode 100644 agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden diff --git a/agent/envoyextensions/registered_extensions.go b/agent/envoyextensions/registered_extensions.go index 4d4d26611605..177ab9cb0342 100644 --- a/agent/envoyextensions/registered_extensions.go +++ b/agent/envoyextensions/registered_extensions.go @@ -6,6 +6,9 @@ package envoyextensions import ( "fmt" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-version" + awslambda "github.com/hashicorp/consul/agent/envoyextensions/builtin/aws-lambda" extauthz "github.com/hashicorp/consul/agent/envoyextensions/builtin/ext-authz" "github.com/hashicorp/consul/agent/envoyextensions/builtin/http/localratelimit" @@ -14,7 +17,6 @@ import ( "github.com/hashicorp/consul/agent/envoyextensions/builtin/wasm" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/envoyextensions/extensioncommon" - "github.com/hashicorp/go-multierror" ) type extensionConstructor func(api.EnvoyExtension) (extensioncommon.EnvoyExtender, error) @@ -50,6 +52,23 @@ func ValidateExtensions(extensions []api.EnvoyExtension) error { output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d]: Name is required", i)) continue } + + if v := ext.EnvoyVersion; v != "" { + _, err := version.NewConstraint(v) + if err != nil { + output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d].EnvoyVersion: %w", i, err)) + continue + } + } + + if v := ext.ConsulVersion; v != "" { + _, err := version.NewConstraint(v) + if err != nil { + output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d].ConsulVersion: %w", i, err)) + continue + } + } + _, err := ConstructExtension(ext) if err != nil { output = multierror.Append(output, fmt.Errorf("invalid EnvoyExtensions[%d][%s]: %w", i, ext.Name, err)) diff --git a/agent/envoyextensions/registered_extensions_test.go b/agent/envoyextensions/registered_extensions_test.go index ebd1bfbbc95b..7f3cb6bbac7d 100644 --- a/agent/envoyextensions/registered_extensions_test.go +++ b/agent/envoyextensions/registered_extensions_test.go @@ -48,6 +48,30 @@ func TestValidateExtensions(t *testing.T) { "missing Script value", }, }, + "invalid consul version constraint": { + input: []api.EnvoyExtension{{ + Name: "builtin/aws/lambda", + Arguments: map[string]interface{}{ + "ARN": "arn:aws:lambda:us-east-1:111111111111:function:lambda-1234", + }, + ConsulVersion: "bad", + }}, + expectErrs: []string{ + "invalid EnvoyExtensions[0].ConsulVersion: Malformed constraint: bad", + }, + }, + "invalid envoy version constraint": { + input: []api.EnvoyExtension{{ + Name: "builtin/aws/lambda", + Arguments: map[string]interface{}{ + "ARN": "arn:aws:lambda:us-east-1:111111111111:function:lambda-1234", + }, + EnvoyVersion: "bad", + }}, + expectErrs: []string{ + "invalid EnvoyExtensions[0].EnvoyVersion: Malformed constraint: bad", + }, + }, } for name, tc := range tests { diff --git a/agent/structs/envoy_extension.go b/agent/structs/envoy_extension.go index 5b69afb0d9de..c788aedf37e8 100644 --- a/agent/structs/envoy_extension.go +++ b/agent/structs/envoy_extension.go @@ -9,9 +9,11 @@ import ( // EnvoyExtension has configuration for an extension that patches Envoy resources. type EnvoyExtension struct { - Name string - Required bool - Arguments map[string]interface{} `bexpr:"-"` + Name string + Required bool + Arguments map[string]interface{} `bexpr:"-"` + ConsulVersion string + EnvoyVersion string } type EnvoyExtensions []EnvoyExtension @@ -20,9 +22,11 @@ func (es EnvoyExtensions) ToAPI() []api.EnvoyExtension { extensions := make([]api.EnvoyExtension, len(es)) for i, e := range es { extensions[i] = api.EnvoyExtension{ - Name: e.Name, - Required: e.Required, - Arguments: e.Arguments, + Name: e.Name, + Required: e.Required, + Arguments: e.Arguments, + EnvoyVersion: e.EnvoyVersion, + ConsulVersion: e.ConsulVersion, } } return extensions diff --git a/agent/structs/structs_filtering_test.go b/agent/structs/structs_filtering_test.go index 1bc6599650a7..9739923e0e5a 100644 --- a/agent/structs/structs_filtering_test.go +++ b/agent/structs/structs_filtering_test.go @@ -197,6 +197,16 @@ var expectedFieldConfigEnvoyExtensions bexpr.FieldConfigurations = bexpr.FieldCo CoerceFn: bexpr.CoerceBool, SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual}, }, + "ConsulVersion": &bexpr.FieldConfiguration{ + StructFieldName: "ConsulVersion", + CoerceFn: bexpr.CoerceString, + SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual, bexpr.MatchIn, bexpr.MatchNotIn, bexpr.MatchMatches, bexpr.MatchNotMatches}, + }, + "EnvoyVersion": &bexpr.FieldConfiguration{ + StructFieldName: "EnvoyVersion", + CoerceFn: bexpr.CoerceString, + SupportedOperations: []bexpr.MatchOperator{bexpr.MatchEqual, bexpr.MatchNotEqual, bexpr.MatchIn, bexpr.MatchNotIn, bexpr.MatchMatches, bexpr.MatchNotMatches}, + }, } var expectedFieldConfigUpstreams bexpr.FieldConfigurations = bexpr.FieldConfigurations{ "DestinationType": &bexpr.FieldConfiguration{ diff --git a/agent/xds/delta.go b/agent/xds/delta.go index 66072e0b81e4..5e4cf702090a 100644 --- a/agent/xds/delta.go +++ b/agent/xds/delta.go @@ -17,6 +17,8 @@ import ( envoy_config_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_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + "github.com/hashicorp/go-hclog" + goversion "github.com/hashicorp/go-version" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -29,6 +31,7 @@ import ( "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/xds/extensionruntime" + "github.com/hashicorp/consul/envoyextensions/extensioncommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/logging" "github.com/hashicorp/consul/version" @@ -255,7 +258,7 @@ func (s *Server) processDelta(stream ADSDeltaStream, reqCh <-chan *envoy_discove s.ResourceMapMutateFn(newResourceMap) } - if err = s.applyEnvoyExtensions(newResourceMap, cfgSnap); err != nil { + if err = s.applyEnvoyExtensions(newResourceMap, cfgSnap, node); err != nil { // err is already the result of calling status.Errorf return err } @@ -400,70 +403,123 @@ func (s *Server) processDelta(stream ADSDeltaStream, reqCh <-chan *envoy_discove } } -func (s *Server) applyEnvoyExtensions(resources *xdscommon.IndexedResources, cfgSnap *proxycfg.ConfigSnapshot) error { +func (s *Server) applyEnvoyExtensions(resources *xdscommon.IndexedResources, cfgSnap *proxycfg.ConfigSnapshot, node *envoy_config_core_v3.Node) error { + var err error + envoyVersion := xdscommon.DetermineEnvoyVersionFromNode(node) + consulVersion, err := goversion.NewVersion(version.Version) + + if err != nil { + return status.Errorf(codes.InvalidArgument, "failed to parse Consul version") + } + serviceConfigs := extensionruntime.GetRuntimeConfigurations(cfgSnap) for _, cfgs := range serviceConfigs { for _, cfg := range cfgs { - logFn := s.Logger.Warn - if cfg.EnvoyExtension.Required { - logFn = s.Logger.Error - } - errorParams := []interface{}{ - "extension", cfg.EnvoyExtension.Name, - "service", cfg.ServiceName.Name, - "namespace", cfg.ServiceName.Namespace, - "partition", cfg.ServiceName.Partition, - } - - getMetricLabels := func(err error) []metrics.Label { - return []metrics.Label{ - {Name: "extension", Value: cfg.EnvoyExtension.Name}, - {Name: "version", Value: "builtin/" + version.Version}, - {Name: "service", Value: cfgSnap.Service}, - {Name: "partition", Value: cfgSnap.ProxyID.PartitionOrDefault()}, - {Name: "namespace", Value: cfgSnap.ProxyID.NamespaceOrDefault()}, - {Name: "error", Value: strconv.FormatBool(err != nil)}, - } - } + err = applyEnvoyExtension(s.Logger, cfgSnap, resources, cfg, envoyVersion, consulVersion) - now := time.Now() - extender, err := envoyextensions.ConstructExtension(cfg.EnvoyExtension) - metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate_arguments"}, now, getMetricLabels(err)) if err != nil { - logFn("failed to construct extension", errorParams...) + return err + } + } + } - if cfg.EnvoyExtension.Required { - return status.Errorf(codes.Unavailable, "failed to construct extension %q for service %q", cfg.EnvoyExtension.Name, cfg.ServiceName.Name) - } + return nil +} - continue - } +func applyEnvoyExtension(logger hclog.Logger, cfgSnap *proxycfg.ConfigSnapshot, resources *xdscommon.IndexedResources, runtimeConfig extensioncommon.RuntimeConfig, envoyVersion, consulVersion *goversion.Version) error { + logFn := logger.Warn + if runtimeConfig.EnvoyExtension.Required { + logFn = logger.Error + } - now = time.Now() - err = extender.Validate(&cfg) - metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate"}, now, getMetricLabels(err)) - if err != nil { - errorParams = append(errorParams, "error", err) - logFn("failed to validate extension arguments", errorParams...) - if cfg.EnvoyExtension.Required { - return status.Errorf(codes.Unavailable, "failed to validate arguments for extension %q for service %q", cfg.EnvoyExtension.Name, cfg.ServiceName.Name) - } + svc := runtimeConfig.ServiceName - continue - } + errorParams := []interface{}{ + "extension", runtimeConfig.EnvoyExtension.Name, + "service", svc.Name, + "namespace", svc.Namespace, + "partition", svc.Partition, + } - now = time.Now() - resources, err = extender.Extend(resources, &cfg) - metrics.MeasureSinceWithLabels([]string{"envoy_extension", "extend"}, now, getMetricLabels(err)) - if err == nil { - continue + getMetricLabels := func(err error) []metrics.Label { + return []metrics.Label{ + {Name: "extension", Value: runtimeConfig.EnvoyExtension.Name}, + {Name: "version", Value: "builtin/" + version.Version}, + {Name: "service", Value: cfgSnap.Service}, + {Name: "partition", Value: cfgSnap.ProxyID.PartitionOrDefault()}, + {Name: "namespace", Value: cfgSnap.ProxyID.NamespaceOrDefault()}, + {Name: "error", Value: strconv.FormatBool(err != nil)}, + } + } + + ext := runtimeConfig.EnvoyExtension + + if v := ext.EnvoyVersion; v != "" { + c, err := goversion.NewConstraint(v) + if err != nil { + logFn("failed to parse Envoy extension version constraint", errorParams...) + + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to parse Envoy version constraint for extension %q for service %q", ext.Name, svc.Name) } + return nil + } + + if !c.Check(envoyVersion) { + logger.Info("skipping envoy extension due to Envoy version constraint violation", errorParams...) + return nil + } + } + + if v := ext.ConsulVersion; v != "" { + c, err := goversion.NewConstraint(v) + if err != nil { + logFn("failed to parse Consul extension version constraint", errorParams...) - logFn("failed to apply envoy extension", errorParams...) - if cfg.EnvoyExtension.Required { - return status.Errorf(codes.Unavailable, "failed to patch xDS resources in the %q extension: %v", cfg.EnvoyExtension.Name, err) + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to parse Consul version constraint for extension %q for service %q", ext.Name, svc.Name) } + return nil + } + + if !c.Check(consulVersion) { + logger.Info("skipping envoy extension due to Consul version constraint violation", errorParams...) + return nil + } + } + + now := time.Now() + extender, err := envoyextensions.ConstructExtension(ext) + metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate_arguments"}, now, getMetricLabels(err)) + if err != nil { + logFn("failed to construct extension", errorParams...) + + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to construct extension %q for service %q", ext.Name, svc.Name) + } + + return nil + } + + now = time.Now() + err = extender.Validate(&runtimeConfig) + metrics.MeasureSinceWithLabels([]string{"envoy_extension", "validate"}, now, getMetricLabels(err)) + if err != nil { + errorParams = append(errorParams, "error", err) + logFn("failed to validate extension arguments", errorParams...) + if ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to validate arguments for extension %q for service %q", ext.Name, svc.Name) } + + return nil + } + + now = time.Now() + _, err = extender.Extend(resources, &runtimeConfig) + metrics.MeasureSinceWithLabels([]string{"envoy_extension", "extend"}, now, getMetricLabels(err)) + logFn("failed to apply envoy extension", errorParams...) + if err != nil && ext.Required { + return status.Errorf(codes.InvalidArgument, "failed to patch xDS resources in the %q extension: %v", ext.Name, err) } return nil diff --git a/agent/xds/delta_envoy_extender_oss_test.go b/agent/xds/delta_envoy_extender_oss_test.go index dc1521edbe34..3d92b6d25de0 100644 --- a/agent/xds/delta_envoy_extender_oss_test.go +++ b/agent/xds/delta_envoy_extender_oss_test.go @@ -16,11 +16,12 @@ import ( 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" "github.com/hashicorp/consul/agent/xds/testcommon" + "github.com/hashicorp/go-hclog" + goversion "github.com/hashicorp/go-version" testinf "github.com/mitchellh/go-testing-interface" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "github.com/hashicorp/consul/agent/envoyextensions" propertyoverride "github.com/hashicorp/consul/agent/envoyextensions/builtin/property-override" "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" @@ -29,9 +30,12 @@ import ( "github.com/hashicorp/consul/envoyextensions/extensioncommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/sdk/testutil" + "github.com/hashicorp/consul/version" ) func TestEnvoyExtenderWithSnapshot(t *testing.T) { + consulVersion, _ := goversion.NewVersion(version.Version) + // If opposite is true, the returned service defaults config entry will have // payload-passthrough=true and invocation-mode=asynchronous. // Otherwise payload-passthrough=false and invocation-mode=synchronous. @@ -65,7 +69,7 @@ func TestEnvoyExtenderWithSnapshot(t *testing.T) { } // Apply Lua extension to the local service and ensure http is used so the extension can be applied. - makeLuaNsFunc := func(inbound bool) func(ns *structs.NodeService) { + makeLuaNsFunc := func(inbound bool, envoyVersion, consulVersion string) func(ns *structs.NodeService) { listener := "inbound" if !inbound { listener = "outbound" @@ -75,7 +79,9 @@ func TestEnvoyExtenderWithSnapshot(t *testing.T) { ns.Proxy.Config["protocol"] = "http" ns.Proxy.EnvoyExtensions = []structs.EnvoyExtension{ { - Name: api.BuiltinLuaExtension, + Name: api.BuiltinLuaExtension, + EnvoyVersion: envoyVersion, + ConsulVersion: consulVersion, Arguments: map[string]interface{}{ "ProxyType": "connect-proxy", "Listener": listener, @@ -464,11 +470,41 @@ end`, name: "lambda-terminating-gateway-with-service-resolvers", create: proxycfg.TestConfigSnapshotTerminatingGatewayWithLambdaServiceAndServiceResolvers, }, + { + name: "lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + // upstreams need to be http in order for lua to be applied to listeners. + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, "< 1.0.0", ">= 1.0.0"), nil, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + Protocol: "http", + }, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "geo-cache", + Protocol: "http", + }) + }, + }, + { + name: "lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + // upstreams need to be http in order for lua to be applied to listeners. + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, ">= 1.0.0", "< 1.0.0"), nil, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "db", + Protocol: "http", + }, &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "geo-cache", + Protocol: "http", + }) + }, + }, { name: "lua-outbound-applies-to-local-upstreams", create: func(t testinf.T) *proxycfg.ConfigSnapshot { // upstreams need to be http in order for lua to be applied to listeners. - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false), nil, &structs.ServiceConfigEntry{ + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, ">= 1.0.0", ">= 1.0.0"), nil, &structs.ServiceConfigEntry{ Kind: structs.ServiceDefaults, Name: "db", Protocol: "http", @@ -487,7 +523,7 @@ end`, create: func(t testinf.T) *proxycfg.ConfigSnapshot { // db is made an HTTP upstream so that the extension _could_ apply, but does not because // the direction for the extension is inbound. - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true), nil, &structs.ServiceConfigEntry{ + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true, "", ""), nil, &structs.ServiceConfigEntry{ Kind: structs.ServiceDefaults, Name: "db", Protocol: "http", @@ -497,7 +533,7 @@ end`, { name: "lua-inbound-applies-to-inbound", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true), nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(true, "", ""), nil) }, }, { @@ -505,14 +541,14 @@ end`, // no upstream HTTP services. We also should not see public listener, which is HTTP, patched. name: "lua-outbound-doesnt-apply-to-inbound", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false), nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, makeLuaNsFunc(false, "", ""), nil) }, }, { name: "lua-outbound-applies-to-local-upstreams-tproxy", create: func(t testinf.T) *proxycfg.ConfigSnapshot { // upstreams need to be http in order for lua to be applied to listeners. - return proxycfg.TestConfigSnapshotTransparentProxyDestinationHTTP(t, makeLuaNsFunc(false)) + return proxycfg.TestConfigSnapshotTransparentProxyDestinationHTTP(t, makeLuaNsFunc(false, "", "")) }, }, { @@ -707,6 +743,7 @@ end`, latestEnvoyVersion := xdscommon.EnvoyVersions[0] for _, envoyVersion := range xdscommon.EnvoyVersions { + parsedEnvoyVersion, _ := goversion.NewVersion(envoyVersion) sf, err := xdscommon.DetermineSupportedProxyFeaturesFromString(envoyVersion) require.NoError(t, err) t.Run("envoy-"+envoyVersion, func(t *testing.T) { @@ -730,11 +767,7 @@ end`, cfgs := extensionruntime.GetRuntimeConfigurations(snap) for _, extensions := range cfgs { for _, ext := range extensions { - extender, err := envoyextensions.ConstructExtension(ext.EnvoyExtension) - require.NoError(t, err) - err = extender.Validate(&ext) - require.NoError(t, err) - indexedResources, err = extender.Extend(indexedResources, &ext) + err := applyEnvoyExtension(hclog.NewNullLogger(), snap, indexedResources, ext, parsedEnvoyVersion, consulVersion) require.NoError(t, err) } } diff --git a/agent/xds/delta_test.go b/agent/xds/delta_test.go index a9febfedfa0c..f9c77835ad11 100644 --- a/agent/xds/delta_test.go +++ b/agent/xds/delta_test.go @@ -14,6 +14,8 @@ import ( "github.com/armon/go-metrics" envoy_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + "github.com/hashicorp/go-hclog" + goversion "github.com/hashicorp/go-version" "github.com/stretchr/testify/require" rpcstatus "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc/codes" @@ -25,6 +27,7 @@ import ( "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/envoyextensions/extensioncommon" "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" @@ -1609,3 +1612,108 @@ func requireExtensionMetrics( require.True(t, foundLabel) } } + +func Test_applyEnvoyExtension_Validations(t *testing.T) { + type testCase struct { + name string + runtimeConfig extensioncommon.RuntimeConfig + err bool + errString string + } + + envoyVersion, _ := goversion.NewVersion("1.25.0") + consulVersion, _ := goversion.NewVersion("1.16.0") + + svc := api.CompoundServiceName{ + Name: "s1", + Partition: "ap1", + Namespace: "ns1", + } + + makeRuntimeConfig := func(required bool, consulVersion string, envoyVersion string, args map[string]interface{}) extensioncommon.RuntimeConfig { + if args == nil { + args = map[string]interface{}{ + "ARN": "arn:aws:lambda:us-east-1:111111111111:function:lambda-1234", + } + + } + return extensioncommon.RuntimeConfig{ + EnvoyExtension: api.EnvoyExtension{ + Name: api.BuiltinAWSLambdaExtension, + Required: required, + ConsulVersion: consulVersion, + EnvoyVersion: envoyVersion, + Arguments: args, + }, + ServiceName: svc, + } + } + + cases := []testCase{ + { + name: "invalid consul version constraint - required", + runtimeConfig: makeRuntimeConfig(true, "bad", ">= 1.0", nil), + err: true, + errString: "failed to parse Consul version constraint for extension", + }, + { + name: "invalid consul version constraint - not required", + runtimeConfig: makeRuntimeConfig(false, "bad", ">= 1.0", nil), + err: false, + }, + { + name: "invalid envoy version constraint - required", + runtimeConfig: makeRuntimeConfig(true, ">= 1.0", "bad", nil), + err: true, + errString: "failed to parse Envoy version constraint for extension", + }, + { + name: "invalid envoy version constraint - not required", + runtimeConfig: makeRuntimeConfig(false, ">= 1.0", "bad", nil), + err: false, + }, + { + name: "no envoy version constraint match", + runtimeConfig: makeRuntimeConfig(false, "", ">= 2.0.0", nil), + err: false, + }, + { + name: "no consul version constraint match", + runtimeConfig: makeRuntimeConfig(false, ">= 2.0.0", "", nil), + err: false, + }, + { + name: "invalid extension arguments - required", + runtimeConfig: makeRuntimeConfig(true, ">= 1.15.0", ">= 1.25.0", map[string]interface{}{"bad": "args"}), + err: true, + errString: "failed to construct extension", + }, + { + name: "invalid extension arguments - not required", + runtimeConfig: makeRuntimeConfig(false, ">= 1.15.0", ">= 1.25.0", map[string]interface{}{"bad": "args"}), + err: false, + }, + { + name: "valid everything", + runtimeConfig: makeRuntimeConfig(false, ">= 1.15.0", ">= 1.25.0", nil), + err: false, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + snap := proxycfg.ConfigSnapshot{ + ProxyID: proxycfg.ProxyID{ + ServiceID: structs.NewServiceID("s1", nil), + }, + } + err := applyEnvoyExtension(hclog.NewNullLogger(), &snap, nil, tc.runtimeConfig, envoyVersion, consulVersion) + if tc.err { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errString) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..c010ac87b0f4 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,127 @@ +{ + "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" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..c010ac87b0f4 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/clusters/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,127 @@ +{ + "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" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..5cb4171b9730 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,75 @@ +{ + "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" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..5cb4171b9730 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/endpoints/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,75 @@ +{ + "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" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..8024198d7c4d --- /dev/null +++ b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,265 @@ +{ + "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.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "upstream.db.default.default.dc1", + "routeConfig": { + "name": "db", + "virtualHosts": [ + { + "name": "db.default.default.dc1", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + } + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.prepared_query_geo-cache", + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "public_listener", + "routeConfig": { + "name": "public_listener", + "virtualHosts": [ + { + "name": "public_listener", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "local_app" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC", + "rules": {} + } + }, + { + "name": "envoy.filters.http.header_to_metadata", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config", + "requestRules": [ + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "trust-domain", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\1" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "partition", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\2" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "namespace", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\3" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "datacenter", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\4" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "service", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\5" + } + } + } + ] + } + }, + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + }, + "forwardClientCertDetails": "APPEND_FORWARD", + "setCurrentClientCertDetails": { + "subject": true, + "cert": true, + "chain": true, + "dns": true, + "uri": true + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + }, + "alpnProtocols": [ + "http/1.1" + ] + }, + "requireClientCertificate": true + } + } + } + ], + "trafficDirection": "INBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..8024198d7c4d --- /dev/null +++ b/agent/xds/testdata/builtin_extension/listeners/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,265 @@ +{ + "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.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "upstream.db.default.default.dc1", + "routeConfig": { + "name": "db", + "virtualHosts": [ + { + "name": "db.default.default.dc1", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + } + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.prepared_query_geo-cache", + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "trafficDirection": "OUTBOUND" + }, + { + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.filters.network.http_connection_manager", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", + "statPrefix": "public_listener", + "routeConfig": { + "name": "public_listener", + "virtualHosts": [ + { + "name": "public_listener", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "local_app" + } + } + ] + } + ] + }, + "httpFilters": [ + { + "name": "envoy.filters.http.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC", + "rules": {} + } + }, + { + "name": "envoy.filters.http.header_to_metadata", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config", + "requestRules": [ + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "trust-domain", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\1" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "partition", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\2" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "namespace", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\3" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "datacenter", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\4" + } + } + }, + { + "header": "x-forwarded-client-cert", + "onHeaderPresent": { + "metadataNamespace": "consul", + "key": "service", + "regexValueRewrite": { + "pattern": { + "googleRe2": {}, + "regex": ".*URI=spiffe://([^/]+.[^/]+)(?:/ap/([^/]+))?/ns/([^/]+)/dc/([^/]+)/svc/([^/;,]+).*" + }, + "substitution": "\\5" + } + } + } + ] + } + }, + { + "name": "envoy.filters.http.router", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" + } + } + ], + "tracing": { + "randomSampling": {} + }, + "forwardClientCertDetails": "APPEND_FORWARD", + "setCurrentClientCertDetails": { + "subject": true, + "cert": true, + "chain": true, + "dns": true, + "uri": true + } + } + } + ], + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + }, + "alpnProtocols": [ + "http/1.1" + ] + }, + "requireClientCertificate": true + } + } + } + ], + "trafficDirection": "INBOUND" + } + ], + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden new file mode 100644 index 000000000000..306f5220e7b9 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-consul-constraint-violation.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden new file mode 100644 index 000000000000..306f5220e7b9 --- /dev/null +++ b/agent/xds/testdata/builtin_extension/routes/lua-outbound-doesnt-apply-to-local-upstreams-with-envoy-constraint-violation.latest.golden @@ -0,0 +1,5 @@ +{ + "versionInfo": "00000001", + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file diff --git a/api/config_entry.go b/api/config_entry.go index b4cc966d1f70..125619b55d08 100644 --- a/api/config_entry.go +++ b/api/config_entry.go @@ -144,9 +144,11 @@ type ExposeConfig struct { // EnvoyExtension has configuration for an extension that patches Envoy resources. type EnvoyExtension struct { - Name string - Required bool - Arguments map[string]interface{} `bexpr:"-"` + Name string + Required bool + Arguments map[string]interface{} `bexpr:"-"` + ConsulVersion string + EnvoyVersion string } type ExposePath struct { diff --git a/envoyextensions/xdscommon/envoy_versioning.go b/envoyextensions/xdscommon/envoy_versioning.go index 06764f2b65e2..393a96bf9e80 100644 --- a/envoyextensions/xdscommon/envoy_versioning.go +++ b/envoyextensions/xdscommon/envoy_versioning.go @@ -30,7 +30,7 @@ type SupportedProxyFeatures struct { } func DetermineSupportedProxyFeatures(node *envoy_core_v3.Node) (SupportedProxyFeatures, error) { - version := determineEnvoyVersionFromNode(node) + version := DetermineEnvoyVersionFromNode(node) return determineSupportedProxyFeaturesFromVersion(version) } @@ -69,7 +69,7 @@ func determineSupportedProxyFeaturesFromVersion(version *version.Version) (Suppo return sf, nil } -func determineEnvoyVersionFromNode(node *envoy_core_v3.Node) *version.Version { +func DetermineEnvoyVersionFromNode(node *envoy_core_v3.Node) *version.Version { if node == nil { return nil } diff --git a/envoyextensions/xdscommon/envoy_versioning_test.go b/envoyextensions/xdscommon/envoy_versioning_test.go index ff9318239348..3e7507dec551 100644 --- a/envoyextensions/xdscommon/envoy_versioning_test.go +++ b/envoyextensions/xdscommon/envoy_versioning_test.go @@ -59,7 +59,7 @@ func TestDetermineEnvoyVersionFromNode(t *testing.T) { for name, tc := range cases { tc := tc t.Run(name, func(t *testing.T) { - got := determineEnvoyVersionFromNode(tc.node) + got := DetermineEnvoyVersionFromNode(tc.node) if tc.expect != nil { require.Equal(t, tc.expect, got) } else { diff --git a/proto/private/pbcommon/common.gen.go b/proto/private/pbcommon/common.gen.go index d7659b834ee3..c29598a2abf7 100644 --- a/proto/private/pbcommon/common.gen.go +++ b/proto/private/pbcommon/common.gen.go @@ -11,6 +11,8 @@ func EnvoyExtensionToStructs(s *EnvoyExtension, t *structs.EnvoyExtension) { t.Name = s.Name t.Required = s.Required t.Arguments = ProtobufTypesStructToMapStringInterface(s.Arguments) + t.ConsulVersion = s.ConsulVersion + t.EnvoyVersion = s.EnvoyVersion } func EnvoyExtensionFromStructs(t *structs.EnvoyExtension, s *EnvoyExtension) { if s == nil { @@ -19,6 +21,8 @@ func EnvoyExtensionFromStructs(t *structs.EnvoyExtension, s *EnvoyExtension) { s.Name = t.Name s.Required = t.Required s.Arguments = MapStringInterfaceToProtobufTypesStruct(t.Arguments) + s.ConsulVersion = t.ConsulVersion + s.EnvoyVersion = t.EnvoyVersion } func LocalityToStructs(s *Locality, t *structs.Locality) { if s == nil { diff --git a/proto/private/pbcommon/common.pb.go b/proto/private/pbcommon/common.pb.go index 8a8ae5fe9401..dd6240ad85e9 100644 --- a/proto/private/pbcommon/common.pb.go +++ b/proto/private/pbcommon/common.pb.go @@ -607,7 +607,9 @@ type EnvoyExtension struct { Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` Required bool `protobuf:"varint,2,opt,name=Required,proto3" json:"Required,omitempty"` // mog: func-to=ProtobufTypesStructToMapStringInterface func-from=MapStringInterfaceToProtobufTypesStruct - Arguments *structpb.Struct `protobuf:"bytes,3,opt,name=Arguments,proto3" json:"Arguments,omitempty"` + Arguments *structpb.Struct `protobuf:"bytes,3,opt,name=Arguments,proto3" json:"Arguments,omitempty"` + ConsulVersion string `protobuf:"bytes,4,opt,name=ConsulVersion,proto3" json:"ConsulVersion,omitempty"` + EnvoyVersion string `protobuf:"bytes,5,opt,name=EnvoyVersion,proto3" json:"EnvoyVersion,omitempty"` } func (x *EnvoyExtension) Reset() { @@ -663,6 +665,20 @@ func (x *EnvoyExtension) GetArguments() *structpb.Struct { return nil } +func (x *EnvoyExtension) GetConsulVersion() string { + if x != nil { + return x.ConsulVersion + } + return "" +} + +func (x *EnvoyExtension) GetEnvoyVersion() string { + if x != nil { + return x.EnvoyVersion + } + return "" +} + // mog annotation: // // target=github.com/hashicorp/consul/agent/structs.Locality @@ -802,36 +818,40 @@ var file_private_pbcommon_common_proto_rawDesc = []byte{ 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x77, 0x0a, 0x0e, 0x45, - 0x6e, 0x76, 0x6f, 0x79, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, - 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x35, 0x0a, - 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x22, 0x36, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, - 0x12, 0x16, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x5a, 0x6f, 0x6e, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x5a, 0x6f, 0x6e, 0x65, 0x42, 0x8b, 0x02, 0x0a, - 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 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, 0x2f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x2f, - 0x70, 0x62, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xa2, 0x02, 0x04, 0x48, 0x43, 0x49, 0x43, 0xaa, - 0x02, 0x20, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, - 0x75, 0x6c, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0xca, 0x02, 0x20, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, - 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xe2, 0x02, 0x2c, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x5c, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x3a, 0x3a, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc1, 0x01, 0x0a, 0x0e, + 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x35, + 0x0a, 0x09, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x09, 0x41, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x45, + 0x6e, 0x76, 0x6f, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0x36, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x52, + 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x52, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x5a, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x5a, 0x6f, 0x6e, 0x65, 0x42, 0x8b, 0x02, 0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x2e, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x32, 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, 0x2f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0xa2, 0x02, 0x04, 0x48, 0x43, 0x49, 0x43, 0xaa, 0x02, 0x20, 0x48, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0xca, 0x02, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0xe2, 0x02, 0x2c, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x43, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x3a, 0x3a, 0x43, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/private/pbcommon/common.proto b/proto/private/pbcommon/common.proto index 237e9b4e29e2..a86aa2dde53d 100644 --- a/proto/private/pbcommon/common.proto +++ b/proto/private/pbcommon/common.proto @@ -185,6 +185,8 @@ message EnvoyExtension { bool Required = 2; // mog: func-to=ProtobufTypesStructToMapStringInterface func-from=MapStringInterfaceToProtobufTypesStruct google.protobuf.Struct Arguments = 3; + string ConsulVersion = 4; + string EnvoyVersion = 5; } // mog annotation: diff --git a/proto/private/pbcommon/convert_pbstruct.go b/proto/private/pbcommon/convert_pbstruct.go index 4370d7f2e783..e48dce9ae6e0 100644 --- a/proto/private/pbcommon/convert_pbstruct.go +++ b/proto/private/pbcommon/convert_pbstruct.go @@ -47,9 +47,11 @@ func EnvoyExtensionsToStructs(args []*EnvoyExtension) []structs.EnvoyExtension { var e structs.EnvoyExtension if args[i] != nil { e = structs.EnvoyExtension{ - Name: args[i].Name, - Required: args[i].Required, - Arguments: ProtobufTypesStructToMapStringInterface(args[i].Arguments), + Name: args[i].Name, + Required: args[i].Required, + ConsulVersion: args[i].ConsulVersion, + EnvoyVersion: args[i].EnvoyVersion, + Arguments: ProtobufTypesStructToMapStringInterface(args[i].Arguments), } } @@ -65,9 +67,11 @@ func EnvoyExtensionsFromStructs(args []structs.EnvoyExtension) []*EnvoyExtension o := make([]*EnvoyExtension, len(args)) for i, e := range args { o[i] = &EnvoyExtension{ - Name: e.Name, - Required: e.Required, - Arguments: MapStringInterfaceToProtobufTypesStruct(e.Arguments), + Name: e.Name, + Required: e.Required, + ConsulVersion: e.ConsulVersion, + EnvoyVersion: e.EnvoyVersion, + Arguments: MapStringInterfaceToProtobufTypesStruct(e.Arguments), } } From 9a4f503b2b379610ec6f7bf84db45c4d5a716fd9 Mon Sep 17 00:00:00 2001 From: Andrew Stucki Date: Thu, 8 Jun 2023 12:18:17 -0400 Subject: [PATCH 004/359] [API Gateway] Fix trust domain for external peered services in synthesis code (#17609) * [API Gateway] Fix trust domain for external peered services in synthesis code * Add changelog --- .changelog/17609.txt | 4 ++++ agent/proxycfg/snapshot.go | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 .changelog/17609.txt diff --git a/.changelog/17609.txt b/.changelog/17609.txt new file mode 100644 index 000000000000..cbace1f8c7d2 --- /dev/null +++ b/.changelog/17609.txt @@ -0,0 +1,4 @@ +```release-note:bug +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. +``` diff --git a/agent/proxycfg/snapshot.go b/agent/proxycfg/snapshot.go index 5e92013b272f..1880dcd669f6 100644 --- a/agent/proxycfg/snapshot.go +++ b/agent/proxycfg/snapshot.go @@ -741,14 +741,23 @@ type configSnapshotAPIGateway struct { func (c *configSnapshotAPIGateway) synthesizeChains(datacenter string, listener structs.APIGatewayListener, boundListener structs.BoundAPIGatewayListener) ([]structs.IngressService, structs.Upstreams, []*structs.CompiledDiscoveryChain, error) { chains := []*structs.CompiledDiscoveryChain{} - trustDomain := "" + + // We leverage the test trust domain knowing + // that the domain will get overridden if + // there is a target to something other than an + // external/peered service. If the below + // code doesn't get a trust domain due to all the + // targets being external, the chain will + // have the domain munged anyway during synthesis. + trustDomain := connect.TestTrustDomain DOMAIN_LOOP: for _, chain := range c.DiscoveryChain { for _, target := range chain.Targets { if !target.External { - trustDomain = connect.TrustDomainForTarget(*target) - if trustDomain != "" { + domain := connect.TrustDomainForTarget(*target) + if domain != "" { + trustDomain = domain break DOMAIN_LOOP } } From 17f46893796017dc9152ff014112644c6dddd4d0 Mon Sep 17 00:00:00 2001 From: Ronald Date: Thu, 8 Jun 2023 12:34:31 -0400 Subject: [PATCH 005/359] backport ent changes to oss (#17614) * backport ent changes to oss * Update .changelog/_5669.txt Co-authored-by: Michael Zalimeni --------- Co-authored-by: Michael Zalimeni --- .changelog/_5669.txt | 3 +++ api/api_test.go | 16 ++++++++++++++++ sdk/testutil/server.go | 6 ++++++ 3 files changed, 25 insertions(+) create mode 100644 .changelog/_5669.txt diff --git a/.changelog/_5669.txt b/.changelog/_5669.txt new file mode 100644 index 000000000000..6528460e69bd --- /dev/null +++ b/.changelog/_5669.txt @@ -0,0 +1,3 @@ +```release-note:improvement +audit-logging: **(Enterprise only)** enable error response and request body logging +``` \ No newline at end of file diff --git a/api/api_test.go b/api/api_test.go index 49670b41eb86..4d5dd1fda830 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -53,6 +53,22 @@ func makeACLClient(t *testing.T) (*Client, *testutil.TestServer) { }) } +// Makes a client with Audit enabled, it requires ACLs +func makeAuditClient(t *testing.T) (*Client, *testutil.TestServer) { + return makeClientWithConfig(t, func(clientConfig *Config) { + clientConfig.Token = "root" + }, func(serverConfig *testutil.TestServerConfig) { + serverConfig.PrimaryDatacenter = "dc1" + serverConfig.ACL.Tokens.InitialManagement = "root" + serverConfig.ACL.Tokens.Agent = "root" + serverConfig.ACL.Enabled = true + serverConfig.ACL.DefaultPolicy = "deny" + serverConfig.Audit = &testutil.TestAuditConfig{ + Enabled: true, + } + }) +} + func makeNonBootstrappedACLClient(t *testing.T, defaultPolicy string) (*Client, *testutil.TestServer) { return makeClientWithConfig(t, func(clientConfig *Config) { diff --git a/sdk/testutil/server.go b/sdk/testutil/server.go index 1c7167d98da5..d00850d5e17a 100644 --- a/sdk/testutil/server.go +++ b/sdk/testutil/server.go @@ -75,6 +75,11 @@ type TestNetworkSegment struct { Advertise string `json:"advertise"` } +// TestAudigConfig contains the configuration for Audit +type TestAuditConfig struct { + Enabled bool `json:"enabled,omitempty"` +} + // Locality is used as the TestServerConfig's Locality. type Locality struct { Region string `json:"region"` @@ -124,6 +129,7 @@ type TestServerConfig struct { Stderr io.Writer `json:"-"` Args []string `json:"-"` ReturnPorts func() `json:"-"` + Audit *TestAuditConfig `json:"audit,omitempty"` } type TestACLs struct { From 85982889a1801ecf4596f9afd013d09da84a2708 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 8 Jun 2023 13:30:05 -0700 Subject: [PATCH 006/359] Update intentions.mdx (#17619) Make behaviour of L7 intentions clearer --- website/content/api-docs/connect/intentions.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/content/api-docs/connect/intentions.mdx b/website/content/api-docs/connect/intentions.mdx index cdfeb463cda0..20a6b5054b93 100644 --- a/website/content/api-docs/connect/intentions.mdx +++ b/website/content/api-docs/connect/intentions.mdx @@ -536,9 +536,7 @@ This endpoint evaluates the intentions for a specific source and destination and returns whether the connection would be authorized or not given the current Consul configuration and set of intentions. --> **Note:** This endpoint will always evaluate intentions with `Permissions` -defined as _deny_ intentions during. This endpoint is only suited for -networking layer 4 (e.g. TCP) integration. +-> **Note:** This endpoint will always evaluate matching intentions with L7 `Permissions` defined as _deny_ intentions because there is no request to check against. For performance and reliability reasons it is desirable to implement intention enforcement by listing [intentions that match the From 7ae457c5867a446a1e694c10eb03a9ca723dfb6c Mon Sep 17 00:00:00 2001 From: Ronald Date: Thu, 8 Jun 2023 19:50:51 -0400 Subject: [PATCH 007/359] enterprise changelog update for audit (#17625) --- .changelog/_5805.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/_5805.txt diff --git a/.changelog/_5805.txt b/.changelog/_5805.txt new file mode 100644 index 000000000000..786effc31025 --- /dev/null +++ b/.changelog/_5805.txt @@ -0,0 +1,3 @@ +```release-note:security +audit-logging: **(Enterprise only)** limit `v1/operator/audit-hash` endpoint to ACL token with `operator:read` privileges. +``` \ No newline at end of file From 30e0c234abce0f0a0dba46bb950dc533fb273c7f Mon Sep 17 00:00:00 2001 From: Michael Zalimeni Date: Thu, 8 Jun 2023 22:37:49 -0400 Subject: [PATCH 008/359] Update list of Envoy versions (#17546) --- .changelog/17546.txt | 3 +++ .github/workflows/test-integrations.yml | 4 ++-- envoyextensions/xdscommon/envoy_versioning_test.go | 7 ++++--- envoyextensions/xdscommon/proxysupport.go | 8 ++++---- website/content/docs/connect/proxies/envoy.mdx | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 .changelog/17546.txt diff --git a/.changelog/17546.txt b/.changelog/17546.txt new file mode 100644 index 000000000000..6f4025553986 --- /dev/null +++ b/.changelog/17546.txt @@ -0,0 +1,3 @@ +```release-note:improvement +connect: update supported envoy versions to 1.23.10, 1.24.8, 1.25.7, 1.26.2 +``` diff --git a/.github/workflows/test-integrations.yml b/.github/workflows/test-integrations.yml index 260044aee8bb..38b6a44cbe01 100644 --- a/.github/workflows/test-integrations.yml +++ b/.github/workflows/test-integrations.yml @@ -239,7 +239,7 @@ jobs: # this is further going to multiplied in envoy-integration tests by the # other dimensions in the matrix. Currently TOTAL_RUNNERS would be # multiplied by 8 based on these values: - # envoy-version: ["1.23.8", "1.24.6", "1.25.4", "1.26.0"] + # envoy-version: ["1.23.10", "1.24.8", "1.25.7", "1.26.2"] # xds-target: ["server", "client"] TOTAL_RUNNERS: 4 JQ_SLICER: '[ inputs ] | [_nwise(length / $runnercount | floor)]' @@ -273,7 +273,7 @@ jobs: strategy: fail-fast: false matrix: - envoy-version: ["1.23.8", "1.24.6", "1.25.4", "1.26.0"] + envoy-version: ["1.23.10", "1.24.8", "1.25.7", "1.26.2"] xds-target: ["server", "client"] test-cases: ${{ fromJSON(needs.generate-envoy-job-matrices.outputs.envoy-matrix) }} env: diff --git a/envoyextensions/xdscommon/envoy_versioning_test.go b/envoyextensions/xdscommon/envoy_versioning_test.go index 3e7507dec551..cc2134c7323d 100644 --- a/envoyextensions/xdscommon/envoy_versioning_test.go +++ b/envoyextensions/xdscommon/envoy_versioning_test.go @@ -151,9 +151,10 @@ func TestDetermineSupportedProxyFeaturesFromString(t *testing.T) { } */ for _, v := range []string{ - "1.23.0", "1.23.1", "1.23.2", "1.23.3", "1.23.4", "1.23.5", "1.23.6", "1.23.7", "1.23.8", - "1.24.0", "1.24.1", "1.24.2", "1.24.3", "1.24.4", "1.24.5", "1.24.6", - "1.25.0", "1.25.1", "1.25.2", "1.25.3", "1.25.4", "1.26.0", + "1.23.0", "1.23.1", "1.23.2", "1.23.3", "1.23.4", "1.23.5", "1.23.6", "1.23.7", "1.23.8", "1.23.9", "1.23.10", + "1.24.0", "1.24.1", "1.24.2", "1.24.3", "1.24.4", "1.24.5", "1.24.6", "1.24.7", "1.24.8", + "1.25.0", "1.25.1", "1.25.2", "1.25.3", "1.25.4", "1.25.5", "1.25.6", "1.25.7", + "1.26.0", "1.26.1", "1.26.2", } { cases[v] = testcase{expect: SupportedProxyFeatures{}} } diff --git a/envoyextensions/xdscommon/proxysupport.go b/envoyextensions/xdscommon/proxysupport.go index ff4b79d7354c..250133a13844 100644 --- a/envoyextensions/xdscommon/proxysupport.go +++ b/envoyextensions/xdscommon/proxysupport.go @@ -12,10 +12,10 @@ import "strings" // // see: https://www.consul.io/docs/connect/proxies/envoy#supported-versions var EnvoyVersions = []string{ - "1.26.0", - "1.25.4", - "1.24.6", - "1.23.8", + "1.26.2", + "1.25.7", + "1.24.8", + "1.23.10", } // UnsupportedEnvoyVersions lists any unsupported Envoy versions (mainly minor versions) that fall diff --git a/website/content/docs/connect/proxies/envoy.mdx b/website/content/docs/connect/proxies/envoy.mdx index 65a01ca61524..e6759113c2c7 100644 --- a/website/content/docs/connect/proxies/envoy.mdx +++ b/website/content/docs/connect/proxies/envoy.mdx @@ -39,7 +39,7 @@ Consul supports **four major Envoy releases** at the beginning of each major Con | Consul Version | Compatible Envoy Versions | | ------------------- | -----------------------------------------------------------------------------------| -| 1.15.x | 1.25.4, 1.24.6, 1.23.8, 1.22.11 | +| 1.15.x | 1.25.6, 1.24.7, 1.23.9, 1.22.11 | | 1.14.x | 1.24.0, 1.23.1, 1.22.5, 1.21.5 | | 1.13.x | 1.23.1, 1.22.5, 1.21.5, 1.20.7 | From 3cb70566a907423795b8e218111f2efc8acb52c2 Mon Sep 17 00:00:00 2001 From: Andrew Stucki Date: Fri, 9 Jun 2023 08:22:32 -0400 Subject: [PATCH 009/359] [API Gateway] Fix rate limiting for API gateways (#17631) * [API Gateway] Fix rate limiting for API gateways * Add changelog * Fix failing unit tests * Fix operator usage tests for api package --- .changelog/17631.txt | 3 + agent/consul/state/state_store_test.go | 19 +++++- agent/consul/state/usage.go | 1 + agent/consul/state/usage_test.go | 15 +++- .../usagemetrics/usagemetrics_oss_test.go | 68 ++++++++++++++++--- agent/operator_endpoint_oss_test.go | 1 + agent/structs/testing_catalog.go | 8 +++ api/operator_usage_test.go | 1 + 8 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 .changelog/17631.txt diff --git a/.changelog/17631.txt b/.changelog/17631.txt new file mode 100644 index 000000000000..b24b7461ec6e --- /dev/null +++ b/.changelog/17631.txt @@ -0,0 +1,3 @@ +```release-note:bug +gateways: Fixed a bug where API gateways were not being taken into account in determining xDS rate limits. +``` diff --git a/agent/consul/state/state_store_test.go b/agent/consul/state/state_store_test.go index dfe8c988b329..fef750253272 100644 --- a/agent/consul/state/state_store_test.go +++ b/agent/consul/state/state_store_test.go @@ -203,11 +203,27 @@ func testRegisterConnectService(t *testing.T, s *Store, idx uint64, nodeID, serv }) } +func testRegisterAPIService(t *testing.T, s *Store, idx uint64, nodeID, serviceID string) { + testRegisterGatewayService(t, s, structs.ServiceKindAPIGateway, idx, nodeID, serviceID) +} + +func testRegisterTerminatingService(t *testing.T, s *Store, idx uint64, nodeID, serviceID string) { + testRegisterGatewayService(t, s, structs.ServiceKindTerminatingGateway, idx, nodeID, serviceID) +} + func testRegisterIngressService(t *testing.T, s *Store, idx uint64, nodeID, serviceID string) { + testRegisterGatewayService(t, s, structs.ServiceKindIngressGateway, idx, nodeID, serviceID) +} + +func testRegisterMeshService(t *testing.T, s *Store, idx uint64, nodeID, serviceID string) { + testRegisterGatewayService(t, s, structs.ServiceKindMeshGateway, idx, nodeID, serviceID) +} + +func testRegisterGatewayService(t *testing.T, s *Store, kind structs.ServiceKind, idx uint64, nodeID, serviceID string) { svc := &structs.NodeService{ ID: serviceID, Service: serviceID, - Kind: structs.ServiceKindIngressGateway, + Kind: kind, Address: "1.1.1.1", Port: 1111, } @@ -227,6 +243,7 @@ func testRegisterIngressService(t *testing.T, s *Store, idx uint64, nodeID, serv t.Fatalf("bad service: %#v", result) } } + func testRegisterCheck(t *testing.T, s *Store, idx uint64, nodeID string, serviceID string, checkID types.CheckID, state string) { testRegisterCheckWithPartition(t, s, idx, diff --git a/agent/consul/state/usage.go b/agent/consul/state/usage.go index 8e455241c299..b3794105508a 100644 --- a/agent/consul/state/usage.go +++ b/agent/consul/state/usage.go @@ -25,6 +25,7 @@ var allConnectKind = []string{ string(structs.ServiceKindIngressGateway), string(structs.ServiceKindMeshGateway), string(structs.ServiceKindTerminatingGateway), + string(structs.ServiceKindAPIGateway), connectNativeInstancesTable, } diff --git a/agent/consul/state/usage_test.go b/agent/consul/state/usage_test.go index 6ccaddb9f7e8..68844ebc1140 100644 --- a/agent/consul/state/usage_test.go +++ b/agent/consul/state/usage_test.go @@ -179,16 +179,25 @@ func TestStateStore_Usage_ServiceUsage(t *testing.T) { testRegisterConnectNativeService(t, s, 13, "node1", "service-native") testRegisterConnectNativeService(t, s, 14, "node2", "service-native") testRegisterConnectNativeService(t, s, 15, "node2", "service-native-1") + testRegisterIngressService(t, s, 16, "node1", "ingress") + testRegisterMeshService(t, s, 17, "node1", "mesh") + testRegisterTerminatingService(t, s, 18, "node1", "terminating") + testRegisterAPIService(t, s, 19, "node1", "api") + testRegisterAPIService(t, s, 20, "node2", "api") ws := memdb.NewWatchSet() idx, usage, err := s.ServiceUsage(ws) require.NoError(t, err) - require.Equal(t, idx, uint64(15)) - require.Equal(t, 5, usage.Services) - require.Equal(t, 8, usage.ServiceInstances) + require.Equal(t, idx, uint64(20)) + require.Equal(t, 9, usage.Services) + require.Equal(t, 13, usage.ServiceInstances) require.Equal(t, 2, usage.ConnectServiceInstances[string(structs.ServiceKindConnectProxy)]) require.Equal(t, 3, usage.ConnectServiceInstances[connectNativeInstancesTable]) require.Equal(t, 6, usage.BillableServiceInstances) + require.Equal(t, 2, usage.ConnectServiceInstances[string(structs.ServiceKindAPIGateway)]) + require.Equal(t, 1, usage.ConnectServiceInstances[string(structs.ServiceKindIngressGateway)]) + require.Equal(t, 1, usage.ConnectServiceInstances[string(structs.ServiceKindTerminatingGateway)]) + require.Equal(t, 1, usage.ConnectServiceInstances[string(structs.ServiceKindMeshGateway)]) testRegisterSidecarProxy(t, s, 16, "node2", "service2") diff --git a/agent/consul/usagemetrics/usagemetrics_oss_test.go b/agent/consul/usagemetrics/usagemetrics_oss_test.go index 1781dca4c50e..8a4b511577c8 100644 --- a/agent/consul/usagemetrics/usagemetrics_oss_test.go +++ b/agent/consul/usagemetrics/usagemetrics_oss_test.go @@ -149,6 +149,22 @@ var baseCases = map[string]testCase{ {Name: "kind", Value: "ingress-gateway"}, }, }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=api-gateway": { // Legacy + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "api-gateway"}, + }, + }, + "consul.usage.test.state.connect_instances;datacenter=dc1;kind=api-gateway": { + Name: "consul.usage.test.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "api-gateway"}, + }, + }, "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=mesh-gateway": { // Legacy Name: "consul.usage.test.consul.state.connect_instances", Value: 0, @@ -624,6 +640,22 @@ var baseCases = map[string]testCase{ {Name: "kind", Value: "ingress-gateway"}, }, }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=api-gateway": { // Legacy + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "api-gateway"}, + }, + }, + "consul.usage.test.state.connect_instances;datacenter=dc1;kind=api-gateway": { + Name: "consul.usage.test.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "api-gateway"}, + }, + }, "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=mesh-gateway": { // Legacy Name: "consul.usage.test.consul.state.connect_instances", Value: 0, @@ -1127,6 +1159,9 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { require.NoError(t, s.EnsureNode(3, &structs.Node{Node: "baz", Address: "127.0.0.2"})) require.NoError(t, s.EnsureNode(4, &structs.Node{Node: "qux", Address: "127.0.0.3"})) + apigw := structs.TestNodeServiceAPIGateway(t) + apigw.ID = "api-gateway" + mgw := structs.TestNodeServiceMeshGateway(t) mgw.ID = "mesh-gateway" @@ -1141,16 +1176,17 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { require.NoError(t, s.EnsureRegistration(10, structs.TestRegisterIngressGateway(t))) require.NoError(t, s.EnsureService(11, "foo", mgw)) require.NoError(t, s.EnsureService(12, "foo", tgw)) - require.NoError(t, s.EnsureService(13, "bar", &structs.NodeService{ID: "db-native", Service: "db", Tags: nil, Address: "", Port: 5000, Connect: structs.ServiceConnect{Native: true}})) - require.NoError(t, s.EnsureConfigEntry(14, &structs.IngressGatewayConfigEntry{ + require.NoError(t, s.EnsureService(13, "foo", apigw)) + require.NoError(t, s.EnsureService(14, "bar", &structs.NodeService{ID: "db-native", Service: "db", Tags: nil, Address: "", Port: 5000, Connect: structs.ServiceConnect{Native: true}})) + require.NoError(t, s.EnsureConfigEntry(15, &structs.IngressGatewayConfigEntry{ Kind: structs.IngressGateway, Name: "foo", })) - require.NoError(t, s.EnsureConfigEntry(15, &structs.IngressGatewayConfigEntry{ + require.NoError(t, s.EnsureConfigEntry(16, &structs.IngressGatewayConfigEntry{ Kind: structs.IngressGateway, Name: "bar", })) - require.NoError(t, s.EnsureConfigEntry(16, &structs.IngressGatewayConfigEntry{ + require.NoError(t, s.EnsureConfigEntry(17, &structs.IngressGatewayConfigEntry{ Kind: structs.IngressGateway, Name: "baz", })) @@ -1191,22 +1227,22 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { } nodesAndSvcsCase.expectedGauges["consul.usage.test.consul.state.services;datacenter=dc1"] = metrics.GaugeValue{ // Legacy Name: "consul.usage.test.consul.state.services", - Value: 7, + Value: 8, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, } nodesAndSvcsCase.expectedGauges["consul.usage.test.state.services;datacenter=dc1"] = metrics.GaugeValue{ Name: "consul.usage.test.state.services", - Value: 7, + Value: 8, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, } nodesAndSvcsCase.expectedGauges["consul.usage.test.consul.state.service_instances;datacenter=dc1"] = metrics.GaugeValue{ // Legacy Name: "consul.usage.test.consul.state.service_instances", - Value: 9, + Value: 10, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, } nodesAndSvcsCase.expectedGauges["consul.usage.test.state.service_instances;datacenter=dc1"] = metrics.GaugeValue{ Name: "consul.usage.test.state.service_instances", - Value: 9, + Value: 10, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, } nodesAndSvcsCase.expectedGauges["consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=connect-proxy"] = metrics.GaugeValue{ // Legacy @@ -1257,6 +1293,22 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { {Name: "kind", Value: "ingress-gateway"}, }, } + nodesAndSvcsCase.expectedGauges["consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=api-gateway"] = metrics.GaugeValue{ // Legacy + Name: "consul.usage.test.consul.state.connect_instances", + Value: 1, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "api-gateway"}, + }, + } + nodesAndSvcsCase.expectedGauges["consul.usage.test.state.connect_instances;datacenter=dc1;kind=api-gateway"] = metrics.GaugeValue{ + Name: "consul.usage.test.state.connect_instances", + Value: 1, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "api-gateway"}, + }, + } nodesAndSvcsCase.expectedGauges["consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=mesh-gateway"] = metrics.GaugeValue{ // Legacy Name: "consul.usage.test.consul.state.connect_instances", Value: 1, diff --git a/agent/operator_endpoint_oss_test.go b/agent/operator_endpoint_oss_test.go index ea144cffa692..90f0e7d0cd14 100644 --- a/agent/operator_endpoint_oss_test.go +++ b/agent/operator_endpoint_oss_test.go @@ -56,6 +56,7 @@ func TestOperator_Usage(t *testing.T) { Services: 5, ServiceInstances: 6, ConnectServiceInstances: map[string]int{ + "api-gateway": 0, "connect-native": 1, "connect-proxy": 1, "ingress-gateway": 0, diff --git a/agent/structs/testing_catalog.go b/agent/structs/testing_catalog.go index 0e560b3906ff..9e72aebc7745 100644 --- a/agent/structs/testing_catalog.go +++ b/agent/structs/testing_catalog.go @@ -174,6 +174,14 @@ func TestNodeServiceMeshGateway(t testing.T) *NodeService { ServiceAddress{Address: "198.18.4.5", Port: 443}) } +func TestNodeServiceAPIGateway(t testing.T) *NodeService { + return &NodeService{ + Kind: ServiceKindAPIGateway, + Service: "api-gateway", + Address: "1.1.1.1", + } +} + func TestNodeServiceTerminatingGateway(t testing.T, address string) *NodeService { return &NodeService{ Kind: ServiceKindTerminatingGateway, diff --git a/api/operator_usage_test.go b/api/operator_usage_test.go index a276682e07de..77b15fcdb586 100644 --- a/api/operator_usage_test.go +++ b/api/operator_usage_test.go @@ -56,6 +56,7 @@ func TestAPI_OperatorUsage(t *testing.T) { require.Equal(t, 4, usage.Usage["dc1"].Services) require.Equal(t, 5, usage.Usage["dc1"].ServiceInstances) require.Equal(t, map[string]int{ + "api-gateway": 0, "connect-native": 1, "connect-proxy": 1, "ingress-gateway": 0, From ec347ef01d8a43b9d8407750a8c92bd1d5d404e7 Mon Sep 17 00:00:00 2001 From: "R.B. Boyer" <4903+rboyer@users.noreply.github.com> Date: Fri, 9 Jun 2023 11:30:56 -0500 Subject: [PATCH 010/359] sort some imports that are wonky between oss and ent (#17637) --- agent/agent_endpoint.go | 10 ++++------ agent/agent_endpoint_test.go | 6 ++---- agent/proxycfg/mesh_gateway.go | 1 - 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/agent/agent_endpoint.go b/agent/agent_endpoint.go index 13e993fc703e..d63936e29466 100644 --- a/agent/agent_endpoint.go +++ b/agent/agent_endpoint.go @@ -11,16 +11,12 @@ import ( "strings" "time" + "github.com/hashicorp/go-bexpr" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-memdb" - "github.com/mitchellh/hashstructure" - - "github.com/hashicorp/consul/envoyextensions/xdscommon" - "github.com/hashicorp/consul/version" - - "github.com/hashicorp/go-bexpr" "github.com/hashicorp/serf/coordinate" "github.com/hashicorp/serf/serf" + "github.com/mitchellh/hashstructure" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -31,11 +27,13 @@ import ( "github.com/hashicorp/consul/agent/structs" token_store "github.com/hashicorp/consul/agent/token" "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/ipaddr" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/logging" "github.com/hashicorp/consul/logging/monitor" "github.com/hashicorp/consul/types" + "github.com/hashicorp/consul/version" ) type Self struct { diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index 2955871c723e..fc0345cee478 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -21,10 +21,6 @@ import ( "time" "github.com/armon/go-metrics" - - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/version" - "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-uuid" "github.com/hashicorp/serf/serf" @@ -44,12 +40,14 @@ import ( "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/token" tokenStore "github.com/hashicorp/consul/agent/token" + "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/envoyextensions/xdscommon" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul/testrpc" "github.com/hashicorp/consul/types" + "github.com/hashicorp/consul/version" ) func createACLTokenWithAgentReadPolicy(t *testing.T, srv *HTTPHandlers) string { diff --git a/agent/proxycfg/mesh_gateway.go b/agent/proxycfg/mesh_gateway.go index 2267a2960a20..cf090b7b0460 100644 --- a/agent/proxycfg/mesh_gateway.go +++ b/agent/proxycfg/mesh_gateway.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/consul/acl" - cachetype "github.com/hashicorp/consul/agent/cache-types" "github.com/hashicorp/consul/agent/proxycfg/internal/watch" "github.com/hashicorp/consul/agent/structs" From 5e846747f4602dd08f3f1a877b95af48c2c3cce7 Mon Sep 17 00:00:00 2001 From: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> Date: Sat, 10 Jun 2023 08:35:22 -0700 Subject: [PATCH 011/359] PmTLS and tproxy improvements with failover and L7 traffic mgmt for k8s (#17624) * porting over changes from enterprise repo to oss * applied feedback on service mesh for k8s overview * fixed typo * removed ent-only build script file * Apply suggestions from code review Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: David Yu Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com> --------- Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com> Co-authored-by: David Yu --- .../content/docs/connect/failover/index.mdx | 45 +++ .../content/docs/connect/l7-traffic/index.mdx | 132 +++----- website/content/docs/k8s/connect/index.mdx | 71 ++--- .../k8s/connect/onboarding-tproxy-mode.mdx | 295 ++++++++++++++++++ .../enable-transparent-proxy.mdx} | 76 ++--- .../k8s/connect/transparent-proxy/index.mdx | 47 +++ .../docs/k8s/l7-traffic/failover-tproxy.mdx | 124 ++++++++ .../l7-traffic/route-to-virtual-services.mdx | 122 ++++++++ website/data/docs-nav-data.json | 79 ++++- 9 files changed, 795 insertions(+), 196 deletions(-) create mode 100644 website/content/docs/connect/failover/index.mdx create mode 100644 website/content/docs/k8s/connect/onboarding-tproxy-mode.mdx rename website/content/docs/{connect/transparent-proxy.mdx => k8s/connect/transparent-proxy/enable-transparent-proxy.mdx} (81%) create mode 100644 website/content/docs/k8s/connect/transparent-proxy/index.mdx create mode 100644 website/content/docs/k8s/l7-traffic/failover-tproxy.mdx create mode 100644 website/content/docs/k8s/l7-traffic/route-to-virtual-services.mdx diff --git a/website/content/docs/connect/failover/index.mdx b/website/content/docs/connect/failover/index.mdx new file mode 100644 index 000000000000..2d9690644098 --- /dev/null +++ b/website/content/docs/connect/failover/index.mdx @@ -0,0 +1,45 @@ +--- +layout: docs +page_title: Failover configuration overview +description: Learn about failover strategies and service mesh features you can implement to route traffic if services become unhealthy or unreachable, including sameness groups, prepared queries, and service resolvers. +--- + +# Failover overview + +Services in your mesh may become unhealthy or unreachable for many reasons, but you can mitigate some of the effects associated with infrastructure issues by configuring Consul to automatically route traffic to and from failover service instances. This topic provides an overview of the failover strategies you can implement with Consul. + +## Service failover strategies in Consul + +There are several methods for implementing failover strategies between datacenters in Consul. You can adopt one of the following strategies based on your deployment configuration and network requirements: + +- Configure the `Failover` stanza in a service resolver configuration entry to explicitly define which services should failover and the targeting logic they should follow. +- Make a prepared query for each service that you can use to automate geo-failover. +- Create a sameness group to identify partitions with identical namespaces and service names to establish default failover targets. + +The following table compares these strategies in deployments with multiple datacenters to help you determine the best approach for your service: + +| Failover Strategy | Supports WAN Federation | Supports Cluster Peering | Multi-Datacenter Failover Strength | Multi-Datacenter Usage Scenario | +| :---------------: | :---------------------: | :----------------------: | :--------------------------------- | :------------------------------ | +| `Failover` stanza | ✅ | ✅ | Enables more granular logic for failover targeting | Configuring failover for a single service or service subset, especially for testing or debugging purposes | +| Prepared query | ✅ | ✅ | Central policies that can automatically target the nearest datacenter | WAN-federated deployments where a primary datacenter is configured. Prepared queries are not replicated over peer connections. | +| Sameness groups | ❌ | ✅ | Group size changes without edits to existing member configurations | Cluster peering deployments with consistently named services and namespaces | + +### Failover configurations for a service mesh with a single datacenter + +You can implement a service resolver configuration entry and specify a pool of failover service instances that other services can exchange messages with when the primary service becomes unhealthy or unreachable. We recommend adopting this strategy as a minimum baseline when implementing Consul service mesh and layering additional failover strategies to build resilience into your application network. + +Refer to the [`Failover` configuration ](/consul/docs/connect/config-entries/service-resolver#failover) for examples of how to configure failover services in the service resolver configuration entry on both VMs and Kubernetes deployments. + +### Failover configuration for WAN-federated datacenters + +If your network has multiple Consul datacenters that are WAN-federated, you can configure your applications to look for failover services with prepared queries. [Prepared queries](/consul/api-docs/) are configurations that enable you to define complex service discovery lookups. This strategy hinges on the secondary datacenter containing service instances that have the same name and residing in the same namespace as their counterparts in the primary datacenter. + +Refer to the [Automate geo-failover with prepared queries tutorial](/consul/tutorials/developer-discovery/automate-geo-failover) for additional information. + +### Failover configuration for peered clusters and partitions + +In networks with multiple datacenters or partitions that share a peer connection, each datacenter or partition functions as an independent unit. As a result, Consul does not correlate services that have the same name, even if they are in the same namespace. + +You can configure sameness groups for this type of network. Sameness groups allow you to define a group of admin partitions where identical services are deployed in identical namespaces. After you configure the sameness group, you can reference the `SamenessGroup` parameter in service resolver, exported service, and service intention configuration entries, enabling you to add or remove cluster peers from the group without making changes to every cluster peer every time. + +Refer to [Sameness groups usage page](/consul/docs/connect/cluster-peering/usage/sameness-groups) for more information. diff --git a/website/content/docs/connect/l7-traffic/index.mdx b/website/content/docs/connect/l7-traffic/index.mdx index 9f5fe8da2b5a..3fb7b392b839 100644 --- a/website/content/docs/connect/l7-traffic/index.mdx +++ b/website/content/docs/connect/l7-traffic/index.mdx @@ -1,126 +1,80 @@ --- layout: docs -page_title: Service Mesh Traffic Management - Overview +page_title: Service mesh traffic management overview description: >- Consul can route, split, and resolve Layer 7 traffic in a service mesh to support workflows like canary testing and blue/green deployments. Learn about the three configuration entry kinds that define L7 traffic management behavior in Consul. --- --> **1.6.0+:** This feature is available in Consul versions 1.6.0 and newer. +# Service mesh traffic management overview -# Service Mesh Traffic Management Overview +This topic provides overview information about the application layer traffic management capabilities available in Consul service mesh. These capabilities are also referred to as *Layer 7* or *L7 traffic management*. -Layer 7 traffic management allows operators to divide L7 traffic between -different -[subsets](/consul/docs/connect/config-entries/service-resolver#service-subsets) of -service instances when using service mesh. +## Introduction -There are many ways you may wish to carve up a single datacenter's pool of -services beyond simply returning all healthy instances for load balancing. -Canary testing, A/B tests, blue/green deploys, and soft multi-tenancy -(prod/qa/staging sharing compute resources) all require some mechanism of -carving out portions of the Consul catalog smaller than the level of a single -service and configuring when that subset should receive traffic. +Consul service mesh allows you to divide application layer traffic between different subsets of service instances. You can leverage L7 traffic management capabilities to perform complex processes, such as configuring backup services for failover scenarios, canary and A-B testing, blue-green deployments, and soft multi-tenancy in which production, QA, and staging environments share compute resources. L7 traffic management with Consul service mesh allows you to designate groups of service instances in the Consul catalog smaller than all instances of single service and configure when that subset should receive traffic. --> **Note:** This feature is not compatible with the -[built-in proxy](/consul/docs/connect/proxies/built-in), -[native proxies](/consul/docs/connect/native), -and some [Envoy proxy escape hatches](/consul/docs/connect/proxies/envoy#escape-hatch-overrides). +You cannot manage L7 traffic with the [built-in proxy](/consul/docs/connect/proxies/built-in), +[native proxies](/consul/docs/connect/native), or some [Envoy proxy escape hatches](/consul/docs/connect/proxies/envoy#escape-hatch-overrides). -## Stages +## Discovery chain -Service mesh proxy upstreams are discovered using a series of stages: routing, -splitting, and resolution. These stages represent different ways of managing L7 -traffic. +Consul uses a series of stages to discover service mesh proxy upstreams. Each stage represents different ways of managing L7 traffic. They are referred to as the _discovery chain_: -![screenshot of L7 traffic visualization in the UI](/img/l7-routing/full.png) - -Each stage of this discovery process can be dynamically reconfigured via various -[configuration entries](/consul/docs/agent/config-entries). When a configuration -entry is missing, that stage will fall back on reasonable default behavior. - -### Routing - -A [`service-router`](/consul/docs/connect/config-entries/service-router) config -entry kind is the first configurable stage. +- routing +- splitting +- resolution -![screenshot of service router in the UI](/img/l7-routing/Router.png) - -A router config entry allows for a user to intercept traffic using L7 criteria -such as path prefixes or http headers, and change behavior such as by sending -traffic to a different service or service subset. - -These config entries may only reference `service-splitter` or -`service-resolver` entries. - -[Examples](/consul/docs/connect/config-entries/service-router#sample-config-entries) -can be found in the `service-router` documentation. - -### Splitting +For information about integrating service mesh proxy upstream discovery using the discovery chain, refer to [Discovery Chain for Service Mesh Traffic Management](/consul/docs/connect/l7-traffic/discovery-chain). -A [`service-splitter`](/consul/docs/connect/config-entries/service-splitter) config -entry kind is the next stage after routing. +The Consul UI shows discovery chain stages in the **Routing** tab of the **Services** page: -![screenshot of service splitter in the UI](/img/l7-routing/Splitter.png) +![screenshot of L7 traffic visualization in the UI](/img/l7-routing/full.png) -A splitter config entry allows for a user to choose to split incoming requests -across different subsets of a single service (like during staged canary -rollouts), or perhaps across different services (like during a v2 rewrite or -other type of codebase migration). +You can define how Consul manages each stage of the discovery chain in a Consul _configuration entry_. [Configuration entries](/consul/docs/connect/config-entries) modify the default behavior of the Consul service mesh. -These config entries may only reference `service-splitter` or -`service-resolver` entries. +When managing L7 traffic with cluster peering, there are additional configuration requirements to resolve peers in the discovery chain. Refer to [Cluster peering L7 traffic management](/consul/docs/connect/cluster-peering/usage/peering-traffic-management) for more information. -If one splitter references another splitter the overall effects are flattened -into one effective splitter config entry which reflects the multiplicative -union. For instance: +### Routing - splitter[A]: A_v1=50%, A_v2=50% - splitter[B]: A=50%, B=50% - --------------------- - splitter[effective_B]: A_v1=25%, A_v2=25%, B=50% +The first stage of the discovery chain is the service router. Routers intercept traffic according to a set of L7 attributes, such as path prefixes and HTTP headers, and route the traffic to a different service or service subset. -[Examples](/consul/docs/connect/config-entries/service-splitter#sample-config-entries) -can be found in the `service-splitter` documentation. +Apply a [service router configuration entry](/consul/docs/connect/config-entries/service-router) to implement a router. Service router configuration entries can only reference service splitter or service resolver configuration entries. -### Resolution +![screenshot of service router in the UI](/img/l7-routing/Router.png) -A [`service-resolver`](/consul/docs/connect/config-entries/service-resolver) config -entry kind is the last stage. +### Splitting -![screenshot of service resolver in the UI](/img/l7-routing/Resolver.png) +The second stage of the discovery chain is the service splitter. Service splitters split incoming requests and route them to different services or service subsets. Splitters enable staged canary rollouts, versioned releases, and similar use cases. -A resolver config entry allows for a user to define which instances of a -service should satisfy discovery requests for the provided name. +Apply a [service splitter configuration entry](/consul/docs/connect/config-entries/service-splitter) to implement a splitter. Service splitters configuration entries can only reference other service splitters or service resolver configuration entries. -Examples of things you can do with resolver config entries: +![screenshot of service splitter in the UI](/img/l7-routing/Splitter.png) -- Control where to send traffic if all instances of `api` in the current - datacenter are unhealthy. +If multiple service splitters are chained, Consul flattens the splits so that they behave as a single service spitter. In the following equation, `splitter[A]` references `splitter[B]`: -- Configure service subsets based on `Service.Meta.version` values. +```text +splitter[A]: A_v1=50%, A_v2=50% +splitter[B]: A=50%, B=50% +--------------------- +splitter[effective_B]: A_v1=25%, A_v2=25%, B=50% +``` -- Send all traffic for `web` that does not specify a service subset to the - `version1` subset. -- Send all traffic for `api` to `new-api`. +### Resolution -- Send all traffic for `api` in all datacenters to instances of `api` in `dc2`. +The third stage of the discovery chain is the service resolver. Service resolvers specify which instances of a service satisfy discovery requests for the provided service name. Service resolvers enable several use cases, including: -- Create a "virtual service" `api-dc2` that sends traffic to instances of `api` - in `dc2`. This can be referenced in upstreams or in other config entries. +- Designate failovers when service instances become unhealthy or unreachable. +- Configure service subsets based on DNS values. +- Route traffic to the latest version of a service. +- Route traffic to specific Consul datacenters. +- Create virtual services that route traffic to instances of the actual service in specific Consul datacenters. -If no resolver config is defined for a service it is assumed 100% of traffic -flows to the healthy instances of a service with the same name in the current -datacenter/namespace and discovery terminates. +Apply a [service resolver configuration entry](/consul/docs/connect/config-entries/service-resolver) to implement a resolver. Service resolver configuration entries can only reference other service resolvers. -This should feel similar in spirit to various uses of Prepared Queries, but is -not intended to be a drop-in replacement currently. -These config entries may only reference other `service-resolver` entries. +![screenshot of service resolver in the UI](/img/l7-routing/Resolver.png) -[Examples](/consul/docs/connect/config-entries/service-resolver#sample-config-entries) -can be found in the `service-resolver` documentation. +If no resolver is configured for a service, Consul sends all traffic to healthy instances of the service that have the same name in the current datacenter or specified namespace and ends the discovery chain. --> **Note:** `service-resolver` config entries kinds can function at L4 (unlike -`service-router` and `service-splitter` kinds). These can be created for -services of any protocol such as `tcp`. \ No newline at end of file +Service resolver configuration entries can also process network layer, also called level 4 (L4), traffic. As a result, you can implement service resolvers for services that communicate over `tcp` and other non-HTTP protocols. \ No newline at end of file diff --git a/website/content/docs/k8s/connect/index.mdx b/website/content/docs/k8s/connect/index.mdx index 7f1dd71c8e8c..afa625a0ba8d 100644 --- a/website/content/docs/k8s/connect/index.mdx +++ b/website/content/docs/k8s/connect/index.mdx @@ -7,30 +7,21 @@ description: >- # How does Consul Service Mesh Work on Kubernetes? -[Consul service mesh](/consul/docs/connect) is a feature built into to Consul that enables -automatic service-to-service authorization and connection encryption across -your Consul services. Consul Service Mesh can be used with Kubernetes to secure pod -communication with other pods and external Kubernetes services. - -The noun _connect_ is used throughout this documentation to refer to the connect -subsystem that provides Consul's service mesh capabilities. -Where you encounter the _noun_ connect, it is usually functionality specific to -service mesh. +Consul service mesh automates service-to-service authorization and encryption across your Consul services. You can use service mesh in Kubernetes-orchestrated networks to secure communication between pods as well as communication between pods and external Kubernetes services. + +## Workflow -Consul can automatically inject the sidecar running Envoy into pods in -your cluster, making configuration for Kubernetes automatic. -This functionality is provided by the -[consul-k8s project](https://github.com/hashicorp/consul-k8s) and can be -automatically installed and configured using the -[Consul Helm chart](/consul/docs/k8s/installation/install#helm-chart-installation). +Consul service mesh is enabled by default when you install Consul on Kubernetes using the Consul Helm chart. Consul also automatically injects sidecars into the pods in your clusters that run Envoy. These sidecar proxies, called Consul dataplanes, are enabled when `connectInject.default` is set to `false` in the Helm chart. Refer to the following documentation for additional information about these concepts: -## Usage +- [Installation and Configuration](#installation-and-configuration) in this topic +- [Consul Helm chart reference](/consul/docs/k8s/helm) +- [Simplified Service Mesh with Consul Dataplane](/consul/docs/connect/dataplane) --> **Important:** As of consul-k8s `v0.26.0` and Consul Helm `v0.32.0`, a Kubernetes -service is required to run services on the Consul service mesh. +If `connectInject.default` is set to `false` or you want to explicitly enable service mesh sidecar proxy injection for a specific deployment, add the `consul.hashicorp.com/connect-inject` annotation to the pod specification template and set it to `true` when connecting services to the mesh. -Installing Consul on Kubernetes with [`connect-inject` enabled](/consul/docs/k8s/connect#installation-and-configuration) adds a sidecar to all pods. By default, it enables service mesh functionality with Consul Dataplane by injecting an Envoy proxy. You can also configure Consul to inject a client agent sidecar to connect to your service mesh. Refer to [Simplified Service Mesh with Consul Dataplane](/consul/docs/connect/dataplane) for more information. +### Example +The following example shows a Kubernetes configuration that specifically enables service mesh connections for the `static-server` service. Consul starts and registers a sidecar proxy that listens on port 20000 by default and proxies valid inbound connections to port 8080. ```yaml apiVersion: v1 @@ -81,37 +72,17 @@ spec: serviceAccountName: static-server ``` -The only change for service mesh is the addition of the -`consul.hashicorp.com/connect-inject` annotation. This enables injection -for the Pod in this Deployment. The injector can also be -[configured](/consul/docs/k8s/connect#installation-and-configuration) -to automatically inject unless explicitly disabled, but the default -installation requires opt-in using the annotation shown above. - -~> **A common mistake** is to set the annotation on the Deployment or -other resource. Ensure that the injector annotations are specified on -the _pod specification template_ as shown above. - -This will start a sidecar proxy that listens on port `20000` registered -with Consul and proxies valid inbound connections to port 8080 in the pod. -To establish a connection to the pod using service mesh, a client must use another mesh -proxy. The client mesh proxy will use Consul service discovery to find -all available upstream proxies and their public ports. - -In the example above, the server is listening on `:8080`. -By default, the Consul service mesh runs in [transparent proxy](/consul/docs/connect/transparent-proxy) mode. -This means that even though the server binds to all interfaces, -the inbound and outbound connections will automatically go through to the sidecar proxy. -It also allows you to use Kubernetes DNS like you normally would without the -Consul Service Mesh. - --> **Note:** As of consul `v1.10.0`, consul-k8s `v0.26.0` and Consul Helm `v0.32.0`, -all Consul Service Mesh services will run with transparent proxy enabled by default. Running with transparent -proxy will enforce all inbound and outbound traffic to go through the Envoy proxy. - -The service name registered in Consul will be set to the name of the Kubernetes service -associated with the Pod. This can be customized with the `consul.hashicorp.com/connect-service` -annotation. If using ACLs, this name must be the same as the Pod's `ServiceAccount` name. +To establish a connection to the Pod using service mesh, a client must use another mesh proxy. The client mesh proxy will use Consul service discovery to find all available upstream proxies and their public ports. + +### Service names + +When the service is onboarded, the name registered in Consul is set to the name of the Kubernetes Service associated with the Pod. You can specify a custom name for the service in the [`consul.hashicorp.com/connect-service` annotation](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-connect-service), but if ACLs are enabled, then the name of the service registered in Consul must match the Pod's `ServiceAccount` name. + +### Transparent proxy mode + +By default, the Consul service mesh runs in transparent proxy mode. This mode forces inbound and outbound traffic through the sidecar proxy even though the service binds to all interfaces. Transparent proxy infers the location of upstream services using Consul service intentions, and also allows you to use Kubernetes DNS as you normally would for your workloads. + +When transparent proxy mode is enabled, all service-to-service traffic is required to use mTLS. While onboarding new services to service mesh, your network may have mixed mTLS and non-mTLS traffic, which can result in broken service-to-service communication. You can temporarily enable permissive mTLS mode during the onboarding process so that existing mesh services can accept traffic from services that are not yet fully onboarded. Permissive mTLS enables sidecar proxies to access both mTLS and non-mTLS traffic. Refer to [Onboard mesh services in transparent proxy mode](/consul/docs/k8s/connect/onboarding-tproxy-mode) for additional information. ### Connecting to Mesh-Enabled Services diff --git a/website/content/docs/k8s/connect/onboarding-tproxy-mode.mdx b/website/content/docs/k8s/connect/onboarding-tproxy-mode.mdx new file mode 100644 index 000000000000..03636b044308 --- /dev/null +++ b/website/content/docs/k8s/connect/onboarding-tproxy-mode.mdx @@ -0,0 +1,295 @@ +--- +layout: docs +page_title: Onboard services in transparent proxy mode +description: Learn how to enable permissive mutual transport layer security (permissive mTLS) so that you can safely add services to your service mesh when transparent proxy is enabled in Kubernetes deployments. +--- + +# Onboard services while in transparent proxy mode + +This topic describes how to run Consul in permissive mTLS mode so that you can safely onboard existing applications to Consul service mesh when transparent proxy mode is enabled. + +## Background + +When [transparent proxy mode](/consul/docs/k8s/transparent-proxy/) is enabled, all service-to-service traffic is secured by mTLS. Until the services that you want to add to the network are fully onboarded, your network may have a mix of mTLS and non-mTLS traffic, which can result in broken service-to-service communication. This situation occurs because sidecar proxies for existing mesh services reject traffic from services that are not yet onboarded. + +You can enable the `permissive` mTLS mode to ensure existing non-mTLS service-to-service traffic is allowed during the onboarding phase. The `permissive` mTLS mode enables sidecar proxies to accept both mTLS and non-mTLS traffic to an application. Using this mode enables you to onboard without downtime and without being required to reconfigure or redeploy your application. + +We recommend enabling permissive mTLS as a temporary operating mode. After onboarding is complete, you should reconfigure all services to `strict` mTLS mode to ensure all service-to-service communication is automatically secured by Consul service mesh. + +!> **Security warning**: We recommend that you disable permissive mTLS mode after onboarding services to prevent non-mTLS connections to the service. Intentions are not enforced and encryption is not enabled for non-mTLS connections. + +## Workflow + +The workflow to configure mTLS settings depends on the applications you are onboarding and the order you intend to onboard them, but the following steps describe the general workflow: + +1. **Configure global settings**: Configure the mesh to allow services to send non-mTLS messages to services outside the mesh. Additionally, configure the mesh to let services in the mesh use permissive mTLS mode. +1. **Enable permissive mTLS mode**: If you are onboarding an upstream service prior to its related downstream services, then enable permissive mTLS mode in the service defaults configuration entry. This allows the upstream service to send encrypted messages from the mesh when you register the service with Consul. +1. **Configure intentions**: Intentions are controls that authorize traffic between services in the mesh. Transparent proxy uses intentions to infer traffic routes between Envoy proxies. Consul does not enforce intentions for non-mTLS connections made while proxies are in permissive mTLS mode, but intentions are necessary for completing the onboarding process. +1. **Register the service**: Create the service definition and configure and deploy its sidecar proxy. +1. **Re-secure the mesh**: If you enabled permissive mTLS mode, switch back to strict mTLS mode and revert the global settings to disable non-mTLS traffic in the service mesh. + +## Requirements + +Permissive mTLS is only supported for services running in transparent proxy mode. Transparent proxy mode is only available on Kubernetes deployments. + +## Configure global settings + +Configure Consul to allow services that are already in the mesh to send non-mTLS messages to services outside the mesh. You can also Consul to allow services to run in permissive mTLS mode. Set both configurations in the mesh gateway configuration entry, which is the global configuration that defines service mesh proxy behavior. + +### Allow outgoing non-mTLS traffic + +You can configure a global setting that allows services in the mesh to send non-mTLS messages to services outside the mesh. + +Add the `MeshDestinationsOnly` property to the mesh configuration entry and set the property to `false`. If the services belong to multiple admin partitions, you must apply the setting in each partition: + + + +```hcl +Kind = "mesh" + +TransparentProxy { + MeshDestinationsOnly = false +} +``` + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: Mesh +metadata: + name: mesh +spec: + allowEnablingPermissiveMutualTLS: true +``` + +```json +{ + "Kind": "mesh", + "TransparentProxy": [ + { + "MeshDestinationsOnly": false + } + ] +} +``` + + + +Alternatively, you can selectively allow outgoing traffic on a per-service basis by configuring [outbound port exclusions](/consul/docs/k8s/connect/transparent-proxy/enable-transparent-proxy#exclude-outbound-ports). This setting excludes outgoing traffic from traffic redirection imposed by transparent proxy. When changing this setting, you must redeploy your application. + +### Allow permissive mTLS modes for incoming traffic + +Set the `AllowEnablingPermissiveMutualTLS` parameter in the mesh configuration entry to `true` so that services in the mesh _are able_ to use permissive mTLS mode for incoming traffic. The parameter does not direct services to use permissive mTLS. It is a global parameter that allows services to run in permissive mTLS mode. + + + +```hcl +Kind = "mesh" + +AllowEnablingPermissiveMutualTLS = true +TransparentProxy { + MeshDestinationsOnly = false +} +``` + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: Mesh +metadata: + name: mesh +spec: + allowEnablingPermissiveMutualTLS: true + transparentProxy: + meshDestinationsOnly: false +``` + + +```json +{ + "Kind": "mesh", + "AllowEnablingPermissiveMutualTLS": true, + "TransparentProxy": [ + { + "MeshDestinationsOnly": false + } + ] +} +``` + + + +You can change this setting back to `false` at any time, even if there are services currently running in permissive mode. Doing so allows you to decide at which point during the onboarding process to stop allowing services to use permissive mTLS. When the `MeshDestinationOnly` is set to `false`, you must configure all new services added to the mesh with `MutualTLSMode=strict` for the Consul to securely route traffic throughout the mesh. + +## Enable permissive mTLS mode + +Depending on the services you are onboarding, you may not need to enable permissive mTLS mode. If the service does not accept incoming traffic or accepts traffic from downstream services that are already part of the service mesh, then permissive mTLS mode is not required to continue. + +To enable permissive mTLS mode for the service, set [`MutualTLSMode=permissive`](/consul/docs/connect/config-entries/service-defaults#mutualtlsmode) in the service defaults configuration entry for the service. The following example shows how to configure this setting for a service named `example-service`. + + + +```hcl +Kind = "service-defaults" +Name = "example-service" + +MutualTLSMode = "permissive" +``` + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceDefaults +metadata: + name: example-service +spec: + mutualTLSMode: "permissive" +``` + +```json +{ + "Kind": "service-defaults", + "Name": "example-service", + "MutualTLSMode": "permissive" +} +``` + + + +Refer to the [service defaults configuration reference](/consul/docs/connect/config-entries/service-defaults) for information about all settings. + +You can change this setting back to `strict` at any time to ensure mTLS is required for incoming traffic to this service. + +## Configure intentions + +Service intentions are mechanisms in Consul that control traffic between services in the mesh. + +We recommend creating intentions that restrict services to accepting only necessary traffic. You must identify the downstream services that send messages to the service you want to add to the mesh and then create an intention to allow traffic to the service from its downstreams. + +When transparent proxy enabled and the `MutualTLSMode` parameter is set to `permissive`, incoming traffic from a downstream service to another upstream service is not secured by mTLS unless that upstream relationship is known to Consul. You must either define an intention so that Consul can infer the upstream relationship from the intention, or you must include an explicit upstream as part of the service definition for the downstream. + +Refer to [Service intentions](/consul/docs/connect/intentions) for additional information about how intentions work and how to create them. + +## Add the service to the mesh + +Register your service into the catalog and update your application to deploy a sidecar proxy. You should also monitor your service to verify its configuration. Refer to the [Consul on Kubernetes service mesh overview](/consul/docs/k8s/connect) for additional information. + +## Re-secure mesh traffic + +If the newly added service was placed in permissive mTLS mode for onboarding, then you should switch to strict mode when it is safe to do so. You should also revert the global settings that allow services to send and receive non-mTLS traffic. + +### Disable permissive mTLS mode + +Configure the service to operate in strict mTLS mode after the service is no longer receiving incoming non-mTLS traffic. After the downstream services that send messages to this service are all onboarded to the mesh, this service should no longer receive non-mTLS traffic. + +Check the following Envoy listener statistics for the sidecar proxy to determine if the sidecar is receiving non-mTLS traffic: + +- The `tcp.permissive_public_listener.*` statistics indicate non-mTLS traffic. If these metrics are static over a sufficient period of time, that indicates the sidecar is not receiving non-mTLS traffic. +- The `tcp.public_listener.*` statistics indicate mTLS traffic. If incoming traffic is expected to this service and these statistics are changing, then the sidecar is receiving mTLS traffic. + +Refer to the [service mesh observability overview](/consul/docs/connect/observability) and [metrics configuration for Consul on Kubernetes documentation](/consul/docs/k8s/connect/observability/metrics) for additional information. + +If your service is still receiving non-mTLS traffic, complete the following steps to determine the source of the non-mTLS traffic: + +1. Verify the list of downstream services. Optionally, you can enable [Envoy access logging](/consul/docs/connect/observability/access-logs) to determine source IP addresses for incoming traffic, and cross-reference those IP addresses with services in your network. +1. Verify that each downstream is onboarded to the service mesh. If a downstream is not onboarded, consider onboarding it next. +1. Verify that each downstream has an intention that allows it to send traffic to the upstream service. + +After you determine it is safe to move the service to strict mode, set `MutualTLSMode=strict` in the service defaults configuration entry. + + + +```hcl +Kind = "service-defaults" +Name = "example-service" + +MutualTLSMode = "strict" +``` + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceDefaults +metadata: + name: example-service +spec: + mutualTLSMode: "strict" +``` + +```json +{ + "Kind": "service-defaults", + "MutualTLSMode": "strict", + "Name": "example-service" +} +``` + + + +### Disable non-mTLS traffic + +After all services are onboarded, revert the global settings that allow non-mTLS traffic and verify that permissive mTLS mode is not being used in the mesh. + +Set `AllowEnablingPermissiveMutualTLS=false` and `MeshDestinationsOnly=true` in the mesh config entry. + + + +```hcl +Kind = “mesh” + +AllowEnablingPermissiveMutualTLS = false +TransparentProxy { + MeshDestinationsOnly = true +} +``` + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: Mesh +metadata: + name: mesh +spec: + allowEnablingPermissiveMutualTLS: false + transparentProxy: + meshDestinationsOnly: true +``` + + +```json +{ + "Kind": "mesh", + "AllowEnablingPermissiveMutualTLS": false, + "TransparentProxy": [ + { + "MeshDestinationsOnly": true + } + ] +} +``` + + + +For each namespace, admin partition, and datacenter in your Consul deployment, run the `consul config list` and `consul config read` commands to verify that no services are using `permissive` mTLS mode. + +The following command returns any service defaults configuration entries that contain `'MutualTLSMode = "permissive"'`: + +```shell-session +$ consul config list -kind service-defaults -filter 'MutualTLSMode == "permissive"' +``` + + In each admin partition and datacenter, verify that `MutualTLSMode = "permissive"` is not set in the proxy defaults configuration entry . If `MutualTLSMode` is either empty or if the configuration entry is not found, then the mode is `strict` by default. + + The following command fetches the proxy defaults configuration entry: + +```shell-session +$ consul config read -kind proxy-defaults -name global +{ + "Kind": "proxy-defaults", + "Name": "global", + "Partition": "default", + "Namespace": "default", + "TransparentProxy": {}, + "MutualTLSMode": "", + "MeshGateway": {}, + "Expose": {}, + "AccessLogs": {}, + "CreateIndex": 26, + "ModifyIndex": 30 +} +``` \ No newline at end of file diff --git a/website/content/docs/connect/transparent-proxy.mdx b/website/content/docs/k8s/connect/transparent-proxy/enable-transparent-proxy.mdx similarity index 81% rename from website/content/docs/connect/transparent-proxy.mdx rename to website/content/docs/k8s/connect/transparent-proxy/enable-transparent-proxy.mdx index 59a00e65077e..7db6a6db0396 100644 --- a/website/content/docs/connect/transparent-proxy.mdx +++ b/website/content/docs/k8s/connect/transparent-proxy/enable-transparent-proxy.mdx @@ -1,37 +1,13 @@ --- layout: docs -page_title: Service Mesh - Enable Transparent Proxy Mode +page_title: Enable transparent proxy mode description: >- - Learn how transparent proxy enables Consul on Kubernetes to direct inbound and outbound traffic through the service mesh. Use transparent proxying to increase application security without configuring individual upstream services. + Learn how to enable transparent proxy mode, which enables Consul on Kubernetes to direct inbound and outbound traffic through the service mesh and increase application security without configuring individual upstream services. --- -# Enable Transparent Proxy Mode +# Enable transparent proxy mode -This topic describes how to use Consul’s transparent proxy feature, which allows applications to communicate through the service mesh without modifying their configurations. Transparent proxy also hardens application security by preventing direct inbound connections that bypass the mesh. - -## Introduction - -When transparent proxy is enabled, Consul is able to perform the following actions automatically: - -- Infer the location of upstream services using service intentions. -- Redirect outbound connections that point to KubeDNS through the proxy. -- Force traffic through the proxy to prevent unauthorized direct access to the application. - -The following diagram shows how transparent proxy routes traffic: - -![Diagram demonstrating that with transparent proxy, connections are automatically routed through the mesh](/img/consul-connect/with-transparent-proxy.png) - -When transparent proxy is disabled, you must manually specify the following configurations so that your applications can communicate with other services in the mesh: - -* Explicitly configure upstream services by specifying a local port to access them. -* Change application to access `localhost:`. -* Configure applications to only listen on the loopback interface to prevent unauthorized traffic from bypassing the mesh. - -The following diagram shows how traffic flows through the mesh without transparent proxy enabled: - -![Diagram demonstrating that without transparent proxy, applications must "opt in" to connecting to their dependencies through the mesh](/img/consul-connect/without-transparent-proxy.png) - -Transparent proxy is available for Kubernetes environments. As part of the integration with Kubernetes, Consul registers Kubernetes Services, injects sidecar proxies, and enables traffic redirection. +This topic describes how to use transparent proxy mode in your service mesh. Transparent proxy allows applications to communicate through the service mesh without modifying their configurations. Transparent proxy also hardens application security by preventing direct inbound connections that bypass the mesh. Refer to [Transparent proxy overview](/consul/docs/k8s/connect/transparent-proxy) for additional information. ## Requirements @@ -40,24 +16,20 @@ Your network must meet the following environment and software requirements to us * Transparent proxy is available for Kubernetes environments. * Consul 1.10.0+ * Consul Helm chart 0.32.0+. If you want to use the Consul CNI plugin to redirect traffic, Helm chart 0.48.0+ is required. Refer to [Enable the Consul CNI plugin](#enable-the-consul-cni-plugin) for additional information. -* [Service intentions](/consul/docs/connect/intentions) must be configured to allow communication between intended services. +* You must create [service intentions](/consul/docs/connect/intentions) that explicitly allow communication between intended services so that Consul can infer upstream connections and use sidecar proxies to route messages appropriately. * The `ip_tables` kernel module must be running on all worker nodes within a Kubernetes cluster. If you are using the `modprobe` Linux utility, for example, issue the following command: `$ modprobe ip_tables` ~> **Upgrading to a supported version**: Always follow the [proper upgrade path](/consul/docs/upgrading/upgrade-specific/#transparent-proxy-on-kubernetes) when upgrading to a supported version of Consul, Consul on Kubernetes (`consul-k8s`), and the Consul Helm chart. -## Configuration - -This section describes how to configure the transparent proxy. - -### Enable transparent proxy +## Enable transparent proxy -You can enable the transparent proxy for an entire cluster, individual Kubernetes namespaces, and individual services. +Transparent proxy mode is enabled for the entire cluster by default when you install Consul on Kubernetes using the Consul Helm chart. Refer to the [Consul Helm chart reference](/consul/docs/k8s/helm) for information about all default configurations. -When you install Consul using the Helm chart, transparent proxy is enabled for the entire cluster by default. +You can explicitly enable transparent proxy for the entire cluster, individual namespaces, and individual services. -#### Entire cluster +### Entire cluster Use the `connectInject.transparentProxy.defaultEnabled` Helm value to enable or disable transparent proxy for the entire cluster: @@ -67,14 +39,14 @@ connectInject: defaultEnabled: true ``` -#### Kubernetes namespace +### Kubernetes namespace Apply the `consul.hashicorp.com/transparent-proxy=true` label to enable transparent proxy for a Kubernetes namespace. The label overrides the `connectInject.transparentProxy.defaultEnabled` Helm value and defines the default behavior of Pods in the namespace. The following example enables transparent proxy for Pods in the `my-app` namespace: ```bash kubectl label namespaces my-app "consul.hashicorp.com/transparent-proxy=true" ``` -#### Individual service +### Individual service Apply the `consul.hashicorp.com/transparent-proxy=true` annotation to enable transparent proxy on the Pod for each service. The annotation overrides the Helm value and the namespace label. The following example enables transparent proxy for the `static-server` service: @@ -126,7 +98,7 @@ spec: serviceAccountName: static-server ``` -### Enable the Consul CNI plugin +## Enable the Consul CNI plugin By default, Consul generates a `connect-inject init` container as part of the Kubernetes Pod startup process. The container configures traffic redirection in the service mesh through the sidecar proxy. To configure redirection, the container requires elevated CAP_NET_ADMIN privileges, which may not be compatible with security policies in your organization. @@ -134,7 +106,7 @@ Instead, you can enable the Consul container network interface (CNI) plugin to p The Consul Helm chart installs the CNI plugin, but it is disabled by default. Refer to the [instructions for enabling the CNI plugin](/consul/docs/k8s/installation/install#enable-the-consul-cni-plugin) in the Consul on Kubernetes installation documentation for additional information. -### Traffic redirection +## Traffic redirection There are two mechanisms for redirecting traffic through the sidecar proxies. By default, Consul injects an init container that redirects all inbound and outbound traffic. The default mechanism requires elevated permissions (CAP_NET_ADMIN) in order to redirect traffic to the service mesh. @@ -142,7 +114,7 @@ Alternatively, you can enable the Consul CNI plugin to handle traffic redirectio Both mechanisms redirect all inbound and outbound traffic, but you can configure exceptions for specific Pods or groups of Pods. The following annotations enable you to exclude certain traffic from being redirected to sidecar proxies. -#### Exclude inbound ports +### Exclude inbound ports The [`consul.hashicorp.com/transparent-proxy-exclude-inbound-ports`](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-transparent-proxy-exclude-inbound-ports) annotation defines a comma-separated list of inbound ports to exclude from traffic redirection when running in transparent proxy mode. The port numbers are string data values. In the following example, services in the pod at port `8200` and `8201` are not redirected through the transparent proxy: @@ -157,7 +129,7 @@ The [`consul.hashicorp.com/transparent-proxy-exclude-inbound-ports`](/consul/doc ``` -#### Exclude outbound ports +### Exclude outbound ports The [`consul.hashicorp.com/transparent-proxy-exclude-outbound-ports`](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-transparent-proxy-exclude-outbound-ports) annotation defines a comma-separated list of outbound ports to exclude from traffic redirection when running in transparent proxy mode. The port numbers are string data values. In the following example, services in the pod at port `8200` and `8201` are not redirected through the transparent proxy: @@ -173,7 +145,7 @@ The [`consul.hashicorp.com/transparent-proxy-exclude-outbound-ports`](/consul/do -#### Exclude outbound CIDR blocks +### Exclude outbound CIDR blocks The [`consul.hashicorp.com/transparent-proxy-exclude-outbound-cidrs`](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-transparent-proxy-exclude-outbound-cidrs) annotation defines a comma-separated list of outbound CIDR blocks to exclude from traffic redirection when running in transparent proxy mode. The CIDR blocks are string data values. @@ -190,7 +162,7 @@ In the following example, services in the `3.3.3.3/24` IP range are not redirect ``` -#### Exclude user IDs +### Exclude user IDs The [`consul.hashicorp.com/transparent-proxy-exclude-uids`](/consul/docs/k8s/annotations-and-labels#consul-hashicorp-com-transparent-proxy-exclude-uids) annotation defines a comma-separated list of additional user IDs to exclude from traffic redirection when running in transparent proxy mode. The user IDs are string data values. @@ -208,20 +180,20 @@ In the following example, services with the IDs `4444 ` and `44444 ` are not red -### Kubernetes HTTP health probes configuration +## Kubernetes HTTP health probes configuration By default, `connect-inject` is disabled. As a result, Consul on Kubernetes uses a mechanism for traffic redirection that interferes with [Kubernetes HTTP health probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). This is because probes expect the kubelet to reach the application container on the probe's endpoint. Instead, traffic is redirected through the sidecar proxy. As a result, health probes return errors because the kubelet does not encrypt that traffic using a mesh proxy. There are two methods for solving this issue. The first method is to set the `connectInject.transparentProxy.defaultOverwriteProbes` annotation to overwrite the Kubernetes HTTP health probes so that they point to the proxy. The second method is to [enable the Consul container network interface (CNI) plugin](#enable-the-consul-cni-plugin) to perform traffic redirection. Refer to the [Consul on Kubernetes installation instructions](/consul/docs/k8s/installation/install) for additional information. -#### Overwrite Kubernetes HTTP health probes +### Overwrite Kubernetes HTTP health probes You can either include the `connectInject.transparentProxy.defaultOverwriteProbes` Helm value to your command or add the `consul.hashicorp.com/transparent-proxy-overwrite-probes` Kubernetes annotation to your pod configuration to overwrite health probes. Refer to [Kubernetes Health Checks in Consul on Kubernetes](/consul/docs/k8s/connect/health) for additional information. -### Dial services across Kubernetes cluster +## Dial services across Kubernetes cluster If your [Consul servers are federated between Kubernetes clusters](/consul/docs/k8s/deployment-configurations/multi-cluster/kubernetes), then you must configure services in one Kubernetes cluster to explicitly dial a service in the datacenter of another Kubernetes cluster using the @@ -243,7 +215,7 @@ The following example configures the service to dial an upstream service called You do not need to configure services to explicitly dial upstream services if your Consul clusters are connected with a [peering connection](/consul/docs/connect/cluster-peering). -## Usage +## Configure service selectors When transparent proxy is enabled, traffic sent to [KubeDNS](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) or Pod IP addresses is redirected through the proxy. You must use a selector to bind Kubernetes Services to Pods as you define Kubernetes Services in the mesh. @@ -275,13 +247,13 @@ spec: Additional services can query the [KubeDNS](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) at `sample-app.default.svc.cluster.local` to reach `sample-app`. If ACLs are enabled and configured with default `deny` policies, the configuration also requires a [`ServiceIntention`](/consul/docs/connect/config-entries/service-intentions) to allow it to talk to `sample-app`. -### Headless Services +### Headless services For services that are not addressed using a virtual cluster IP, you must configure the upstream service using the [DialedDirectly](/consul/docs/connect/config-entries/service-defaults#dialeddirectly) option. Then, use DNS to discover individual instance addresses and dial them through the transparent proxy. When this mode is enabled on the upstream, services present service mesh certificates for mTLS and intentions are enforced at the destination. Note that when dialing individual instances, Consul ignores the HTTP routing rules configured with configuration entries. The transparent proxy acts as a TCP proxy to the original destination IP address. -## Known Limitations +## Known limitations - Deployment configurations with federation across or a single datacenter spanning multiple clusters must explicitly dial a service in another datacenter or cluster using annotations. -- When dialing headless services, the request is proxied using a plain TCP proxy. Consul does not take into consideration the upstream's protocol. +- When dialing headless services, the request is proxied using a plain TCP proxy. Consul does not take into consideration the upstream's protocol. \ No newline at end of file diff --git a/website/content/docs/k8s/connect/transparent-proxy/index.mdx b/website/content/docs/k8s/connect/transparent-proxy/index.mdx new file mode 100644 index 000000000000..78db657133f6 --- /dev/null +++ b/website/content/docs/k8s/connect/transparent-proxy/index.mdx @@ -0,0 +1,47 @@ +--- +layout: docs +page_title: Transparent proxy overview +description: >- + Transparent proxy enables Consul on Kubernetes to direct inbound and outbound traffic through the service mesh. Learn how transparently proxying increases application security without configuring individual upstream services. +--- + +# Transparent proxy overview + +This topic provides overview information about transparent proxy mode, which allows applications to communicate through the service mesh without modifying their configurations. Transparent proxy also hardens application security by preventing direct inbound connections that bypass the mesh. + +## Introduction + +When service mesh proxies are in transparent mode, Consul service mesh uses IPtables to direct all inbound and outbound traffic to the sidecar. Consul also uses information configured in service intentions to infer routes, which eliminates the need to explicitly configure upstreams. + +### Transparent proxy enabled + +The following diagram shows how Consul routes traffic when proxies are in transparent mode: + +![Diagram demonstrating that with transparent proxy, connections are automatically routed through the mesh](/img/consul-connect/with-transparent-proxy.png) + +### Transparent proxy disabled + +When transparent proxy mode is disabled, you must manually configure explicit upstreams, configure your applications to query for services at `localhost:`, and configure applications to only listen on the loopback interface to prevent services from bypassing the mesh. + +The following diagram shows how Consul routes traffic when transparent proxy mode is disabled: + +![Diagram demonstrating that without transparent proxy, applications must "opt in" to connecting to their dependencies through the mesh](/img/consul-connect/without-transparent-proxy.png) + +Transparent proxy is available for Kubernetes environments. As part of the integration with Kubernetes, Consul registers Kubernetes Services, injects sidecar proxies, and enables traffic redirection. + +## Supported networking architectures + +Transparent proxy mode enables several networking architectures and workflows. You can query Consul DNS to discover upstreams for single services, virtual services, and failover service instances that are in peered clusters. + +Consul supports the following intra-datacenter connection types for discovering upstreams when transparent proxy mode is enabled: + +- KubeDNS lookups across WAN-federated datacenters +- Consul DNS lookups across WAN-federated datacenters +- KubeDNS lookups in peered clusters and admin partitions +- Consul DNS lookups in peered clusters and admin partitions + +## Mutual TLS for transparent proxy mode + +Transparent proxy mode is enabled by default when you install Consul on Kubernetes using the Consul Helm chart. As a result, all services in the mesh must communicate through sidecar proxies, which enforce service intentions and mTLS encryption for the service mesh. While onboarding new services to service mesh, your network may have mixed mTLS and non-mTLS traffic, which can result in broken service-to-service communication. + +You can temporarily enable permissive mTLS mode during the onboarding process so that existing mesh services can accept traffic from services that are not yet fully onboarded. Permissive mTLS enables sidecar proxies to access both mTLS and non-mTLS traffic. Refer to [Onboard mesh services in transparent proxy mode](/consul/docs/k8s/connect/onboarding-tproxy-mode) for additional information. diff --git a/website/content/docs/k8s/l7-traffic/failover-tproxy.mdx b/website/content/docs/k8s/l7-traffic/failover-tproxy.mdx new file mode 100644 index 000000000000..6c76b6bd87ec --- /dev/null +++ b/website/content/docs/k8s/l7-traffic/failover-tproxy.mdx @@ -0,0 +1,124 @@ +--- +layout: docs +page_title: Configure failover service instances +description: Learn how to define failover services in Consul on Kubernetes when proxies are in transparent proxy mode. Consul can send traffic to backup service instances if a destination service becomes unhealthy or unresponsive. +--- + +# Configure failover service instances + +This topic describes how to configure failover service instances in Consul on Kubernetes when proxies are in transparent proxy mode. If a service becomes unhealthy or unresponsive, Consul can use the service resolver configuration entry to send inbound requests to backup services. Service resolvers are part of the service mesh proxy upstream discovery chain. Refer to [Service mesh traffic management](/consul/docs/connect/l7-traffic) for additional information. + +## Overview + +Complete the following steps to configure failover service instances in Consul on Kubernetes when proxies are in transparent proxy mode: + +- Create a service resolver configuration entry +- Create intentions that allow the downstream service to access the primary and failover service instances. +- Configure your application to call the discovery chain using the Consul DNS or KubeDNS. + +## Requirements + +- `consul-k8s` v1.2.0-beta1 or newer. +- Consul service mesh must be enabled. Refer to [How does Consul Service Mesh Work on Kubernetes](/consul/docs/k8s/connect). +- Proxies must be configured to run in transparent proxy mode. +- To query virtual DNS names, you must use Consul DNS. +- To query the discovery chain using KubeDNS, the service resolver must be in the same partition as the running service. + +### ACL requirements + +The default ACLs that the Consul Helm chart configures are suitable for most cases, but if you have more complex security policies for Consul API access, refer to the [ACL documentation](/consul/docs/security/acl) for additional guidance. + +## Create a service resolver configuration entry + +Specify the target failover in the [`spec.failover.targets`](/consul/docs/connect/config-entries/service-resolver#failover-targets-service) field in the service resolver configuration entry. In the following example, the `api-beta` service is configured to failover to the `api` service in any service subset: + + + +```yaml +apiversion: consul.hashicorp.com/v1alpha1 +kind: ServiceResolver +metadata: + name: api-beta +spec: + failover: + '*': + targets: + - service: api +``` + + + +Refer to the [service resolver configuration entry reference](/consul/docs/connect/config-entries/service-resolver) documentation for information about all service resolver configurations. + +You can apply the configuration using the `kubectl apply` command: + +```shell-session +$ kubectl apply -f api-beta-failover.yaml +``` + +## Create service intentions + +If intentions are not already defined, create and apply intentions that allow the appropriate downstream to access the target service and the failover service. In the following examples, the `frontend` service is allowed to send messages to the `api` service, which is allowed to send messages to the `api-beta` failover service. + + + + +```yaml +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceIntentions +metadata: + name: api +spec: + destination: + name: api + sources: + - name: frontend + action: allow +--- +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceIntentions +metadata: + name: api-beta +spec: + destination: + name: api-beta + sources: + - name: frontend + action: allow +``` + + + +Refer to the [service intentions configuration entry reference](/consul/docs/connect/config-entries/service-intentions) for additional information about configuring service intentions. + +You can apply the configuration using the `kubectl apply` command: + +```shell-session +$ kubectl apply -f frontend-api-api-beta-allow.yaml +``` + +## Configure your application to call the DNS + +Configure your application to contact the discovery chain in either the Consul DNS or the KubeDNS. + +### Consul DNS + +You can query the Consul DNS using the `.virtual.consul` lookup format. For Consul Enterprise, your query string may need to include the namespace, partition, or both. Refer to the [DNS documentation](/consul/docs/services/discovery/dns-static-lookups#service-virtual-ip-lookups) for details on building virtual service lookups. + +In the following example, the application queries the Consul catalog for `api-beta` over HTTP. By default, the lookup would query the `default` partition and `default` namespace if Consul Enterprise manages the network infrastructure: + +```text +http://api-beta.virtual.consul/ +``` + +### KubeDNS + +You can query the KubeDNS if the failover service is in the same Kubernetes cluster as the primary service. In the following example, the application queries KubeDNS for `api-beta` over HTTP: + +```text +http://api-beta..svc.cluster.local +``` + +Note that you cannot use KubeDNS if a corresponding Kubernetes service and pod do not exist. + + diff --git a/website/content/docs/k8s/l7-traffic/route-to-virtual-services.mdx b/website/content/docs/k8s/l7-traffic/route-to-virtual-services.mdx new file mode 100644 index 000000000000..c8951d356cf6 --- /dev/null +++ b/website/content/docs/k8s/l7-traffic/route-to-virtual-services.mdx @@ -0,0 +1,122 @@ +--- +layout: docs +page_title: Route traffic to a virtual service +description: Define virtual services in service resolver config entries so that Consul on Kubernetes can route traffic to virtual services when transparent proxy mode is enabled for Envoy proxies. +--- + +# Route traffic to a virtual service + +This topic describes how to define virtual services so that Consul on Kubernetes can route traffic to virtual services when transparent proxy mode is enabled for Envoy proxies. + +## Overview + +You can define virtual services in service resolver configuration entries so that downstream applications can send requests to a virtual service using a Consul DNS name in peered clusters. Your applications can send requests to virtual services in the same cluster using KubeDNS. Service resolvers are part of the service mesh proxy upstream discovery chain. Refer to [Service mesh traffic management](/consul/docs/connect/l7-traffic) for additional information. + +Complete the following steps to configure failover service instances in Consul on Kubernetes when proxies are in transparent proxy mode: + +1. Create a service resolver configuration entry. +1. Create intentions that allow the downstream service to access the real service and the virtual service. +1. Configure your application to call the discovery chain using the Consul DNS or KubeDNS. + +## Requirements + +- `consul-k8s` v1.2.0-beta1 or newer. +- Consul service mesh must be enabled. Refer to [How does Consul service mesh work on Kubernetes](/consul/docs/k8s/connect). +- Proxies must be configured to run in transparent proxy mode. +- To query virtual DNS names, you must use Consul DNS. +- To query the discovery chain using KubeDNS, the service resolver must be in the same partition as the running service. + +### ACL requirements + +The default ACLs that the Consul Helm chart configures are suitable for most cases, but if you have more complex security policies for Consul API access, refer to the [ACL documentation](/consul/docs/security/acl) for additional guidance. + +## Create a service resolver configuration entry + +Specify the target failover in the [`spec.redirect.service`](/consul/docs/connect/config-entries/service-resolver#spec-redirect-service) field in the service resolver configuration entry. In the following example, the `virtual-api` service is configured to redirect to the `real-api`: + + + +```yaml +apiversion: consul.hashicorp.com/v1alpha1 +kind: ServiceResolver +metadata: + name: virtual-api +spec: + redirect: + service: real-api +``` + + + +Refer to the [service resolver configuration entry reference](/consul/docs/connect/config-entries/service-resolver) documentation for information about all service resolver configurations. + +You can apply the configuration using the `kubectl apply` command: + +```shell-session +$ kubectl apply -f virtual-api-redirect.yaml +``` + +## Create service intentions + +If intentions are not already defined, create and apply intentions that allow the appropriate downstream to access the real service and the target redirect service. In the following examples, the `frontend` service is allowed to send messages to the `virtual-api` and `real-api` services: + + + + +```yaml +apiversion: consul.hashicorp.com/v1alpha1 +kind: ServiceIntentions +metadata: + name: virtual-api +spec: + destination: + name: virtual-api + sources: + - name: frontend + action: allow +--- +apiversion: consul.hashicorp.com/v1alpha1 +kind: ServiceIntentions +metadata: + name: real-api +spec: + destination: + name: real-api + sources: + - name: frontend + action: allow +``` + + + +Refer to the [service intentions configuration entry reference](/consul/docs/connect/config-entries/service-intentions) for additional information about configuring service intentions. + +You can apply the configuration using the `kubectl apply` command: + +```shell-session +$ kubectl apply -f frontend-api-api-beta-allow.yaml +``` + +## Configure your application to call the DNS + +Configure your application to contact the discovery chain in either the Consul DNS or the KubeDNS. + +### Consul DNS + +You can query the Consul DNS using the `.virtual.consul` lookup format. For Consul Enterprise, your query string may need to include the namespace, partition, or both. Refer to the [DNS documentation](/consul/docs/services/discovery/dns-static-lookups#service-virtual-ip-lookups) for details on building virtual service lookups. + +In the following example, the application queries the Consul catalog for `virtual-api` over HTTP. By default, the lookup would query the `default` partition and `default` namespace if Consul Enterprise manages the network infrastructure: + +```text +http://virtual-api.virtual.consul/ +``` + +### KubeDNS + +You can query the KubeDNS if the real and virtual services are in the same Kubernetes cluster by specifying the name of the service. In the following example, the application queries KubeDNS for `virtual-api` over HTTP: + +```text +http://virtual-api..svc.cluster.local +``` + +Note that you cannot use KubeDNS if a corresponding Kubernetes service and pod do not exist. \ No newline at end of file diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index e8f3ce7d597e..20335f715b0e 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -559,10 +559,6 @@ } ] }, - { - "title": "Transparent Proxy", - "path": "connect/transparent-proxy" - }, { "title": "Observability", "routes": [ @@ -729,6 +725,45 @@ } ] }, + { + "title": "Failover", + "routes": [ + { + "title": "Overview", + "path": "connect/failover" + }, + { + "title": "Usage", + "routes": [ + { + "title": "Configure failover services for Kubernetes", + "href": "/docs/k8s/l7-traffic/failover-tproxy" + }, + { + "title": "Automate geo-failover with prepared queries", + "href": "/tutorials/developer-discovery/automate-geo-failover" + } + ] + }, + { + "title": "Configuration", + "routes": [ + { + "title": "Sameness groups", + "href": "/consul/docs/connect/config-entries/service-resolver" + }, + { + "title": "Service resolver", + "href": "/consul/docs/connect/config-entries/service-resolver" + }, + { + "title": "Service intentions", + "href": "/consul/docs/connect/config-entries/service-intentions" + } + ] + } + ] + }, { "title": "Nomad", "path": "connect/nomad" @@ -1222,7 +1257,24 @@ }, { "title": "Transparent Proxy", - "href": "/docs/connect/transparent-proxy" + "routes": [ + { + "title": "Overview", + "path": "k8s/connect/transparent-proxy" + }, + { + "title": "Enable transparent proxy", + "path": "k8s/connect/transparent-proxy/enable-transparent-proxy" + }, + { + "title": "Route traffic to virtual services", + "href": "/docs/k8s/l7-traffic/route-to-virtual-services" + } + ] + }, + { + "title": "Onboarding services in transparent proxy mode", + "path": "k8s/connect/onboarding-tproxy-mode" }, { "title": "Ingress Gateways", @@ -1255,6 +1307,23 @@ } ] }, + { + "title": "L7 traffic management", + "routes": [ + { + "title": "Overview", + "href": "/docs/connect/l7-traffic" + }, + { + "title": "Configure failover services", + "path": "k8s/l7-traffic/failover-tproxy" + }, + { + "title": "Route traffic to virtual services", + "path": "k8s/l7-traffic/route-to-virtual-services" + } + ] + }, { "title": "Service Sync", "path": "k8s/service-sync" From b1d3ec0cdbd39ecdb84f9bbeb64693ad2197f0fd Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Mon, 12 Jun 2023 09:20:29 -0500 Subject: [PATCH 012/359] Delete check-legacy-links-format.yml (#17647) --- .../workflows/check-legacy-links-format.yml | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/check-legacy-links-format.yml diff --git a/.github/workflows/check-legacy-links-format.yml b/.github/workflows/check-legacy-links-format.yml deleted file mode 100644 index 85dbb0e70f2e..000000000000 --- a/.github/workflows/check-legacy-links-format.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -name: Legacy Link Format Checker - -on: - push: - paths: - - "website/content/**/*.mdx" - - "website/data/*-nav-data.json" - -jobs: - check-links: - uses: hashicorp/dev-portal/.github/workflows/docs-content-check-legacy-links-format.yml@475289345d312552b745224b46895f51cc5fc490 - with: - repo-owner: "hashicorp" - repo-name: "consul" - commit-sha: ${{ github.sha }} - mdx-directory: "website/content" - nav-data-directory: "website/data" From 809c188b341e1076c495d7125f8ced09678a4c4f Mon Sep 17 00:00:00 2001 From: Paul Glass Date: Mon, 12 Jun 2023 10:11:36 -0500 Subject: [PATCH 013/359] docs: Reference doc updates for permissive mTLS settings (#17371) * Reference doc updates for permissive mTLS settings * Document config entry filtering * Fix minor doc errors (double slashes in link url paths) --------- Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> --- website/content/api-docs/config.mdx | 1 + website/content/commands/config/list.mdx | 10 +++++ .../docs/connect/config-entries/mesh.mdx | 6 +++ .../connect/config-entries/proxy-defaults.mdx | 17 +++++++++ .../config-entries/service-defaults.mdx | 37 ++++++++++++++++++- .../docs/release-notes/consul/v1_13_x.mdx | 4 +- .../services/discovery/dns-configuration.mdx | 24 ++++++------ 7 files changed, 83 insertions(+), 16 deletions(-) diff --git a/website/content/api-docs/config.mdx b/website/content/api-docs/config.mdx index 96e6a7b4de77..a79e024fa46f 100644 --- a/website/content/api-docs/config.mdx +++ b/website/content/api-docs/config.mdx @@ -215,6 +215,7 @@ The corresponding CLI command is [`consul config list`](/consul/commands/config/ ### Path Parameters - `kind` `(string: )` - Specifies the kind of the entry to list. +- `filter` `(string: "")` - Specifies an expression to use for filtering the results. ### Query Parameters diff --git a/website/content/commands/config/list.mdx b/website/content/commands/config/list.mdx index 1a70af178725..e453b1194319 100644 --- a/website/content/commands/config/list.mdx +++ b/website/content/commands/config/list.mdx @@ -44,6 +44,7 @@ Usage: `consul config list [options]` #### Command Options - `-kind` - Specifies the kind of the config entry to list. +- `-filter` - Specifies an expression to use for filtering the results. #### Enterprise Options @@ -57,7 +58,16 @@ Usage: `consul config list [options]` ## Examples +To list all service-defaults config entries: + $ consul config list -kind service-defaults billing db web + +The following lists service-defaults with a filter expression: + + $ consul config list -kind service-defaults -filter 'MutualTLSMode == "permissive"' + db + web + diff --git a/website/content/docs/connect/config-entries/mesh.mdx b/website/content/docs/connect/config-entries/mesh.mdx index f65ed6162287..a323a6d90f17 100644 --- a/website/content/docs/connect/config-entries/mesh.mdx +++ b/website/content/docs/connect/config-entries/mesh.mdx @@ -338,6 +338,12 @@ Note that the Kubernetes example does not include a `partition` field. Configura }, ], }, + { + name: 'AllowEnablingPermissiveMutualTLS', + type: 'bool: false', + description: + 'Controls whether `MutualTLSMode=permissive` can be set in the `proxy-defaults` and `service-defaults` configuration entries. ' + }, { name: 'TLS', type: 'TLSConfig: ', diff --git a/website/content/docs/connect/config-entries/proxy-defaults.mdx b/website/content/docs/connect/config-entries/proxy-defaults.mdx index 917bc0504494..1d94a79389b6 100644 --- a/website/content/docs/connect/config-entries/proxy-defaults.mdx +++ b/website/content/docs/connect/config-entries/proxy-defaults.mdx @@ -53,6 +53,7 @@ TransparentProxy { OutboundListenerPort = DialedDirectly = } +MutualTLSMode = "" MeshGateway { Mode = "" } @@ -92,6 +93,7 @@ spec: transparentProxy: outboundListenerPort: dialedDirectly: + mutualTLSMode: meshGateway: mode: expose: @@ -120,6 +122,7 @@ spec: "Config": { "": }, + "MutualTLSMode": "", "Mode": "", "TransparentProxy": { "OutboundListenerPort": , @@ -175,6 +178,7 @@ TransparentProxy { OutboundListenerPort = DialedDirectly = } +MutualTLSMode = "" MeshGateway { Mode = "" } @@ -215,6 +219,7 @@ spec: transparentProxy: outboundListenerPort: dialedDirectly: + mutualTLSMode: meshGateway: mode: expose: @@ -249,6 +254,7 @@ spec: "OutboundListenerPort": , "DialedDirectly": }, + "MutualTLSMode": "", "MeshGateway": { "Mode": = "" }, @@ -405,6 +411,17 @@ spec: }, ], }, + { + name: 'MutualTLSMode', + type: 'string: ""', + description: `Controls the default mutual TLS mode for all proxies. This setting is only + supported for services with transparent proxy enabled. One of \`""\`, \`strict\`, or \`permissive\`. + When unset or \`""\`, the mode defaults to \`strict\`. When set to \`strict\`, the sidecar proxy + requires mutual TLS for incoming traffic. When set to \`permissive\`, the sidecar proxy accepts + mutual TLS traffic on the sidecar proxy service port and accepts any traffic on the destination + service port. We recommend only using \`permissive\` mode if necessary while onboarding services to + the service mesh. `, + }, { name: 'MeshGateway', type: 'MeshGatewayConfig: ', diff --git a/website/content/docs/connect/config-entries/service-defaults.mdx b/website/content/docs/connect/config-entries/service-defaults.mdx index 000b63246c4e..507176506f4f 100644 --- a/website/content/docs/connect/config-entries/service-defaults.mdx +++ b/website/content/docs/connect/config-entries/service-defaults.mdx @@ -10,7 +10,7 @@ This topic describes how to configure service defaults configuration entries. Th ## Configuration model -The following outline shows how to format the service splitter configuration entry. Click on a property name to view details about the configuration. +The following outline shows how to format the service defaults configuration entry. Click on a property name to view details about the configuration. @@ -58,6 +58,7 @@ The following outline shows how to format the service splitter configuration ent - [`TransparentProxy`](#transparentproxy): map | no default - [`OutboundListenerPort`](#transparentproxy): integer | `15001` - [`DialedDirectly`](#transparentproxy ): boolean | `false` +- [`MutualTLSMode`](#mutualtlsmode): string | `""` - [`EnvoyExtensions`](#envoyextensions): list | no default - [`Name`](#envoyextensions): string | `""` - [`Required`](#envoyextensions): string | `""` @@ -126,6 +127,7 @@ The following outline shows how to format the service splitter configuration ent - [`transparentProxy`](#transparentproxy): map | no default - [`outboundListenerPort`](#transparentproxy): integer | `15001` - [`dialedDirectly`](#transparentproxy): boolean | `false` + - [`mutualTLSMode`](#mutualtlsmode): string | `""` - [`envoyExtensions`](#envoyextensions): list | no default - [`name`](#envoyextensions): string | `""` - [`required`](#envoyextensions): string | `""` @@ -152,7 +154,7 @@ The following outline shows how to format the service splitter configuration ent ## Complete configuration -When every field is defined, a service splitter configuration entry has the following form: +When every field is defined, a service-defaults configuration entry has the following form: @@ -213,6 +215,7 @@ TransparentProxy = { OutboundListenerPort = 15002 DialedDirectly = true } +MutualTLSMode = "strict" Destination = { Addresses = [ "First IP address", @@ -288,6 +291,7 @@ spec: transparentProxy: outboundListenerPort: 15001 dialedDirectly: false + mutualTLSMode: strict destination: addresses: - @@ -370,6 +374,7 @@ spec: "outboundListenerPort": 15001, "dialedDirectly": false }, + "mutualTLSMode": "strict", "destination": { "addresses": [ "", @@ -697,6 +702,19 @@ You can configure the following parameters in the `TransparentProxy` block: | `OutboundListenerPort` | Specifies the port that the proxy listens on for outbound traffic. This must be the same port number where outbound application traffic is redirected. | integer | `15001` | | `DialedDirectly` | Enables transparent proxies to dial the proxy instance's IP address directly when set to `true`. Transparent proxies commonly dial upstreams at the `"virtual"` tagged address, which load balances across instances. Dialing individual instances can be helpful for stateful services, such as a database cluster with a leader. | boolean | `false` | +### `MutualTLSMode` + +Controls whether mutual TLS is required for incoming connections to this service. This setting is +only supported for services with transparent proxy enabled. We recommend only using `permissive` +mode if necessary while onboarding services to the service mesh. + +You can specify the following string values for the `MutualTLSMode` field: + +- `""`: When this field is empty, the value is inherited from the `proxy-defaults` config entry. +- `strict`: The sidecar proxy requires mutual TLS for incoming traffic. +- `permissive`: The sidecar proxy accepts mutual TLS traffic on the sidecar proxy service port, + and accepts any traffic on the destination service's port. + ### `EnvoyExtensions` List of extensions to modify Envoy proxy configuration. Refer to [Envoy Extensions](/consul/docs/connect/proxies/envoy-extensions) for additional information. @@ -1089,6 +1107,21 @@ You can configure the following parameters in the `TransparentProxy` block: | `outboundListenerPort` | Specifies the port that the proxy listens on for outbound traffic. This must be the same port number where outbound application traffic is redirected. | integer | `15001` | | `dialedDirectly` | Enables transparent proxies to dial the proxy instance's IP address directly when set to `true`. Transparent proxies commonly dial upstreams at the `"virtual"` tagged address, which load balances across instances. Dialing individual instances can be helpful for stateful services, such as a database cluster with a leader. | boolean | `false` | +### `spec.mutualTLSMode` + +Controls whether mutual TLS is required for incoming connections to this service. This setting is +only supported for services with transparent proxy enabled. We recommend only using `permissive` +mode if necessary while onboarding services to the service mesh. + +#### Values + +You can specify the following string values for the `MutualTLSMode` field: + +- `""`: When this field is empty, the value is inherited from the `proxy-defaults` config entry. +- `strict`: The sidecar proxy requires mutual TLS for incoming traffic. +- `permissive`: The sidecar proxy accepts mutual TLS traffic on the sidecar proxy service port, + and accepts any traffic on the destination service's port. + ### `spec.envoyExtensions` List of extensions to modify Envoy proxy configuration. Refer to [Envoy Extensions](/consul/docs/connect/proxies/envoy-extensions) for additional information. diff --git a/website/content/docs/release-notes/consul/v1_13_x.mdx b/website/content/docs/release-notes/consul/v1_13_x.mdx index dd3f7cfe3090..f0c4f586a906 100644 --- a/website/content/docs/release-notes/consul/v1_13_x.mdx +++ b/website/content/docs/release-notes/consul/v1_13_x.mdx @@ -15,7 +15,7 @@ description: >- - **Enables TLS on the Envoy Prometheus endpoint**: The Envoy prometheus endpoint can be enabled when `envoy_prometheus_bind_addr` is set and then secured over TLS using new CLI flags for the `consul connect envoy` command. These commands are: `-prometheus-ca-file`, `-prometheus-ca-path`, `-prometheus-cert-file` and `-prometheus-key-file`. The CA, cert, and key can be provided to Envoy by a Kubernetes mounted volume so that Envoy can watch the files and dynamically reload the certs when the volume is updated. -- **UDP Health Checks**: Adds the ability to register service discovery health checks that periodically send UDP datagrams to the specified IP/hostname and port. Refer to [UDP checks](/consul/docs//services/usage/checks#udp-checks). +- **UDP Health Checks**: Adds the ability to register service discovery health checks that periodically send UDP datagrams to the specified IP/hostname and port. Refer to [UDP checks](/consul/docs/services/usage/checks#udp-checks). ## What's Changed @@ -46,4 +46,4 @@ The changelogs for this major release version and any maintenance versions are l - [1.13.3](https://github.com/hashicorp/consul/releases/tag/v1.13.3) - [1.13.4](https://github.com/hashicorp/consul/releases/tag/v1.13.4) - [1.13.5](https://github.com/hashicorp/consul/releases/tag/v1.13.5) -- [1.13.6](https://github.com/hashicorp/consul/releases/tag/v1.13.6) \ No newline at end of file +- [1.13.6](https://github.com/hashicorp/consul/releases/tag/v1.13.6) diff --git a/website/content/docs/services/discovery/dns-configuration.mdx b/website/content/docs/services/discovery/dns-configuration.mdx index 794be43a206a..0a10edecdd9d 100644 --- a/website/content/docs/services/discovery/dns-configuration.mdx +++ b/website/content/docs/services/discovery/dns-configuration.mdx @@ -1,7 +1,7 @@ --- layout: docs -page_title: Configure Consul DNS behavior -description: -> +page_title: Configure Consul DNS behavior +description: -> Learn how to modify the default DNS behavior so that services and nodes can easily discover other services and nodes in your network. --- @@ -12,29 +12,29 @@ This topic describes the default behavior of the Consul DNS functionality and ho ## Introduction The Consul DNS is the primary interface for querying records when Consul service mesh is disabled and your network runs in a non-Kubernetes environment. The DNS enables you to look up services and nodes registered with Consul using terminal commands instead of making HTTP API requests to Consul. Refer to the [Discover Consul Nodes and Services Overview](/consul/docs/services/discovery/dns-overview) for additional information. -## Configure DNS behaviors +## Configure DNS behaviors By default, the Consul DNS listens for queries at `127.0.0.1:8600` and uses the `consul` domain. Specify the following parameters in the agent configuration to determine DNS behavior when querying services: - [`client_addr`](/consul/docs/agent/config/config-files#client_addr) - [`ports.dns`](/consul/docs/agent/config/config-files#dns_port) - [`recursors`](/consul/docs/agent/config/config-files#recursors) -- [`domain`](/consul/docs/agent/config/config-files#domain) +- [`domain`](/consul/docs/agent/config/config-files#domain) - [`alt_domain`](/consul/docs/agent/config/config-files#alt_domain) -- [`dns_config`](/consul/docs/agent/config/config-files#dns_config) +- [`dns_config`](/consul/docs/agent/config/config-files#dns_config) ### Configure WAN address translation By default, Consul DNS queries return a node's local address, even when being queried from a remote datacenter. You can configure the DNS to reach a node from outside its datacenter by specifying the address in the following configuration fields in the Consul agent: -- [advertise-wan](/consul/docs/agent/config/cli-flags#_advertise-wan) -- [translate_wan_addrs](/consul//docs/agent/config/config-files#translate_wan_addrs) +- [advertise-wan](/consul/docs/agent/config/cli-flags#_advertise-wan) +- [translate_wan_addrs](/consul/docs/agent/config/config-files#translate_wan_addrs) ### Use a custom DNS resolver library You can specify a list of addresses in the agent's [`recursors`](/consul/docs/agent/config/config-files#recursors) field to provide upstream DNS servers that recursively resolve queries that are outside the service domain for Consul. - -Nodes that query records outside the `consul.` domain resolve to an upstream DNS. You can specify IP addresses or use `go-sockaddr` templates. Consul resolves IP addresses in the specified order and ignores duplicates. + +Nodes that query records outside the `consul.` domain resolve to an upstream DNS. You can specify IP addresses or use `go-sockaddr` templates. Consul resolves IP addresses in the specified order and ignores duplicates. ### Enable non-Consul queries -You enable non-Consul queries to be resolved by setting Consul as the DNS server for a node and providing a [`recursors`](/consul/docs/agent/config/config-files#recursors) configuration. +You enable non-Consul queries to be resolved by setting Consul as the DNS server for a node and providing a [`recursors`](/consul/docs/agent/config/config-files#recursors) configuration. ### Forward queries to an agent You can forward all queries sent to the `consul.` domain from the existing DNS server to a Consul agent. Refer to [Forward DNS for Consul Service Discovery](/consul/tutorials/networking/dns-forwarding) for instructions. @@ -42,7 +42,7 @@ You can forward all queries sent to the `consul.` domain from the existing DNS s ### Query an alternate domain By default, Consul responds to DNS queries in the `consul` domain, but you can set a specific domain for responding to DNS queries by configuring the [`domain`](/consul/docs/agent/config/config-files#domain) parameter. -You can also specify an additional domain in the [`alt_domain`](/consul/docs/agent/config/config-files#alt_domain) agent configuration option, which configures Consul to respond to queries in a secondary domain. Configuring an alternate domain may be useful during a DNS migration or to distinguish between internal and external queries, for example. +You can also specify an additional domain in the [`alt_domain`](/consul/docs/agent/config/config-files#alt_domain) agent configuration option, which configures Consul to respond to queries in a secondary domain. Configuring an alternate domain may be useful during a DNS migration or to distinguish between internal and external queries, for example. Consul's DNS response uses the same domain as the query. @@ -62,7 +62,7 @@ machine.node.dc1.test-domain. 0 IN A 127.0.0.1 machine.node.dc1.test-domain. 0 IN TXT "consul-network-segment=" ``` #### PTR queries -Responses to pointer record (PTR) queries, such as `.in-addr.arpa.`, always use the [primary domain](/consul/docs/agent/config/config-files#domain) and not the alternative domain. +Responses to pointer record (PTR) queries, such as `.in-addr.arpa.`, always use the [primary domain](/consul/docs/agent/config/config-files#domain) and not the alternative domain. ### Caching By default, DNS results served by Consul are not cached. Refer to the [DNS Caching tutorial](/consul/tutorials/networking/dns-caching) for instructions on how to enable caching. From baaf6d84c749f7abb7b99d895c39b677647e87cd Mon Sep 17 00:00:00 2001 From: Matt Keeler Date: Mon, 12 Jun 2023 11:32:43 -0400 Subject: [PATCH 014/359] Add generic experiments configuration and use it to enable catalog v2 resources (#17604) * Add generic experiments configuration and use it to enable catalog v2 resources * Run formatting with -s as CI will validate that this has been done --- GNUmakefile | 2 +- agent/config/builder.go | 1 + agent/config/config.go | 1 + agent/config/default.go | 3 +++ agent/config/runtime.go | 3 +++ agent/config/runtime_test.go | 2 ++ .../testdata/TestRuntimeConfig_Sanitize.golden | 1 + agent/config/testdata/full-config.hcl | 3 +++ agent/config/testdata/full-config.json | 17 ++++++++++------- agent/consul/options.go | 2 ++ agent/consul/server.go | 16 +++++++++++----- agent/setup.go | 1 + 12 files changed, 39 insertions(+), 13 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index e874fa0eb706..3443b71db7b7 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -337,7 +337,7 @@ fmt: $(foreach mod,$(GO_MODULES),fmt/$(mod)) .PHONY: fmt/% fmt/%: @echo "--> Running go fmt ($*)" - @cd $* && go fmt ./... + @cd $* && gofmt -s -l -w . .PHONY: lint lint: $(foreach mod,$(GO_MODULES),lint/$(mod)) lint-container-test-deps diff --git a/agent/config/builder.go b/agent/config/builder.go index 063771b0f7d0..665688b8c864 100644 --- a/agent/config/builder.go +++ b/agent/config/builder.go @@ -828,6 +828,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) { Version: stringVal(c.Version), VersionPrerelease: stringVal(c.VersionPrerelease), VersionMetadata: stringVal(c.VersionMetadata), + Experiments: c.Experiments, // What is a sensible default for BuildDate? BuildDate: timeValWithDefault(c.BuildDate, time.Date(1970, 1, 00, 00, 00, 01, 0, time.UTC)), diff --git a/agent/config/config.go b/agent/config/config.go index d8d7149afebf..8917a60858d6 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -183,6 +183,7 @@ type Config struct { EncryptKey *string `mapstructure:"encrypt" json:"encrypt,omitempty"` EncryptVerifyIncoming *bool `mapstructure:"encrypt_verify_incoming" json:"encrypt_verify_incoming,omitempty"` EncryptVerifyOutgoing *bool `mapstructure:"encrypt_verify_outgoing" json:"encrypt_verify_outgoing,omitempty"` + Experiments []string `mapstructure:"experiments" json:"experiments,omitempty"` GossipLAN GossipLANConfig `mapstructure:"gossip_lan" json:"-"` GossipWAN GossipWANConfig `mapstructure:"gossip_wan" json:"-"` HTTPConfig HTTPConfig `mapstructure:"http_config" json:"-"` diff --git a/agent/config/default.go b/agent/config/default.go index 3af8d0867d4c..536ac7ac3340 100644 --- a/agent/config/default.go +++ b/agent/config/default.go @@ -209,6 +209,9 @@ func DevSource() Source { ports = { grpc = 8502 } + experiments = [ + "resource-apis" + ] `, } } diff --git a/agent/config/runtime.go b/agent/config/runtime.go index dca9abe0e7f9..1a8dc13794d3 100644 --- a/agent/config/runtime.go +++ b/agent/config/runtime.go @@ -1498,6 +1498,9 @@ type RuntimeConfig struct { Reporting ReportingConfig + // List of experiments to enable + Experiments []string + EnterpriseRuntimeConfig } diff --git a/agent/config/runtime_test.go b/agent/config/runtime_test.go index 3b1a77b2cb95..c1cd85ac502f 100644 --- a/agent/config/runtime_test.go +++ b/agent/config/runtime_test.go @@ -325,6 +325,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) { rt.DisableAnonymousSignature = true rt.DisableKeyringFile = true rt.EnableDebug = true + rt.Experiments = []string{"resource-apis"} rt.UIConfig.Enabled = true rt.LeaveOnTerm = false rt.Logging.LogLevel = "DEBUG" @@ -6355,6 +6356,7 @@ func TestLoad_FullConfig(t *testing.T) { EnableRemoteScriptChecks: true, EnableLocalScriptChecks: true, EncryptKey: "A4wELWqH", + Experiments: []string{"foo"}, StaticRuntimeConfig: StaticRuntimeConfig{ EncryptVerifyIncoming: true, EncryptVerifyOutgoing: true, diff --git a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden index 334f5f8c8ff5..b6ee9a98129f 100644 --- a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden +++ b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden @@ -199,6 +199,7 @@ "EnableRemoteScriptChecks": false, "EncryptKey": "hidden", "EnterpriseRuntimeConfig": {}, + "Experiments": [], "ExposeMaxPort": 0, "ExposeMinPort": 0, "GRPCAddrs": [], diff --git a/agent/config/testdata/full-config.hcl b/agent/config/testdata/full-config.hcl index 660e1036086d..6029d2ea2e6b 100644 --- a/agent/config/testdata/full-config.hcl +++ b/agent/config/testdata/full-config.hcl @@ -285,6 +285,9 @@ enable_syslog = true encrypt = "A4wELWqH" encrypt_verify_incoming = true encrypt_verify_outgoing = true +experiments = [ + "foo" +] http_config { block_endpoints = [ "RBvAFcGD", "fWOWFznh" ] allow_write_http_from = [ "127.0.0.1/8", "22.33.44.55/32", "0.0.0.0/0" ] diff --git a/agent/config/testdata/full-config.json b/agent/config/testdata/full-config.json index 52dab37bfa53..cd407d3e5dae 100644 --- a/agent/config/testdata/full-config.json +++ b/agent/config/testdata/full-config.json @@ -327,6 +327,9 @@ "encrypt": "A4wELWqH", "encrypt_verify_incoming": true, "encrypt_verify_outgoing": true, + "experiments": [ + "foo" + ], "http_config": { "block_endpoints": [ "RBvAFcGD", @@ -407,17 +410,17 @@ "raft_snapshot_interval": "30s", "raft_trailing_logs": 83749, "raft_logstore": { - "backend" : "wal", - "disable_log_cache": true, + "backend": "wal", + "disable_log_cache": true, "verification": { - "enabled": true, - "interval":"12345s" + "enabled": true, + "interval": "12345s" }, "boltdb": { - "no_freelist_sync": true + "no_freelist_sync": true }, "wal": { - "segment_size_mb": 15 + "segment_size_mb": 15 } }, "read_replica": true, @@ -927,4 +930,4 @@ "xds": { "update_max_per_second": 9526.2 } -} +} \ No newline at end of file diff --git a/agent/consul/options.go b/agent/consul/options.go index ac6bfc41065b..26cb2471a89b 100644 --- a/agent/consul/options.go +++ b/agent/consul/options.go @@ -39,6 +39,8 @@ type Deps struct { // HCP contains the dependencies required when integrating with the HashiCorp Cloud Platform HCP hcp.Deps + Experiments []string + EnterpriseDeps } diff --git a/agent/consul/server.go b/agent/consul/server.go index 418db2da1ffe..6bb424c67535 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -79,6 +79,7 @@ import ( raftstorage "github.com/hashicorp/consul/internal/storage/raft" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib/routine" + "github.com/hashicorp/consul/lib/stringslice" "github.com/hashicorp/consul/logging" "github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/proto/private/pbsubscribe" @@ -131,6 +132,8 @@ const ( reconcileChSize = 256 LeaderTransferMinVersion = "1.6.0" + + catalogResourceExperimentName = "resource-apis" ) const ( @@ -807,7 +810,7 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server, incom s.internalResourceServiceClient, logger.Named(logging.ControllerRuntime), ) - s.registerResources() + s.registerResources(flat) go s.controllerManager.Run(&lib.StopChannelContext{StopCh: shutdownCh}) go s.trackLeaderChanges() @@ -858,11 +861,14 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server, incom return s, nil } -func (s *Server) registerResources() { - catalog.RegisterTypes(s.typeRegistry) - catalog.RegisterControllers(s.controllerManager, catalog.DefaultControllerDependencies()) +func (s *Server) registerResources(deps Deps) { + if stringslice.Contains(deps.Experiments, catalogResourceExperimentName) { + catalog.RegisterTypes(s.typeRegistry) + catalog.RegisterControllers(s.controllerManager, catalog.DefaultControllerDependencies()) + + mesh.RegisterTypes(s.typeRegistry) + } - mesh.RegisterTypes(s.typeRegistry) reaper.RegisterControllers(s.controllerManager) if s.config.DevMode { diff --git a/agent/setup.go b/agent/setup.go index fba5c2b5dd6c..6a9efb5f7442 100644 --- a/agent/setup.go +++ b/agent/setup.go @@ -73,6 +73,7 @@ func NewBaseDeps(configLoader ConfigLoader, logOut io.Writer, providedLogger hcl return d, err } d.WatchedFiles = result.WatchedFiles + d.Experiments = result.RuntimeConfig.Experiments cfg := result.RuntimeConfig logConf := cfg.Logging logConf.Name = logging.Agent From 1074252361949b02fe6d43c744dfcecb8a23613e Mon Sep 17 00:00:00 2001 From: Nathan Coleman Date: Mon, 12 Jun 2023 12:06:04 -0400 Subject: [PATCH 015/359] api-gateway: stop adding all header filters to virtual host when generating xDS (#17644) * Add header filter to api-gateway xDS golden test * Stop adding all header filters to virtual host when generating xDS for api-gateway * Regenerate xDS golden file for api-gateway w/ header filter --- agent/xds/resources_test.go | 13 +++++ agent/xds/routes.go | 12 ----- ...route-and-inline-certificate.latest.golden | 51 +++++++++++++------ 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/agent/xds/resources_test.go b/agent/xds/resources_test.go index 4687c4a7d637..29743c060bfd 100644 --- a/agent/xds/resources_test.go +++ b/agent/xds/resources_test.go @@ -415,6 +415,19 @@ func getAPIGatewayGoldenTestCases(t *testing.T) []goldenTestCase { Kind: structs.HTTPRoute, Name: "route", Rules: []structs.HTTPRouteRule{{ + Filters: structs.HTTPFilters{ + Headers: []structs.HTTPHeaderFilter{ + { + Add: map[string]string{ + "X-Header-Add": "added", + }, + Set: map[string]string{ + "X-Header-Set": "set", + }, + Remove: []string{"X-Header-Remove"}, + }, + }, + }, Services: []structs.HTTPService{{ Name: "service", }}, diff --git a/agent/xds/routes.go b/agent/xds/routes.go index dbd74f511ed0..a86747a9c080 100644 --- a/agent/xds/routes.go +++ b/agent/xds/routes.go @@ -477,8 +477,6 @@ func (s *ResourceGenerator) routesForAPIGateway(cfgSnap *proxycfg.ConfigSnapshot return nil, err } - addHeaderFiltersToVirtualHost(&reformatedRoute, virtualHost) - defaultRoute.VirtualHosts = append(defaultRoute.VirtualHosts, virtualHost) } @@ -1097,16 +1095,6 @@ func injectHeaderManipToRoute(dest *structs.ServiceRouteDestination, r *envoy_ro return nil } -func addHeaderFiltersToVirtualHost(dest *structs.HTTPRouteConfigEntry, vh *envoy_route_v3.VirtualHost) { - for _, rule := range dest.Rules { - for _, header := range rule.Filters.Headers { - vh.RequestHeadersToAdd = append(vh.RequestHeadersToAdd, makeHeadersValueOptions(header.Add, true)...) - vh.RequestHeadersToAdd = append(vh.RequestHeadersToAdd, makeHeadersValueOptions(header.Set, false)...) - vh.RequestHeadersToRemove = append(vh.RequestHeadersToRemove, header.Remove...) - } - } -} - func injectHeaderManipToVirtualHost(dest *structs.IngressService, vh *envoy_route_v3.VirtualHost) error { if !dest.RequestHeaders.IsZero() { vh.RequestHeadersToAdd = append( diff --git a/agent/xds/testdata/routes/api-gateway-with-http-route-and-inline-certificate.latest.golden b/agent/xds/testdata/routes/api-gateway-with-http-route-and-inline-certificate.latest.golden index 6abc6f2946b4..a1669268ec4e 100644 --- a/agent/xds/testdata/routes/api-gateway-with-http-route-and-inline-certificate.latest.golden +++ b/agent/xds/testdata/routes/api-gateway-with-http-route-and-inline-certificate.latest.golden @@ -1,31 +1,50 @@ { - "versionInfo": "00000001", - "resources": [ + "versionInfo": "00000001", + "resources": [ { - "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", - "name": "8080", - "virtualHosts": [ + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "8080", + "virtualHosts": [ { - "name": "api-gateway-listener-9b9265b", - "domains": [ + "name": "api-gateway-listener-9b9265b", + "domains": [ "*", "*:8080" ], - "routes": [ + "routes": [ { - "match": { - "prefix": "/" + "match": { + "prefix": "/" }, - "route": { - "cluster": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" - } + "route": { + "cluster": "service.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "requestHeadersToAdd": [ + { + "header": { + "key": "X-Header-Add", + "value": "added" + }, + "append": true + }, + { + "header": { + "key": "X-Header-Set", + "value": "set" + }, + "append": false + } + ], + "requestHeadersToRemove": [ + "X-Header-Remove" + ] } ] } ], - "validateClusters": true + "validateClusters": true } ], - "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", - "nonce": "00000001" + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" } \ No newline at end of file From f8d3721885e2a1bbf0a078b5940b340197853081 Mon Sep 17 00:00:00 2001 From: Poonam Jadhav Date: Mon, 12 Jun 2023 12:07:43 -0400 Subject: [PATCH 016/359] fix: add agent info reporting log (#17654) --- command/agent/agent.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/command/agent/agent.go b/command/agent/agent.go index c2d0dcea0962..c241fa2b7bc8 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -231,6 +231,9 @@ func (c *cmd) run(args []string) int { ui.Info(fmt.Sprintf(" Gossip Encryption: %t", config.EncryptKey != "")) ui.Info(fmt.Sprintf(" Auto-Encrypt-TLS: %t", config.AutoEncryptTLS || config.AutoEncryptAllowTLS)) ui.Info(fmt.Sprintf(" ACL Enabled: %t", config.ACLsEnabled)) + if config.ServerMode { + ui.Info(fmt.Sprintf(" Reporting Enabled: %t", config.Reporting.License.Enabled)) + } ui.Info(fmt.Sprintf("ACL Default Policy: %s", config.ACLResolverSettings.ACLDefaultPolicy)) ui.Info(fmt.Sprintf(" HTTPS TLS: Verify Incoming: %t, Verify Outgoing: %t, Min Version: %s", config.TLS.HTTPS.VerifyIncoming, config.TLS.HTTPS.VerifyOutgoing, config.TLS.HTTPS.TLSMinVersion)) From 862e78f063b40db49d1160690b092a6e9afa5888 Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Mon, 12 Jun 2023 10:30:04 -0700 Subject: [PATCH 017/359] Add new Consul 1.16 docs (#17651) * Merge pull request #5773 from hashicorp/docs/rate-limiting-from-ip-addresses-1.16 updated docs for rate limiting for IP addresses - 1.16 * Merge pull request #5609 from hashicorp/docs/enterprise-utilization-reporting Add docs for enterprise utilization reporting * Merge pull request #5734 from hashicorp/docs/envoy-ext-1.16 Docs/envoy ext 1.16 * Merge pull request #5773 from hashicorp/docs/rate-limiting-from-ip-addresses-1.16 updated docs for rate limiting for IP addresses - 1.16 * Merge pull request #5609 from hashicorp/docs/enterprise-utilization-reporting Add docs for enterprise utilization reporting * Merge pull request #5734 from hashicorp/docs/envoy-ext-1.16 Docs/envoy ext 1.16 * fix build errors --------- Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com> --- .../docs/agent/config/config-files.mdx | 4 + website/content/docs/agent/config/index.mdx | 1 + website/content/docs/agent/limits/index.mdx | 49 +- .../limits/set-global-traffic-rate-limits.mdx | 114 --- .../limits/{ => usage}/init-rate-limits.mdx | 9 +- .../usage/limit-request-rates-from-ips.mdx | 66 ++ .../limits/usage/monitor-rate-limits.mdx | 77 ++ .../usage/set-global-traffic-rate-limits.mdx | 62 ++ .../control-plane-request-limit.mdx | 224 ++++++ .../configuration/ext-authz.mdx | 726 ++++++++++++++++++ .../configuration/property-override.mdx | 273 +++++++ .../envoy-extensions/configuration/wasm.mdx | 484 ++++++++++++ .../proxies/envoy-extensions/index.mdx | 23 +- .../envoy-extensions/usage/ext-authz.mdx | 147 ++++ .../usage/property-override.mdx | 203 +++++ .../proxies/envoy-extensions/usage/wasm.mdx | 191 +++++ .../license/utilization-reporting.mdx | 168 ++++ .../partials/envoy_ext_rule_matcher.mdx | 9 + website/data/docs-nav-data.json | 93 ++- 19 files changed, 2765 insertions(+), 158 deletions(-) delete mode 100644 website/content/docs/agent/limits/set-global-traffic-rate-limits.mdx rename website/content/docs/agent/limits/{ => usage}/init-rate-limits.mdx (68%) create mode 100644 website/content/docs/agent/limits/usage/limit-request-rates-from-ips.mdx create mode 100644 website/content/docs/agent/limits/usage/monitor-rate-limits.mdx create mode 100644 website/content/docs/agent/limits/usage/set-global-traffic-rate-limits.mdx create mode 100644 website/content/docs/connect/config-entries/control-plane-request-limit.mdx create mode 100644 website/content/docs/connect/proxies/envoy-extensions/configuration/ext-authz.mdx create mode 100644 website/content/docs/connect/proxies/envoy-extensions/configuration/property-override.mdx create mode 100644 website/content/docs/connect/proxies/envoy-extensions/configuration/wasm.mdx create mode 100644 website/content/docs/connect/proxies/envoy-extensions/usage/ext-authz.mdx create mode 100644 website/content/docs/connect/proxies/envoy-extensions/usage/property-override.mdx create mode 100644 website/content/docs/connect/proxies/envoy-extensions/usage/wasm.mdx create mode 100644 website/content/docs/enterprise/license/utilization-reporting.mdx create mode 100644 website/content/partials/envoy_ext_rule_matcher.mdx diff --git a/website/content/docs/agent/config/config-files.mdx b/website/content/docs/agent/config/config-files.mdx index 6e50cbb44abe..4183a5a7d213 100644 --- a/website/content/docs/agent/config/config-files.mdx +++ b/website/content/docs/agent/config/config-files.mdx @@ -711,6 +711,10 @@ Refer to the [formatting specification](https://golang.org/pkg/time/#ParseDurati servers in all federated datacenters must have this enabled before any client can use [`use_streaming_backend`](#use_streaming_backend). +- `reporting` - This option allows options for HashiCorp reporting. + - `license` - The license object allows users to control automatic reporting of license utilization metrics to HashiCorp. + - `enabled`: (Defaults to `true`) Enables automatic license utilization reporting. + - `segment` - Equivalent to the [`-segment` command-line flag](/consul/docs/agent/config/cli-flags#_segment). ~> **Warning:** The `segment` option cannot be used with the [`partition`](#partition-1) option. diff --git a/website/content/docs/agent/config/index.mdx b/website/content/docs/agent/config/index.mdx index 0ea4a030fb7f..c620ef72e05a 100644 --- a/website/content/docs/agent/config/index.mdx +++ b/website/content/docs/agent/config/index.mdx @@ -73,6 +73,7 @@ The following agent configuration options are reloadable at runtime: them without a restart provides a recovery path that doesn't involve downtime. They generally shouldn't be changed otherwise. - [RPC rate limits](/consul/docs/agent/config/config-files#limits) +- [Reporting](/consul/docs/agent/config/config-files#reporting) - [HTTP Maximum Connections per Client](/consul/docs/agent/config/config-files#http_max_conns_per_client) - Services - TLS Configuration diff --git a/website/content/docs/agent/limits/index.mdx b/website/content/docs/agent/limits/index.mdx index ffa259cfd672..0d12f1127a9e 100644 --- a/website/content/docs/agent/limits/index.mdx +++ b/website/content/docs/agent/limits/index.mdx @@ -2,32 +2,51 @@ layout: docs page_title: Limit Traffic Rates Overview description: Rate limiting is a set of Consul server agent configurations that you can use to mitigate the risks to Consul servers when clients send excessive requests to Consul resources. - --- # Traffic rate limiting overview -This topic provides an overview of the rates limits you can configure for Consul servers. + +This topic provides overview information about the traffic rates limits you can configure for Consul datacenters. ## Introduction -You can configure global RPC rate limits to mitigate the risks to Consul servers when clients send excessive read or write requests to Consul resources. A _read request_ is defined as any request that does not modify Consul internal state. A _write request_ is defined as any request that modifies Consul internal state. Rate limits for read and write requests are configured separately. -## Rate limit modes +Configuring rate limits on RPC and gRPC traffic mitigates the risks to Consul servers when client agents or services send excessive read or write requests to Consul resources. A _read_ request is defined as any request that does not modify Consul internal state. A _write_ request is defined as any request that modifies Consul internal state. Configure read and write request limits independently. + +## Workflow + +You can set global limits on the rate of read and write requests that affect individual servers in the datacenter. You can set limits for all source IP addresses, which enables you to specify a budget for read and write requests to prevent any single source IP from overwhelming the Consul server and negatively affecting the network. The following steps describe the general process for setting global read and write rate limits: + +1. Set arbitrary limits to begin understanding the upper boundary of RPC and gRPC loads in your network. Refer to [Initialize rate limit settings](/consul/docs/agent/limits/usage/init-rate-limits) for additional information. -You can set one of the following modes to determine how Consul servers react when exceeding request limits. - -- **Enforcing mode**: The rate limiter denies requests to a server once they exceed the configured rate. In this mode, Consul generates metrics and logs to help you understand your network's load and configure limits accordingly. -- **Permissive mode**: The rate limiter allows requests to a server once they exceed the configured rate. In this mode, Consul generates metrics and logs to help you understand your Consul load and configure limits accordingly. Use this mode to help you debug specific issues as you configure limits. -- **Disabled mode**: Disables the rate limiter. This mode allows all requests Consul does not generate logs or metrics. This is the default mode. +1. Monitor the metrics and logs and readjust the initial configurations as necessary. Refer to [Monitor rate limit data](/consul/docs/agent/limits/usage/monitor-rate-limit-data) -Refer to [`rate_limits`](/consul/docs/agent/config/config-files#request_limits) for additional configuration information. +1. Define your final operational limits based on your observations. If you are defining global rate limits, refer to [Set global traffic rate limits](/consul/docs/agent/limits/usage/set-global-rate-limits) for additional information. For information about setting limits based on source IP, refer to [Limit traffic rates for a source IP](/consul/docs/agent/limits/usage/set-source-ip-rate-limits). -## Request denials +### Order of operations -When an HTTP request is denied for rate limiting reason, Consul returns one of the following errors: +You can define request rate limits in the agent configuration and in the control plane request limit configuration entry. The configuration entry also supports rate limit configurations for Consul resources. Consul perfroms the following order of operations when determing request rate limits: -- **429 Resource Exhausted**: Indicates that a server is not able to perform the request but that another server could potentially fulfill it. This error is most common on stale reads because any server may fulfill stale read requests. To resolve this type of error, we recommend immediately retrying the request to another server. If the request came from a Consul client agent, the agent automatically retries the request up to the limit set in the [`rpc_hold_timeout`](/consul/docs/agent/config/config-files#rpc_hold_timeout) configuration . +1. Parse request. +1. Does the request reach a global server limit? + - No: Proceed to the next stage. + - Yes: Return an error that the requested resource has been exhausted. +1. Does the request reach a limit associated with its source IP address? + - No: Proceed to the next stage. + - Yes: Return an error that the requested resource has been exhausted. +1. Resolve the Consul Enterprise metadata. +1. Does the request reach a limit associated with the source partition? + - No: Proceed to the next stage. + - Yes: Return an error that the requested resource has been exhausted. +1. Does the request reach a limit associated with the source namespace? + - No: Proceed to the next stage. + - Yes: Return an error that the requested resource has been exhausted. +1. Resolve the ACL identity associated with the request. +1. Does the request reach a limit associated with its identity? + - No: Proceed to the next stage. + - Yes: Return an error that the requested resource has been exhausted. +1. Handle the request. -- **503 Service Unavailable**: Indicates that server is unable to perform the request and that no other server can fulfill the request, either. This usually occurs on consistent reads or for writes. In this case we recommend retrying according to an exponential backoff schedule. If the request came from a Consul client agent, the agent automatically retries the request according to the [`rpc_hold_timeout`](/consul/docs/agent/config/config-files#rpc_hold_timeout) configuration. +## Kubernetes -Refer to [Rate limit reached on the server](/consul/docs/troubleshoot/common-errors#rate-limit-reached-on-the-server) for additional information. \ No newline at end of file +To define global rate limits, configure the `request_limits` settings in the Consul Helm chart. Refer to the [Helm chart reference](/consul/docs/k8s/helm) for additional information. Refer to the [control plane request limit configuration entry reference](/consul/docs/connect/config-entries/control-plane-request-limit) for information about applying a CRD for limiting traffic rates from source IPs. \ No newline at end of file diff --git a/website/content/docs/agent/limits/set-global-traffic-rate-limits.mdx b/website/content/docs/agent/limits/set-global-traffic-rate-limits.mdx deleted file mode 100644 index 5d4fc43df02f..000000000000 --- a/website/content/docs/agent/limits/set-global-traffic-rate-limits.mdx +++ /dev/null @@ -1,114 +0,0 @@ ---- -layout: docs -page_title: Set a Global Limit on Traffic Rates -description: Use global rate limits to prevent excessive rates of requests to Consul servers. ---- - -# Set a global limit on traffic rates - -This topic describes how to configure rate limits for RPC and gRPC traffic to the Consul server. - -## Introduction - -Rate limits apply to each Consul server separately and limit the number of read requests or write requests to the server on the RPC and internal gRPC endpoints. - -Because all requests coming to a Consul server eventually perform an RPC or an internal gRPC request, global rate limits apply to Consul's user interfaces, such as the HTTP API interface, the CLI, and the external gRPC endpoint for services in the service mesh. - -Refer to [Initialize Rate Limit Settings](/consul/docs/agent/limits/init-rate-limits) for additional information about right-sizing your gRPC request configurations. - -## Set a global rate limit for a Consul server - -Configure the following settings in your Consul server configuration to limit the RPC and gRPC traffic rates. - -- Set the rate limiter [`mode`](/consul/docs/agent/config/config-files#mode-1) -- Set the [`read_rate`](/consul/docs/agent/config/config-files#read_rate) -- Set the [`write_rate`](/consul/docs/agent/config/config-files#write_rate) - -In the following example, the Consul server is configured to prevent more than `500` read and `200` write RPC calls: - - - -```hcl -limits = { - rate_limit = { - mode = "enforcing" - read_rate = 500 - write_rate = 200 - } -} -``` - -```json -{ - "limits" : { - "rate_limit" : { - "mode" : "enforcing", - "read_rate" : 500, - "write_rate" : 200 - } - } -} - -``` - - - -## Access rate limit logs - -Consul prints a log line for each rate limit request. The log includes information to identify the source of the request and the server's configured limit. Consul prints to `DEBUG` log level, and can be configured to drop log lines to avoid affecting the server health. Dropping a log line increments the `rpc.rate_limit.log_dropped` metric. - -The following example log shows that RPC request from `127.0.0.1:53562` to `KVS.Apply` exceeded the rate limit: - - - -```shell-session -2023-02-17T10:01:15.565-0500 [DEBUG] agent.server.rpc-rate-limit: RPC -exceeded allowed rate limit: rpc=KVS.Apply source_addr=127.0.0.1:53562 -limit_type=global/write limit_enforced=false -``` - - -## Review rate limit metrics - -Consul captures the following metrics associated with rate limits: - -- Type of limit -- Operation -- Rate limit mode - -Call the `agent/metrics` API endpoint to view the metrics associated with rate limits. Refer to [View Metrics](/consul/api-docs/agent#view-metrics) for API usage information. - -In the following example, Consul dropped a call to the `consul` service because it exceeded the limit by one call: - -```shell-session -$ curl http://127.0.0.1:8500/v1/agent/metrics -{ - . . . - "Counters": [ - { - "Name": "consul.rpc.rate_limit.exceeded", - "Count": 1, - "Sum": 1, - "Min": 1, - "Max": 1, - "Mean": 1, - "Stddev": 0, - "Labels": { - "service": "consul" - } - }, - { - "Name": "consul.rpc.rate_limit.log_dropped", - "Count": 1, - "Sum": 1, - "Min": 1, - "Max": 1, - "Mean": 1, - "Stddev": 0, - "Labels": {} - } - ], - . . . -``` - -Refer to [Telemetry](/consul/docs/agent/telemetry) for additional information. diff --git a/website/content/docs/agent/limits/init-rate-limits.mdx b/website/content/docs/agent/limits/usage/init-rate-limits.mdx similarity index 68% rename from website/content/docs/agent/limits/init-rate-limits.mdx rename to website/content/docs/agent/limits/usage/init-rate-limits.mdx index 7dbabbe6c72a..e90aaf77af22 100644 --- a/website/content/docs/agent/limits/init-rate-limits.mdx +++ b/website/content/docs/agent/limits/usage/init-rate-limits.mdx @@ -1,6 +1,6 @@ --- layout: docs -page_title: Initialize Rate Limit Settings +page_title: Initialize rate limit settings description: Learn how to determine regular and peak loads in your network so that you can set the initial global rate limit configurations. --- @@ -14,7 +14,7 @@ Because each network has different needs and application, you need to find out w - Number of servers and the projected load - Existing metrics expressing requests per second -1. Set the `mode` to `permissive`. In the following example, the configuration allows up to 1000 reads and 500 writes per second for each Consul agent: +1. Set the [`limits.request_limits.mode`](/consul/docs/agent/config/config-files#mode-1) parameter in the agent configuration to `permissive`. In the following example, the configuration allows up to 1000 reads and 500 writes per second for each Consul agent: ```hcl request_limits { @@ -22,9 +22,8 @@ Because each network has different needs and application, you need to find out w read_rate = 1000.0 write_rate = 500.0 } - ``` - -1. Observe the logs and metrics for your application's typical cycle, such as a 24 hour period. Refer to [`log_file`](/consul/docs/agent/config/config-files#log_file) for information about where to retrieve logs. Call the [`/agent/metrics`](/consul/api-docs/agent#view-metrics) HTTP API endpoint and check the data for the following metrics: + ``` +1. Observe the logs and metrics for your application's typical cycle, such as a 24 hour period. Refer to [Monitor traffic rate limit data](/consul/docs/agent/limits/usage/monitor-rate-limit) for additional information. Call the [`/agent/metrics`](/consul/api-docs/agent#view-metrics) HTTP API endpoint and check the data for the following metrics: - `rpc.rate_limit.exceeded` with value `global/read` for label `limit_type` - `rpc.rate_limit.exceeded` with value `global/write` for label `limit_type` diff --git a/website/content/docs/agent/limits/usage/limit-request-rates-from-ips.mdx b/website/content/docs/agent/limits/usage/limit-request-rates-from-ips.mdx new file mode 100644 index 000000000000..c074d3007af7 --- /dev/null +++ b/website/content/docs/agent/limits/usage/limit-request-rates-from-ips.mdx @@ -0,0 +1,66 @@ +--- +layout: docs +page_title: Limit traffic rates for a source IP address +description: Learn how to set read and request rate limits on RPC and gRPC traffic from all source IP addresses to a Consul resource. +--- + +# Limit traffic rates from source IP addresses + +This topic describes how to configure RPC and gRPC traffic rate limits for source IP addresses. This enables you to specify a budget for read and write requests to prevent any single source IP from overwhelming the Consul server and negatively affecting the network. For information about setting global traffic rate limits, refer to [Set a global limit on traffic rates](/consul/docs/agent/limits/usage/set-glogal-traffic-rate-limits). For an overview of Consul's server rate limiting capabilities, refer to [Limit traffic rates overview](/consul/docs/agent/limits/overview). + +## Overview + +You can set limits on the rate of read and write requests from source IP addresses to specific resources, which mitigates the risks to Consul servers when consul clients send excessive requests to a specific resource type. Before configuring traffic rate limits, you should complete the initialization process to understand normal traffic loads in your network. Refer to [Initialize rate limit settings](/consul/docs/agent/limits/init-rate-limits) for additional information. + +Complete the following steps to configure traffic rate limits from a source IP address: + +1. Define rate limits in a control plan request limit configuration entry. You can set limits for different types of resources calls. + +1. Apply the configuration entry to enact the limits. + +You should also monitor read and write rate activity and make any necessary adjustments. Refer to [Monitor rate limit data](/consul/docs/agent/limits/usage/monitor-rate-limits) for additional information. + +## Define rate limits + +Create a control plane request limit configuration entry in the `default` partition. The configuration entry applies to all client requests targeting any partition. Refer to the [control plane request limit configuration entry](/consul/docs/connect/config-entries/control-plan-request-limit) reference documentation for details about the available configuration parameters. + +Specify the following parameters: + +- `kind`: This must be set to `control-plane-request-limit`. +- `name`: Specify the name of the service that you want to limit read and write operations to. +- `read_rate`: Specify overall number of read operations per second allowed from the service. +- `write_rate`: Specify overall number of write operations per second allowed from the service. + +You can also configure limits on calls to the key-value store, ACL system, and Consul catalog. + +## Apply the configuration entry + +If your network is deployed to virtual machines, use the `consul config write` command and specify the control plane request limit configuration entry to apply the configuration. For Kubernetes-orchestrated networks, use the `kubectl apply` command. + + + + +```shell-session +$ consul config write control-plane-request-limit.hcl +``` + + + + +```shell-session +$ consul config write control-plane-request-limit.json +``` + + + + +```shell-session +$ kubectl apply control-plane-request-limit.yaml +``` + + + + +## Disable request rate limits + +Set the [limits.request_limits.mode](/consul/docs/agent/config/config-files#mode-1) in the agent configuration to `disabled` to allow services to exceed the specified read and write requests limits. The `disabled` mode applies to all request rate limits, even limits specifed in the [control plane request limits configuration entry](/consul/docs/connect/config-entries/control-plane-request-limits). Note that any other mode specified in the agent configuration only applies to global traffic rate limits. \ No newline at end of file diff --git a/website/content/docs/agent/limits/usage/monitor-rate-limits.mdx b/website/content/docs/agent/limits/usage/monitor-rate-limits.mdx new file mode 100644 index 000000000000..23906041b34d --- /dev/null +++ b/website/content/docs/agent/limits/usage/monitor-rate-limits.mdx @@ -0,0 +1,77 @@ +--- +layout: docs +page_title: Monitor traffic rate limit data +description: Learn about the metrics and logs you can use to monitor server rate limiting activity, include rate limits for read operations and writer operations +--- + +# Monitor traffic rate limit data + +This topic describes Consul functionality that enables you to monitor read and write request operations taking place in your network. Use the functionality to help you understand normal workloads and set safe limits on the number of requests Consul client agents and services can make to Consul servers. + +## Access rate limit logs + +Consul prints a log line for each rate limit request. The log provides the necessary information for identifying the source of the request and the configured limit. The log provides the information necessary for identifying the source of the request and the configured limit. Consul prints the log `DEBUG` log level and can drop the log to avoid affecting the server health. Dropping a log line increments the `rpc.rate_limit.log_dropped` metric. + +The following example log shows that RPC request from `127.0.0.1:53562` to `KVS.Apply` exceeded the limit: + +```text +2023-02-17T10:01:15.565-0500 [DEBUG] agent.server.rpc-rate-limit: RPC +exceeded allowed rate limit: rpc=KVS.Apply source_addr=127.0.0.1:53562 +limit_type=global/write limit_enforced=false +``` + +Refer to [`log_file`](/consul/docs/agent/config/config-files#log_file) for information about where to retrieve log files. + +## Review rate limit metrics + +Consul captures the following metrics associated with rate limits: + +- Type of limit +- Operation +- Rate limit mode + +Call the `/agent/metrics` API endpoint to view the metrics associated with rate limits. Refer to [View Metrics](/consul/api-docs/agent#view-metrics) for API usage information. In the following example, Consul dropped a call to the consul service because it exceeded the limit by one call: + +```shell-session +$ curl http://127.0.0.1:8500/v1/agent/metrics +{ + . . . + "Counters": [ + { + "Name": "consul.rpc.rate_limit.exceeded", + "Count": 1, + "Sum": 1, + "Min": 1, + "Max": 1, + "Mean": 1, + "Stddev": 0, + "Labels": { + "service": "consul" + } + }, + { + "Name": "consul.rpc.rate_limit.log_dropped", + "Count": 1, + "Sum": 1, + "Min": 1, + "Max": 1, + "Mean": 1, + "Stddev": 0, + "Labels": {} + } + ], + . . . +} +``` + +Refer to [Telemetry](/consul/docs/telemetry) for additional information. + +## Request denials + +When an HTTP request is denied for rate limiting reason, Consul returns one of the following errors: + +- **429 Resource Exhausted**: Indicates that a server is not able to perform the request but that another server could potentially fulfill it. This error is most common on stale reads because any server may fulfill stale read requests. To resolve this type of error, we recommend immediately retrying the request to another server. If the request came from a Consul client agent, the agent automatically retries the request up to the limit set in the [`rpc_hold_timeout`](/consul/docs/agent/config/config-files#rpc_hold_timeout) configuration . + +- **503 Service Unavailable**: Indicates that server is unable to perform the request and that no other server can fulfill the request, either. This usually occurs on consistent reads or for writes. In this case we recommend retrying according to an exponential backoff schedule. If the request came from a Consul client agent, the agent automatically retries the request according to the [`rpc_hold_timeout`](/consul/docs/agent/config/config-files#rpc_hold_timeout) configuration. + +Refer to [Rate limit reached on the server](/consul/docs/troubleshoot/common-errors#rate-limit-reached-on-the-server) for additional information. \ No newline at end of file diff --git a/website/content/docs/agent/limits/usage/set-global-traffic-rate-limits.mdx b/website/content/docs/agent/limits/usage/set-global-traffic-rate-limits.mdx new file mode 100644 index 000000000000..61a4066ec9e0 --- /dev/null +++ b/website/content/docs/agent/limits/usage/set-global-traffic-rate-limits.mdx @@ -0,0 +1,62 @@ +--- +layout: docs +page_title: Set a global limit on traffic rates +description: Use global rate limits to prevent excessive rates of requests to Consul servers. +--- + +# Set a global limit on traffic rates + +This topic describes how to configure rate limits for RPC and gRPC traffic to the Consul server. + +## Introduction + +Rate limits apply to each Consul server separately and limit the number of read requests or write requests to the server on the RPC and internal gRPC endpoints. + +Because all requests coming to a Consul server eventually perform an RPC or an internal gRPC request, global rate limits apply to Consul's user interfaces, such as the HTTP API interface, the CLI, and the external gRPC endpoint for services in the service mesh. + +Refer to [Initialize Rate Limit Settings](/consul/docs/agent/limits/init-rate-limits) for additional information about right-sizing your gRPC request configurations. + +## Set a global rate limit for a Consul server + +Configure the following settings in your Consul server configuration to limit the RPC and gRPC traffic rates. + +- Set the rate limiter [`mode`](/consul/docs/agent/config/config-files#mode-1) +- Set the [`read_rate`](/consul/docs/agent/config/config-files#read_rate) +- Set the [`write_rate`](/consul/docs/agent/config/config-files#write_rate) + +In the following example, the Consul server is configured to prevent more than `500` read and `200` write RPC calls: + + + +```hcl +limits = { + rate_limit = { + mode = "enforcing" + read_rate = 500 + write_rate = 200 + } +} +``` + +```json +{ + "limits" : { + "rate_limit" : { + "mode" : "enforcing", + "read_rate" : 500, + "write_rate" : 200 + } + } +} + +``` + + + +## Monitor request rate traffic + +You should continue to mmonitor request traffic to ensure that request rates remain within the threshold you defined. Refer to [Monitor traffic rate limit data](/consul/docs/agent/limits/usage/monitor-rate-limits) for instructions about checking metrics and log entries, as well as troubleshooting informaiton. + +## Disable request rate limits + +Set the [limits.request_limits.mode](/consul/docs/agent/config/config-files#mode-1) to `disabled` to allow services to exceed the specified read and write requests limits, even limits specifed in the [control plane request limits configuration entry](/consul/docs/connect/config-entries/control-plane-request-limits). Note that any other mode specified in the agent configuration only applies to global traffic rate limits. diff --git a/website/content/docs/connect/config-entries/control-plane-request-limit.mdx b/website/content/docs/connect/config-entries/control-plane-request-limit.mdx new file mode 100644 index 000000000000..c6b44436ac56 --- /dev/null +++ b/website/content/docs/connect/config-entries/control-plane-request-limit.mdx @@ -0,0 +1,224 @@ +--- +layout: docs +page_title: Control Plane Request Limit Configuration Entry Configuration Reference +description: Learn how to configure the control-plane-request-limit configuration entry, which defines how Consul agents limit read and reqeust traffic rate limits. +--- + +# Control Plane Request Limit Configuration Entry Configuration Reference + +This topic describes the configuration options for the `control-plane-request-limit` configuration entry. You can only write the `control-plane-request-limit` configuration entry to the `default` partition, but the configuration entry applies to all client requests that target any partition. + +## Configuration model + +The following list outlines field hierarchy, language-specific data types, and requirements in a control plane request limit configuration entry. Click on a property name to view additional details, including default values. + +- [`kind`](#kind): string | required | must be set to `control-plane-request-limit` +- [`mode`](#mode): string | required | default is `permissive` +- [`name`](#name): string | required +- [`read_rate`](#read-rate): number | `100` +- [`write_rate`](#write-rate): number | `100` +- [`kv`](#kv): map | no default + - [`read_rate`](#kv-read-rate): number | `100` + - [`write_rate`](#kv-write-rate): number | `100` +- [`acl`](#acl): map | no default + - [`read_rate`](#acl-read-rate): number | `100` + - [`write_rate`](#acl-write-rate): number | `100` +- [`catalog`](#catalog): map + - [`read_rate`](#catalog-read-rate): number | default is `100` + - [`write_rate`](#catalog-write-rate): number | default is `100` + +## Complete configuration + +When every field is defined, a control plane request limit configuration entry has the following form: + + + +```hcl +kind = "control-plane-request-limit" +mode = "permissive" +name = "" +read_rate = 100 +write_rate = 100 +kv = { + read_rate = 100 + write_rate = 100 + } +acl = { + read_rate = 100 + write_rate = 100 +mode = "permissive" + } +catalog = { + read_rate = 100 + write_rate = 100 + } +``` + +```json +{ + "kind": "control-plane-request-limit", + "mode": "permissive", + "name": "", + "read_rate": 100, + "write_rate": 100, + "kv": { + "read_rate": 100, + "write_rate": 100 + }, + "acl": { + "read_rate": 100, + "write_rate": 100 + }, + "catalog: { + "read_rate": 100, + "write_rate": 100 + } +} +``` + +```yaml +kind: control-plane-request-limit +mode: permissive +name: +read_rate: 100 +write_rate: 100 +kv: + read_rate: 100 + write_rate: 100 +acl: + read_rate: 100 + write_rate: 100 +catalog: + read_rate: 100 + write_rate: 100 +``` + + + +## Specification + +This section provides details about the fields you can configure in the control plane request limit configuration entry. + +### `kind` + +Specifies the type of configuration entry to implement. Must be set to`control-plane-request-limit` + +#### Values + +- Default: none +- This field is required. +- Data type: String value that must be set to`control-plane-request-limit`. + +### `mode` + +Specifies an action to take if the rate of requests exceeds the limit. + +#### Values + +- Default: None +- This field is required. +- One of the following string values: + - `permissive`: The server continues to allow requests and records an error in the logs. This is the default value for `mode`. + - `enforcing`: The server stops accepting requests and records an error in the logs. + - `disabled`: Limits are not enforced or tracked. + +### `name` + +Specifies the name of the configuration entry. + +#### Values + +- Default: none +- This field is required. +- Data type: string + +### `read_rate` + +Specifies the maximum number of read requests per second that the agent allows. + +#### Values + +- Default: No limit. +- Data type: number + +### `write_rate` + +Specifies the maximum number of write requests per second that the agent allows. + +#### Values + +- Default: No limit. +- Data type: number + +### `kv` + +Specifies the maximum number of read and write requests to the Consul key-value store. + +#### Values + +- Default: none +- Data type is a map containing the following parameters: + - `read_rate` + - `write_rate` + +### `kv.read_rate` + +Specifies the maximum number of read requests per second allowed to the Consul key-value store. + +#### Values + +- Default: No limit. +- Data type: number + +### `kv.write_rate` + +Specifies the maximum number of write requests per second allowed to the Consul key-value store. + +#### Values + +- Default: No limit. +- Data type: number + +### `acl` + +Specifies the maximum number of read and write ACL requests to the Consul server. + +### `acl.read_rate` +S +pecifies the maximum number of ACL read requests per second allowed to the Consul server. + +#### Values + +- Default: No limit. +- Data type: number + +### `acl.write_rate` + +Specifies the maximum number of ACL write requests per second allowed to the Consul server. + +#### Values + +- Default: No limit. +- Data type: number + +### catalog + +Specifies the maximum number of read and write requests to the Consul catalog. + +### `catalog.read_rate` + +Specifies the maximum number of read requests per second allowed to the Consul catalog. + +#### Values + +- Default: No limit. +- Data type: number + +### `catalog.write_rate` + +Specifies the maximum number of write requests per second allowed to the Consul catalog. + +#### Values + +- Default: No limit. +- Data type: number \ No newline at end of file diff --git a/website/content/docs/connect/proxies/envoy-extensions/configuration/ext-authz.mdx b/website/content/docs/connect/proxies/envoy-extensions/configuration/ext-authz.mdx new file mode 100644 index 000000000000..6b5d8cc272aa --- /dev/null +++ b/website/content/docs/connect/proxies/envoy-extensions/configuration/ext-authz.mdx @@ -0,0 +1,726 @@ +--- +layout: docs +page_title: External authorization extension configuration reference +description: Learn how to configure the ext-authz Envoy extension, which is a builtin Consul extension that configures Envoy proxies to request authorization from an external service. +--- + +# External authorization extension configuration reference + +This topic describes how to configure the external authorization Envoy extension, which configures Envoy proxies to request authorization from an external service. Refer to [Delegate authorization to an external service](/consul/docs/connect/proxies/envoy-extensions/usage/ext-authz) for usage information. + +## Configuration model + +The following list outlines the field hierarchy, data types, and requirements for the external authorization configuration. Place the configuration inside the `EnvoyExtension.Arguments` field in the proxy defaults or service defaults configuration entry. Refer to the following documentation for additional information: + +- [`EnvoyExtensions` in proxy defaults](/consul/docs/connect/config-entries/proxy-defaults#envoyextensions) +- [`EnvoyExtensions` in service defaults](/consul/docs/connect/config-entries/service-defaults#envoyextensions) + - [Envoy External Authorization documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto) + +Click on a property name to view additional details, including default values. + +- [`Name`](#name): string | required | must be set to `builtin/ext-authz` +- [`Arguments`](#arguments): map | required + - [`ProxyType`](#arguments-proxytype): string | required | `connect-proxy` + - [`InsertOptions`](#arguments-insertoptions): map + - [`Location`](#arguments-insertoptions-location): string + - [FilterName](#arguments-insertoptions-filtername): string + - [`Config`](#arguments-config): map | required + - [`BootstrapMetadataLabelsKey`](#arguments-config-bootstrapmetadatalabelskey): string + - [`ClearRouteCache`](#arguments-config-grpcservice): boolean | `false` | HTTP only + - [`GrpcService`](#arguments-config-grpcservice): map + - [`Target`](#arguments-config-grpcservice-target): map | required + - [`Service`](#arguments-config-grpcservice-target-service): map + - [`Name`](#arguments-config-grpcservice-target-service): string + - [`Namespace`](#arguments-config-grpcservice-target-service): string | + - [`Partition`](#arguments-config-grpcservice-target-service): string | + - [`URI`](#arguments-config-grpcservice-target-uri): string + - [`Timeout`](#arguments-config-grpcservice-target-uri): string | `1s` + - [`Authority`](#arguments-config-grpcservice-authority): string + - [`InitialMetadata`](#arguments-config-grpcservice-initialmetadata): list + - [`Key`](#arguments-config-grpcservice-initialmetadata): string + - [`Value`](#arguments-config-grpcservice-initialmetadata): string + - [`HttpService`](#arguments-config-httpservice): map + - [`Target`](#arguments-config-httpservice-target): map | required + - [`Service`](#arguments-config-httpservice): string + - [`Name`](#arguments-config-httpservice-target-service): string + - [`Namespace`](#arguments-config-httpservice-target-service): string | + - [`Partition`](#arguments-config-httpservice-target-service): string | + - [`URI`](#arguments-config-httpservice): string + - [`Timeout`](#arguments-config-httpservice): string | `1s` + - [`PathPrefix`](#arguments-config-httpservice-pathprefix): string + - [`AuthorizationRequest`](#arguments-config-httpservice-authorizationrequest): map + - [`AllowedHeaders`](#arguments-config-httpservice-authorizationrequest-allowedheaders): list + - [`Contains`](#arguments-config-httpservice-authorizationrequest-allowedheaders): string + - [`Exact`](#arguments-config-httpservice-authorizationrequest-allowedheaders): string + - [`IgnoreCase`](#arguments-config-httpservice-authorizationrequest-allowedheaders): boolean + - [`Prefix`](#arguments-config-httpservice-authorizationrequest-allowedheaders): string + - [`SafeRegex`](#arguments-config-httpservice-authorizationrequest-allowedheaders): string + - [`HeadersToAdd`](#arguments-config-httpservice-authorizationrequest-headerstoadd): list + - [`Key`](#arguments-config-httpservice-authorizationrequest-headerstoadd): string + - [`Value`](#arguments-config-httpservice-authorizationrequest-headerstoadd): string + - [`AuthorizationResponse`](#arguments-config-httpservice-authorizationresponse): map + - [`AllowedUpstreamHeaders`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaders): list + - [`Contains`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaders): string + - [`Exact`](#arguments-config-httpservice-authorizationresponse-allowedheaders): string + - [`IgnoreCase`](#arguments-config-httpservice-authorizationresponse-allowedheaders): boolean + - [`Prefix`](#arguments-config-httpservice-authorizationresponse-allowedheaders): string + - [`SafeRegex`](#arguments-config-httpservice-authorizationresponse-allowedheaders): string + - [`Suffix`](#arguments-config-httpservice-authorizationresponse-allowedheaders): string + - [`AllowedUpstreamHeadersToAppend`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend): list + - [`Contains`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend): string + - [`Exact`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend): string + - [`IgnoreCase`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend): boolean + - [`Prefix`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend): string + - [`SafeRegex`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend): string + - [`Suffix`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend): string + - [`AllowedClientHeaders`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders): list + - [`Contains`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders): string + - [`Exact`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders): string + - [`IgnoreCase`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders): boolean + - [`Prefix`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders): string + - [`SafeRegex`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders): string + - [`Suffix`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders): string + - [`AllowedClientHeadersOnSuccess`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess): list + - [`Contains`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess): string + - [`Exact`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess): string + - [`IgnoreCase`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess): boolean + - [`Prefix`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess): string + - [`SafeRegex`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess): string + - [`Suffix`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess): string + - [`DynamicMetadataFromHeaders`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders): list + - [`Contains`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders): string + - [`Exact`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders): string + - [`IgnoreCase`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders): boolean + - [`Prefix`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders): string + - [`SafeRegex`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders): string + - [`Suffix`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders): string + - [`IncludePeerCertificate`](#arguments-config-includepeercertificate): boolean | `false` + - [`MetadataContextNamespaces`](#arguments-config-metadatacontextnamespaces): list of strings | HTTP only + - [`StatusOnError`](#arguments-config-statusonerror): number | `403` | HTTP only + - [`StatPrefix`](#arguments-config-statprefix): string | `response` + - [`WithRequestBody`](#arguments-config-withrequestbody): map | HTTP only + - [`MaxRequestBytes`](#arguments-config-withrequestbody-maxrequestbytes): number + - [`AllowPartialMessage`](#arguments-config-withrequestbody-allowpartialmessage): boolean | `false` + - [`PackAsBytes`](#arguments-config-withrequestbody-packasbytes): boolean | `false` + +## Complete configuration + +When each field is defined, an `ext-authz` configuration has the following form: + +```hcl +Name = "builtin/ext-authz" +Arguments = { + ProxyType = "connect-proxy" + InsertOptions = { + Location = "" + FilterName = "" + } + Config = { + BootstrapMetadataLabelsKey = "" + ClearRouteCache = false // HTTP only + GrpcService = { + Target = { + Service = { + Name = "" + Namespace = "" + Partition = "" + URI = "" + Timeout = "1s" + Authority = "" + InitialMetadata = [ + "" : "" + HttpService = { + Target = { + Service = { + Name = "" + Namespace = "" + Partition = "" + URI = "" + Timeout = "1s" + } + } + PathPrefix = "//" + AuthorizationRequest = { + AllowedHeaders = [ + Contains = "", + Exact = "", + IgnoreCase = false, + Prefix = "", + SafeRegex = "" + ] + HeadersToAdd = [ + "
" = "
" + ] + } + AuthorizationResponse = { + AllowedUpstreamHeaders = [ + Contains = "", + Exact = "", + IgnoreCase = false, + Prefix = "", + SafeRegex = "" + Suffix = "" + ] + AllowedUpstreamHeadersToAppend = [ + Contains = "", + Exact = "", + IgnoreCase = false, + Prefix = "", + SafeRegex = "" + Suffix = "" + ] + AllowedClientHeaders = [ + Contains = "", + Exact = "", + IgnoreCase = false, + Prefix = "", + SafeRegex = "" + Suffix = "" + ] + AllowedClientHeadersOnSuccess = [ + Contains = "", + Exact = "", + IgnoreCase = false, + Prefix = "", + SafeRegex = "" + Suffix = "" + DynamicMetadataFromHeaders = [ + Contains = "", + Exact = "", + IgnoreCase = false, + Prefix = "", + SafeRegex = "" + Suffix = "" + ] + IncludePeerCertificate = false + MetadataContextNamespaces = [ + "" + ] + StatusOnError = 403 // HTTP only + StatPrefix = "response" + WithRequestBody = { //HTTP only + MaxRequestBytes = + AllowPartialMessage = false + PackAsBytes = false +``` + +## Specification + +This section provides details about the fields you can configure for the external authorization extension. +### `Name` + +Specifies the name of the extension. Must be set to `builtin/ext-authz`. + +#### Values + +- Default: None +- This field is required. +- Data type: String value set to `builtin/ext-authz`. + +### `Arguments` + +Contains the global configuration for the extension. + +#### Values + +- Default: None +- This field is required. +- Data type: Map + +### `Arguments.ProxyType` + +Specifies the type of Envoy proxy that this extension applies to. The extension only applies to proxies that match this type and is ignored for all other proxy types. The only supported value is `connect-proxy`. + +#### Values + +- Default: `connect-proxy` +- This field is required. +- Data type: String + +### `Arguments.InsertOptions` + +Specifies options for defining the insertion point for the external authorization filter in the Envoy filter chain. By default, the external authorization filter is inserted as the first filter in the filter chain per the default setting for the [`Location`](#arguments-insertoptions-location) field. + +#### Values + +- Default: None +- Data type: Map + +### `Arguments.InsertOptions.Location` + +Specifies the insertion point for the external authorization filter in the Envoy filter chain. You can specify one of the following string values: + +- `First`: Inserts the filter as the first filter in the filter chain, regardless of the filter specified in the `FilterName` field. +- `BeforeLast`: Inserts the filter before the last filter in the chain, regardless of the filter specified in the `FilterName` field. This allows the filter to be inserted after all other filters and immediately before the terminal filter. +- `AfterFirstMatch`: Inserts the filter after the first filter in the chain that has a name matching the value of the `FilterName` field. +- `AfterLastMatch`: Inserts the filter after the last filter in the chain that has a name matching the value of the `FilterName` field. +- `BeforeFirstMatch`: Inserts the filter before the first filter in the chain that has a name matching the value of the `FilterName` field. +- `BeforeLastMatch`: Inserts the filter before the last filter in the chain that has a name matching the value of the `FilterName` field. + +#### Values + +- Default: `BeforeFirstMatch` +- Data type: String + +### `Arguments.InsertOptions.FilterName` + +Specifies the name of an existing filter in the chain to match when inserting the external authorization filter. Specifying a filter name enables you to configure an insertion point relative to the position of another filter in the chain. + +#### Values + +- Default: `envoy.filters.network.tcp_proxy` for TCP services. `envoy.filters.http.router` for HTTP services. +- Data type: String + +### `Arguments.Config` + +Contains the configuration settings for the extension. + +#### Values + +- Default: None +- This field is required. +- Data type: Map + +### `Arguments.Config.BootstrapMetadataLabelsKey` + +Specifies a key from the Envoy bootstrap metadata. Envoy adds labels associated with the key to the authorization request context. + +#### Values + +- Default: None +- Data type: String + +### `Arguments.Config.ClearRouteCache` + +Directs Envoy to clear the route cache so that the external authorization service correctly affects routing decisions. If set to `true`, the filter clears all cached routes. + +Envoy also clears cached routes if the status returned from the authorization service is `200` for HTTP responses or `0` for gRPC responses. Envoy also clears cached routes if at least one authorization response header is added to the client request or is used for altering another client request header. + +#### Values + +- Default: `false` +- Data type: Boolean + + +### `Arguments.Config.GrpcService` + +Specifies the external authorization configuration for gRPC requests. Configure the `GrpcService` or the [`HttpService`](#arguments-config-httpservice) settings, but not both. + +#### Values + +- Default: None +- Either the `GrpcService` or the `HttpService` configuration is required. +- Data type: Map + +### `Arguments.Config.GrpcService.Target` + +Configuration for specifying the service to send gRPC authorization requests to. The `Target` field may contain the following fields: + +- [`Service`](#arguments-config-grpcservice-target-service) or [`Uri`](#arguments-config-grpcservice-target-uri) +- [`Timeout`](#arguments-config-grpcservice-target-timeout) + + +#### Values + +- Default: None +- This field is required. +- Data type: Map + +### `Arguments{}.Config{}.GrpcService{}.Target{}.Service{}` + +Specifies the upstream external authorization service. Configure this field when authorization requests are sent to an upstream service within the service mesh. The service must be configured as an upstream of the service that the filter is applied to. + +Configure either the `Service` field or the [`Uri`](#arguments-config-grpcservice-target-uri) field, but not both. + +#### Values + +- Default: None +- This field or [`Uri`](#arguments-config-grpcservice-target-uri) is required. +- Data type: Map + +The following table describes how to configure parameters for the `Service` field: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `Name` | Specifies the name of the upstream service. | String | None | +| `Namespace` | Specifies the Consul namespace that the upstream service belongs to. | String | `default` | +| `Partition` | Specifies the Consul admin partition that the upstream service belongs to. | String | `default` | + +### `Arguments.Config.GrpcService.Target.Uri` + +Specifies the URI of the external authorization service. Configure this field when you must provide an explicit URI to the external authorization service, such as cases in which the authorization service is running on the same host or pod. If set, the value of this field must be either `localhost:` or `127.0.0.1:` + +Configure either the `Uri` field or the [`Service`](#arguments-config-grpcservice-target-service) field, but not both. + +#### Values + +- Default: None +- This field or [`Service`](#arguments-config-grpcservice-target-service) is required. +- Data type: String + +### `Arguments.Config.GrpcService.Target.Timeout` + +Specifies the maximum duration that a response can take to arrive upon request. + +#### Values + +- Default: `1s` +- Data type: String + +### `Arguments.Config.GrpcService.Authority` + +Specifies the authority header to send in the gRPC request. If this field is not set, the authority field is set to the cluster name. This field does not override the SNI that Envoy sends to the external authorization service. + +#### Values + +- Default: Cluster name +- Data type: String + +### `Arguments.Config.GrpcService.InitialMetadata[]` + +Specifies additional metadata to include in streams initiated to the `GrpcService`. You can specify metadata for injecting additional ad-hoc authorization headers, for example, `x-foo-bar: baz-key`. For more information, including details on header value syntax, refer to the [Envoy documentation on custom request headers](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-custom-request-headers). + +#### Values + +- Default: None +- Data type: List of one or more key-value pairs: + + - KEY: String + - VALUE: String + +### `Arguments{}.Config{}.HttpService{}` + +Contains the configuration for raw HTTP communication between the filter and the external authorization service. Configure the `HttpService` or the [`GrpcService`](#arguments-config-grpcservice) settings, but not both. + +#### Values + +- Default: None +- Either the `HttpService` or the `GrpcService` configuration is required. +- Data type: Map + +### `Arguments{}.Config{}.HttpService{}.Target{}` + +Configuration for specifying the service to send HTTP authorization requests to. The `Target` field may contain the following fields: + +- [`Service`](#arguments-config-httpservice-target-service) or [`Uri`](#arguments-config-httpservice-target-uri) +- [`Timeout`](#arguments-config-httpservice-target-timeout) + + +#### Values + +- Default: None +- This field is required. +- Data type: Map + +### `Arguments{}.Config{}.HttpService{}.Target{}.Service{}` + +Specifies the upstream external authorization service. Configure this field when HTTP authorization requests are sent to an upstream service within the service mesh. The service must be configured as an upstream of the service that the filter is applied to. + +Configure either the `Service` field or the [`Uri`](#arguments-config-httpservice-target-uri) field, but not both. + +#### Values + +- Default: None +- This field or [`Uri`](#arguments-config-httpservice-target-uri) is required. +- Data type: Map + +The following table describes how to configure parameters for the `Service` field: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `Name` | Specifies the name of the upstream service. | String | None | +| `Namespace` | Specifies the Consul namespace that the upstream service belongs to. | String | `default` | +| `Partition` | Specifies the Consul admin partition that the upstream service belongs to. | String | `default` | + +### `Arguments{}.Config{}.HttpService{}.Target{}.Uri` + +Specifies the URI of the external authorization service. Configure this field when you must provide an explicit URI to the external authorization service, such as cases in which the authorization service is running on the same host or pod. + +Configure either the `Uri` field or the [`Service`](#arguments-config-httpservice-target-service) field, but not both. + +#### Values + +- Default: None +- This field or [`Service`](#arguments-config-httpservice-target-service) is required. +- Data type: String + +### `Arguments{}.Config{}.HttpService{}.Target{}.Timeout` + +Specifies the maximum duration that a response can take to arrive upon request. + +#### Values + +- Default: `1s` +- Data type: String + +### `Arguments{}.Config{}.HttpService{}.PathPrefix` + +Specifies a prefix for the value of the authorization request header `Path`. You must include the preceding forward slash (`/`). + +#### Values + +- Default: None +- Data type: String + +### `Arguments{}.Config{}.HttpService{}.AuthorizationRequest{}` + +HTTP-only configuration that controls the HTTP authorization request metadata. The `AuthorizationRequest` field may contain the following parameters: + +- [`AllowHeaders`](#arguments-config-httpservice-authorizationrequest-allowheaders) +- [`HeadersToAdd`](#arguments-config-httpservice-authorizationrequest-headerstoadd) + +#### Values + +- Default: None +- Data type: Map + +### `Arguments{}.Config{}.HttpService{}.AuthorizationRequest{}.AllowHeaders[]` + +Specifies a set of rules for matching client request headers. The request to the external authorization service includes any client request headers that satisfy any of the rules. Refer to the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto#extensions-filters-http-ext-authz-v3-extauthz) for a detailed explanation. + +#### Values + +- Default: None +- Data type: List of key-value pairs + +The following table describes the matching rules you can configure in the `AllowHeaders` field: + +@include 'envoy_ext_rule_matcher.mdx' + +### `Arguments{}.Config{}.HttpService{}.AuthorizationRequest{}.HeadersToAdd[]` + +Specifies a list of headers to include in the request to the authorization service. Note that Envoy overwrites client request headers with the same key. + +#### Values + +- Default: None +- Data type: List of one or more key-value pairs: + + - KEY: String + - VALUE: String + +### `Arguments{}.Config{}.HttpService{}.AuthorizationResponse{}` + +HTTP-only configuration that controls HTTP authorization response metadata. The `AuthorizationResponse` field may contain the following parameters: + +- [`AllowedUpstreamHeaders`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaders) +- [`AllowedUpstreamHeadersToAppend`](#arguments-config-httpservice-authorizationresponse-allowedupstreamheaderstoappend) +- [`AllowedClientHeaders`](#arguments-config-httpservice-authorizationresponse-allowedclientheaders) +- [`AllowedClientHeadersOnSuccess`](#arguments-config-httpservice-authorizationresponse-allowedclientheadersonsuccess) +- [`DynamicMetadataFromHeaders`](#arguments-config-httpservice-authorizationresponse-dynamicmetadatafromheaders) + +#### Values + +- Default: None +- Data type: Map + +### `Arguments{}.Config{}.HttpService{}.AuthorizationResponse{}.AllowedUpstreamHeaders[]` + +Specifies a set of rules for matching authorization response headers. Envoy adds any headers from the external authorization service to the client response that satisfy the rules. Envoy overwrites existing headers. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the matching rules you can configure in the `AllowedUpstreamHeaders` field: + +@include 'envoy_ext_rule_matcher.mdx' + +### `Arguments{}.Config{}.HttpService{}.AuthorizationResponse{}.AllowedUpstreamHeadersToAppend[]` + +Specifies a set of rules for matching authorization response headers. Envoy appends any headers from the external authorization service to the client response that satisfy the rules. Envoy appends existing headers. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the matching rules you can configure in the `AllowedUpstreamHeadersToAppend` field: + +@include 'envoy_ext_rule_matcher.mdx' + +### `Arguments{}.Config{}.HttpService{}.AuthorizationResponse{}.AllowedClientHeaders[]` + +Specifies a set of rules for matching client response headers. Envoy adds any headers from the external authorization service to the client response that satisfy the rules. When the list is not set, Envoy includes all authorization response headers except `Authority (Host)`. When a header is included in this list, Envoy automatically adds the following headers: + +- `Path` +- `Status` +- `Content-Length` +- `WWWAuthenticate` +- `Location` + +#### Values + +- Default: None +- Data type: Map + +The following table describes the matching rules you can configure in the `AllowedClientHeaders` field: + +@include 'envoy_ext_rule_matcher.mdx' + +### `Arguments{}.Config{}.HttpService{}.AuthorizationResponse{}.AllowedClientHeadersOnSuccess[]` + +Specifies a set of rules for matching client response headers. Envoy adds headers from the external authorization service to the client response when the headers satisfy the rules and the authorization is successful. If the headers match the rules but the authorization fails or is denied, the headers are not added. If this field is not set, Envoy does not add any additional headers to the client's response on success. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the matching rules you can configure in the `AllowedClientHeadersOnSuccess` field: + +@include 'envoy_ext_rule_matcher.mdx' + +### `Arguments{}.Config{}.HttpService{}.AuthorizationResponse{}.DynamicMetadataFromHeaders[]` + +Specifies a set of rules for matching authorization response headers. Envoy emits headers from the external authorization service as dynamic metadata that the next filter in the chain can consume. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the matching rules you can configure in the `DynamicMetadataFromHeaders` field: + +@include 'envoy_ext_rule_matcher.mdx' + +### `Arguments{}.Config{}.IncludePeerCertificate` + +If set to `true`, Envoy includes the peer X.509 certificate in the authorization request if the certificate is available. + +#### Values + +- Default: `false` +- Data type: Boolean + +### `Arguments{}.Config{}.MetadataContextNamespace[]` + +HTTP only field that specifies a list of metadata namespaces. The values of the namespaces are included in the authorization request context. The `consul` namespace is always included in addition to the namespaces you configure. + +#### Values + +- Default: `["consul"]` +- Data type: List of string values + +### `Arguments{}.Config{}.StatusOnError` + +HTTP only field that specifies a return code status to respond with on error. Refer to the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/type/v3/http_status.proto#enum-type-v3-statuscode) for additional information. + +#### Values + +- Default: `403` +- Data type: Integer + +### `Arguments{}.Config{}.StatPrefix` + +Specifies a prefix to add when writing statistics. + +#### Values + +- Default: `response` +- Data type: String + +### `Arguments{}.Config{}.WithRequestBody{}` + +HTTP only field that configures Envoy to buffer the client request body and send it with the authorization request. If unset, the request body is not sent with the authorization request. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the parameters that you can include in the `WithRequestBody` field: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `MaxRequestBytes` | Specifies the maximum size of the message body that the filter holds in memory. Envoy returns HTTP `403` and does not initiate the authorization process when the buffer reaches the number set in this field unless `AllowPartialMessage` is set to `true`. | uint32 | None | +| `AllowPartialMessage` | If set to `true`, Envoy buffers the request body until the value of `MaxRequestBytes` is reached. The authorization request is dispatched with a partial body and no `413` HTTP error returns by the filter. | Boolean | `false` | +| `PackAsBytes` | If set to `true`, Envoy sends the request body to the external authorization as raw bytes. Otherwise, Envoy sends the request body as a UTF-8 encoded string. | Boolean | `false` | + +## Examples + +The following examples demonstrate common configuration patterns for specific use cases. + +### Authorize gRPC requests to a URI + +In the following example, a service defaults configuration entry contains an `ext-authz` configuration. The configuration allows the `api` service to make gRPC authorization requests to a service at `localhost:9191`: + +```hcl +Kind = "service-defaults" +Name = "api" +EnvoyExtensions = [ + { + Name = "builtin/ext-authz" + Arguments = { + ProxyType = "connect-proxy" + Config = { + GrpcService = { + Target = { + URI = "127.0.0.1:9191" + } + } + } + } + } +] +``` + +### Upstream authorization + +In the following example, a service defaults configuration entry contains an `ext-authz` configuration. The configuration allows the `api` service to make gRPC authorization requests to a service named `authz`: + +```hcl +Kind = "service-defaults" +Name = "api" +EnvoyExtensions = [ + { + Name = "builtin/ext-authz" + Arguments = { + ProxyType = "connect-proxy" + Config = { + GrpcService = { + Target = { + Service = { + Name = "authz" + } + } + } + } + } + } +] +``` + +### Authorization requests after service intentions for Consul Enterprise + +In the following example for Consul Enterprise, the `api` service is configured to make an HTTP authorization requests to a service named `authz` in the `foo` namespace and `bar` partition. Envoy also inserts the external authorization filter after the `envoy.filters.http.rbac` filter: + +```hcl +Kind = "service-defaults" +Name = "api" +Protocol = "http" +EnvoyExtensions = [ + { + Name = "builtin/ext-authz" + Arguments = { + ProxyType = "connect-proxy" + InsertOptions = { + Location = "AfterLastMatch" + FilterName = "envoy.filters.http.rbac" + } + Config = { + HttpService = { + Target = { + Service = { + Name = "authz" + Namespace = "foo" + Partition = "bar" + } + } + } + } + } + } +] +``` diff --git a/website/content/docs/connect/proxies/envoy-extensions/configuration/property-override.mdx b/website/content/docs/connect/proxies/envoy-extensions/configuration/property-override.mdx new file mode 100644 index 000000000000..9b13cb940b23 --- /dev/null +++ b/website/content/docs/connect/proxies/envoy-extensions/configuration/property-override.mdx @@ -0,0 +1,273 @@ +--- +layout: docs +page_title: Property override configuration reference +description: Learn how to configure the property-override plugin, which is a builtin Consul plugin that allows you to set and remove Envoy proxy properties. +--- + +# Property override configuration reference + +This topic describes how to configure the `property-override` extension so that you can set and remove individual properties on the Envoy resources Consul generates. Refer to [Configure Envoy proxy properties](/consul/docs/connect/proxies/envoy-extensions/usage/property-override) for usage information. + +## Configuration model + +The following list outlines the field hierarchy, data types, and requirements for the `property-override` configuration. Place the configuration inside the `EnvoyExtension.Arguments` field in the proxy defaults or service defaults configuration entry. Refer the following documentation for additional information: + +- [`EnvoyExtensions` in proxy defaults](/consul/docs/connect/config-entries/proxy-defaults#envoyextensions) +- [`EnvoyExtensions` in service defaults](/consul/docs/connect/config-entries/service-defaults#envoyextensions) + +Click on a property name to view additional details, including default values. + +- [`ProxyType`](#proxytype): string | required +- [`Debug`](#debug): bool | `false` +- [`Patches`](#patches): list | required + - [`ResourceFilter`](#patches-resourcefilter): map + - [`ResourceType`](#patches-resourcefilter-resourcetype): string | required + - [`TrafficDirection`](#patches-resourcefilter-trafficdirection): string | required + - [`Services`](#patches-resourcefilter-services): list + - [`Name`](#patches-resourcefilter-services-name): string + - [`Namespace`](#patches-resourcefilter-services-namespace): string | `default` | + - [`Partition`](#patches-resourcefilter-services-partition): string | `default` | + - [`Op`](#patches-op): string | required + - [`Path`](#patches-path): string | required + - [`Value`](#patches-value): map, number, boolean, or string + +## Complete configuration + +When each field is defined, a `property-override` configuration has the following form: + + +```hcl +ProxyType = "connect-proxy" +Debug = false +Patches = [ + { + ResourceFilter = { + ResourceType = "" + TrafficDirection = "" + Services = [ + { + Name = "", + Namespace = "" + Partition = "" + } + ] + Op = "", + Path = "", + Value = "" + } +] +``` + +## Specification + +This section provides details about the fields you can configure for the `property-override` extension. + +### `ProxyType` + +Specifies the type of Envoy proxy that the extension applies to. The only supported value is `connect-proxy`. + +#### Values + +- Default: `connect-proxy` +- This field is required. +- Data type: String + +### `Debug` + +Enables full debug mode. When `Debug` is set to `true`, all possible fields for the given `ResourceType` and first unmatched segment of `Path` are returned on error. When set to `false`, the error message only includes the first ten possible fields. + +#### Values + +- Default: `false` +- Data type: Boolean + +### `Patches[]` + +Specifies a list of one or more JSON Patches that map to the Envoy proxy configurations you want to modify. Refer to [IETF RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902/) for information about the JSON Patch specification. + +#### Values + +- Default: None +- The `Patches` parameter is a list of configurations in JSON Patch format. Each patch can contain the following fields: + - [`ResourceFilter`](#patches-resourcefilter) + - [`Op`](#patches-op) + - [`Path`](#patches-path) + - [`Value`](#patches-value) + + +### `Patches[].ResourceFilter{}` + +Specifies the filter for targeting specific Envoy resources. The `ResourceFilter` configuration is not part of the JSON Patch specification. + +#### Values + +- Default: None +- This field is required. +- Data type: Map + +The following table describes how to configure a `ResourceFilter`: + +| Parameter | Description | Type | +| --- | --- | --- | +| `ProxyType` | Specifies the proxy type that the extension applies to. The only supported value is `connect-proxy`. | String | +| `ResourceType` | Specifies the Envoy resource type that the extension applies to. You can specify one of the following values for each `ResourceFilter`:
  • `cluster`
  • `cluster-load-assignment`
  • `route`
  • `listener`
| String | +| `TrafficDirection` | Specifies the type of traffic that the extension applies to relative to the current proxy. You can specify one of the following values for each `ResourceFilter`:
  • `inbound`: Targets resources for the proxy's inbound traffic.
  • `outbound`: Targets resources for the proxy's upstream services.
| String | +| `Services` | Specifies a list of services to target. Each member of the list has the following fields:
  • `Name`: Specifies the service associated with the traffic.
  • `Namespace`: Specifies the Consul Enterprise namespace the service is in.
  • `Partition`: Specifies the Consul Enterprise admin partition the service is in.
If `TrafficDirection` is set to `outbound`, upstream services in this field correspond to local Envoy resources that Consul patches at runtime.

Do not configure the `Services` field if `TrafficDirection` is set to `inbound`.

If this field is not set, Envoy targets all applicable resources. When patching outbound listeners, the patch includes the outbound transparent proxy listener only if `Services` is unset and if the local service is in transparent proxy mode. | List of maps | + +### `Patches[].Op` + +Specifies the JSON Patch operation to perform when the `ResourceFilter` matches a local Envoy proxy configuration. You can specify one of the following values for each patch: + +- `add`: Replaces a property or message specified by [`Path`](#patches-path) with the given value. The JSON patch format does not merge objects. To emulate merges, you must configure discrete `add` operations for each changed field. Consul returns an error if the target field does not exist in the corresponding schema. +- `remove`: Unsets the value of the field specified by [`Path`](#patches-path). If the field is not set, no changes are made. Consul returns an error if the target field does not exist in the corresponding schema. + +#### Values + +- Default: None +- This field is required. +- Data type is one of the following string values: + - `add` + - `remove` + +### `Patches[].Path` + +Specifies where the extension performs the associated operation on the specified resource type. Refer to [`ResourceType`](#patches-resourcefilter) for information about specifying a resource type to target. Refer to [`Op`](#patches-op) for information about setting an operation to perform on the resources. + +The `Path` field does not support addressing array elements or protobuf map field entries. Refer to [Constructing paths](/consul/docs/connect/proxies/envoy-extensions/usage/property-override#constructing-paths) for information about how to construct paths. + +When setting fields, the extension sets any unset intermediate fields to their default values. A a single operation on a nested field can set multiple intermediate fields. Because Consul sets the intermediate fields to their default values, you may need to configure subsequent patches to satisfy Envoy or Consul validation. + +#### Values + +- Default: None +- This field is required. +- Data type: String + +### `Patches[].Value{}` + +Defines a value to set at the specified [path](#patches-path) if the [operation](#patches-op) is set to `add`. You can specify either a scalar or enum value or define a map that contains string keys and values corresponding to scalar or enum child fields. Refer to the [example configurations](#examples) for additional guidance and to the [Envoy API documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/api) for additional information about Envoy proxy interfaces. + +If Envoy specifies a wrapper as the target field type, the extension automatically coerces simple values to the wrapped type when patching. For example, the value `32768` is allowed when targeting a cluster's `per_connection_buffer_limit_bytes`, which is a `UInt32Value` field. Refer to the [protobuf documentation](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/wrappers.proto) for additional information about wrappers. +#### Values + +- Default: None +- This field is required if [`Op`](#patches-op) is set to `add`, otherwise you must omit the field. +- This field takes one of the following data types: + - scalar + - enum + - map + +## Examples + +The following examples demonstrate patterns that you may be able to model your configurations on. + +### Enable `enforcing_consecutive_5xx` outlier detection + +In the following example, the `add` operation patches an outlier detection property into outbound cluster traffic. The `Path` specifies the `enforcing_consecutive_5xx` interface and sets a value of `1234`: + +```hcl +Kind = "service-defaults" +Name = "my-svc" +Protocol = "http" +EnvoyExtensions = [ + { + Name = "builtin/property-override", + Arguments = { + ProxyType = "connect-proxy", + Patches = [ + { + "ResourceFilter" = { + "ResourceType" = "cluster", + "TrafficDirection" = "outbound", + "Service" = { + "Name" = "other-svc" + }, + }, + "Op" = "add", + "Path" = "/outlier_detection/enforcing_consecutive_5xx", + "Value" = 1234, + } + ] + } + } +] +``` + +### Update multiple values in the default map + +In the following example, two `ResourceFilter` blocks target outbound traffic to the `db` service and add `/outlier_detection/enforcing_consecutive_5xx` and `/outlier_detection/failure_percentage_request_volume` properties: + +```hcl +Kind = "service-defaults" +Name = "my-svc" +Protocol = "http" +EnvoyExtensions = [ + { + Name = "builtin/property-override", + Arguments = { + ProxyType = "connect-proxy", + Patches = [ + { + ResourceFilter = { + ResourceType = "cluster", + TrafficDirection = "outbound", + Services = [{ + Name = "other-svc" + }], + }, + Op = "add", + Path = "/outlier_detection/enforcing_consecutive_5xx", + Value = 1234, + }, + { + ResourceFilter = { + ResourceType = "cluster", + TrafficDirection = "outbound", + Services = [{ + Name = "other-svc" + }], + }, + Op = "add", + Path = "/outlier_detection/failure_percentage_request_volume", + Value = 2345, + } + ] + } + } +] +``` + +### Set multiple values that replace the map + +In the following example, a `ResourceFilter` targets outbound traffic to the `db` service and replaces the map of properties located at `/outlier_detection` with `enforcing_consecutive_5xx` and `failure_percentage_request_volume` and properties: + +```hcl +Kind = "service-defaults" +Name = "my-svc" +Protocol = "http" +EnvoyExtensions = [ + { + Name = "builtin/property-override", + Arguments = { + ProxyType = "connect-proxy", + Patches = [ + { + ResourceFilter = { + ResourceType = "cluster", + TrafficDirection = "outbound", + Services = [{ + Name = "other-svc" + }], + }, + Op = "add", + Path = "/outlier_detection", + Value = { + "enforcing_consecutive_5xx" = 1234, + "failure_percentage_request_volume" = 2345, + }, + } + ] + } + } +] +``` diff --git a/website/content/docs/connect/proxies/envoy-extensions/configuration/wasm.mdx b/website/content/docs/connect/proxies/envoy-extensions/configuration/wasm.mdx new file mode 100644 index 000000000000..ed1e2061a5d5 --- /dev/null +++ b/website/content/docs/connect/proxies/envoy-extensions/configuration/wasm.mdx @@ -0,0 +1,484 @@ +--- +layout: docs +page_title: WebAssembly extension configuration reference +description: Learn how to configure the wasm Envoy extension, which is a builtin Consul extension that allows you to run WebAssembly plugins in Envoy proxies. +--- + +# WebAssembly extension configuration reference + +This topic describes how to configure the `wasm` extension, which directs Consul to run WebAssembly (Wasm) plugins in Envoy proxies. Refer to [Run WebAssembly plug-ins in Envoy proxy](/consul/docs/connect/proxies/envoy-extensions/usage/wasm) for usage information. + +## Configuration model + +The following list outlines the field hierarchy, data types, and requirements for the `wasm` configuration. Place the configuration inside the `EnvoyExtension.Arguments` field in the proxy defaults or service defaults configuration entry. Refer the following documentation for additional information: + +- [`EnvoyExtensions` in proxy defaults](/consul/docs/connect/config-entries/proxy-defaults#envoyextensions) +- [`EnvoyExtensions` in service defaults](/consul/docs/connect/config-entries/service-defaults#envoyextensions) + +Click on a property name to view additional details, including default values. + +- [`Protocol`](#protocol): string +- [`ListenerType`](#listenertype): string | required +- [`ProxyType`](#proxytype): string | `connect-proxy` +- [`PluginConfig`](#pluginconfig): map | required + - [`Name`](#pluginconfig-name): string + - [`RootID`](#pluginconfig-rootid): string | required + - [`VmConfig`](#pluginconfig-vmconfig): map + - [`VmID`](#pluginconfig-vmconfig-vmid): string + - [`Runtime`](#pluginconfig-vmconfig): string | `v8` + - [`Code`](#pluginconfig-vmconfig-code): map + - [`Local`](#pluginconfig-vmconfig-code-local): map + - [`Filename`](#pluginconfig-vmconfig-code-local): string + - [`Remote`](#pluginconfig-vmconfig-code-remote): map + - [`HttpURI`](#pluginconfig-vmconfig-code-remote-httpuri): map + - [`Service`](#pluginconfig-vmconfig-code-remote-httpuri-service): map + - [`Name`](#pluginconfig-vmconfig-code-remote-httpuri-service): string + - [`Namespace`](#pluginconfig-vmconfig-code-remote-httpuri-service): string + - [`Partition`](#pluginconfig-vmconfig-code-remote-httpuri-service): string + - [`URI`](#pluginconfig-vmconfig-code-remote-httpuri-uri): string + - [`Timeout`](#pluginconfig-vmconfig-code-remote-httpuri-timeout): string + - [`SHA256`](#pluginconfig-vmconfig-code-remote-sha256): string + - [`RetryPolicy`](#pluginconfig-vmconfig-code-remote-retrypolicy): map + - [`RetryBackOff`](#pluginconfig-vmconfig-code-remote-retrypolicy-retrybackoff): map + - [`BaseInterval`](#pluginconfig-vmconfig-code-remote-retrypolicy-retrybackoff): string + - [`MaxInterval`](#pluginconfig-vmconfig-code-remote-retrypolicy-retrybackoff): string + - [`NumRetries`](#pluginconfig-vmconfig-code-remote-retrypolicy-numretries): number | `-1` + - [`Configuration`](#pluginconfig-vmconfig-configuration): string + - [`EnvironmentVariables`](#pluginconfig-vmconfig-environmentvariables): map + - [`HostEnvKeys`](#pluginconfig-vmconfig-environmentvariables-hostenvkeys): list of strings + - [`KeyValues`](#pluginconfig-vmconfig-environmentvariables-keyvalues): map + - [`Configuration`](#pluginconfig-configuration): string + - [`CapabilityRestrictionConfiguration`](#pluginconfig-vmconfig-capabilityrestrictionconfiguration): map + - [`AllowedCapabilities`](#pluginconfig-vmconfig-capabilityrestrictionconfiguration): map of strings + +## Complete configuration + +When all parameters are set for the extension, the configuration has the following form: + +```hcl +Protocol = "" +ListenerType = "" +ProxyType = "connect-proxy" +PluginConfig = { + Name = "" + RootID = "" + VmConfig = { + VmID = "" + Runtime = "v8" + Code = { + Local = { # Set either `Local` or `Remote', not both + Filename = "
" + } + Remote = { # Set either `Local` or `Remote', not both + HttpURI = { + Service = { + Name = "" + Namespace = "" + Partition = "" + } + URI = "" + Timeout = "1s" + SHA256 = "" + RetryPolicy = { + RetryBackOff = { + BaseInterval = "1s" + MaxInterval = "10s" + } + NumRetries = -1 + } + } + Configuration = "" + EnvironmentVariables = { + HostEnvKeys = [ + <"keys"> + ] + KeyValues = { + [ + <"key = value"> + ] + } + } + Configuration = "" + CapabilityRestrictionConfiguration = { + AllowedCapabilities = { + "fd_read" = {} + "fd_seek" = {} + "environ_get" = {} + "clock_get_time" = {} + } + } +} +``` + +## Specification + +This section provides details about the fields you can configure for the `wasm` extension. + +### `Protocol` + +Specifies the type of Wasm filter to apply. You can set either `tcp` or `http`. Set the `Protocol` to the protocol that the Wasm plugin implements when loaded by the filter. For Consul to apply the filter, the protocol must match the service’s protocol. + +#### Values + +- Default: None +- This field is required. +- Data type is one of the following string values: + - `tcp` + - `http` + +### `ListenerType` + +Specifies the type of listener the extension applies to. The listener type is either `inbound` or `outbound`. If the listener type is set to `inbound`, Consul applies the extension so the Wasm plugin is run when other services in the mesh send messages to the service attached to the proxy. If the listener type is set to `outbound`, Consul applies the extension so the Wasm plugin is run when the attached proxy sends messages to other services in the mesh. + +#### Values + +- Default: None +- This field is required. +- Data type is one of the following string values: + - `inbound` + - `outbound` + +### `ProxyType` + +Specifies the type of Envoy proxy that the extension applies to. The only supported value is `connect-proxy`. + +#### Values + +- Default: `connect-proxy` +- This field is required. +- Data type: String + +### `PluginConfig{}` + +Map containing the following configuration parameters for your Wasm plugin: + +- [`Name`](#pluginconfig-name) +- [`RootID`](#pluginconfig-rootid) +- [`VmConfig`](#pluginconfig-vmconfig) +- [`Configuration`](#pluginconfig-configuration) +- [`CapabilitiesRestrictionConfiguration`](#pluginconfig-capabilitiesrestrictionconfiguration) + +#### Values + +- Default: None +- This field is required. +- Data type: Map + +### `PluginConfig{}.Name` + +Specifies a unique name for a filter in a VM. Envoy uses the name to identify specific filters if multiple filters are processed on a VM with the same `VmID` and `RootID`. The name also appears in logs for debugging purposes. + +#### Values + +- Default: None +- Data type: String + +### `PluginConfig{}.RootID` + +Specifies a unique ID for a set of filters in a VM that share a `RootContext` and `Contexts`, such as a Wasm `HttpFilter` and a Wasm `AccessLog`, if applicable. All filters with the same `RootID` and `VmID` share `Context`s. + +#### Values + +- Default: None +- Data type: String + +### `PluginConfig{}.VmConfig{}` + +Map containing the following configuration parameters for the VM that runs your Wasm plugin: + +- [`VmID`](#pluginconfig-vmconfig-vmid) +- [`Runtime`](#pluginconfig-vmconfig-runtime) +- [`Code`](#pluginconfig-vmconfig-code) +- [`Configuration`](#pluginconfig-vmconfig-configuration) +- [`EnvironmentVariables`](#pluginconfig-vmconfig-environmentvariables) + +#### Values + +- Default: None +- Data type: Map + +### `PluginConfig{}.VmConfig{}.VmID` + +Specifies an ID that Envoy uses with a hash of the Wasm code to determine which VM runs the plugin. All plugins with the same `VmID` and `Code` use the same VM. If unspecified, all plugins with the same code run in the same VM. Sharing a VM between plugins may have security implications, but can reduce memory utilization and can make data sharing easier. + +#### Values + +- Default: None +- Data type: String + +### `PluginConfig{}.VmConfig{}.Runtime` + +Specifies the type of Wasm runtime. +#### Values + +- Default: `v8` +- Data type is one of the following string values: + - `v8` + - `wastime` + - `wamr` + - `wavm` + +### `PluginConfig{}.VmConfig{}.Code{}` + +Map containing one of the following configuration parameters: + +- [`Local`](#pluginconfig-vmconfig-code-local) +- [`Remote`](#pluginconfig-vmconfig-code-local) + +You can configure either `Local` or `Remote`, but not both. The `Code` block instructs Consul how to find the Wasm plugin code for Envoy to execute. + +#### Values + +- Default: None +- This field is required. +- Data type is a map containing one of the following configurations: + - [`Local`](#pluginconfig-vmconfig-code-local) + - [`Remote`](#pluginconfig-vmconfig-code-local) + +### `PluginConfig{}.VmConfig{}.Code{}.Local{}` + +Instructs Envoy to load the plugin code from a local volume. Do not configure the `Local` parameter if the plugin code is on a remote server. + +The `Local` field is a map that contains a `Filename` parameter. The `Filename` parameter takes a string value that specifies the path to the plugin on the local file system. + +Local plug-ins are not supported in Kubernetes-orchestrated environments. + +#### Values + +- Default: None +- Data type is a map containing the `Filename` parameter. The `Filename` parameter takes a string value that specifies the path to the plugin on the local file system. + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}` + +Instructs Envoy to load the plugin code from a remote server. Do not configure the `Remote` parameter if the plugin code is on the local VM. + +The `Remote` field is a map containing the following parameters: + +- [`HttpURI`](#pluginconfig-vmconfig-code-remote-httpuri) +- [`SHA256`](#pluginconfig-vmconfig-code-remote-sha256) +- [`RetryPolicy`](#pluginconfig-vmconfig-code-remote-retrypolicy) + +#### Values + +- Default: None +- Data type: Map + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.HttpURI{}` + +Specifies the configuration for fetching the remote data. The `HttpURI` field is a map containing the following parameters: + +- [`Service`](#pluginconfig-vmconfig-code-remote-httpuri-service) +- [`URI`](#pluginconfig-vmconfig-code-remote-httpuri-uri) +- [`Timeout`](#pluginconfig-vmconfig-code-remote-httpuri-uri) + +#### Values + +- Default: None +- Data type: Map + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.HttpURI{}.Service` + +Specifies the upstream service to fetch the remote plugin from. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the fields you can specify in the `Service` map: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `Name` | Specifies the name of the upstream service. | String | None | +| `Namespace` | Specifies the Consul namespace that the upstream service belongs to. | String | `default` | +| `Partition` | Specifies the Consul admin partition that the upstream service belongs to. | String | `default` | + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.HttpURI{}.URI` + +Specifies the URI Envoy uses to fetch the plugin file from the upstream. This field is required for Envoy to retrieve plugin code from a remote location. You must specify the fully-qualified domain name (FDQN) of the remote URI, which includes the protocol, host, and path. + +#### Values + +- Default: None +- This field is required. +- Data type: String value that specifies a FDQN + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.HttpURI{}.Timeout` + +Specifies the maximum duration that a response can take to complete the request for the plugin data. + +#### Values + +- Default: `1s` +- Data type: String + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.SHA256` + +Specifies the required SHA256 string for verifying the remote data. + +#### Values + +- Default: None +- This field is required. +- Data type: String + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.RetryPolicy{}` + +Defines a policy for retrying requests to the upstream service when fetching the plugin data. The `RetryPolicy` field is a map containing the following parameters: + +- [`RetryBackoff`](#pluginconfig-vmconfig-code-remote-retrypolicy) +- [`NumRetries`](#pluginconfig-vmconfig-code-remote-numretries) + +#### Values + +- Default: None +- Data type: Map +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.RetryPolicy{}.RetryBackOff{}` + +Specifies parameters that control retry backoff strategy. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the fields you can specify in the `RetryBackOff` map: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `BaseInterval` | Specifies the base interval for determining the next backoff computation. Set a value greater than `0` and less than or equal to the `MaxInterval` value. | String | `1s` | +| `MaxInterval` | Specifies the maximum interval between retries. Set the value greater than or equal to the `BaseInterval` value. | String | `10s` | + +### `PluginConfig{}.VmConfig{}.Code{}.Remote{}.RetryPolicy{}.NumRetries` + +Specifies the number of times Envoy retries to fetch plugin data if the initial attempt is unsuccessful. + +#### Values + +- Default: `1` +- Data type: Integer + +### `PluginConfig{}.VmConfig{}.Configuration` + +Specifies the configuration Envoy encodes as bytes and passes to the plugin during VM startup. Refer to [`proxy_on_vm_start` in the Proxy Wasm ABI documentation](https://github.com/proxy-wasm/spec/tree/master/abi-versions/vNEXT#proxy_on_vm_start) for additional information. + +#### Values + +- Default: None +- This field is required. +- Data type: String + +### `PluginConfig{}.VmConfig{}.EnvironmentVariables{}` + +Specifies environment variables for Enovy to inject into this VM so that they are available through WASI’s `environ_get` and `environ_get_sizes` system calls. + +In most cases, WASI calls the functions implicitly in your language’s standard library. As a result, you do not need to call them directly. You can also access environment variables as you would on native platforms. + +Envoy rejects the configuration if there’s conflict of key space. + +The `EnvironmentVariables` field is a map containing parameters for setting the keys and values. + +#### Values + +- Default: None +- Data type: Map + +The following table describes the parameters contained in the `EnvironmentVariables` map: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `HostEnvKeys` | Specifies a list of Envoy environment variable keys to expose to the VM. If a key exists in Envoy’s environment variables, then the key-value pair is injected. Envoy ignores `HostEnvKeys` that do not exist in its environment variables. | List | None | +| `KeyValues` | Specifies a map of explicit key-value pairs to inject into the VM. | Map of string keys and values | None | + +### `PluginConfig{}.Configuration` + +Specifies the configuration Consul encodes as bytes and passes to the plugin during plugin startup. Refer to [`proxy_on_configure` in the Envoy documentation](https://github.com/proxy-wasm/spec/tree/master/abi-versions/vNEXT#proxy_on_configure) for additional information. + +#### Values + +- Default: None +- Data type: String + +### `PluginConfig{}.CapabilityRestrictionConfiguration{}` + +Specifies a configuration for restricting the proxy-Wasm capabilities that are available to the module. + +The `CapabilityRestrictionConfiguration` field is a map that contains a `AllowedCapabilities` parameter. The `AllowedCapabilities` parameter takes a map of string values that correspond to Envoy capability names. Refer to the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/wasm/v3/wasm.proto#extensions-wasm-v3-capabilityrestrictionconfig) for additional information. + +!> **Security warning**: Consul ignores the value that each capability maps to. You can leave the `AllowedCapabilities` empty to allow all capabilities, but doing so gives the configured plugin full unrestricted access to the runtime API provided by the Wasm VM. You must set this to a non-empty map if you want to restrict access to specific capabilities provided by the Wasm runtime API. + +#### Values + +- Default: `""` +- Data type is a map containing the `AllowedCapabilities` parameter. The `AllowedCapabilities` parameter takes a map of string values that correspond to Envoy capability names. Refer to the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/wasm/v3/wasm.proto#extensions-wasm-v3-capabilityrestrictionconfig) for additional information. + +## Examples + +The following examples demonstrate patterns that you may be able to model your configurations on. + +### Run a Wasm plugin from a local file + +In the following example, Consul figures the Envoy proxy for the `db` service with an inbound TCP Wasm filter that uses the plugin code from the local `/consul/extensions/sqli.wasm` file. + +```hcl + +Kind = "service-defaults" +Name = "db" +Protocol = "tcp" +EnvoyExtensions = [ + { + Name = "builtin/wasm" + Required = true + Arguments = { + Protocol = "tcp" + ListenerType = “inbound” + PluginConfig = { + VmConfig = { + Code = { + Local = { + Filename = "file:///consul/extensions/sqli.wasm" + } + } + } + Configuration = < + + + +```hcl +Kind = "service-defaults" +Name = "api" +EnvoyExtensions = [ + { + Name = "builtin/ext-authz" + Arguments = { + ProxyType = "connect-proxy" + Config = { + GrpcService = { + Target = { + Service = { + Name = "authz" + } + } + } + } + } + } +] +``` + + + + + +```json +"Kind": "service-defaults", +"Name": "api", +"EnvoyExtensions": [{ + "Name": "builtin/ext-authz", + "Arguments": { + "ProxyType": "connect-proxy", + "Config": { + "GrpcService": { + "Target": { + "Service": { + "Name": "authz" + } + } + } + } + } + } +] +``` + + + + + + +```yaml +kind: ServiceDefaults +name: api +envoyExtensions: + - name: builtin/ext-authz + arguments: + proxyType: connect-proxy + config: + grpcService: + target: + service: + name: authz +``` + + + + +Refer to the [external authorization extension configuration reference](/consul/docs/connect/proxies/envoy-extensions/configuration/ext-authz) for details on how to configure the extension. + +Refer to the [proxy defaults configuration entry reference](/consul/docs/connect/config-entries/proxy-defaults) and [service defaults configuration entry reference](/consul/docs/connect/config-entries/service-defaults) for details on how to define the configuration entries. + +!> **Warning:** Adding Envoy extensions default proxy configurations may have unintended consequences. We recommend configuring `EnvoyExtensions` in service defaults configuration entries in most cases. + +### Unsupported Envoy configuration fields + +The following Envoy configurations are not supported: + +| Configuration | Workaround | +| --- | --- | +| `deny_at_disable` | Disable filter by removing it from the service’s configuration in the configuration entry. | +| `failure_mode_allow` | Set the `EnvoyExtension.Required` field to `true` in the [service defaults configuration entry](/consul/docs/connect/config-entries/service-defaults#envoyextensions) or [proxy defaults configuration entry](/consul/docs/connect/config-entries/proxy-defaults#envoyextensions). | +| `filter_enabled` | Set the `EnvoyExtension.Required` field to `true` in the [service defaults configuration entry](/consul/docs/connect/config-entries/service-defaults#envoyextensions) or [proxy defaults configuration entry](/consul/docs/connect/config-entries/proxy-defaults#envoyextensions). | +| `filter_enabled_metadata` | Set the `EnvoyExtension.Required` field to `true` in the [service defaults configuration entry](/consul/docs/connect/config-entries/service-defaults#envoyextensions) or [proxy defaults configuration entry](/consul/docs/connect/config-entries/proxy-defaults#envoyextensions). | +| `transport_api_version` | Consul only supports v3 of the transport API. As a result, there is no workaround for implement the behavior of this field. | + +## Apply the configuration entry + +If your network is deployed to virtual machines, use the `consul config write` command and specify the proxy defaults or service defaults configuration entry to apply the configuration. For Kubernetes-orchestrated networks, use the `kubectl apply` command. The following example applies the extension in a proxy defaults configuration entry. + + + + +```shell-session +$ consul config write api-auth-service-defaults.hcl +``` + + + + +```shell-session +$ consul config write api-auth-service-defaults.json + +``` + + + + +```shell-session +$ kubectl apply api-auth-service-defaults.yaml +``` + + + diff --git a/website/content/docs/connect/proxies/envoy-extensions/usage/property-override.mdx b/website/content/docs/connect/proxies/envoy-extensions/usage/property-override.mdx new file mode 100644 index 000000000000..0166f84ec193 --- /dev/null +++ b/website/content/docs/connect/proxies/envoy-extensions/usage/property-override.mdx @@ -0,0 +1,203 @@ +--- +layout: docs +page_title: Configure Envoy proxy properties +description: Learn how to use the property-override extension for Envoy proxies to set and remove individual properties for the Envoy resources Consul generates. +--- + +# Configure Envoy proxy properties + +This topic describes how to use the `property-override` extension to set and remove individual properties for the Envoy resources Consul generates. The extension uses the [protoreflect](https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect), which enables Consul to dynamically manipulate messages. + +## Workflow + +- Complete the following steps to use the `property-override` extension: +- Configure an `EnvoyExtensions` block in a service defaults or proxy defaults configuration entry. +- Apply the configuration entry. + +!> **Security warning**: The property override extension is an advanced feature capable of introducing unintended consequences or reducing cluster security if used incorrectly. Consul does not enforce TLS retention, intentions, or other security-critical components of the Envoy configuration. Additionally, Consul does not verify that the configuration does not contain errors that affect service traffic. + +## Add the `EnvoyExtensions` + +Add Envoy extension configurations to a proxy defaults or service defaults configuration entry. Place the extension configuration in an `EnvoyExtensions` block in the configuration entry. + +- When you configure Envoy extensions on proxy defaults, they apply to every service. +- When you configure Envoy extensions on service defaults, they apply to a specific service. + +Consul applies Envoy extensions configured in proxy defaults before it applies extensions in service defaults. As a result, the Envoy extension configuration in service defaults may override configurations in proxy defaults. + +In the following service defaults configuration entry example, Consul adds a new `/upstream_connection_options/tcp_keepalive/keepalive_probes-5` field to each of the proxy's cluster configuration for the outbound `db`service upstream. The configuration applies to all `connect-proxy` proxies with services configured to communicate over HTTP: + + + + + +```hcl +Kind = "service-defaults" +Name = "global" +Protocol = "http" +EnvoyExtensions = [ + { + Name = "builtin/property-override" + Arguments = { + ProxyType = "connect-proxy", + Patches = [ + { + ResourceFilter = { + ResourceType = "cluster", + TrafficDirection = "outbound" + Services = [{ + Name = "other-svc" + }], + Op = "add" + Path = "/upstream_connection_options/tcp_keepalive/keepalive_probes", + Value = 5, + } + ] + } +] +``` + + + + + + +```json +"kind": "service-defaults", +"name": "global", +"protocol": "http", +"envoy_extensions": [{ + "name": "builtin/property-override", + "arguments": { + "proxyType": "connect-proxy", + "patches": [{ + "resourceFilter": { + "resourceType": "cluster", + "trafficDirection": "outbound", + "services": [{ "name": "other-svc" }], + "op": "add", + "path": "/upstream_connection_options/tcp_keepalive/keepalive_probes", + "value": 5 + } + }] + } +}] +``` + + + + + +```yaml +apiversion: consul.hashicorp.com/v1alpha1 +kind: ServiceDefaults +metadata: + name: global +spec: + protocol: http + envoyExtensions: + name = "builtin/property-override" + arguments: + proxyType: "connect-proxy", + patches: + - resourceFilter: + resourceType: "cluster" + trafficDirection: "outbound" + services: + - name: "other-svc" + op: "add" + path: "/upstream_connection_options/tcp_keepalive/keepalive_probes", + value: 5 +``` + + + + + + +Refer to the [property override configuration reference](/consul/docs/connect/proxies/envoy-extensions/configuration/property-override) for details on how to configure the extension. + +Refer to the [proxy defaults configuration entry reference](/consul/docs/connect/config-entries/proxy-defaults) and [service defaults configuration entry reference](/consul/docs/connect/config-entries/service-defaults) for details on how to define the configuration entries. + +!> **Warning:** Adding Envoy extensions default proxy configurations may have unintended consequences. We recommend configuring `EnvoyExtensions` in service defaults configuration entries in most cases. + +### Constructing paths + +To target the properties for an Envoy resource type, you must specify the path where the properties exist in the [`Path` field](/consul/docs/connect/proxies/envoy-extensions/configuration/property-override#patches-path) of the property override extension configuration. Set the `Path` field to an empty or partially invalid string when saving the configuration entry and Consul returns an error with a list of supported fields for the first unrecognized segment of the path. By default, Consul only returns the first ten fields, but you can set the [`Debug` field](/consul/docs/connect/proxies/envoy-extensions/configuration/property-override#debug) to `true` to direct Consul to output all possible fields. + +In the following example, Consul outputs the top-level fields available for the Envoy cluster resource: + +```hcl +Kind = "service-defaults" +Name = "api" +EnvoyExtensions = [ + { + Name = "builtin/property-override" + Arguments = { + ProxyType = "connect-proxy" + Patches = [ + { + ResourceFilter = { + ResourceType = "cluster" + TrafficDirection = "outbound" + } + Op = "add" + Path = "" + Value = 5 + } + ] + } + } +] +``` + +After applying the configuration entry, Consul prints a message that includes the possible fields for the resource: + +```shell-session +$ consul config write api.hcl +non-empty, non-root Path is required. available cluster fields: +/outlier_detection +/outlier_detection/enforcing_consecutive_5xx +/outlier_detection/failure_percentage_request_volume +/round_robin_lb_config +/round_robin_lb_config/slow_start_config +``` + +You can use the output to help you construct the appropriate value for the `Path` field. For example: + +```shell-session +$ consul config write api.hcl | grep round_robin +/round_robin_lb_config +``` + + + + +## Apply the configuration entry + +If your network is deployed to virtual machines, use the `consul config write` command and specify the proxy defaults or service defaults configuration entry to apply the configuration. For Kubernetes-orchestrated networks, use the `kubectl apply` command. The following example applies the extension in a proxy defaults configuration entry. + + + + +```shell-session +$ consul config write property-override-extension-service-defaults.hcl +``` + + + + +```shell-session +$ consul config write property-override-extension-service-defaults.json + +``` + + + + +```shell-session +$ kubectl apply property-override-extension-service-defaults.yaml +``` + + + diff --git a/website/content/docs/connect/proxies/envoy-extensions/usage/wasm.mdx b/website/content/docs/connect/proxies/envoy-extensions/usage/wasm.mdx new file mode 100644 index 000000000000..de899efe48c6 --- /dev/null +++ b/website/content/docs/connect/proxies/envoy-extensions/usage/wasm.mdx @@ -0,0 +1,191 @@ +--- +layout: docs +page_title: Run WebAssembly plug-ins in Envoy proxy +description: Learn how to use the Consul wasm extension for Envoy, which directs Consul to run your WebAssembly (Wasm) plugins for Envoy proxies in your service mesh. +--- + + +# Run WebAssembly plug-ins in Envoy proxy + +This topic describes how to use the `wasm` extension, which directs Consul to run your WebAssembly (Wasm) plug-ins for Envoy proxies. + +## Workflow + +You can create Wasm plugins for Envoy and integrate them using the `wasm` extension. Wasm is a binary instruction format for stack-based virtual machines that has the potential to run anywhere after it has been compiled. Wasm plug-ins run as filters in a service mesh application's sidecar proxy. + +The following steps describe the process of integrating Wasm plugins: + +- Create your Wasm plugin. You must ensure that your plugin functions as expected. Refer to the [WebAssembly website](https://webassembly.org/) for information and links to documentation. +- Configure an `EnvoyExtensions` block in a service defaults or proxy defaults configuration entry. +- Apply the configuration entry. + +## Add the `EnvoyExtensions` + +Add Envoy extension configuration to a proxy defaults or service defaults configuration entry. Place the extension configuration in an `EnvoyExtensions` block in the configuration entry. + +- When you configure Envoy extensions on proxy defaults, they apply to every service. +- When you configure Envoy extensions on service defaults, they apply to a specific service. + +Consul applies Envoy extensions configured in proxy defaults before it applies extensions in service defaults. As a result, the Envoy extension configuration in service defaults may override configurations in proxy defaults. + +In the following example, the extension uses an upstream service named `file-server` to serve a Wasm-based web application firewall (WAF). + + + + + +```hcl +Kind = "service-defaults" +Name = "api" +Protocol = "http" +EnvoyExtensions = [ + { + Name = "builtin/wasm" + Arguments = { + Protocol = "http" + ListenerType = "inbound" + PluginConfig = { + VmConfig = { + Code = { + Remote = { + HttpURI = { + Service = { + Name = "file-server" + } + URI = "https://file-server/waf.wasm" + } + SHA256 = "c9ef17f48dcf0738b912111646de6d30575718ce16c0cbde3e38b21bb1771807" + } + } + } + Configuration = < + + + + +```json +{ + "kind": "service-defaults", + "name": "api", + "protocol": "http", + "envoyExtensions": [{ + "name": "builtin/wasm", + "arguments": { + "protocol": "http", + "listenerType": "inbound", + "pluginConfig": { + "VmConfig": { + "Code": { + "Remote": { + "HttpURI": { + "Service": { + "Name": "file-server" + }, + "URI": "https://file-server/waf.wasm" + } + } + } + }, + "Configuration": { + "rules": [ + "Include @demo-conf", + "Include @crs-setup-demo-conf", + "SecDebugLogLevel 9", + "SecRuleEngine On", + "Include @owasp_crs/*.conf" + ] + } + + } + } + }] +} +``` + + + + + + + +```yaml +kind: service-defaults +name: api +protocol: http +envoyExtensions: + - name: builtin/wasm + required: true + arguments: + protocol: http + listenerType: inbound + pluginConfig: + VmConfig: + Code: + Remote: + HttpURI: + Service: + Name: file-server + URI: https://file-server/waf.wasm + Configuration: + rules: + - Include @demo-conf + - Include @crs-setup-demo-conf + - SecDebugLogLevel 9 + - SecRuleEngine On + - Include @owasp_crs/*.conf +``` + + + + + + +Refer to the [Wasm extension configuration reference](/consul/docs/connect/proxies/envoy-extensions/configuration/wasm) for details on how to configure the extension. + +Refer to the [proxy defaults configuration entry reference](/consul/docs/connect/config-entries/proxy-defaults) and [service defaults configuration entry reference](/consul/docs/connect/config-entries/service-defaults) for details on how to define the configuration entries. + +!> **Warning:** Adding Envoy extensions default proxy configurations may have unintended consequences. We recommend configuring `EnvoyExtensions` in service defaults configuration entries in most cases. + +## Apply the configuration entry + +If your network is deployed to virtual machines, use the `consul config write` command and specify the proxy defaults or service defaults configuration entry to apply the configuration. For Kubernetes-orchestrated networks, use the `kubectl apply` command. The following example applies the extension in a proxy defaults configuration entry. + + + + +```shell-session +$ consul config write wasm-extension-serve-waf.hcl +``` + + + + +```shell-session +$ consul config write wasm-extension-serve-waf.json +``` + + + + +```shell-session +$ kubectl apply wasm-extension-serve-waf.yaml +``` + + + diff --git a/website/content/docs/enterprise/license/utilization-reporting.mdx b/website/content/docs/enterprise/license/utilization-reporting.mdx new file mode 100644 index 000000000000..50db53860979 --- /dev/null +++ b/website/content/docs/enterprise/license/utilization-reporting.mdx @@ -0,0 +1,168 @@ +--- +page_title: Automated license utilization reporting +description: >- + Learn what data HashiCorp collects to meter Enterprise license utilization. Enable or disable reporting. Review sample payloads and logs. +--- + +# Automated license utilization reporting + +Automated license utilization reporting sends license utilization data to HashiCorp without requiring you to manually collect and report them. It also enables you to review your license usage with the monitoring solution you already use, such as Splunk and Datadog, as you optimize and manage your deployments. You can use these reports to understand how much more you can deploy under your current contract, which can help you protect against overutilization and budget for predicted consumption. + +Automated reporting shares the minimum data required to validate license utilization as defined in our contracts. This data mostly consists of computed metrics, and it will never contain Personal Identifiable Information (PII) or other sensitive information. Automated reporting shares the data with HashiCorp using a secure unidirectional HTTPS API and makes an auditable record in the product logs each time it submits a report. + +## Enable automated reporting + +Before you enable automated reporting, make sure that outbound network traffic is configured correctly and upgrade your enterprise product to a version that supports it. If your installation is air-gapped or network settings are not in place, automated reporting will not work. + +To enable automated reporting, complete the following steps: + +1. [Allow outbound HTTPS traffic on port 443](#allow-outbound-https-traffic) +1. Upgrade to Consul Enterprise v1.16.0 or newer (#upgrade-to-consul-enterprise) +1. Check product logs(#check-product-logs) + +### Allow outbound HTTPS traffic on port 443 + +Make sure that your network allows HTTPS egress on port 443 from `https://reporting.hashicorp.services` by allow-listing the following IP addresses: + +- `100.20.70.12` +- `35.166.5.222` +- `23.95.85.111` +- `44.215.244.1` + +### Upgrade to Consul Enterprise v1.16.0 or newer + +Upgrade to a release that supports license utilization reporting. These [releases](https://releases.hashicorp.com/consul/) include: + +- Consul Enterprise 1.16.0 and newer. +- Consul Enterprise 1.15.4 and newer. +- Consul Enterprise 1.14.8 and newer. +- Consul Enterprise 1.13.9 and newer. + +### Check product logs + +Automatic license utilization reporting starts sending data within 24 hours. Check the product logs for records that the data sent successfully. + + + +``` +[DEBUG] beginning snapshot export +[DEBUG] creating payload +[DEBUG] marshalling payload to json +[DEBUG] generating authentication headers +[DEBUG] creating request +[DEBUG] sending request +[DEBUG] performing request: method=POST url=https://census.license.hashicorp.services +[DEBUG] recording audit record +[INFO] reporting: Report sent: auditRecord={"payload":{"payload_version":"1","license_id":"d2cdd857-4202-5a45-70a6-e4b531050c34","product":"consul","product_version":"1.16.0-dev+ent","export_timestamp":"2023-05-26T20:09:13.753921087Z","snapshots":[{"snapshot_version":1,"snapshot_id":"0001J724F90F4XWQDSAA76ZQWA","process_id":"01H1CTJPC1S8H7Q45MKTJ689ZW","timestamp":"2023-05-26T20:09:13.753513962Z","schema_version":"1.0.0","service":"consul","metrics":{"consul.billable.nodes":{"key":"consul.billable.nodes","kind":"counter","mode":"write","value":2},"consul.billable.service_instances":{"key":"consul.billable.service_instances","kind":"counter","mode":"write","value":2}}}],"metadata":{}}} +[DEBUG] completed recording audit record +[DEBUG] export finished successfully" +``` + + + +If your installation is air-gapped or your network does not allow the correct egress, the logs show an error. + + + +``` +[DEBUG] reporting: beginning snapshot export +[DEBUG] reporting: creating payload +[DEBUG] reporting: marshalling payload to json +[DEBUG] reporting: generating authentication headers +[DEBUG] reporting: creating request +[DEBUG] reporting: sending request +[DEBUG] reporting: performing request: method=POST url=https://census.license.hashicorp.services +[DEBUG] reporting: error status code received: statusCode=403 +``` + + + +In this case, reconfigure your network to allow egress and check back in 24 hours. + +## Opt out + +If your installation is air-gapped or you want to manually collect and report on the same license utilization metrics, you can opt out of automated reporting. + +Manually reporting these metrics can be time consuming. Opting out of automated reporting does not mean that you also opt out from sending license utilization metrics. Customers who opt out of automated reporting are still required to manually collect and send license utilization metrics to HashiCorp. + +If you are considering opting out because you are worried about the data, we strongly recommend that you review the [example payloads](#example-payloads) before opting out. If you have concerns with any of the automatically reported data, raise these concerns with your account manager. + +There are two methods for opting out of automated reporting: + +- HCL configuration (recommended) +- Environment variable (requires restart) + +We recommend opting out in your product's configuration file because it does not require a system restart. Add the following block to your `configuration.hcl` or `configuration.json` file. + +```hcl +reporting { + license { + enabled = false + } +} +``` + +When you opt out using an environment variable, once you restart your system it will provide a startup message confirming that you have disabled automated reporting. Set the following environment variable to disable automated reporting: + + + +```shell-session +$ export OPTOUT_LICENSE_REPORTING=true +``` + + + +After you set the environment variable, restart your system to complete the process for opting out. + +```shell-session +$ consul reload +``` + + +Check your product logs 24 hours after opting out to make sure that the system is not trying to send reports. Keep in mind that if your configuration file and environment variable differ, the environment variable setting takes precedence. + +## Example payloads + +HashiCorp collects the following utilization data as JSON payloads: +`exporter_version` - The version of the licensing exporter + + + +```json +{ + "payload": { + "payload_version": "1", + "license_id": "d2cdd857-4202-5a45-70a6-e4b531050c34", + "product": "consul", + "product_version": "1.16.0-dev+ent", + "export_timestamp": "2023-05-26T20:09:13.753921087Z", + "snapshots": [ + { + "snapshot_version": 1, + "snapshot_id": "0001J724F90F4XWQDSAA76ZQWA", + "process_id": "01H1CTJPC1S8H7Q45MKTJ689ZW", + "timestamp": "2023-05-26T20:09:13.753513962Z", + "schema_version": "1.0.0", + "service": "consul", + "metrics": { + "consul.billable.nodes": { + "key": "consul.billable.nodes", + "kind": "counter", + "mode": "write", + "value": 2 + }, + "consul.billable.service_instances": { + "key": "consul.billable.service_instances", + "kind": "counter", + "mode": "write", + "value": 2 + } + } + } + ], + "metadata": {} + } +} +``` + + \ No newline at end of file diff --git a/website/content/partials/envoy_ext_rule_matcher.mdx b/website/content/partials/envoy_ext_rule_matcher.mdx new file mode 100644 index 000000000000..1d97c34e4b8d --- /dev/null +++ b/website/content/partials/envoy_ext_rule_matcher.mdx @@ -0,0 +1,9 @@ + +| Rule | Description | Data type | Default | +| --- | --- | --- | --- | +| `Contains` | Specifies a string that the input string must contain. | String | N/A | +| `Exact` | Specifies a string that the input string must match exactly. | String | N/A | +| `IgnoreCase` | Directs Envoy to ignore capitalization. If set to `true`, the other matching rules in the configuration are not case sensitive. This rule does not affect `SafeRegex`. | Boolean | `false` | +| `Prefix` | Specifies a string that the input string must begin with. | String | N/A | +| `SafeRegex` | Specifies a regular expression for matching the input string programmatically. Envoy supports [Google's RE2 regex engine](https://github.com/google/re2/wiki/Syntax). | String | N/A | +| `Suffix` | Specifies a string that the input string must end with. | String | N/A | \ No newline at end of file diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 20335f715b0e..edd16a4eb86f 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -394,14 +394,14 @@ "path": "connect/configuration" }, { - "title": "Configuration Entries", + "title": "Configuration entries", "routes": [ { "title": "Overview", "path": "connect/config-entries" }, { - "title": "API Gateway", + "title": "API gateway", "href": "/consul/docs/connect/gateways/api-gateway/configuration/api-gateway", "badge": { "text": "BETA", @@ -410,7 +410,7 @@ } }, { - "title": "HTTP Route", + "title": "HTTP route", "href": "/consul/docs/connect/gateways/api-gateway/configuration/http-route", "badge": { "text": "BETA", @@ -419,7 +419,7 @@ } }, { - "title": "TCP Route", + "title": "TCP route", "href": "/consul/docs/connect/gateways/api-gateway/configuration/tcp-route", "badge": { "text": "BETA", @@ -428,7 +428,7 @@ } }, { - "title": "Inline Certificate", + "title": "Inline certificate", "href": "/consul/docs/connect/gateways/api-gateway/configuration/inline-certificate", "badge": { "text": "BETA", @@ -437,7 +437,7 @@ } }, { - "title": "Ingress Gateway", + "title": "Ingress gateway", "path": "connect/config-entries/ingress-gateway" }, { @@ -445,36 +445,40 @@ "path": "connect/config-entries/mesh" }, { - "title": "Exported Services", + "title": "Exported services", "path": "connect/config-entries/exported-services" }, { - "title": "Proxy Defaults", + "title": "Proxy defaults", "path": "connect/config-entries/proxy-defaults" }, { - "title": "Service Defaults", + "title": "Service defaults", "path": "connect/config-entries/service-defaults" }, { - "title": "Service Intentions", + "title": "Service intentions", "path": "connect/config-entries/service-intentions" }, { - "title": "Service Resolver", + "title": "Service resolver", "path": "connect/config-entries/service-resolver" }, { - "title": "Service Router", + "title": "Service router", "path": "connect/config-entries/service-router" }, { - "title": "Service Splitter", + "title": "Service splitter", "path": "connect/config-entries/service-splitter" }, { - "title": "Terminating Gateway", + "title": "Terminating gateway", "path": "connect/config-entries/terminating-gateway" + }, + { + "title": "Control plane request limit", + "path": "connect/config-entries/control-plane-request-limit" } ] }, @@ -499,6 +503,10 @@ { "title": "Usage", "routes": [ + { + "title": "Delegate authorization to external services", + "path": "connect/proxies/envoy-extensions/usage/ext-authz" + }, { "title": "Run Lua scripts in Envoy proxies", "path": "connect/proxies/envoy-extensions/usage/lua" @@ -506,8 +514,32 @@ { "title": "Invoke Lambda functions in Envoy proxies", "path": "connect/proxies/envoy-extensions/usage/lambda" + }, + { + "title": "Configure Envoy proxy properties", + "path": "connect/proxies/envoy-extensions/usage/property-override" + }, + { + "title": "Run WebAssembly plug-ins in Envoy proxies", + "path": "connect/proxies/envoy-extensions/usage/wasm" + } ] + }, + { + "title": "Configuration", + "routes": [ + { + "title": "External authorization", + "path": "connect/proxies/envoy-extensions/configuration/ext-authz" + }, + { + "title": "Property override", + "path": "connect/proxies/envoy-extensions/configuration/property-override" + }, + { + "title": "WebAssembly", + "path": "connect/proxies/envoy-extensions/configuration/wasm" } - ] + ] } ] }, @@ -960,19 +992,36 @@ ] }, { - "title": "Limit Traffic Rates", + "title": "Limit traffic rates", "routes": [ { "title": "Overview", "path": "agent/limits" }, { - "title": "Initialize Rate Limit Settings", - "path": "agent/limits/init-rate-limits" + "title": "Usage", + "routes": [ + { + "title": "Initialize rate limit settings", + "path": "agent/limits/usage/init-rate-limits" + }, + { + "title": "Monitor traffic rate limits", + "path": "agent/limits/usage/monitor-rate-limits" + }, + { + "title": "Set global traffic rate limits", + "path": "agent/limits/usage/set-global-traffic-rate-limits" + }, + { + "title": "Limit traffic rates from source IP addresses", + "path": "agent/limits/usage/limit-request-rates-from-ips" + } + ] }, { - "title": "Set Global Traffic Rate Limits", - "path": "agent/limits/set-global-traffic-rate-limits" + "title": "Configuration", + "href": "/docs/connect/config-entries/control-plane-request-limit" } ] }, @@ -1607,6 +1656,10 @@ "title": "Overview", "path": "enterprise/license/overview" }, + { + "title": "Automated entitlement utilization reporting", + "path": "enterprise/license/utilization-reporting" + }, { "title": "FAQ", "path": "enterprise/license/faq" From c04c122ef3a02bd23dd63851923cf1e257003466 Mon Sep 17 00:00:00 2001 From: Chris Thain <32781396+cthain@users.noreply.github.com> Date: Mon, 12 Jun 2023 10:47:31 -0700 Subject: [PATCH 018/359] Default `ProxyType` for builtin extensions (#17657) --- .../builtin/http/localratelimit/ratelimit.go | 5 +++- .../http/localratelimit/ratelimit_test.go | 24 +++++++++++++++++++ agent/envoyextensions/builtin/lua/lua.go | 5 +++- agent/envoyextensions/builtin/lua/lua_test.go | 9 +++++++ .../property-override/property_override.go | 3 +++ .../property_override_test.go | 2 +- 6 files changed, 45 insertions(+), 3 deletions(-) diff --git a/agent/envoyextensions/builtin/http/localratelimit/ratelimit.go b/agent/envoyextensions/builtin/http/localratelimit/ratelimit.go index 77619826044c..07e981ae2d4e 100644 --- a/agent/envoyextensions/builtin/http/localratelimit/ratelimit.go +++ b/agent/envoyextensions/builtin/http/localratelimit/ratelimit.go @@ -60,6 +60,9 @@ 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() } @@ -188,7 +191,7 @@ func (r ratelimit) PatchFilter(p extensioncommon.FilterPayload) (*envoy_listener } func validateProxyType(t string) error { - if t != "connect-proxy" { + if t != string(api.ServiceKindConnectProxy) { return fmt.Errorf("unexpected ProxyType %q", t) } diff --git a/agent/envoyextensions/builtin/http/localratelimit/ratelimit_test.go b/agent/envoyextensions/builtin/http/localratelimit/ratelimit_test.go index 4d8344ad1d03..2b208bf3e7e8 100644 --- a/agent/envoyextensions/builtin/http/localratelimit/ratelimit_test.go +++ b/agent/envoyextensions/builtin/http/localratelimit/ratelimit_test.go @@ -111,6 +111,30 @@ func TestConstructor(t *testing.T) { 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", diff --git a/agent/envoyextensions/builtin/lua/lua.go b/agent/envoyextensions/builtin/lua/lua.go index 8293228a7981..aefea37e6c49 100644 --- a/agent/envoyextensions/builtin/lua/lua.go +++ b/agent/envoyextensions/builtin/lua/lua.go @@ -45,6 +45,9 @@ func (l *lua) fromArguments(args map[string]interface{}) error { if err := mapstructure.Decode(args, l); err != nil { return fmt.Errorf("error decoding extension arguments: %v", err) } + if l.ProxyType == "" { + l.ProxyType = string(api.ServiceKindConnectProxy) + } return l.validate() } @@ -53,7 +56,7 @@ func (l *lua) validate() error { if l.Script == "" { resultErr = multierror.Append(resultErr, fmt.Errorf("missing Script value")) } - if l.ProxyType != "connect-proxy" { + if l.ProxyType != string(api.ServiceKindConnectProxy) { resultErr = multierror.Append(resultErr, fmt.Errorf("unexpected ProxyType %q", l.ProxyType)) } if l.Listener != "inbound" && l.Listener != "outbound" { diff --git a/agent/envoyextensions/builtin/lua/lua_test.go b/agent/envoyextensions/builtin/lua/lua_test.go index d80a3b333ab0..3ea2ba716c1d 100644 --- a/agent/envoyextensions/builtin/lua/lua_test.go +++ b/agent/envoyextensions/builtin/lua/lua_test.go @@ -54,6 +54,15 @@ func TestConstructor(t *testing.T) { arguments: makeArguments(map[string]interface{}{"Listener": "invalid"}), ok: false, }, + "default proxy type": { + arguments: makeArguments(map[string]interface{}{"ProxyType": ""}), + expected: lua{ + ProxyType: "connect-proxy", + Listener: "inbound", + Script: "lua-script", + }, + ok: true, + }, "valid everything": { arguments: makeArguments(map[string]interface{}{}), expected: lua{ diff --git a/agent/envoyextensions/builtin/property-override/property_override.go b/agent/envoyextensions/builtin/property-override/property_override.go index 8164a8092a7f..51d78368523f 100644 --- a/agent/envoyextensions/builtin/property-override/property_override.go +++ b/agent/envoyextensions/builtin/property-override/property_override.go @@ -261,6 +261,9 @@ func (p *propertyOverride) validate() error { } } + if p.ProxyType == "" { + p.ProxyType = api.ServiceKindConnectProxy + } if err := validProxyTypes.CheckRequired(string(p.ProxyType), "ProxyType"); err != nil { resultErr = multierror.Append(resultErr, err) } diff --git a/agent/envoyextensions/builtin/property-override/property_override_test.go b/agent/envoyextensions/builtin/property-override/property_override_test.go index ca549353faca..21889d840f4a 100644 --- a/agent/envoyextensions/builtin/property-override/property_override_test.go +++ b/agent/envoyextensions/builtin/property-override/property_override_test.go @@ -236,7 +236,7 @@ func TestConstructor(t *testing.T) { // enforces expected behavior until we do. Multi-member slices should be unaffected // by WeakDecode as it is a more-permissive version of the default behavior. "single value Patches decoded as map construction succeeds": { - arguments: makeArguments(map[string]any{"Patches": makePatch(map[string]any{})}), + arguments: makeArguments(map[string]any{"Patches": makePatch(map[string]any{}), "ProxyType": nil}), expected: validTestCase(OpAdd, extensioncommon.TrafficDirectionOutbound, ResourceTypeRoute).expected, ok: true, }, From 446a64032351a9865863cb8014ef0cdc0ea76df1 Mon Sep 17 00:00:00 2001 From: Michael Zalimeni Date: Mon, 12 Jun 2023 14:28:51 -0400 Subject: [PATCH 019/359] Post 1.16.0-rc1 updates (#17663) - Update changelog to include new entries from release - Update submodule versions to latest published --- CHANGELOG.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 10 ++++---- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee1dccacc139..ef4edc700404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,70 @@ +## 1.16.0-rc1 (June 12, 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: + +* 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)] +* 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 [[GH-5669](https://github.com/hashicorp/consul/issues/5669)] +* 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