You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
consul/agent/xds/config/config.go

261 lines
11 KiB

// Copyright (c) HashiCorp, Inc.
[COMPLIANCE] License changes (#18443) * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at <Blog URL>, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
1 year ago
// SPDX-License-Identifier: BUSL-1.1
package config
import (
"strings"
"time"
Support Incremental xDS mode (#9855) This adds support for the Incremental xDS protocol when using xDS v3. This is best reviewed commit-by-commit and will not be squashed when merged. Union of all commit messages follows to give an overarching summary: xds: exclusively support incremental xDS when using xDS v3 Attempts to use SoTW via v3 will fail, much like attempts to use incremental via v2 will fail. Work around a strange older envoy behavior involving empty CDS responses over incremental xDS. xds: various cleanups and refactors that don't strictly concern the addition of incremental xDS support Dissolve the connectionInfo struct in favor of per-connection ResourceGenerators instead. Do a better job of ensuring the xds code uses a well configured logger that accurately describes the connected client. xds: pull out checkStreamACLs method in advance of a later commit xds: rewrite SoTW xDS protocol tests to use protobufs rather than hand-rolled json strings In the test we very lightly reuse some of the more boring protobuf construction helper code that is also technically under test. The important thing of the protocol tests is testing the protocol. The actual inputs and outputs are largely already handled by the xds golden output tests now so these protocol tests don't have to do double-duty. This also updates the SoTW protocol test to exclusively use xDS v2 which is the only variant of SoTW that will be supported in Consul 1.10. xds: default xds.Server.AuthCheckFrequency at use-time instead of construction-time
4 years ago
envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
"google.golang.org/protobuf/types/known/durationpb"
Support Incremental xDS mode (#9855) This adds support for the Incremental xDS protocol when using xDS v3. This is best reviewed commit-by-commit and will not be squashed when merged. Union of all commit messages follows to give an overarching summary: xds: exclusively support incremental xDS when using xDS v3 Attempts to use SoTW via v3 will fail, much like attempts to use incremental via v2 will fail. Work around a strange older envoy behavior involving empty CDS responses over incremental xDS. xds: various cleanups and refactors that don't strictly concern the addition of incremental xDS support Dissolve the connectionInfo struct in favor of per-connection ResourceGenerators instead. Do a better job of ensuring the xds code uses a well configured logger that accurately describes the connected client. xds: pull out checkStreamACLs method in advance of a later commit xds: rewrite SoTW xDS protocol tests to use protobufs rather than hand-rolled json strings In the test we very lightly reuse some of the more boring protobuf construction helper code that is also technically under test. The important thing of the protocol tests is testing the protocol. The actual inputs and outputs are largely already handled by the xds golden output tests now so these protocol tests don't have to do double-duty. This also updates the SoTW protocol test to exclusively use xDS v2 which is the only variant of SoTW that will be supported in Consul 1.10. xds: default xds.Server.AuthCheckFrequency at use-time instead of construction-time
4 years ago
"github.com/mitchellh/mapstructure"
"google.golang.org/protobuf/types/known/wrapperspb"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib/decode"
)
func parseConfig[T any](m map[string]any, cfg *T) error {
d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
DecodeHook: mapstructure.ComposeDecodeHookFunc(
decode.HookWeakDecodeFromSlice,
decode.HookTranslateKeys,
),
Result: cfg,
WeaklyTypedInput: true,
})
if err != nil {
return err
}
return d.Decode(m)
}
// XDSCommonConfig contains the configuration from the opaque map that is common to both gateways and sidecar proxies.
type XDSCommonConfig struct {
// XDSFetchTimeoutMs specifies the amount of milliseconds to wait for dynamically configured Envoy data (EDS, RDS).
// Uses the Envoy default value if not specified or negative. A value of zero disables the timeout.
XDSFetchTimeoutMs *int `mapstructure:"xds_fetch_timeout_ms"`
}
// ParseXDSCommonConfig returns the XDSCommonConfig parsed from an opaque map. If an
// error occurs during parsing, it is returned along with the default config. This
// allows the caller to choose whether and how to report the error
func ParseXDSCommonConfig(m map[string]interface{}) (XDSCommonConfig, error) {
var cfg XDSCommonConfig
err := parseConfig(m, &cfg)
return cfg, err
}
func (c *XDSCommonConfig) GetXDSFetchTimeout() *durationpb.Duration {
if c == nil || c.XDSFetchTimeoutMs == nil {
return nil
}
if *c.XDSFetchTimeoutMs >= 0 {
return durationpb.New(time.Duration(*c.XDSFetchTimeoutMs) * time.Millisecond)
}
return nil
}
// ProxyConfig describes the keys we understand from Connect.Proxy.Config. Note
// that this only includes config keys that affects runtime config delivered by
// xDS. For Envoy config keys that affect bootstrap generation see
// command/connect/envoy/bootstrap_config.go.
type ProxyConfig struct {
// PublicListenerJSON is a complete override ("escape hatch") for the
// upstream's public listener. The Connect server TLS certificate and
// validation context will be injected overriding any TLS settings present. An
// AuthZ filter will also be prepended to each filterChain provided to enforce
// Connect's access control.
//
// Note: This escape hatch is compatible with the discovery chain.
PublicListenerJSON string `mapstructure:"envoy_public_listener_json"`
// ListenerTracingJSON is a complete override ("escape hatch") for the
// listeners tracing configuration.
//
// Note: This escape hatch is compatible with the discovery chain.
ListenerTracingJSON string `mapstructure:"envoy_listener_tracing_json"`
// LocalClusterJSON is a complete override ("escape hatch") for the
// local application cluster.
//
// Note: This escape hatch is compatible with the discovery chain.
LocalClusterJSON string `mapstructure:"envoy_local_cluster_json"`
// LocalConnectTimeoutMs is the number of milliseconds to timeout making a new
// connection to the local app instance. Defaults to 5000 (5 seconds) if not
// set.
LocalConnectTimeoutMs int `mapstructure:"local_connect_timeout_ms"`
// LocalRequestTimeoutMs is the number of milliseconds to timeout HTTP requests
// to the local app instance. If not set, no value is set, Envoy defaults are
// respected (15s)
LocalRequestTimeoutMs *int `mapstructure:"local_request_timeout_ms"`
// LocalIdleTimeoutMs is the number of milliseconds to timeout HTTP streams
// to the local app instance. If not set, no value is set, Envoy defaults are
// respected (300s)
LocalIdleTimeoutMs *int `mapstructure:"local_idle_timeout_ms"`
// Protocol describes the service's protocol. Valid values are "tcp",
// "http" and "grpc". Anything else is treated as tcp. This enables
// protocol aware features like per-request metrics and connection
// pooling, tracing, routing etc.
Protocol string `mapstructure:"protocol"`
// BindAddress overrides the address the proxy's listener binds to. This
// enables proxies in network namespaces to bind to a different address
// than the host address.
BindAddress string `mapstructure:"bind_address"`
// BindPort overrides the port the proxy's listener binds to. This
// enable proxies in network namespaces to bind to a different port
// than the host port being advertised.
BindPort int `mapstructure:"bind_port"`
// MaxInboundConnections is the maximum number of inbound connections to
// the proxy. If not set, the default is 0 (no limit).
MaxInboundConnections int `mapstructure:"max_inbound_connections"`
// BalanceInboundConnections indicates how the proxy should attempt to distribute
// connections across worker threads. Only used by envoy proxies.
BalanceInboundConnections string `json:",omitempty" alias:"balance_inbound_connections"`
}
// ParseProxyConfig returns the ProxyConfig parsed from the an opaque map. If an
// error occurs during parsing it is returned along with the default config this
// allows caller to choose whether and how to report the error.
func ParseProxyConfig(m map[string]interface{}) (ProxyConfig, error) {
var cfg ProxyConfig
if err := parseConfig(m, &cfg); err != nil {
return cfg, err
}
if cfg.Protocol == "" {
cfg.Protocol = "tcp"
} else {
cfg.Protocol = strings.ToLower(cfg.Protocol)
}
if cfg.LocalConnectTimeoutMs < 1 {
cfg.LocalConnectTimeoutMs = 5000
}
return cfg, nil
}
type GatewayConfig struct {
// BindTaggedAddresses when set will cause all of the services tagged
// addresses to have listeners bound to them in addition to the main service
// address listener. This is only suitable when the tagged addresses are IP
// addresses of network interfaces Envoy can see. i.e. When using DNS names
// for those addresses or where an external entity maps that IP to the Envoy
// (like AWS EC2 mapping a public IP to the private interface) then this
// cannot be used. See the BindAddresses config instead
BindTaggedAddresses bool `mapstructure:"envoy_gateway_bind_tagged_addresses" alias:"envoy_mesh_gateway_bind_tagged_addresses"`
// BindAddresses additional bind addresses to configure listeners for
BindAddresses map[string]structs.ServiceAddress `mapstructure:"envoy_gateway_bind_addresses" alias:"envoy_mesh_gateway_bind_addresses"`
// NoDefaultBind indicates that we should not bind to the default address of the
// gateway service
NoDefaultBind bool `mapstructure:"envoy_gateway_no_default_bind" alias:"envoy_mesh_gateway_no_default_bind"`
// DNSDiscoveryType indicates the DNS service discovery type.
// See: https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/service_discovery#arch-overview-service-discovery-types
DNSDiscoveryType string `mapstructure:"envoy_dns_discovery_type"`
// ConnectTimeoutMs is the number of milliseconds to timeout making a new
// connection to this upstream. Defaults to 5000 (5 seconds) if not set.
ConnectTimeoutMs int `mapstructure:"connect_timeout_ms"`
// TCP keepalive settings for remote gateway upstreams (mesh gateways and terminating gateway upstreams).
// See: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/address.proto#envoy-v3-api-msg-config-core-v3-tcpkeepalive
TcpKeepaliveEnable bool `mapstructure:"envoy_gateway_remote_tcp_enable_keepalive"`
TcpKeepaliveTime int `mapstructure:"envoy_gateway_remote_tcp_keepalive_time"`
TcpKeepaliveInterval int `mapstructure:"envoy_gateway_remote_tcp_keepalive_interval"`
TcpKeepaliveProbes int `mapstructure:"envoy_gateway_remote_tcp_keepalive_probes"`
}
// ParseGatewayConfig returns the GatewayConfig parsed from an opaque map. If an
// error occurs during parsing, it is returned along with the default config. This
// allows the caller to choose whether and how to report the error
func ParseGatewayConfig(m map[string]interface{}) (GatewayConfig, error) {
var cfg GatewayConfig
if err := parseConfig(m, &cfg); err != nil {
return cfg, err
}
if cfg.ConnectTimeoutMs < 1 {
cfg.ConnectTimeoutMs = 5000
}
cfg.DNSDiscoveryType = strings.ToLower(cfg.DNSDiscoveryType)
return cfg, nil
}
// Return an envoy.OutlierDetection populated by the values from structs.PassiveHealthCheck.
// If all values are zero a default empty OutlierDetection will be returned to
// enable outlier detection with default values.
// - If override is not nil, it will overwrite the values from p, e.g., ingress gateway defaults
// - allowZero is added to handle the legacy case where connect-proxy and mesh gateway can set 0
// for EnforcingConsecutive5xx. Due to the definition of proto of PassiveHealthCheck, ingress
// gateway's EnforcingConsecutive5xx must be > 0.
func ToOutlierDetection(p *structs.PassiveHealthCheck, override *structs.PassiveHealthCheck, allowZero bool) *envoy_cluster_v3.OutlierDetection {
od := &envoy_cluster_v3.OutlierDetection{}
if p != nil {
if p.Interval != 0 {
od.Interval = durationpb.New(p.Interval)
}
if p.MaxFailures != 0 {
od.Consecutive_5Xx = &wrapperspb.UInt32Value{Value: p.MaxFailures}
}
if p.EnforcingConsecutive5xx != nil {
// NOTE: EnforcingConsecutive5xx must be greater than 0 for ingress-gateway
if *p.EnforcingConsecutive5xx != 0 {
od.EnforcingConsecutive_5Xx = &wrapperspb.UInt32Value{Value: *p.EnforcingConsecutive5xx}
} else if allowZero {
od.EnforcingConsecutive_5Xx = &wrapperspb.UInt32Value{Value: *p.EnforcingConsecutive5xx}
}
}
if p.MaxEjectionPercent != nil {
od.MaxEjectionPercent = &wrapperspb.UInt32Value{Value: *p.MaxEjectionPercent}
}
if p.BaseEjectionTime != nil {
od.BaseEjectionTime = durationpb.New(*p.BaseEjectionTime)
}
}
if override == nil {
return od
}
// override the default outlier detection value
if override.Interval != 0 {
od.Interval = durationpb.New(override.Interval)
}
if override.MaxFailures != 0 {
od.Consecutive_5Xx = &wrapperspb.UInt32Value{Value: override.MaxFailures}
}
if override.EnforcingConsecutive5xx != nil {
// NOTE: EnforcingConsecutive5xx must be great than 0 for ingress-gateway
if *override.EnforcingConsecutive5xx != 0 {
od.EnforcingConsecutive_5Xx = &wrapperspb.UInt32Value{Value: *override.EnforcingConsecutive5xx}
}
// Because only ingress gateways have overrides and they cannot have a value of 0, there is no allowZero
// override case to handle
}
if override.MaxEjectionPercent != nil {
od.MaxEjectionPercent = &wrapperspb.UInt32Value{Value: *override.MaxEjectionPercent}
}
if override.BaseEjectionTime != nil {
od.BaseEjectionTime = durationpb.New(*override.BaseEjectionTime)
}
return od
}