mirror of https://github.com/status-im/consul.git
499 lines
18 KiB
Go
499 lines
18 KiB
Go
package config
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net"
|
|
"reflect"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
"github.com/hashicorp/consul/tlsutil"
|
|
"github.com/hashicorp/consul/types"
|
|
"golang.org/x/time/rate"
|
|
)
|
|
|
|
// RuntimeConfig specifies the configuration the consul agent actually
|
|
// uses. Is is derived from one or more Config structures which can come
|
|
// from files, flags and/or environment variables.
|
|
type RuntimeConfig struct {
|
|
// non-user configurable values
|
|
AEInterval time.Duration
|
|
ACLDisabledTTL time.Duration
|
|
CheckDeregisterIntervalMin time.Duration
|
|
CheckReapInterval time.Duration
|
|
SegmentLimit int
|
|
SegmentNameLimit int
|
|
SyncCoordinateRateTarget float64
|
|
SyncCoordinateIntervalMin time.Duration
|
|
Revision string
|
|
Version string
|
|
VersionPrerelease string
|
|
|
|
// consul config
|
|
ConsulCoordinateUpdateMaxBatches int
|
|
ConsulCoordinateUpdateBatchSize int
|
|
ConsulCoordinateUpdatePeriod time.Duration
|
|
ConsulRaftElectionTimeout time.Duration
|
|
ConsulRaftHeartbeatTimeout time.Duration
|
|
ConsulRaftLeaderLeaseTimeout time.Duration
|
|
ConsulSerfLANGossipInterval time.Duration
|
|
ConsulSerfLANProbeInterval time.Duration
|
|
ConsulSerfLANProbeTimeout time.Duration
|
|
ConsulSerfLANSuspicionMult int
|
|
ConsulSerfWANGossipInterval time.Duration
|
|
ConsulSerfWANProbeInterval time.Duration
|
|
ConsulSerfWANProbeTimeout time.Duration
|
|
ConsulSerfWANSuspicionMult int
|
|
ConsulServerHealthInterval time.Duration
|
|
|
|
ACLAgentMasterToken string
|
|
ACLAgentToken string
|
|
ACLDatacenter string
|
|
ACLDefaultPolicy string
|
|
ACLDownPolicy string
|
|
ACLEnforceVersion8 bool
|
|
ACLEnableKeyListPolicy bool
|
|
ACLMasterToken string
|
|
ACLReplicationToken string
|
|
ACLTTL time.Duration
|
|
ACLToken string
|
|
|
|
AutopilotCleanupDeadServers bool
|
|
AutopilotDisableUpgradeMigration bool
|
|
AutopilotLastContactThreshold time.Duration
|
|
AutopilotMaxTrailingLogs int
|
|
AutopilotRedundancyZoneTag string
|
|
AutopilotServerStabilizationTime time.Duration
|
|
AutopilotUpgradeVersionTag string
|
|
|
|
DNSAllowStale bool
|
|
DNSDisableCompression bool
|
|
DNSDomain string
|
|
DNSEnableTruncate bool
|
|
DNSMaxStale time.Duration
|
|
DNSNodeTTL time.Duration
|
|
DNSOnlyPassing bool
|
|
DNSRecursorTimeout time.Duration
|
|
DNSServiceTTL map[string]time.Duration
|
|
DNSUDPAnswerLimit int
|
|
DNSRecursors []string
|
|
|
|
HTTPBlockEndpoints []string
|
|
HTTPResponseHeaders map[string]string
|
|
|
|
// TelemetryCirconus*: see https://github.com/circonus-labs/circonus-gometrics
|
|
// for more details on the various configuration options.
|
|
// Valid configuration combinations:
|
|
// - CirconusAPIToken
|
|
// metric management enabled (search for existing check or create a new one)
|
|
// - CirconusSubmissionUrl
|
|
// metric management disabled (use check with specified submission_url,
|
|
// broker must be using a public SSL certificate)
|
|
// - CirconusAPIToken + CirconusCheckSubmissionURL
|
|
// metric management enabled (use check with specified submission_url)
|
|
// - CirconusAPIToken + CirconusCheckID
|
|
// metric management enabled (use check with specified id)
|
|
|
|
// TelemetryCirconusAPIApp is an app name associated with API token.
|
|
// Default: "consul"
|
|
//
|
|
// hcl: telemetry { circonus_api_app = string }
|
|
TelemetryCirconusAPIApp string
|
|
|
|
// TelemetryCirconusAPIToken is a valid API Token used to create/manage check. If provided,
|
|
// metric management is enabled.
|
|
// Default: none
|
|
//
|
|
// hcl: telemetry { circonous_api_token = string }
|
|
TelemetryCirconusAPIToken string
|
|
|
|
// TelemetryCirconusAPIURL is the base URL to use for contacting the Circonus API.
|
|
// Default: "https://api.circonus.com/v2"
|
|
//
|
|
// hcl: telemetry { circonus_api_url = string }
|
|
TelemetryCirconusAPIURL string
|
|
|
|
// TelemetryCirconusBrokerID is an explicit broker to use when creating a new check. The numeric portion
|
|
// of broker._cid. If metric management is enabled and neither a Submission URL nor Check ID
|
|
// is provided, an attempt will be made to search for an existing check using Instance ID and
|
|
// Search Tag. If one is not found, a new HTTPTRAP check will be created.
|
|
// Default: use Select Tag if provided, otherwise, a random Enterprise Broker associated
|
|
// with the specified API token or the default Circonus Broker.
|
|
// Default: none
|
|
//
|
|
// hcl: telemetry { circonus_broker_id = string }
|
|
TelemetryCirconusBrokerID string
|
|
|
|
// TelemetryCirconusBrokerSelectTag is a special tag which will be used to select a broker when
|
|
// a Broker ID is not provided. The best use of this is to as a hint for which broker
|
|
// should be used based on *where* this particular instance is running.
|
|
// (e.g. a specific geo location or datacenter, dc:sfo)
|
|
// Default: none
|
|
//
|
|
// hcl: telemetry { circonus_broker_select_tag = string }
|
|
TelemetryCirconusBrokerSelectTag string
|
|
|
|
// TelemetryCirconusCheckDisplayName is the name for the check which will be displayed in the Circonus UI.
|
|
// Default: value of CirconusCheckInstanceID
|
|
//
|
|
// hcl: telemetry { circonus_check_display_name = string }
|
|
TelemetryCirconusCheckDisplayName string
|
|
|
|
// TelemetryCirconusCheckForceMetricActivation will force enabling metrics, as they are encountered,
|
|
// if the metric already exists and is NOT active. If check management is enabled, the default
|
|
// behavior is to add new metrics as they are encoutered. If the metric already exists in the
|
|
// check, it will *NOT* be activated. This setting overrides that behavior.
|
|
// Default: "false"
|
|
//
|
|
// hcl: telemetry { circonus_check_metrics_activation = (true|false)
|
|
TelemetryCirconusCheckForceMetricActivation string
|
|
|
|
// TelemetryCirconusCheckID is the check id (not check bundle id) from a previously created
|
|
// HTTPTRAP check. The numeric portion of the check._cid field.
|
|
// Default: none
|
|
//
|
|
// hcl: telemetry { circonus_check_id = string }
|
|
TelemetryCirconusCheckID string
|
|
|
|
// TelemetryCirconusCheckInstanceID serves to uniquely identify the metrics coming from this "instance".
|
|
// It can be used to maintain metric continuity with transient or ephemeral instances as
|
|
// they move around within an infrastructure.
|
|
// Default: hostname:app
|
|
//
|
|
// hcl: telemetry { circonus_check_instance_id = string }
|
|
TelemetryCirconusCheckInstanceID string
|
|
|
|
// TelemetryCirconusCheckSearchTag is a special tag which, when coupled with the instance id, helps to
|
|
// narrow down the search results when neither a Submission URL or Check ID is provided.
|
|
// Default: service:app (e.g. service:consul)
|
|
//
|
|
// hcl: telemetry { circonus_check_search_tag = string }
|
|
TelemetryCirconusCheckSearchTag string
|
|
|
|
// TelemetryCirconusCheckSearchTag is a special tag which, when coupled with the instance id, helps to
|
|
// narrow down the search results when neither a Submission URL or Check ID is provided.
|
|
// Default: service:app (e.g. service:consul)
|
|
//
|
|
// hcl: telemetry { circonus_check_tags = string }
|
|
TelemetryCirconusCheckTags string
|
|
|
|
// TelemetryCirconusSubmissionInterval is the interval at which metrics are submitted to Circonus.
|
|
// Default: 10s
|
|
//
|
|
// hcl: telemetry { circonus_submission_interval = "duration" }
|
|
TelemetryCirconusSubmissionInterval string
|
|
|
|
// TelemetryCirconusCheckSubmissionURL is the check.config.submission_url field from a
|
|
// previously created HTTPTRAP check.
|
|
// Default: none
|
|
//
|
|
// hcl: telemetry { circonus_submission_url = string }
|
|
TelemetryCirconusSubmissionURL string
|
|
|
|
// DisableHostname will disable hostname prefixing for all metrics.
|
|
//
|
|
// hcl: telemetry { disable_hostname = (true|false)
|
|
TelemetryDisableHostname bool
|
|
|
|
// TelemetryDogStatsdAddr is the address of a dogstatsd instance. If provided,
|
|
// metrics will be sent to that instance
|
|
//
|
|
// hcl: telemetry { dogstatsd_addr = string }
|
|
TelemetryDogstatsdAddr string
|
|
|
|
// TelemetryDogStatsdTags are the global tags that should be sent with each packet to dogstatsd
|
|
// It is a list of strings, where each string looks like "my_tag_name:my_tag_value"
|
|
//
|
|
// hcl: telemetry { dogstatsd_tags = []string }
|
|
TelemetryDogstatsdTags []string
|
|
|
|
// TelemetryFilterDefault is the default for whether to allow a metric that's not
|
|
// covered by the filter.
|
|
//
|
|
// hcl: telemetry { filter_default = (true|false) }
|
|
TelemetryFilterDefault bool
|
|
|
|
// TelemetryAllowedPrefixes is a list of filter rules to apply for allowing metrics
|
|
// by prefix. Use the 'prefix_filter' option and prefix rules with '+' to be
|
|
// included.
|
|
//
|
|
// hcl: telemetry { prefix_filter = []string{"+<expr>", "+<expr>", ...} }
|
|
TelemetryAllowedPrefixes []string
|
|
|
|
// TelemetryBlockedPrefixes is a list of filter rules to apply for blocking metrics
|
|
// by prefix. Use the 'prefix_filter' option and prefix rules with '-' to be
|
|
// excluded.
|
|
//
|
|
// hcl: telemetry { prefix_filter = []string{"-<expr>", "-<expr>", ...} }
|
|
TelemetryBlockedPrefixes []string
|
|
|
|
// TelemetryMetricsPrefix is the prefix used to write stats values to.
|
|
// Default: "consul."
|
|
//
|
|
// hcl: telemetry { metrics_prefix = string }
|
|
TelemetryMetricsPrefix string
|
|
|
|
// TelemetryStatsdAddr is the address of a statsd instance. If provided,
|
|
// metrics will be sent to that instance.
|
|
//
|
|
// hcl: telemetry { statsd_addr = string }
|
|
TelemetryStatsdAddr string
|
|
|
|
// TelemetryStatsiteAddr is the address of a statsite instance. If provided,
|
|
// metrics will be streamed to that instance.
|
|
//
|
|
// hcl: telemetry { statsite_addr = string }
|
|
TelemetryStatsiteAddr string
|
|
|
|
// Datacenter and NodeName are exposed via /v1/agent/self from here and
|
|
// used in lots of places like CLI commands. Treat this as an interface
|
|
// that must be stable.
|
|
Datacenter string
|
|
NodeName string
|
|
|
|
AdvertiseAddrLAN *net.IPAddr
|
|
AdvertiseAddrWAN *net.IPAddr
|
|
BindAddr *net.IPAddr
|
|
Bootstrap bool
|
|
BootstrapExpect int
|
|
CAFile string
|
|
CAPath string
|
|
CertFile string
|
|
CheckUpdateInterval time.Duration
|
|
Checks []*structs.CheckDefinition
|
|
ClientAddrs []*net.IPAddr
|
|
DNSAddrs []net.Addr
|
|
DNSPort int
|
|
DataDir string
|
|
DevMode bool
|
|
DisableAnonymousSignature bool
|
|
DisableCoordinates bool
|
|
DisableHostNodeID bool
|
|
DisableKeyringFile bool
|
|
DisableRemoteExec bool
|
|
DisableUpdateCheck bool
|
|
DiscardCheckOutput bool
|
|
EnableACLReplication bool
|
|
EnableDebug bool
|
|
EnableScriptChecks bool
|
|
EnableSyslog bool
|
|
EnableUI bool
|
|
EncryptKey string
|
|
EncryptVerifyIncoming bool
|
|
EncryptVerifyOutgoing bool
|
|
HTTPAddrs []net.Addr
|
|
HTTPPort int
|
|
HTTPSAddrs []net.Addr
|
|
HTTPSPort int
|
|
KeyFile string
|
|
LeaveDrainTime time.Duration
|
|
LeaveOnTerm bool
|
|
LogLevel string
|
|
NodeID types.NodeID
|
|
NodeMeta map[string]string
|
|
NonVotingServer bool
|
|
PidFile string
|
|
RPCAdvertiseAddr *net.TCPAddr
|
|
RPCBindAddr *net.TCPAddr
|
|
RPCHoldTimeout time.Duration
|
|
RPCMaxBurst int
|
|
RPCProtocol int
|
|
RPCRateLimit rate.Limit
|
|
RaftProtocol int
|
|
ReconnectTimeoutLAN time.Duration
|
|
ReconnectTimeoutWAN time.Duration
|
|
RejoinAfterLeave bool
|
|
RetryJoinIntervalLAN time.Duration
|
|
RetryJoinIntervalWAN time.Duration
|
|
RetryJoinLAN []string
|
|
RetryJoinMaxAttemptsLAN int
|
|
RetryJoinMaxAttemptsWAN int
|
|
RetryJoinWAN []string
|
|
SegmentName string
|
|
Segments []structs.NetworkSegment
|
|
SerfAdvertiseAddrLAN *net.TCPAddr
|
|
SerfAdvertiseAddrWAN *net.TCPAddr
|
|
SerfBindAddrLAN *net.TCPAddr
|
|
SerfBindAddrWAN *net.TCPAddr
|
|
SerfPortLAN int
|
|
SerfPortWAN int
|
|
ServerMode bool
|
|
ServerName string
|
|
ServerPort int
|
|
Services []*structs.ServiceDefinition
|
|
SessionTTLMin time.Duration
|
|
SkipLeaveOnInt bool
|
|
StartJoinAddrsLAN []string
|
|
StartJoinAddrsWAN []string
|
|
SyslogFacility string
|
|
TLSCipherSuites []uint16
|
|
TLSMinVersion string
|
|
TLSPreferServerCipherSuites bool
|
|
TaggedAddresses map[string]string
|
|
TranslateWANAddrs bool
|
|
UIDir string
|
|
UnixSocketGroup string
|
|
UnixSocketMode string
|
|
UnixSocketUser string
|
|
VerifyIncoming bool
|
|
VerifyIncomingHTTPS bool
|
|
VerifyIncomingRPC bool
|
|
VerifyOutgoing bool
|
|
VerifyServerHostname bool
|
|
Watches []map[string]interface{}
|
|
}
|
|
|
|
// IncomingHTTPSConfig returns the TLS configuration for HTTPS
|
|
// connections to consul.
|
|
func (c *RuntimeConfig) IncomingHTTPSConfig() (*tls.Config, error) {
|
|
tc := &tlsutil.Config{
|
|
VerifyIncoming: c.VerifyIncoming || c.VerifyIncomingHTTPS,
|
|
VerifyOutgoing: c.VerifyOutgoing,
|
|
CAFile: c.CAFile,
|
|
CAPath: c.CAPath,
|
|
CertFile: c.CertFile,
|
|
KeyFile: c.KeyFile,
|
|
NodeName: c.NodeName,
|
|
ServerName: c.ServerName,
|
|
TLSMinVersion: c.TLSMinVersion,
|
|
CipherSuites: c.TLSCipherSuites,
|
|
PreferServerCipherSuites: c.TLSPreferServerCipherSuites,
|
|
}
|
|
return tc.IncomingTLSConfig()
|
|
}
|
|
|
|
// Sanitized returns a JSON/HCL compatible representation of the runtime
|
|
// configuration where all fields with potential secrets had their
|
|
// values replaced by 'hidden'. In addition, network addresses and
|
|
// time.Duration values are formatted to improve readability.
|
|
func (c *RuntimeConfig) Sanitized() map[string]interface{} {
|
|
return sanitize("rt", reflect.ValueOf(c)).Interface().(map[string]interface{})
|
|
}
|
|
|
|
// isSecret determines whether a field name represents a field which
|
|
// may contain a secret.
|
|
func isSecret(name string) bool {
|
|
name = strings.ToLower(name)
|
|
return strings.Contains(name, "key") || strings.Contains(name, "token") || strings.Contains(name, "secret")
|
|
}
|
|
|
|
// cleanRetryJoin sanitizes the go-discover config strings key=val key=val...
|
|
// by scrubbing the individual key=val combinations.
|
|
func cleanRetryJoin(a string) string {
|
|
var fields []string
|
|
for _, f := range strings.Fields(a) {
|
|
if isSecret(f) {
|
|
kv := strings.SplitN(f, "=", 2)
|
|
fields = append(fields, kv[0]+"=hidden")
|
|
} else {
|
|
fields = append(fields, f)
|
|
}
|
|
}
|
|
return strings.Join(fields, " ")
|
|
}
|
|
|
|
func sanitize(name string, v reflect.Value) reflect.Value {
|
|
typ := v.Type()
|
|
switch {
|
|
|
|
// check before isStruct and isPtr
|
|
case isNetAddr(typ):
|
|
if v.IsNil() {
|
|
return reflect.ValueOf("")
|
|
}
|
|
switch x := v.Interface().(type) {
|
|
case *net.TCPAddr:
|
|
return reflect.ValueOf("tcp://" + x.String())
|
|
case *net.UDPAddr:
|
|
return reflect.ValueOf("udp://" + x.String())
|
|
case *net.UnixAddr:
|
|
return reflect.ValueOf("unix://" + x.String())
|
|
case *net.IPAddr:
|
|
return reflect.ValueOf(x.IP.String())
|
|
default:
|
|
return v
|
|
}
|
|
|
|
// check before isNumber
|
|
case isDuration(typ):
|
|
x := v.Interface().(time.Duration)
|
|
return reflect.ValueOf(x.String())
|
|
|
|
case isString(typ):
|
|
if strings.HasPrefix(name, "RetryJoinLAN[") || strings.HasPrefix(name, "RetryJoinWAN[") {
|
|
x := v.Interface().(string)
|
|
return reflect.ValueOf(cleanRetryJoin(x))
|
|
}
|
|
if isSecret(name) {
|
|
return reflect.ValueOf("hidden")
|
|
}
|
|
return v
|
|
|
|
case isNumber(typ) || isBool(typ):
|
|
return v
|
|
|
|
case isPtr(typ):
|
|
if v.IsNil() {
|
|
return v
|
|
}
|
|
return sanitize(name, v.Elem())
|
|
|
|
case isStruct(typ):
|
|
m := map[string]interface{}{}
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
key := typ.Field(i).Name
|
|
m[key] = sanitize(key, v.Field(i)).Interface()
|
|
}
|
|
return reflect.ValueOf(m)
|
|
|
|
case isArray(typ) || isSlice(typ):
|
|
ma := make([]interface{}, 0)
|
|
for i := 0; i < v.Len(); i++ {
|
|
ma = append(ma, sanitize(fmt.Sprintf("%s[%d]", name, i), v.Index(i)).Interface())
|
|
}
|
|
return reflect.ValueOf(ma)
|
|
|
|
case isMap(typ):
|
|
m := map[string]interface{}{}
|
|
for _, k := range v.MapKeys() {
|
|
key := k.String()
|
|
m[key] = sanitize(key, v.MapIndex(k)).Interface()
|
|
}
|
|
return reflect.ValueOf(m)
|
|
|
|
default:
|
|
return v
|
|
}
|
|
}
|
|
|
|
func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) }
|
|
func isMap(t reflect.Type) bool { return t.Kind() == reflect.Map }
|
|
func isNetAddr(t reflect.Type) bool { return t.Implements(reflect.TypeOf((*net.Addr)(nil)).Elem()) }
|
|
func isPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr }
|
|
func isArray(t reflect.Type) bool { return t.Kind() == reflect.Array }
|
|
func isSlice(t reflect.Type) bool { return t.Kind() == reflect.Slice }
|
|
func isString(t reflect.Type) bool { return t.Kind() == reflect.String }
|
|
func isStruct(t reflect.Type) bool { return t.Kind() == reflect.Struct }
|
|
func isBool(t reflect.Type) bool { return t.Kind() == reflect.Bool }
|
|
func isNumber(t reflect.Type) bool { return isInt(t) || isUint(t) || isFloat(t) || isComplex(t) }
|
|
func isInt(t reflect.Type) bool {
|
|
return t.Kind() == reflect.Int ||
|
|
t.Kind() == reflect.Int8 ||
|
|
t.Kind() == reflect.Int16 ||
|
|
t.Kind() == reflect.Int32 ||
|
|
t.Kind() == reflect.Int64
|
|
}
|
|
func isUint(t reflect.Type) bool {
|
|
return t.Kind() == reflect.Uint ||
|
|
t.Kind() == reflect.Uint8 ||
|
|
t.Kind() == reflect.Uint16 ||
|
|
t.Kind() == reflect.Uint32 ||
|
|
t.Kind() == reflect.Uint64
|
|
}
|
|
func isFloat(t reflect.Type) bool { return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64 }
|
|
func isComplex(t reflect.Type) bool {
|
|
return t.Kind() == reflect.Complex64 || t.Kind() == reflect.Complex128
|
|
}
|