package config import ( "fmt" "net" "reflect" "strings" "time" "github.com/hashicorp/go-uuid" "golang.org/x/time/rate" "github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/consul" "github.com/hashicorp/consul/agent/dns" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/token" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/logging" "github.com/hashicorp/consul/tlsutil" "github.com/hashicorp/consul/types" ) type RuntimeSOAConfig struct { Refresh uint32 // 3600 by default Retry uint32 // 600 Expire uint32 // 86400 Minttl uint32 // 0, } // StaticRuntimeConfig specifies the subset of configuration the consul agent actually // uses and that are not reloadable by configuration auto reload. type StaticRuntimeConfig struct { // EncryptVerifyIncoming enforces incoming gossip encryption and can be // used to upshift to encrypted gossip on a running cluster. // // hcl: encrypt_verify_incoming = (true|false) EncryptVerifyIncoming bool // EncryptVerifyOutgoing enforces outgoing gossip encryption and can be // used to upshift to encrypted gossip on a running cluster. // // hcl: encrypt_verify_outgoing = (true|false) EncryptVerifyOutgoing bool } // 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 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 ConsulServerHealthInterval time.Duration // ACLsEnabled is used to determine whether ACLs should be enabled // // hcl: acl.enabled = boolean ACLsEnabled bool ACLTokens token.Config ACLResolverSettings consul.ACLResolverSettings // ACLEnableKeyListPolicy is used to opt-in to the "list" policy added to // KV ACLs in Consul 1.0. // // See https://www.consul.io/docs/guides/acl.html#list-policy-for-keys for // more details. // // hcl: acl.enable_key_list_policy = (true|false) ACLEnableKeyListPolicy bool // ACLInitialManagementToken is used to bootstrap the ACL system. It should be specified // on the servers in the PrimaryDatacenter. When the leader comes online, it ensures // that the initial management token is available. This provides the initial token. // // hcl: acl.tokens.initial_management = string ACLInitialManagementToken string // ACLtokenReplication is used to indicate that both tokens and policies // should be replicated instead of just policies // // hcl: acl.token_replication = boolean ACLTokenReplication bool // AutopilotCleanupDeadServers enables the automatic cleanup of dead servers when new ones // are added to the peer list. Defaults to true. // // hcl: autopilot { cleanup_dead_servers = (true|false) } AutopilotCleanupDeadServers bool // AutopilotDisableUpgradeMigration will disable Autopilot's upgrade migration // strategy of waiting until enough newer-versioned servers have been added to the // cluster before promoting them to voters. (Enterprise-only) // // hcl: autopilot { disable_upgrade_migration = (true|false) AutopilotDisableUpgradeMigration bool // AutopilotLastContactThreshold is the limit on the amount of time a server can go // without leader contact before being considered unhealthy. // // hcl: autopilot { last_contact_threshold = "duration" } AutopilotLastContactThreshold time.Duration // AutopilotMaxTrailingLogs is the amount of entries in the Raft Log that a server can // be behind before being considered unhealthy. The value must be positive. // // hcl: autopilot { max_trailing_logs = int } AutopilotMaxTrailingLogs int // AutopilotMinQuorum sets the minimum number of servers required in a cluster // before autopilot can prune dead servers. // //hcl: autopilot { min_quorum = int } AutopilotMinQuorum uint // AutopilotRedundancyZoneTag is the Meta tag to use for separating servers // into zones for redundancy. If left blank, this feature will be disabled. // (Enterprise-only) // // hcl: autopilot { redundancy_zone_tag = string } AutopilotRedundancyZoneTag string // AutopilotServerStabilizationTime is the minimum amount of time a server must be // in a stable, healthy state before it can be added to the cluster. Only // applicable with Raft protocol version 3 or higher. // // hcl: autopilot { server_stabilization_time = "duration" } AutopilotServerStabilizationTime time.Duration // AutopilotUpgradeVersionTag is the node tag to use for version info when // performing upgrade migrations. If left blank, the Consul version will be used. // // (Enterprise-only) // // hcl: autopilot { upgrade_version_tag = string } AutopilotUpgradeVersionTag string // DNSAllowStale is used to enable lookups with stale // data. This gives horizontal read scalability since // any Consul server can service the query instead of // only the leader. // // hcl: dns_config { allow_stale = (true|false) } DNSAllowStale bool // DNSARecordLimit is used to limit the maximum number of DNS Resource // Records returned in the ANSWER section of a DNS response for A or AAAA // records for both UDP and TCP queries. // // This is not normally useful and will be limited based on the querying // protocol, however systems that implemented §6 Rule 9 in RFC3484 // may want to set this to `1` in order to subvert §6 Rule 9 and // re-obtain the effect of randomized resource records (i.e. each // answer contains only one IP, but the IP changes every request). // RFC3484 sorts answers in a deterministic order, which defeats the // purpose of randomized DNS responses. This RFC has been obsoleted // by RFC6724 and restores the desired behavior of randomized // responses, however a large number of Linux hosts using glibc(3) // implemented §6 Rule 9 and may need this option (e.g. CentOS 5-6, // Debian Squeeze, etc). // // hcl: dns_config { a_record_limit = int } DNSARecordLimit int // DNSDisableCompression is used to control whether DNS responses are // compressed. In Consul 0.7 this was turned on by default and this // config was added as an opt-out. // // hcl: dns_config { disable_compression = (true|false) } DNSDisableCompression bool // DNSDomain is the DNS domain for the records. Should end with a dot. // Defaults to "consul." // // hcl: domain = string // flag: -domain string DNSDomain string // DNSAltDomain can be set to support resolution on an additional // consul domain. Should end with a dot. // If left blank, only the primary domain will be used. // // hcl: alt_domain = string // flag: -alt-domain string DNSAltDomain string // DNSEnableTruncate is used to enable setting the truncate // flag for UDP DNS queries. This allows unmodified // clients to re-query the consul server using TCP // when the total number of records exceeds the number // returned by default for UDP. // // hcl: dns_config { enable_truncate = (true|false) } DNSEnableTruncate bool // DNSMaxStale is used to bound how stale of a result is // accepted for a DNS lookup. This can be used with // AllowStale to limit how old of a value is served up. // If the stale result exceeds this, another non-stale // stale read is performed. // // hcl: dns_config { max_stale = "duration" } DNSMaxStale time.Duration // DNSNodeTTL provides the TTL value for a node query. // // hcl: dns_config { node_ttl = "duration" } DNSNodeTTL time.Duration // DNSOnlyPassing is used to determine whether to filter nodes // whose health checks are in any non-passing state. By // default, only nodes in a critical state are excluded. // // hcl: dns_config { only_passing = (true|false) } DNSOnlyPassing bool // DNSRecursorStrategy controls the order in which DNS recursors are queried. // 'sequential' queries recursors in the order they are listed under `recursors`. // 'random' causes random selection of recursors which has the effect of // spreading the query load among all listed servers, rather than having // client agents try the first server in the list every time. // // hcl: dns_config { recursor_strategy = "(random|sequential)" } DNSRecursorStrategy dns.RecursorStrategy // DNSRecursorTimeout specifies the timeout in seconds // for Consul's internal dns client used for recursion. // This value is used for the connection, read and write timeout. // // hcl: dns_config { recursor_timeout = "duration" } DNSRecursorTimeout time.Duration // DNSServiceTTL provides the TTL value for a service // query for given service. The "*" wildcard can be used // to set a default for all services. // // hcl: dns_config { service_ttl = map[string]"duration" } DNSServiceTTL map[string]time.Duration // DNSUDPAnswerLimit is used to limit the maximum number of DNS Resource // Records returned in the ANSWER section of a DNS response for UDP // responses without EDNS support (limited to 512 bytes). // This parameter is deprecated, if you want to limit the number of // records returned by A or AAAA questions, please use DNSARecordLimit // instead. // // hcl: dns_config { udp_answer_limit = int } DNSUDPAnswerLimit int // DNSNodeMetaTXT controls whether DNS queries will synthesize // TXT records for the node metadata and add them when not specifically // request (query type = TXT). If unset this will default to true DNSNodeMetaTXT bool // DNSRecursors can be set to allow the DNS servers to recursively // resolve non-consul domains. // // hcl: recursors = []string // flag: -recursor string [-recursor string] DNSRecursors []string // DNSUseCache whether or not to use cache for dns queries // // hcl: dns_config { use_cache = (true|false) } DNSUseCache bool // DNSUseCache whether or not to use cache for dns queries // // hcl: dns_config { cache_max_age = "duration" } DNSCacheMaxAge time.Duration // HTTPUseCache whether or not to use cache for http queries. Defaults // to true. // // hcl: http_config { use_cache = (true|false) } HTTPUseCache bool // HTTPBlockEndpoints is a list of endpoint prefixes to block in the // HTTP API. Any requests to these will get a 403 response. // // hcl: http_config { block_endpoints = []string } HTTPBlockEndpoints []string // AllowWriteHTTPFrom restricts the agent write endpoints to the given // networks. Any request to a protected endpoint that is not mactched // by one of these networks will get a 403 response. // An empty slice means no restriction. // // hcl: http_config { allow_write_http_from = []string } AllowWriteHTTPFrom []*net.IPNet // HTTPResponseHeaders are used to add HTTP header response fields to the HTTP API responses. // // hcl: http_config { response_headers = map[string]string } HTTPResponseHeaders map[string]string // Embed Telemetry Config Telemetry lib.TelemetryConfig // Datacenter is the datacenter this node is in. Defaults to "dc1". // // Datacenter is 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. // // hcl: datacenter = string // flag: -datacenter string Datacenter string // Defines the maximum stale value for discovery path. Defaults to "0s". // Discovery paths are /v1/heath/ paths // // If not set to 0, it will try to perform stale read and perform only a // consistent read whenever the value is too old. // hcl: discovery_max_stale = "duration" DiscoveryMaxStale time.Duration // Node name is the name we use to advertise. Defaults to hostname. // // NodeName is 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. // // hcl: node_name = string // flag: -node string NodeName string // AdvertiseAddrLAN is the address we use for advertising our Serf, and // Consul RPC IP. The address can be specified as an ip address or as a // go-sockaddr template which resolves to a single ip address. If not // specified, the bind address is used. // // hcl: advertise_addr = string AdvertiseAddrLAN *net.IPAddr // AdvertiseAddrWAN is the address we use for advertising our Serf, and // Consul RPC IP. The address can be specified as an ip address or as a // go-sockaddr template which resolves to a single ip address. If not // specified, the bind address is used. // // hcl: advertise_addr_wan = string AdvertiseAddrWAN *net.IPAddr // BindAddr is used to control the address we bind to. // If not specified, the first private IP we find is used. // This controls the address we use for cluster facing // services (Gossip, Server RPC) // // The value can be either an ip address or a go-sockaddr // template which resolves to a single ip address. // // hcl: bind_addr = string // flag: -bind string BindAddr *net.IPAddr // Bootstrap is used to bring up the first Consul server, and // permits that node to elect itself leader // // hcl: bootstrap = (true|false) // flag: -bootstrap Bootstrap bool // BootstrapExpect tries to automatically bootstrap the Consul cluster, by // having servers wait to bootstrap until enough servers join, and then // performing the bootstrap process automatically. They will disable their // automatic bootstrap process if they detect any servers that are part of // an existing cluster, so it's safe to leave this set to a non-zero value. // // hcl: bootstrap_expect = int // flag: -bootstrap-expect=int BootstrapExpect int // Cache represent cache configuration of agent Cache cache.Options // CheckUpdateInterval controls the interval on which the output of a health check // is updated if there is no change to the state. For example, a check in a steady // state may run every 5 second generating a unique output (timestamp, etc), forcing // constant writes. This allows Consul to defer the write for some period of time, // reducing the write pressure when the state is steady. // // See also: DiscardCheckOutput // // hcl: check_update_interval = "duration" CheckUpdateInterval time.Duration // Maximum size for the output of a healtcheck // hcl check_output_max_size int // flag: -check_output_max_size int CheckOutputMaxSize int // Checks contains the provided check definitions. // // hcl: checks = [ // { // id = string // name = string // notes = string // service_id = string // token = string // status = string // script = string // args = string // http = string // header = map[string][]string // method = string // tcp = string // h2ping = string // interval = string // docker_container_id = string // shell = string // tls_skip_verify = (true|false) // timeout = "duration" // ttl = "duration" // success_before_passing = int // failures_before_warning = int // failures_before_critical = int // deregister_critical_service_after = "duration" // }, // ... // ] Checks []*structs.CheckDefinition // ClientAddrs contains the list of ip addresses the DNS, HTTP and HTTPS // endpoints will bind to if the endpoints are enabled (ports > 0) and the // addresses are not overwritten. // // The ip addresses must be provided as a space separated list of ip // addresses and go-sockaddr templates. // // Client addresses cannot contain UNIX socket addresses since a socket // cannot be shared across multiple endpoints (no ports). To use UNIX // sockets configure it in 'addresses'. // // hcl: client_addr = string // flag: -client string ClientAddrs []*net.IPAddr // ConfigEntryBootstrap contains a list of ConfigEntries to ensure are created // If entries of the same Kind/Name exist already these will not update them. ConfigEntryBootstrap []structs.ConfigEntry // AutoEncryptTLS requires the client to acquire TLS certificates from // servers. AutoEncryptTLS bool // Additional DNS SAN entries that clients request during auto_encrypt // flow for their certificates. AutoEncryptDNSSAN []string // Additional IP SAN entries that clients request during auto_encrypt // flow for their certificates. AutoEncryptIPSAN []net.IP // AutoEncryptAllowTLS enables the server to respond to // AutoEncrypt.Sign requests. AutoEncryptAllowTLS bool // AutoConfig is a grouping of the configurations around the agent auto configuration // process including how servers can authorize requests. AutoConfig AutoConfig // ConnectEnabled opts the agent into connect. It should be set on all clients // and servers in a cluster for correct connect operation. ConnectEnabled bool // ConnectServerlessPluginEnabled opts the agent into the serverless plugin. // This plugin allows services to be configured as AWS Lambdas. After the // Lambda service is configured, Connect services can invoke the Lambda // service like any other upstream. ConnectServerlessPluginEnabled bool // ConnectSidecarMinPort is the inclusive start of the range of ports // allocated to the agent for asigning to sidecar services where no port is // specified. ConnectSidecarMinPort int // ConnectSidecarMaxPort is the inclusive end of the range of ports // allocated to the agent for asigning to sidecar services where no port is // specified ConnectSidecarMaxPort int // ExposeMinPort is the inclusive start of the range of ports // allocated to the agent for exposing checks through a proxy ExposeMinPort int // ExposeMinPort is the inclusive start of the range of ports // allocated to the agent for exposing checks through a proxy ExposeMaxPort int // ConnectCAProvider is the type of CA provider to use with Connect. ConnectCAProvider string // ConnectCAConfig is the config to use for the CA provider. ConnectCAConfig map[string]interface{} // ConnectMeshGatewayWANFederationEnabled determines if wan federation of // datacenters should exclusively traverse mesh gateways. ConnectMeshGatewayWANFederationEnabled bool // ConnectTestCALeafRootChangeSpread is used to control how long the CA leaf // cache with spread CSRs over when a root change occurs. For now we don't // expose this in public config intentionally but could later with a rename. // We only set this from during tests to effectively make CA rotation tests // deterministic again. ConnectTestCALeafRootChangeSpread time.Duration // DNSAddrs contains the list of TCP and UDP addresses the DNS server will // bind to. If the DNS endpoint is disabled (ports.dns <= 0) the list is // empty. // // The ip addresses are taken from 'addresses.dns' which should contain a // space separated list of ip addresses and/or go-sockaddr templates. // // If 'addresses.dns' was not provided the 'client_addr' addresses are // used. // // The DNS server cannot be bound to UNIX sockets. // // hcl: client_addr = string addresses { dns = string } ports { dns = int } DNSAddrs []net.Addr // DNSPort is the port the DNS server listens on. The default is 8600. // Setting this to a value <= 0 disables the endpoint. // // hcl: ports { dns = int } // flags: -dns-port int DNSPort int // DNSSOA is the settings applied for DNS SOA // hcl: soa {} DNSSOA RuntimeSOAConfig // DataDir is the path to the directory where the local state is stored. // // hcl: data_dir = string // flag: -data-dir string DataDir string // DefaultQueryTime is the amount of time a blocking query will wait before // Consul will force a response. This value can be overridden by the 'wait' // query parameter. // // hcl: default_query_time = "duration" // flag: -default-query-time string DefaultQueryTime time.Duration // DevMode enables a fast-path mode of operation to bring up an in-memory // server with minimal configuration. Useful for developing Consul. // // flag: -dev DevMode bool // DisableAnonymousSignature is used to turn off the anonymous signature // send with the update check. This is used to deduplicate messages. // // hcl: disable_anonymous_signature = (true|false) DisableAnonymousSignature bool // DisableCoordinates controls features related to network coordinates. // // hcl: disable_coordinates = (true|false) DisableCoordinates bool // DisableHostNodeID will prevent Consul from using information from the // host to generate a node ID, and will cause Consul to generate a // random ID instead. // // hcl: disable_host_node_id = (true|false) // flag: -disable-host-node-id DisableHostNodeID bool // DisableHTTPUnprintableCharFilter will bypass the filter preventing HTTP // URLs from containing unprintable chars. This filter was added in 1.0.3 as a // response to a vulnerability report. Disabling this is never recommended in // general however some users who have keys written in older versions of // Consul may use this to temporarily disable the filter such that they can // delete those keys again! We do not recommend leaving it disabled long term. // // hcl: disable_http_unprintable_char_filter DisableHTTPUnprintableCharFilter bool // DisableKeyringFile disables writing the keyring to a file. // // hcl: disable_keyring_file = (true|false) // flag: -disable-keyring-file DisableKeyringFile bool // DisableRemoteExec is used to turn off the remote execution // feature. This is for security to prevent unknown scripts from running. // // hcl: disable_remote_exec = (true|false) DisableRemoteExec bool // DisableUpdateCheck is used to turn off the automatic update and // security bulletin checking. // // hcl: disable_update_check = (true|false) DisableUpdateCheck bool // DiscardCheckOutput is used to turn off storing and comparing the // output of health checks. This reduces the write rate on the server // for checks with highly volatile output. (reloadable) // // See also: CheckUpdateInterval // // hcl: discard_check_output = (true|false) DiscardCheckOutput bool // EnableAgentTLSForChecks is used to apply the agent's TLS settings in // order to configure the HTTP client used for health checks. Enabling // this allows HTTP checks to present a client certificate and verify // the server using the same TLS configuration as the agent (CA, cert, // and key). EnableAgentTLSForChecks bool // EnableCentralServiceConfig controls whether the agent should incorporate // centralized config such as service-defaults into local service registrations. // // hcl: enable_central_service_config = (true|false) EnableCentralServiceConfig bool // EnableDebug is used to enable various debugging features. // // hcl: enable_debug = (true|false) EnableDebug bool // EnableLocalScriptChecks controls whether health checks declared from the local // config file which execute scripts are enabled. This includes regular script // checks and Docker checks. // // hcl: (enable_script_checks|enable_local_script_checks) = (true|false) // flag: -enable-script-checks, -enable-local-script-checks EnableLocalScriptChecks bool // EnableRemoeScriptChecks controls whether health checks declared from the http API // which execute scripts are enabled. This includes regular script checks and Docker // checks. // // hcl: enable_script_checks = (true|false) // flag: -enable-script-checks EnableRemoteScriptChecks bool // EncryptKey contains the encryption key to use for the Serf communication. // // hcl: encrypt = string // flag: -encrypt string EncryptKey string // GRPCPort is the port the gRPC server listens on. Currently this only // exposes the xDS and ext_authz APIs for Envoy and it is disabled by default. // // hcl: ports { grpc = int } // flags: -grpc-port int GRPCPort int // GRPCAddrs contains the list of TCP addresses and UNIX sockets the gRPC // server will bind to. If the gRPC endpoint is disabled (ports.grpc <= 0) // the list is empty. // // The addresses are taken from 'addresses.grpc' which should contain a // space separated list of ip addresses, UNIX socket paths and/or // go-sockaddr templates. UNIX socket paths must be written as // 'unix://', e.g. 'unix:///var/run/consul-grpc.sock'. // // If 'addresses.grpc' was not provided the 'client_addr' addresses are // used. // // hcl: client_addr = string addresses { grpc = string } ports { grpc = int } GRPCAddrs []net.Addr // HTTPAddrs contains the list of TCP addresses and UNIX sockets the HTTP // server will bind to. If the HTTP endpoint is disabled (ports.http <= 0) // the list is empty. // // The addresses are taken from 'addresses.http' which should contain a // space separated list of ip addresses, UNIX socket paths and/or // go-sockaddr templates. UNIX socket paths must be written as // 'unix://', e.g. 'unix:///var/run/consul-http.sock'. // // If 'addresses.http' was not provided the 'client_addr' addresses are // used. // // hcl: client_addr = string addresses { http = string } ports { http = int } HTTPAddrs []net.Addr // HTTPPort is the port the HTTP server listens on. The default is 8500. // Setting this to a value <= 0 disables the endpoint. // // hcl: ports { http = int } // flags: -http-port int HTTPPort int // HTTPSAddrs contains the list of TCP addresses and UNIX sockets the HTTPS // server will bind to. If the HTTPS endpoint is disabled (ports.https <= // 0) the list is empty. // // The addresses are taken from 'addresses.https' which should contain a // space separated list of ip addresses, UNIX socket paths and/or // go-sockaddr templates. UNIX socket paths must be written as // 'unix://', e.g. 'unix:///var/run/consul-https.sock'. // // If 'addresses.https' was not provided the 'client_addr' addresses are // used. // // hcl: client_addr = string addresses { https = string } ports { https = int } HTTPSAddrs []net.Addr // HTTPMaxConnsPerClient limits the number of concurrent TCP connections the // HTTP(S) server will accept from any single source IP address. // // hcl: limits{ http_max_conns_per_client = 200 } HTTPMaxConnsPerClient int // HTTPMaxHeaderBytes controls the maximum number of bytes the // server will read parsing the request header's keys and // values, including the request line. It does not limit the // size of the request body. // // If zero, or negative, http.DefaultMaxHeaderBytes is used. HTTPMaxHeaderBytes int // HTTPSHandshakeTimeout is the time allowed for HTTPS client to complete the // TLS handshake and send first bytes of the request. // // hcl: limits{ https_handshake_timeout = "5s" } HTTPSHandshakeTimeout time.Duration // HTTPSPort is the port the HTTP server listens on. The default is -1. // Setting this to a value <= 0 disables the endpoint. // // hcl: ports { https = int } // flags: -https-port int HTTPSPort int // KVMaxValueSize controls the max allowed value size. If not set defaults // to raft's suggested max value size. // // hcl: limits { kv_max_value_size = uint64 } KVMaxValueSize uint64 // LeaveDrainTime is used to wait after a server has left the LAN Serf // pool for RPCs to drain and new requests to be sent to other servers. // // hcl: performance { leave_drain_time = "duration" } LeaveDrainTime time.Duration // LeaveOnTerm controls if Serf does a graceful leave when receiving // the TERM signal. Defaults true on clients, false on servers. (reloadable) // // hcl: leave_on_terminate = (true|false) LeaveOnTerm bool // Logging configuration used to initialize agent logging. Logging logging.Config // MaxQueryTime is the maximum amount of time a blocking query can wait // before Consul will force a response. Consul applies jitter to the wait // time. The jittered time will be capped to MaxQueryTime. // // hcl: max_query_time = "duration" // flags: -max-query-time string MaxQueryTime time.Duration // Node ID is a unique ID for this node across space and time. Defaults // to a randomly-generated ID that persists in the data-dir. // // todo(fs): don't we have a requirement for this to be a UUID in a specific format? // // hcl: node_id = string // flag: -node-id string NodeID types.NodeID // NodeMeta contains metadata key/value pairs. These are excluded from JSON output // because they can be reloaded and might be stale when shown from the // config instead of the local state. // todo(fs): should the sanitizer omit them from output as well since they could be stale? // // hcl: node_meta = map[string]string // flag: -node-meta "key:value" -node-meta "key:value" ... NodeMeta map[string]string // ReadReplica is whether this server will act as a non-voting member // of the cluster to help provide read scalability. (Enterprise-only) // // hcl: non_voting_server = (true|false) // flag: -non-voting-server ReadReplica bool // PidFile is the file to store our PID in. // // hcl: pid_file = string PidFile string // PrimaryDatacenter is the central datacenter that holds authoritative // ACL records, replicates intentions and holds the root CA for Connect. // This must be the same for the entire cluster. Off by default. // // hcl: primary_datacenter = string PrimaryDatacenter string // PrimaryGateways is a list of addresses and/or go-discover expressions to // discovery the mesh gateways in the primary datacenter. See // https://www.consul.io/docs/agent/options.html#cloud-auto-joining for // details. // // hcl: primary_gateways = []string // flag: -primary-gateway string -primary-gateway string PrimaryGateways []string // PrimaryGatewaysInterval specifies the amount of time to wait in between discovery // attempts on agent start. The minimum allowed value is 1 second and // the default is 30s. // // hcl: primary_gateways_interval = "duration" PrimaryGatewaysInterval time.Duration // RPCAdvertiseAddr is the TCP address Consul advertises for its RPC endpoint. // By default this is the bind address on the default RPC Server port. If the // advertise address is specified then it is used. // // hcl: bind_addr = string advertise_addr = string ports { server = int } RPCAdvertiseAddr *net.TCPAddr // RPCBindAddr is the TCP address Consul will bind to for its RPC endpoint. // By default this is the bind address on the default RPC Server port. // // hcl: bind_addr = string ports { server = int } RPCBindAddr *net.TCPAddr // RPCHandshakeTimeout is the timeout for reading the initial magic byte on a // new RPC connection. If this is set high it may allow unauthenticated users // to hold connections open arbitrarily long, even when mutual TLS is being // enforced. It may be set to 0 explicitly to disable the timeout but this // should never be used in production. Default is 5 seconds. // // hcl: limits { rpc_handshake_timeout = "duration" } RPCHandshakeTimeout time.Duration // RPCHoldTimeout is how long an RPC can be "held" before it is errored. // This is used to paper over a loss of leadership by instead holding RPCs, // so that the caller experiences a slow response rather than an error. // This period is meant to be long enough for a leader election to take // place, and a small jitter is applied to avoid a thundering herd. // // hcl: performance { rpc_hold_timeout = "duration" } RPCHoldTimeout time.Duration // RPCRateLimit and RPCMaxBurst control how frequently RPC calls are allowed // to happen. In any large enough time interval, rate limiter limits the // rate to RPCRateLimit tokens per second, with a maximum burst size of // RPCMaxBurst events. As a special case, if RPCRateLimit == Inf (the infinite // rate), RPCMaxBurst is ignored. // // See https://en.wikipedia.org/wiki/Token_bucket for more about token // buckets. // // hcl: limit { rpc_rate = (float64|MaxFloat64) rpc_max_burst = int } RPCRateLimit rate.Limit RPCMaxBurst int // RPCMaxConnsPerClient limits the number of concurrent TCP connections the // RPC server will accept from any single source IP address. // // hcl: limits{ rpc_max_conns_per_client = 100 } RPCMaxConnsPerClient int // RPCProtocol is the Consul protocol version to use. // // hcl: protocol = int RPCProtocol int RPCConfig consul.RPCConfig // UseStreamingBackend enables streaming as a replacement for agent/cache // in the client agent for endpoints which support streaming. UseStreamingBackend bool // RaftProtocol sets the Raft protocol version to use on this server. // Defaults to 3. // // hcl: raft_protocol = int RaftProtocol int // RaftSnapshotThreshold sets the minimum threshold of raft commits after which // a snapshot is created. Defaults to 8192 // // hcl: raft_snapshot_threshold = int RaftSnapshotThreshold int // RaftSnapshotInterval sets the interval to use when checking whether to create // a new snapshot. Defaults to 5 seconds. // hcl: raft_snapshot_threshold = int RaftSnapshotInterval time.Duration // RaftTrailingLogs sets the number of log entries that will be left in the // log store after a snapshot. This must be large enough that a follower can // transfer and restore an entire snapshot of the state before this many new // entries have been appended. In vast majority of cases the default is plenty // but if there is a sustained high write throughput coupled with a huge // multi-gigabyte snapshot setting this higher may be necessary to allow // followers time to reload from snapshot without becoming unhealthy. If it's // too low then followers are unable to ever recover from a restart and will // enter a loop of constantly downloading full snapshots and never catching // up. If you need to change this you should reconsider your usage of Consul // as it is not designed to store multiple-gigabyte data sets with high write // throughput. Defaults to 10000. // // hcl: raft_trailing_logs = int RaftTrailingLogs int RaftBoltDBConfig consul.RaftBoltDBConfig // ReconnectTimeoutLAN specifies the amount of time to wait to reconnect with // another agent before deciding it's permanently gone. This can be used to // control the time it takes to reap failed nodes from the cluster. // // hcl: reconnect_timeout = "duration" ReconnectTimeoutLAN time.Duration // ReconnectTimeoutWAN specifies the amount of time to wait to reconnect with // another agent before deciding it's permanently gone. This can be used to // control the time it takes to reap failed nodes from the cluster. // // hcl: reconnect_timeout = "duration" ReconnectTimeoutWAN time.Duration // AdvertiseReconnectTimeout specifies the amount of time other agents should // wait for us to reconnect before deciding we are permanently gone. This // should only be set for client agents that are run in a stateless or // ephemeral manner in order to realize their deletion sooner than we // would otherwise. AdvertiseReconnectTimeout time.Duration // RejoinAfterLeave controls our interaction with the cluster after leave. // When set to false (default), a leave causes Consul to not rejoin // the cluster until an explicit join is received. If this is set to // true, we ignore the leave, and rejoin the cluster on start. // // hcl: rejoin_after_leave = (true|false) // flag: -rejoin RejoinAfterLeave bool // RetryJoinIntervalLAN specifies the amount of time to wait in between join // attempts on agent start. The minimum allowed value is 1 second and // the default is 30s. // // hcl: retry_interval = "duration" RetryJoinIntervalLAN time.Duration // RetryJoinIntervalWAN specifies the amount of time to wait in between join // attempts on agent start. The minimum allowed value is 1 second and // the default is 30s. // // hcl: retry_interval_wan = "duration" RetryJoinIntervalWAN time.Duration // RetryJoinLAN is a list of addresses and/or go-discover expressions to // join with retry enabled. See // https://www.consul.io/docs/agent/options.html#cloud-auto-joining for // details. // // hcl: retry_join = []string // flag: -retry-join string -retry-join string RetryJoinLAN []string // RetryJoinMaxAttemptsLAN specifies the maximum number of times to retry // joining a host on startup. This is useful for cases where we know the // node will be online eventually. // // hcl: retry_max = int // flag: -retry-max int RetryJoinMaxAttemptsLAN int // RetryJoinMaxAttemptsWAN specifies the maximum number of times to retry // joining a host on startup. This is useful for cases where we know the // node will be online eventually. // // hcl: retry_max_wan = int // flag: -retry-max-wan int RetryJoinMaxAttemptsWAN int // RetryJoinWAN is a list of addresses and/or go-discover expressions to // join -wan with retry enabled. See // https://www.consul.io/docs/agent/options.html#cloud-auto-joining for // details. // // hcl: retry_join_wan = []string // flag: -retry-join-wan string -retry-join-wan string RetryJoinWAN []string // SegmentName is the network segment for this client to join. // (Enterprise-only) // // hcl: segment = string SegmentName string // Segments is the list of network segments for this server to // initialize. // // hcl: segment = [ // { // # name is the name of the segment // name = string // // # bind is the bind ip address for this segment. // bind = string // // # port is the bind port for this segment. // port = int // // # advertise is the advertise ip address for this segment. // # Defaults to the bind address if not set. // advertise = string // // # rpc_listener controls whether or not to bind a separate // # RPC listener to the bind address. // rpc_listener = (true|false) // }, // ... // ] Segments []structs.NetworkSegment // SerfAdvertiseAddrLAN is the TCP address which is used for advertising // the LAN Gossip pool for both client and server. The address is the // combination of AdvertiseAddrLAN and the SerfPortLAN. If the advertise // address is not given the bind address is used. // // hcl: bind_addr = string advertise_addr = string ports { serf_lan = int } SerfAdvertiseAddrLAN *net.TCPAddr // SerfAdvertiseAddrWAN is the TCP address which is used for advertising // the WAN Gossip pool on the server only. The address is the combination // of AdvertiseAddrWAN and the SerfPortWAN. If the advertise address is not // given the bind address is used. // // hcl: bind_addr = string advertise_addr_wan = string ports { serf_wan = int } SerfAdvertiseAddrWAN *net.TCPAddr // SerfAllowedCIDRsLAN if set to a non-empty value, will restrict which networks // are allowed to connect to Serf on the LAN. // hcl: serf_lan_allowed_cidrs = []string // flag: serf-lan-allowed-cidrs string (can be specified multiple times) SerfAllowedCIDRsLAN []net.IPNet // SerfAllowedCIDRsWAN if set to a non-empty value, will restrict which networks // are allowed to connect to Serf on the WAN. // hcl: serf_wan_allowed_cidrs = []string // flag: serf-wan-allowed-cidrs string (can be specified multiple times) SerfAllowedCIDRsWAN []net.IPNet // SerfBindAddrLAN is the address to bind the Serf LAN TCP and UDP // listeners to. The ip address is either the default bind address or the // 'serf_lan' address which can be either an ip address or a go-sockaddr // template which resolves to a single ip address. // // hcl: bind_addr = string serf_lan = string ports { serf_lan = int } // flag: -serf-lan string SerfBindAddrLAN *net.TCPAddr // SerfBindAddrWAN is the address to bind the Serf WAN TCP and UDP // listeners to. The ip address is either the default bind address or the // 'serf_wan' address which can be either an ip address or a go-sockaddr // template which resolves to a single ip address. // // hcl: bind_addr = string serf_wan = string ports { serf_wan = int } // flag: -serf-wan string SerfBindAddrWAN *net.TCPAddr // SerfPortLAN is the port used for the LAN Gossip pool for both client and server. // The default is 8301. // // hcl: ports { serf_lan = int } SerfPortLAN int // SerfPortWAN is the port used for the WAN Gossip pool for the server only. // The default is 8302. // // hcl: ports { serf_wan = int } SerfPortWAN int // GossipLANGossipInterval is the interval between sending messages that need // to be gossiped that haven't been able to piggyback on probing messages. // If this is set to zero, non-piggyback gossip is disabled. By lowering // this value (more frequent) gossip messages are propagated across // the cluster more quickly at the expense of increased bandwidth. This // configuration only applies to LAN gossip communications // // The default is: 200ms // // hcl: gossip_lan { gossip_interval = duration} GossipLANGossipInterval time.Duration // GossipLANGossipNodes is the number of random nodes to send gossip messages to // per GossipInterval. Increasing this number causes the gossip messages to // propagate across the cluster more quickly at the expense of increased // bandwidth. This configuration only applies to LAN gossip communications // // The default is: 3 // // hcl: gossip_lan { gossip_nodes = int } GossipLANGossipNodes int // GossipLANProbeInterval is the interval between random node probes. Setting // this lower (more frequent) will cause the memberlist cluster to detect // failed nodes more quickly at the expense of increased bandwidth usage. // This configuration only applies to LAN gossip communications // // The default is: 1s // // hcl: gossip_lan { probe_interval = duration } GossipLANProbeInterval time.Duration // GossipLANProbeTimeout is the timeout to wait for an ack from a probed node // before assuming it is unhealthy. This should be set to 99-percentile // of RTT (round-trip time) on your network. This configuration // only applies to the LAN gossip communications // // The default is: 500ms // // hcl: gossip_lan { probe_timeout = duration } GossipLANProbeTimeout time.Duration // GossipLANSuspicionMult is the multiplier for determining the time an // inaccessible node is considered suspect before declaring it dead. This // configuration only applies to LAN gossip communications // // The actual timeout is calculated using the formula: // // SuspicionTimeout = SuspicionMult * log(N+1) * ProbeInterval // // This allows the timeout to scale properly with expected propagation // delay with a larger cluster size. The higher the multiplier, the longer // an inaccessible node is considered part of the cluster before declaring // it dead, giving that suspect node more time to refute if it is indeed // still alive. // // The default is: 4 // // hcl: gossip_lan { suspicion_mult = int } GossipLANSuspicionMult int // GossipLANRetransmitMult is the multiplier for the number of retransmissions // that are attempted for messages broadcasted over gossip. This // configuration only applies to LAN gossip communications. The actual // count of retransmissions is calculated using the formula: // // Retransmits = RetransmitMult * log(N+1) // // This allows the retransmits to scale properly with cluster size. The // higher the multiplier, the more likely a failed broadcast is to converge // at the expense of increased bandwidth. // // The default is: 4 // // hcl: gossip_lan { retransmit_mult = int } GossipLANRetransmitMult int // GossipWANGossipInterval is the interval between sending messages that need // to be gossiped that haven't been able to piggyback on probing messages. // If this is set to zero, non-piggyback gossip is disabled. By lowering // this value (more frequent) gossip messages are propagated across // the cluster more quickly at the expense of increased bandwidth. This // configuration only applies to WAN gossip communications // // The default is: 500ms // // hcl: gossip_wan { gossip_interval = duration} GossipWANGossipInterval time.Duration // GossipWANGossipNodes is the number of random nodes to send gossip messages to // per GossipInterval. Increasing this number causes the gossip messages to // propagate across the cluster more quickly at the expense of increased // bandwidth. This configuration only applies to WAN gossip communications // // The default is: 4 // // hcl: gossip_wan { gossip_nodes = int } GossipWANGossipNodes int // GossipWANProbeInterval is the interval between random node probes. Setting // this lower (more frequent) will cause the memberlist cluster to detect // failed nodes more quickly at the expense of increased bandwidth usage. // This configuration only applies to WAN gossip communications // // The default is: 5s // // hcl: gossip_wan { probe_interval = duration } GossipWANProbeInterval time.Duration // GossipWANProbeTimeout is the timeout to wait for an ack from a probed node // before assuming it is unhealthy. This should be set to 99-percentile // of RTT (round-trip time) on your network. This configuration // only applies to the WAN gossip communications // // The default is: 3s // // hcl: gossip_wan { probe_timeout = duration } GossipWANProbeTimeout time.Duration // GossipWANSuspicionMult is the multiplier for determining the time an // inaccessible node is considered suspect before declaring it dead. This // configuration only applies to WAN gossip communications // // The actual timeout is calculated using the formula: // // SuspicionTimeout = SuspicionMult * log(N+1) * ProbeInterval // // This allows the timeout to scale properly with expected propagation // delay with a larger cluster size. The higher the multiplier, the longer // an inaccessible node is considered part of the cluster before declaring // it dead, giving that suspect node more time to refute if it is indeed // still alive. // // The default is: 6 // // hcl: gossip_wan { suspicion_mult = int } GossipWANSuspicionMult int // GossipWANRetransmitMult is the multiplier for the number of retransmissions // that are attempted for messages broadcasted over gossip. This // configuration only applies to WAN gossip communications. The actual // count of retransmissions is calculated using the formula: // // Retransmits = RetransmitMult * log(N+1) // // This allows the retransmits to scale properly with cluster size. The // higher the multiplier, the more likely a failed broadcast is to converge // at the expense of increased bandwidth. // // The default is: 4 // // hcl: gossip_wan { retransmit_mult = int } GossipWANRetransmitMult int // ServerMode controls if this agent acts like a Consul server, // or merely as a client. Servers have more state, take part // in leader election, etc. // // hcl: server = (true|false) // flag: -server ServerMode bool // ServerName is used with the TLS certificates to ensure the name we // provide matches the certificate. // // hcl: server_name = string ServerName string // ServerPort is the port the RPC server will bind to. // The default is 8300. // // hcl: ports { server = int } ServerPort int // Services contains the provided service definitions: // // hcl: services = [ // { // id = string // name = string // tags = []string // address = string // check = { check definition } // checks = [ { check definition}, ... ] // token = string // enable_tag_override = (true|false) // }, // ... // ] Services []*structs.ServiceDefinition // Minimum Session TTL. // // hcl: session_ttl_min = "duration" SessionTTLMin time.Duration // SkipLeaveOnInt controls if Serf skips a graceful leave when // receiving the INT signal. Defaults false on clients, true on // servers. (reloadable) // // hcl: skip_leave_on_interrupt = (true|false) SkipLeaveOnInt bool // AutoReloadConfig indicate if the config will be //auto reloaded bases on config file modification // hcl: auto_reload_config = (true|false) AutoReloadConfig bool // StartJoinAddrsLAN is a list of addresses to attempt to join -lan when the // agent starts. If Serf is unable to communicate with any of these // addresses, then the agent will error and exit. // // hcl: start_join = []string // flag: -join string -join string StartJoinAddrsLAN []string // StartJoinWAN is a list of addresses to attempt to join -wan when the // agent starts. If Serf is unable to communicate with any of these // addresses, then the agent will error and exit. // // hcl: start_join_wan = []string // flag: -join-wan string -join-wan string StartJoinAddrsWAN []string // TLS configures certificates, CA, cipher suites, and other TLS settings // on Consul's listeners (i.e. Internal multiplexed RPC, HTTPS and gRPC). // // hcl: tls { ... } TLS tlsutil.Config // TaggedAddresses are used to publish a set of addresses for // for a node, which can be used by the remote agent. We currently // populate only the "wan" tag based on the SerfWan advertise address, // but this structure is here for possible future features with other // user-defined tags. The "wan" tag will be used by remote agents if // they are configured with TranslateWANAddrs set to true. // // hcl: tagged_addresses = map[string]string TaggedAddresses map[string]string // TranslateWANAddrs controls whether or not Consul should prefer // the "wan" tagged address when doing lookups in remote datacenters. // See TaggedAddresses below for more details. // // hcl: translate_wan_addrs = (true|false) TranslateWANAddrs bool // TxnMaxReqLen configures the upper limit for the size (in bytes) of the // incoming request bodies for transactions to the /txn endpoint. // // hcl: limits { txn_max_req_len = uint64 } TxnMaxReqLen uint64 // UIConfig holds various runtime options that control both the agent's // behavior while serving the UI (e.g. whether it's enabled, what path it's // mounted on) as well as options that enable or disable features within the // UI. // // NOTE: Never read from this field directly once the agent has started up // since the UI config is reloadable. The on in the agent's config field may // be out of date. Use the agent.getUIConfig() method to get the latest config // in a thread-safe way. // // hcl: ui_config { ... } UIConfig UIConfig // UnixSocketGroup contains the group of the file permissions when // Consul binds to UNIX sockets. // // hcl: unix_sockets { group = string } UnixSocketGroup string // UnixSocketMode contains the mode of the file permissions when // Consul binds to UNIX sockets. // // hcl: unix_sockets { mode = string } UnixSocketMode string // UnixSocketUser contains the user of the file permissions when // Consul binds to UNIX sockets. // // hcl: unix_sockets { user = string } UnixSocketUser string StaticRuntimeConfig StaticRuntimeConfig // Watches are used to monitor various endpoints and to invoke a // handler to act appropriately. These are managed entirely in the // agent layer using the standard APIs. // // See https://www.consul.io/docs/agent/watches.html for details. // // hcl: watches = [ // { type=string ... }, // { type=string ... }, // ... // ] // Watches []map[string]interface{} EnterpriseRuntimeConfig } type AutoConfig struct { Enabled bool IntroToken string IntroTokenFile string ServerAddresses []string DNSSANs []string IPSANs []net.IP Authorizer AutoConfigAuthorizer } type AutoConfigAuthorizer struct { Enabled bool AuthMethod structs.ACLAuthMethod // AuthMethodConfig ssoauth.Config ClaimAssertions []string AllowReuse bool } type UIConfig struct { Enabled bool Dir string ContentPath string MetricsProvider string MetricsProviderFiles []string MetricsProviderOptionsJSON string MetricsProxy UIMetricsProxy DashboardURLTemplates map[string]string } type UIMetricsProxy struct { BaseURL string AddHeaders []UIMetricsProxyAddHeader PathAllowlist []string } type UIMetricsProxyAddHeader struct { Name string Value string } func (c *RuntimeConfig) apiAddresses(maxPerType int) (unixAddrs, httpAddrs, httpsAddrs []string) { if len(c.HTTPSAddrs) > 0 { for i, addr := range c.HTTPSAddrs { if maxPerType < 1 || i < maxPerType { httpsAddrs = append(httpsAddrs, addr.String()) } else { break } } } if len(c.HTTPAddrs) > 0 { unix_count := 0 http_count := 0 for _, addr := range c.HTTPAddrs { switch addr.(type) { case *net.UnixAddr: if maxPerType < 1 || unix_count < maxPerType { unixAddrs = append(unixAddrs, addr.String()) unix_count += 1 } default: if maxPerType < 1 || http_count < maxPerType { httpAddrs = append(httpAddrs, addr.String()) http_count += 1 } } } } return } func (c *RuntimeConfig) ClientAddress() (unixAddr, httpAddr, httpsAddr string) { unixAddrs, httpAddrs, httpsAddrs := c.apiAddresses(0) if len(unixAddrs) > 0 { unixAddr = "unix://" + unixAddrs[0] } http_any := "" if len(httpAddrs) > 0 { for _, addr := range httpAddrs { host, port, err := net.SplitHostPort(addr) if err != nil { continue } if host == "0.0.0.0" || host == "::" { if http_any == "" { if host == "0.0.0.0" { http_any = net.JoinHostPort("127.0.0.1", port) } else { http_any = net.JoinHostPort("::1", port) } } continue } httpAddr = addr break } if httpAddr == "" && http_any != "" { httpAddr = http_any } } https_any := "" if len(httpsAddrs) > 0 { for _, addr := range httpsAddrs { host, port, err := net.SplitHostPort(addr) if err != nil { continue } if host == "0.0.0.0" || host == "::" { if https_any == "" { if host == "0.0.0.0" { https_any = net.JoinHostPort("127.0.0.1", port) } else { https_any = net.JoinHostPort("::1", port) } } continue } httpsAddr = addr break } if httpsAddr == "" && https_any != "" { httpsAddr = https_any } } return } func (c *RuntimeConfig) ConnectCAConfiguration() (*structs.CAConfiguration, error) { ca := &structs.CAConfiguration{ Provider: "consul", Config: map[string]interface{}{ "LeafCertTTL": structs.DefaultLeafCertTTL, "IntermediateCertTTL": structs.DefaultIntermediateCertTTL, "RootCertTTL": structs.DefaultRootCertTTL, }, } // Allow config to specify cluster_id provided it's a valid UUID. This is // meant only for tests where a deterministic ID makes fixtures much simpler // to work with but since it's only read on initial cluster bootstrap it's not // that much of a liability in production. The worst a user could do is // configure logically separate clusters with same ID by mistake but we can // avoid documenting this is even an option. if clusterID, ok := c.ConnectCAConfig["cluster_id"]; ok { // If they tried to specify an ID but typoed it then don't ignore as they // will then bootstrap with a new ID and have to throw away the whole cluster // and start again. // ensure the cluster_id value in the opaque config is a string cIDStr, ok := clusterID.(string) if !ok { return nil, fmt.Errorf("cluster_id was supplied but was not a string") } // ensure that the cluster_id string is a valid UUID _, err := uuid.ParseUUID(cIDStr) if err != nil { return nil, fmt.Errorf("cluster_id was supplied but was not a valid UUID") } // now that we know the cluster_id is okay we can set it in the CAConfiguration ca.ClusterID = cIDStr } if c.ConnectCAProvider != "" { ca.Provider = c.ConnectCAProvider } // Merge connect CA Config regardless of provider (since there are some // common config options valid to all like leaf TTL). for k, v := range c.ConnectCAConfig { ca.Config[k] = v } return ca, nil } func (c *RuntimeConfig) APIConfig(includeClientCerts bool) (*api.Config, error) { tls := c.TLS.HTTPS cfg := &api.Config{ Datacenter: c.Datacenter, TLSConfig: api.TLSConfig{InsecureSkipVerify: !tls.VerifyOutgoing}, } unixAddr, httpAddr, httpsAddr := c.ClientAddress() if httpsAddr != "" { cfg.Address = httpsAddr cfg.Scheme = "https" cfg.TLSConfig.CAFile = tls.CAFile cfg.TLSConfig.CAPath = tls.CAPath if includeClientCerts { cfg.TLSConfig.CertFile = tls.CertFile cfg.TLSConfig.KeyFile = tls.KeyFile } } else if httpAddr != "" { cfg.Address = httpAddr cfg.Scheme = "http" } else if unixAddr != "" { cfg.Address = unixAddr // this should be ignored - however we are still talking http over a unix socket // so it makes sense to set it like this cfg.Scheme = "http" } else { return nil, fmt.Errorf("No suitable client address can be found") } return cfg, nil } // 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 { // special cases for AuthMethod locality and intro token file if name == "TokenLocality" || name == "IntroTokenFile" { return false } 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()) case *net.IPNet: return reflect.ValueOf(x.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, v.Len()) if name == "AddHeaders" { // must be UIConfig.MetricsProxy.AddHeaders for i := 0; i < v.Len(); i++ { addr := v.Index(i).Addr() hdr := addr.Interface().(*UIMetricsProxyAddHeader) hm := map[string]interface{}{ "Name": hdr.Name, "Value": "hidden", } ma = append(ma, hm) } return reflect.ValueOf(ma) } if strings.HasPrefix(name, "SerfAllowedCIDRs") { for i := 0; i < v.Len(); i++ { addr := v.Index(i).Addr() ip := addr.Interface().(*net.IPNet) ma = append(ma, ip.String()) } return reflect.ValueOf(ma) } 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 } // ApplyDefaultQueryOptions returns a function which will set default values on // the options based on the configuration. The RuntimeConfig must not be nil. func ApplyDefaultQueryOptions(config *RuntimeConfig) func(options *structs.QueryOptions) { return func(options *structs.QueryOptions) { switch { case options.MaxQueryTime > config.MaxQueryTime: options.MaxQueryTime = config.MaxQueryTime case options.MaxQueryTime == 0: options.MaxQueryTime = config.DefaultQueryTime } } }