2017-09-25 18:40:42 +00:00
package config
import (
"encoding/base64"
"encoding/json"
2020-08-17 21:39:49 +00:00
"errors"
2017-09-25 18:40:42 +00:00
"fmt"
"net"
2020-09-10 16:25:56 +00:00
"net/url"
2017-09-25 18:40:42 +00:00
"os"
2020-10-30 21:49:54 +00:00
"path"
2017-09-25 18:40:42 +00:00
"path/filepath"
"reflect"
"regexp"
"sort"
2021-03-26 20:00:44 +00:00
"strconv"
2017-09-25 18:40:42 +00:00
"strings"
"time"
2020-11-16 20:44:47 +00:00
"github.com/armon/go-metrics/prometheus"
2020-10-05 20:28:13 +00:00
"github.com/hashicorp/go-bexpr"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-sockaddr/template"
"github.com/hashicorp/memberlist"
"golang.org/x/time/rate"
2022-10-18 19:05:09 +00:00
hcpconfig "github.com/hashicorp/consul/agent/hcp/config"
2020-07-27 21:11:11 +00:00
"github.com/hashicorp/consul/agent/cache"
2019-06-26 15:43:25 +00:00
"github.com/hashicorp/consul/agent/checks"
2018-06-13 08:40:03 +00:00
"github.com/hashicorp/consul/agent/connect/ca"
2017-09-25 18:40:42 +00:00
"github.com/hashicorp/consul/agent/consul"
2020-06-16 19:03:22 +00:00
"github.com/hashicorp/consul/agent/consul/authmethod/ssoauth"
2020-08-17 21:24:49 +00:00
"github.com/hashicorp/consul/agent/dns"
2022-03-31 17:49:37 +00:00
"github.com/hashicorp/consul/agent/rpc/middleware"
2017-09-25 18:40:42 +00:00
"github.com/hashicorp/consul/agent/structs"
2020-08-25 04:10:12 +00:00
"github.com/hashicorp/consul/agent/token"
2017-09-25 18:40:42 +00:00
"github.com/hashicorp/consul/ipaddr"
2018-06-14 12:52:48 +00:00
"github.com/hashicorp/consul/lib"
2022-03-31 19:11:49 +00:00
"github.com/hashicorp/consul/lib/stringslice"
2020-06-16 19:03:22 +00:00
libtempl "github.com/hashicorp/consul/lib/template"
2020-08-19 17:17:05 +00:00
"github.com/hashicorp/consul/logging"
2017-09-25 18:40:42 +00:00
"github.com/hashicorp/consul/tlsutil"
"github.com/hashicorp/consul/types"
)
2020-12-21 18:25:32 +00:00
// LoadOpts used by Load to construct and validate a RuntimeConfig.
type LoadOpts struct {
// FlagValues contains the command line arguments that can also be set
// in a config file.
FlagValues Config
// ConfigFiles is a slice of paths to config files and directories that will
// be loaded.
ConfigFiles [ ] string
// ConfigFormat forces all config files to be interpreted as this format
// independent of their extension. Value may be `hcl` or `json`.
ConfigFormat string
// DevMode indicates whether the agent should be started in development
// mode. This cannot be configured in a config file.
DevMode * bool
// HCL is a slice of config data in hcl format. Each one will be loaded as
// if it were the source of a config file. Values from HCL will override
// values from ConfigFiles and FlagValues.
HCL [ ] string
// DefaultConfig is an optional source that is applied after other defaults
// but before ConfigFiles and all other user specified config.
DefaultConfig Source
// Overrides are optional config sources that are applied as the very last
// config source so they can override any previous values.
Overrides [ ] Source
// hostname is a shim for testing, allowing tests to specify a replacement
// for os.Hostname.
hostname func ( ) ( string , error )
// getPrivateIPv4 and getPublicIPv6 are shims for testing, allowing tests to
// specify a replacement for ipaddr.GetPrivateIPv4 and ipaddr.GetPublicIPv6.
getPrivateIPv4 func ( ) ( [ ] * net . IPAddr , error )
getPublicIPv6 func ( ) ( [ ] * net . IPAddr , error )
2021-07-06 22:22:59 +00:00
// sources is a shim for testing. Many test cases used explicit sources instead
// paths to config files. This shim allows us to preserve those test cases
// while using Load as the entrypoint.
sources [ ] Source
2020-12-21 18:25:32 +00:00
}
// Load will build the configuration including the config source injected
2020-08-12 16:35:30 +00:00
// after all other defaults but before any user supplied configuration and the overrides
// source injected as the final source in the configuration parsing chain.
2020-12-21 18:25:32 +00:00
//
// The caller is responsible for handling any warnings in LoadResult.Warnings.
func Load ( opts LoadOpts ) ( LoadResult , error ) {
r := LoadResult { }
2020-12-21 18:55:53 +00:00
b , err := newBuilder ( opts )
2020-08-12 16:35:30 +00:00
if err != nil {
2020-12-21 18:25:32 +00:00
return r , err
2020-08-12 16:35:30 +00:00
}
2021-07-06 22:22:59 +00:00
cfg , err := b . build ( )
2020-08-12 16:35:30 +00:00
if err != nil {
2020-12-21 18:25:32 +00:00
return r , err
2020-08-12 16:35:30 +00:00
}
2021-07-06 22:22:59 +00:00
if err := b . validate ( cfg ) ; err != nil {
return r , err
}
2022-03-31 19:11:49 +00:00
watcherFiles := stringslice . CloneStringSlice ( opts . ConfigFiles )
return LoadResult { RuntimeConfig : & cfg , Warnings : b . Warnings , WatchedFiles : watcherFiles } , nil
2020-12-21 18:25:32 +00:00
}
2020-08-12 16:35:30 +00:00
2020-12-21 18:25:32 +00:00
// LoadResult is the result returned from Load. The caller is responsible for
// handling any warnings.
type LoadResult struct {
RuntimeConfig * RuntimeConfig
Warnings [ ] string
2022-03-31 19:11:49 +00:00
WatchedFiles [ ] string
2020-08-12 16:35:30 +00:00
}
2020-12-21 18:55:53 +00:00
// builder constructs and validates a runtime configuration from multiple
2017-09-25 18:40:42 +00:00
// configuration sources.
//
// The sources are merged in the following order:
//
2022-08-19 17:07:22 +00:00
// - default configuration
// - config files in alphabetical order
// - command line arguments
// - overrides
2017-09-25 18:40:42 +00:00
//
2020-12-21 18:55:53 +00:00
// The config sources are merged sequentially and later values overwrite
// previously set values. Slice values are merged by concatenating the two slices.
// Map values are merged by over-laying the later maps on top of earlier ones.
type builder struct {
2020-12-21 18:25:32 +00:00
opts LoadOpts
2017-09-25 18:40:42 +00:00
// Head, Sources, and Tail are used to manage the order of the
// config sources, as described in the comments above.
Head [ ] Source
Sources [ ] Source
Tail [ ] Source
// Warnings contains the warnings encountered when
// parsing the configuration.
Warnings [ ] string
// err contains the first error that occurred during
// building the runtime configuration.
err error
}
2020-12-21 18:55:53 +00:00
// newBuilder returns a new configuration Builder from the LoadOpts.
func newBuilder ( opts LoadOpts ) ( * builder , error ) {
2020-08-14 23:17:44 +00:00
configFormat := opts . ConfigFormat
if configFormat != "" && configFormat != "json" && configFormat != "hcl" {
return nil , fmt . Errorf ( "config: -config-format must be either 'hcl' or 'json'" )
}
2020-12-21 18:55:53 +00:00
b := & builder {
2020-11-20 23:29:57 +00:00
opts : opts ,
Head : [ ] Source { DefaultSource ( ) , DefaultEnterpriseSource ( ) } ,
2017-09-25 18:40:42 +00:00
}
2020-11-20 23:58:45 +00:00
if boolVal ( opts . DevMode ) {
2017-09-25 18:40:42 +00:00
b . Head = append ( b . Head , DevSource ( ) )
}
// Since the merge logic is to overwrite all fields with later
// values except slices which are merged by appending later values
// we need to merge all slice values defined in flags before we
// merge the config files since the flag values for slices are
// otherwise appended instead of prepended.
2020-12-21 18:25:32 +00:00
slices , values := splitSlicesAndValues ( opts . FlagValues )
2020-11-20 20:23:58 +00:00
b . Head = append ( b . Head , LiteralSource { Name : "flags.slices" , Config : slices } )
2020-12-21 18:25:32 +00:00
if opts . DefaultConfig != nil {
b . Head = append ( b . Head , opts . DefaultConfig )
}
2021-07-06 22:22:59 +00:00
b . Sources = opts . sources
2020-05-01 22:45:15 +00:00
for _ , path := range opts . ConfigFiles {
2020-05-02 00:17:27 +00:00
sources , err := b . sourcesFromPath ( path , opts . ConfigFormat )
2017-10-31 22:30:01 +00:00
if err != nil {
2017-09-25 18:40:42 +00:00
return nil , err
}
2017-10-31 22:30:01 +00:00
b . Sources = append ( b . Sources , sources ... )
2017-09-25 18:40:42 +00:00
}
2020-11-20 20:23:58 +00:00
b . Tail = append ( b . Tail , LiteralSource { Name : "flags.values" , Config : values } )
2020-05-01 22:45:15 +00:00
for i , s := range opts . HCL {
2020-08-10 16:46:28 +00:00
b . Tail = append ( b . Tail , FileSource {
2017-10-31 22:30:01 +00:00
Name : fmt . Sprintf ( "flags-%d.hcl" , i ) ,
2017-09-25 18:40:42 +00:00
Format : "hcl" ,
Data : s ,
} )
}
2020-11-20 23:14:17 +00:00
b . Tail = append ( b . Tail , NonUserSource ( ) , DefaultConsulSource ( ) , OverrideEnterpriseSource ( ) , defaultVersionSource ( ) )
2020-11-20 23:58:45 +00:00
if boolVal ( opts . DevMode ) {
2017-09-25 18:40:42 +00:00
b . Tail = append ( b . Tail , DevConsulSource ( ) )
}
2020-12-21 18:25:32 +00:00
if len ( opts . Overrides ) != 0 {
b . Tail = append ( b . Tail , opts . Overrides ... )
}
2017-09-25 18:40:42 +00:00
return b , nil
}
2020-05-01 22:45:15 +00:00
// sourcesFromPath reads a single config file or all files in a directory (but
// not its sub-directories) and returns Sources created from the
// files.
2020-12-21 18:55:53 +00:00
func ( b * builder ) sourcesFromPath ( path string , format string ) ( [ ] Source , error ) {
2017-09-25 18:40:42 +00:00
f , err := os . Open ( path )
if err != nil {
2017-10-31 22:30:01 +00:00
return nil , fmt . Errorf ( "config: Open failed on %s. %s" , path , err )
2017-09-25 18:40:42 +00:00
}
defer f . Close ( )
fi , err := f . Stat ( )
if err != nil {
2017-10-31 22:30:01 +00:00
return nil , fmt . Errorf ( "config: Stat failed on %s. %s" , path , err )
2017-09-25 18:40:42 +00:00
}
if ! fi . IsDir ( ) {
2020-05-02 00:17:27 +00:00
if ! shouldParseFile ( path , format ) {
b . warn ( "skipping file %v, extension must be .hcl or .json, or config format must be set" , path )
2020-05-01 22:45:15 +00:00
return nil , nil
}
2020-05-02 00:17:27 +00:00
src , err := newSourceFromFile ( path , format )
2017-10-31 22:30:01 +00:00
if err != nil {
return nil , err
}
return [ ] Source { src } , nil
2017-09-25 18:40:42 +00:00
}
fis , err := f . Readdir ( - 1 )
if err != nil {
2017-10-31 22:30:01 +00:00
return nil , fmt . Errorf ( "config: Readdir failed on %s. %s" , path , err )
2017-09-25 18:40:42 +00:00
}
// sort files by name
sort . Sort ( byName ( fis ) )
2017-10-31 22:30:01 +00:00
var sources [ ] Source
2017-09-25 18:40:42 +00:00
for _ , fi := range fis {
2018-01-12 19:11:59 +00:00
fp := filepath . Join ( path , fi . Name ( ) )
// check for a symlink and resolve the path
if fi . Mode ( ) & os . ModeSymlink > 0 {
var err error
fp , err = filepath . EvalSymlinks ( fp )
if err != nil {
return nil , err
}
fi , err = os . Stat ( fp )
if err != nil {
return nil , err
}
}
2017-09-25 18:40:42 +00:00
// do not recurse into sub dirs
if fi . IsDir ( ) {
continue
}
2020-05-02 00:17:27 +00:00
if ! shouldParseFile ( fp , format ) {
b . warn ( "skipping file %v, extension must be .hcl or .json, or config format must be set" , fp )
2020-05-01 22:45:15 +00:00
continue
}
2020-05-02 00:17:27 +00:00
src , err := newSourceFromFile ( fp , format )
2020-05-01 22:45:15 +00:00
if err != nil {
return nil , err
2017-09-25 18:40:42 +00:00
}
2020-05-01 22:45:15 +00:00
sources = append ( sources , src )
2017-09-25 18:40:42 +00:00
}
2017-10-31 22:30:01 +00:00
return sources , nil
2017-09-25 18:40:42 +00:00
}
2020-05-01 22:45:15 +00:00
// newSourceFromFile creates a Source from the contents of the file at path.
func newSourceFromFile ( path string , format string ) ( Source , error ) {
2022-11-10 16:26:01 +00:00
data , err := os . ReadFile ( path )
2017-09-25 18:40:42 +00:00
if err != nil {
2020-08-10 16:46:28 +00:00
return nil , fmt . Errorf ( "config: failed to read %s: %s" , path , err )
2017-09-25 18:40:42 +00:00
}
2020-05-01 22:45:15 +00:00
if format == "" {
format = formatFromFileExtension ( path )
2017-09-25 18:40:42 +00:00
}
2020-08-10 16:46:28 +00:00
return FileSource { Name : path , Data : string ( data ) , Format : format } , nil
2017-09-25 18:40:42 +00:00
}
2019-04-30 18:43:32 +00:00
// shouldParse file determines whether the file to be read is of a supported extension
2020-05-01 22:45:15 +00:00
func shouldParseFile ( path string , configFormat string ) bool {
srcFormat := formatFromFileExtension ( path )
return configFormat != "" || srcFormat == "hcl" || srcFormat == "json"
}
2019-04-30 18:43:32 +00:00
2020-05-01 22:45:15 +00:00
func formatFromFileExtension ( name string ) string {
switch {
case strings . HasSuffix ( name , ".json" ) :
return "json"
case strings . HasSuffix ( name , ".hcl" ) :
return "hcl"
default :
return ""
2019-04-30 18:43:32 +00:00
}
}
2017-09-25 18:40:42 +00:00
type byName [ ] os . FileInfo
func ( a byName ) Len ( ) int { return len ( a ) }
func ( a byName ) Swap ( i , j int ) { a [ i ] , a [ j ] = a [ j ] , a [ i ] }
func ( a byName ) Less ( i , j int ) bool { return a [ i ] . Name ( ) < a [ j ] . Name ( ) }
2021-07-15 15:22:46 +00:00
// build constructs the runtime configuration from the config sources
2017-09-25 18:40:42 +00:00
// and the command line flags. The config sources are processed in the
// order they were added with the flags being processed last to give
// precedence over the other sources. If the error is nil then
// warnings can still contain deprecation or format warnings that should
// be presented to the user.
2021-07-06 22:22:59 +00:00
func ( b * builder ) build ( ) ( rt RuntimeConfig , err error ) {
2020-08-14 23:17:44 +00:00
srcs := make ( [ ] Source , 0 , len ( b . Head ) + len ( b . Sources ) + len ( b . Tail ) )
2017-09-25 18:40:42 +00:00
srcs = append ( srcs , b . Head ... )
2020-05-01 22:45:15 +00:00
srcs = append ( srcs , b . Sources ... )
2017-09-25 18:40:42 +00:00
srcs = append ( srcs , b . Tail ... )
// parse the config sources into a configuration
var c Config
for _ , s := range srcs {
2020-08-10 16:46:28 +00:00
c2 , md , err := s . Parse ( )
switch {
case err == ErrNoData :
2017-09-25 18:40:42 +00:00
continue
2020-08-10 16:46:28 +00:00
case err != nil :
return RuntimeConfig { } , fmt . Errorf ( "failed to parse %v: %w" , s . Source ( ) , err )
2017-09-25 18:40:42 +00:00
}
2017-09-26 08:14:14 +00:00
2020-05-29 21:16:03 +00:00
var unusedErr error
for _ , k := range md . Unused {
2021-04-08 18:07:32 +00:00
switch {
case k == "acl_enforce_version_8" :
2020-05-29 21:16:03 +00:00
b . warn ( "config key %q is deprecated and should be removed" , k )
2021-04-08 18:07:32 +00:00
case strings . HasPrefix ( k , "audit.sink[" ) && strings . HasSuffix ( k , "].name" ) :
b . warn ( "config key audit.sink[].name is deprecated and should be removed" )
2020-05-29 21:16:03 +00:00
default :
unusedErr = multierror . Append ( unusedErr , fmt . Errorf ( "invalid config key %s" , k ) )
}
}
if unusedErr != nil {
2020-08-10 16:46:28 +00:00
return RuntimeConfig { } , fmt . Errorf ( "failed to parse %v: %s" , s . Source ( ) , unusedErr )
2020-05-29 21:16:03 +00:00
}
2020-11-20 22:43:32 +00:00
for _ , err := range validateEnterpriseConfigKeys ( & c2 ) {
b . warn ( "%s" , err )
}
2020-12-22 19:19:34 +00:00
b . Warnings = append ( b . Warnings , md . Warnings ... )
2020-04-28 13:45:33 +00:00
2017-09-26 08:14:14 +00:00
// if we have a single 'check' or 'service' we need to add them to the
// list of checks and services first since we cannot merge them
// generically and later values would clobber earlier ones.
2020-12-22 19:19:34 +00:00
// TODO: move to applyDeprecatedConfig
2017-09-26 08:14:14 +00:00
if c2 . Check != nil {
c2 . Checks = append ( c2 . Checks , * c2 . Check )
c2 . Check = nil
}
if c2 . Service != nil {
c2 . Services = append ( c2 . Services , * c2 . Service )
c2 . Service = nil
}
2017-09-25 18:40:42 +00:00
c = Merge ( c , c2 )
}
// ----------------------------------------------------------------
// process/merge some complex values
//
2021-08-20 16:57:45 +00:00
dnsServiceTTL := map [ string ] time . Duration { }
2017-09-25 18:40:42 +00:00
for k , v := range c . DNS . ServiceTTL {
dnsServiceTTL [ k ] = b . durationVal ( fmt . Sprintf ( "dns_config.service_ttl[%q]" , k ) , & v )
}
Added SOA configuration for DNS settings. (#4714)
This will allow to fine TUNE SOA settings sent by Consul in DNS responses,
for instance to be able to control negative ttl.
Will fix: https://github.com/hashicorp/consul/issues/4713
# Example
Override all settings:
* min_ttl: 0 => 60s
* retry: 600 (10m) => 300s (5 minutes),
* expire: 86400 (24h) => 43200 (12h)
* refresh: 3600 (1h) => 1800 (30 minutes)
```
consul agent -dev -hcl 'dns_config={soa={min_ttl=60,retry=300,expire=43200,refresh=1800}}'
```
Result:
```
dig +multiline @localhost -p 8600 service.consul
; <<>> DiG 9.12.1 <<>> +multiline @localhost -p 8600 service.consul
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 36557
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;service.consul. IN A
;; AUTHORITY SECTION:
consul. 0 IN SOA ns.consul. hostmaster.consul. (
1537959133 ; serial
1800 ; refresh (30 minutes)
300 ; retry (5 minutes)
43200 ; expire (12 hours)
60 ; minimum (1 minute)
)
;; Query time: 4 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Wed Sep 26 12:52:13 CEST 2018
;; MSG SIZE rcvd: 93
```
2018-10-10 19:50:56 +00:00
soa := RuntimeSOAConfig { Refresh : 3600 , Retry : 600 , Expire : 86400 , Minttl : 0 }
if c . DNS . SOA != nil {
if c . DNS . SOA . Expire != nil {
soa . Expire = * c . DNS . SOA . Expire
}
if c . DNS . SOA . Minttl != nil {
soa . Minttl = * c . DNS . SOA . Minttl
}
if c . DNS . SOA . Refresh != nil {
soa . Refresh = * c . DNS . SOA . Refresh
}
if c . DNS . SOA . Retry != nil {
soa . Retry = * c . DNS . SOA . Retry
}
}
2020-11-20 23:58:45 +00:00
leaveOnTerm := ! boolVal ( c . ServerMode )
2017-09-25 18:40:42 +00:00
if c . LeaveOnTerm != nil {
2020-11-20 23:58:45 +00:00
leaveOnTerm = boolVal ( c . LeaveOnTerm )
2017-09-25 18:40:42 +00:00
}
2020-11-20 23:58:45 +00:00
skipLeaveOnInt := boolVal ( c . ServerMode )
2017-09-25 18:40:42 +00:00
if c . SkipLeaveOnInt != nil {
2020-11-20 23:58:45 +00:00
skipLeaveOnInt = boolVal ( c . SkipLeaveOnInt )
2017-09-25 18:40:42 +00:00
}
// ----------------------------------------------------------------
// checks and services
//
var checks [ ] * structs . CheckDefinition
if c . Check != nil {
checks = append ( checks , b . checkVal ( c . Check ) )
}
for _ , check := range c . Checks {
checks = append ( checks , b . checkVal ( & check ) )
}
var services [ ] * structs . ServiceDefinition
for _ , service := range c . Services {
services = append ( services , b . serviceVal ( & service ) )
}
if c . Service != nil {
services = append ( services , b . serviceVal ( c . Service ) )
}
// ----------------------------------------------------------------
// addresses
//
// determine port values and replace values <= 0 and > 65535 with -1
dnsPort := b . portVal ( "ports.dns" , c . Ports . DNS )
httpPort := b . portVal ( "ports.http" , c . Ports . HTTP )
httpsPort := b . portVal ( "ports.https" , c . Ports . HTTPS )
serverPort := b . portVal ( "ports.server" , c . Ports . Server )
2021-09-08 15:48:41 +00:00
grpcPort := b . portVal ( "ports.grpc" , c . Ports . GRPC )
2022-08-19 17:07:22 +00:00
grpcTlsPort := b . portVal ( "ports.grpc_tls" , c . Ports . GRPCTLS )
2022-11-09 17:29:55 +00:00
// default gRPC TLS port for servers is 8503
if c . Ports . GRPCTLS == nil && boolVal ( c . ServerMode ) {
grpcTlsPort = 8503
}
2017-09-25 18:40:42 +00:00
serfPortLAN := b . portVal ( "ports.serf_lan" , c . Ports . SerfLAN )
serfPortWAN := b . portVal ( "ports.serf_wan" , c . Ports . SerfWAN )
2018-06-06 20:35:44 +00:00
proxyMinPort := b . portVal ( "ports.proxy_min_port" , c . Ports . ProxyMinPort )
proxyMaxPort := b . portVal ( "ports.proxy_max_port" , c . Ports . ProxyMaxPort )
2018-09-27 13:33:12 +00:00
sidecarMinPort := b . portVal ( "ports.sidecar_min_port" , c . Ports . SidecarMinPort )
sidecarMaxPort := b . portVal ( "ports.sidecar_max_port" , c . Ports . SidecarMaxPort )
2019-09-26 02:55:52 +00:00
exposeMinPort := b . portVal ( "ports.expose_min_port" , c . Ports . ExposeMinPort )
exposeMaxPort := b . portVal ( "ports.expose_max_port" , c . Ports . ExposeMaxPort )
2018-06-06 20:35:44 +00:00
if proxyMaxPort < proxyMinPort {
return RuntimeConfig { } , fmt . Errorf (
"proxy_min_port must be less than proxy_max_port. To disable, set both to zero." )
}
2018-09-27 13:33:12 +00:00
if sidecarMaxPort < sidecarMinPort {
return RuntimeConfig { } , fmt . Errorf (
"sidecar_min_port must be less than sidecar_max_port. To disable, set both to zero." )
}
2019-09-26 02:55:52 +00:00
if exposeMaxPort < exposeMinPort {
return RuntimeConfig { } , fmt . Errorf (
"expose_min_port must be less than expose_max_port. To disable, set both to zero." )
}
2017-09-25 18:40:42 +00:00
// determine the default bind and advertise address
//
// First check whether the user provided an ANY address or whether
// the expanded template results in an ANY address. In that case we
// derive an advertise address from the current network
// configuration since we can listen on an ANY address for incoming
// traffic but cannot advertise it as the address on which the
// server can be reached.
bindAddrs := b . expandAddrs ( "bind_addr" , c . BindAddr )
if len ( bindAddrs ) == 0 {
return RuntimeConfig { } , fmt . Errorf ( "bind_addr cannot be empty" )
}
if len ( bindAddrs ) > 1 {
return RuntimeConfig { } , fmt . Errorf ( "bind_addr cannot contain multiple addresses. Use 'addresses.{dns,http,https}' instead." )
}
if isUnixAddr ( bindAddrs [ 0 ] ) {
return RuntimeConfig { } , fmt . Errorf ( "bind_addr cannot be a unix socket" )
}
if ! isIPAddr ( bindAddrs [ 0 ] ) {
return RuntimeConfig { } , fmt . Errorf ( "bind_addr must be an ip address" )
}
2020-11-20 23:58:45 +00:00
if ipaddr . IsAny ( stringVal ( c . AdvertiseAddrLAN ) ) {
2017-09-27 20:57:55 +00:00
return RuntimeConfig { } , fmt . Errorf ( "Advertise address cannot be 0.0.0.0, :: or [::]" )
}
2020-11-20 23:58:45 +00:00
if ipaddr . IsAny ( stringVal ( c . AdvertiseAddrWAN ) ) {
2017-09-27 20:57:55 +00:00
return RuntimeConfig { } , fmt . Errorf ( "Advertise WAN address cannot be 0.0.0.0, :: or [::]" )
}
2017-09-25 18:40:42 +00:00
bindAddr := bindAddrs [ 0 ] . ( * net . IPAddr )
2020-11-20 23:58:45 +00:00
advertiseAddr := makeIPAddr ( b . expandFirstIP ( "advertise_addr" , c . AdvertiseAddrLAN ) , bindAddr )
2020-01-17 14:54:17 +00:00
2017-09-27 19:59:47 +00:00
if ipaddr . IsAny ( advertiseAddr ) {
2020-12-21 22:51:44 +00:00
addrtyp , detect := advertiseAddrFunc ( b . opts , advertiseAddr )
2017-09-25 18:40:42 +00:00
advertiseAddrs , err := detect ( )
if err != nil {
return RuntimeConfig { } , fmt . Errorf ( "Error detecting %s address: %s" , addrtyp , err )
}
if len ( advertiseAddrs ) == 0 {
return RuntimeConfig { } , fmt . Errorf ( "No %s address found" , addrtyp )
}
if len ( advertiseAddrs ) > 1 {
2018-01-10 17:53:41 +00:00
return RuntimeConfig { } , fmt . Errorf ( "Multiple %s addresses found. Please configure one with 'bind' and/or 'advertise'." , addrtyp )
2017-09-25 18:40:42 +00:00
}
advertiseAddr = advertiseAddrs [ 0 ]
}
// derive other bind addresses from the bindAddr
rpcBindAddr := b . makeTCPAddr ( bindAddr , nil , serverPort )
serfBindAddrLAN := b . makeTCPAddr ( b . expandFirstIP ( "serf_lan" , c . SerfBindAddrLAN ) , bindAddr , serfPortLAN )
2018-03-27 14:44:41 +00:00
// Only initialize serf WAN bind address when its enabled
var serfBindAddrWAN * net . TCPAddr
if serfPortWAN >= 0 {
serfBindAddrWAN = b . makeTCPAddr ( b . expandFirstIP ( "serf_wan" , c . SerfBindAddrWAN ) , bindAddr , serfPortWAN )
}
2017-09-25 18:40:42 +00:00
// derive other advertise addresses from the advertise address
2020-11-20 23:58:45 +00:00
advertiseAddrLAN := makeIPAddr ( b . expandFirstIP ( "advertise_addr" , c . AdvertiseAddrLAN ) , advertiseAddr )
2020-01-17 14:54:17 +00:00
advertiseAddrIsV6 := advertiseAddr . IP . To4 ( ) == nil
var advertiseAddrV4 , advertiseAddrV6 * net . IPAddr
if ! advertiseAddrIsV6 {
advertiseAddrV4 = advertiseAddr
} else {
advertiseAddrV6 = advertiseAddr
}
2020-11-20 23:58:45 +00:00
advertiseAddrLANIPv4 := makeIPAddr ( b . expandFirstIP ( "advertise_addr_ipv4" , c . AdvertiseAddrLANIPv4 ) , advertiseAddrV4 )
2020-01-17 14:54:17 +00:00
if advertiseAddrLANIPv4 != nil && advertiseAddrLANIPv4 . IP . To4 ( ) == nil {
return RuntimeConfig { } , fmt . Errorf ( "advertise_addr_ipv4 must be an ipv4 address" )
}
2020-11-20 23:58:45 +00:00
advertiseAddrLANIPv6 := makeIPAddr ( b . expandFirstIP ( "advertise_addr_ipv6" , c . AdvertiseAddrLANIPv6 ) , advertiseAddrV6 )
2020-01-17 14:54:17 +00:00
if advertiseAddrLANIPv6 != nil && advertiseAddrLANIPv6 . IP . To4 ( ) != nil {
return RuntimeConfig { } , fmt . Errorf ( "advertise_addr_ipv6 must be an ipv6 address" )
}
2020-11-20 23:58:45 +00:00
advertiseAddrWAN := makeIPAddr ( b . expandFirstIP ( "advertise_addr_wan" , c . AdvertiseAddrWAN ) , advertiseAddrLAN )
2020-01-17 14:54:17 +00:00
advertiseAddrWANIsV6 := advertiseAddrWAN . IP . To4 ( ) == nil
var advertiseAddrWANv4 , advertiseAddrWANv6 * net . IPAddr
if ! advertiseAddrWANIsV6 {
advertiseAddrWANv4 = advertiseAddrWAN
} else {
advertiseAddrWANv6 = advertiseAddrWAN
}
2020-11-20 23:58:45 +00:00
advertiseAddrWANIPv4 := makeIPAddr ( b . expandFirstIP ( "advertise_addr_wan_ipv4" , c . AdvertiseAddrWANIPv4 ) , advertiseAddrWANv4 )
2020-01-17 14:54:17 +00:00
if advertiseAddrWANIPv4 != nil && advertiseAddrWANIPv4 . IP . To4 ( ) == nil {
return RuntimeConfig { } , fmt . Errorf ( "advertise_addr_wan_ipv4 must be an ipv4 address" )
}
2020-11-20 23:58:45 +00:00
advertiseAddrWANIPv6 := makeIPAddr ( b . expandFirstIP ( "advertise_addr_wan_ipv6" , c . AdvertiseAddrWANIPv6 ) , advertiseAddrWANv6 )
2020-01-17 14:54:17 +00:00
if advertiseAddrWANIPv6 != nil && advertiseAddrWANIPv6 . IP . To4 ( ) != nil {
return RuntimeConfig { } , fmt . Errorf ( "advertise_addr_wan_ipv6 must be an ipv6 address" )
}
2017-09-29 09:35:51 +00:00
rpcAdvertiseAddr := & net . TCPAddr { IP : advertiseAddrLAN . IP , Port : serverPort }
serfAdvertiseAddrLAN := & net . TCPAddr { IP : advertiseAddrLAN . IP , Port : serfPortLAN }
2018-03-27 14:44:41 +00:00
// Only initialize serf WAN advertise address when its enabled
var serfAdvertiseAddrWAN * net . TCPAddr
if serfPortWAN >= 0 {
serfAdvertiseAddrWAN = & net . TCPAddr { IP : advertiseAddrWAN . IP , Port : serfPortWAN }
}
2017-09-25 18:40:42 +00:00
// determine client addresses
clientAddrs := b . expandIPs ( "client_addr" , c . ClientAddr )
2021-11-01 13:27:50 +00:00
if len ( clientAddrs ) == 0 {
b . warn ( "client_addr is empty, client services (DNS, HTTP, HTTPS, GRPC) will not be listening for connections" )
}
2017-09-25 18:40:42 +00:00
dnsAddrs := b . makeAddrs ( b . expandAddrs ( "addresses.dns" , c . Addresses . DNS ) , clientAddrs , dnsPort )
httpAddrs := b . makeAddrs ( b . expandAddrs ( "addresses.http" , c . Addresses . HTTP ) , clientAddrs , httpPort )
httpsAddrs := b . makeAddrs ( b . expandAddrs ( "addresses.https" , c . Addresses . HTTPS ) , clientAddrs , httpsPort )
2021-09-08 15:48:41 +00:00
grpcAddrs := b . makeAddrs ( b . expandAddrs ( "addresses.grpc" , c . Addresses . GRPC ) , clientAddrs , grpcPort )
2022-08-19 17:07:22 +00:00
grpcTlsAddrs := b . makeAddrs ( b . expandAddrs ( "addresses.grpc_tls" , c . Addresses . GRPCTLS ) , clientAddrs , grpcTlsPort )
2017-09-25 18:40:42 +00:00
for _ , a := range dnsAddrs {
if x , ok := a . ( * net . TCPAddr ) ; ok {
dnsAddrs = append ( dnsAddrs , & net . UDPAddr { IP : x . IP , Port : x . Port } )
}
}
2017-10-20 13:36:52 +00:00
// expand dns recursors
uniq := map [ string ] bool { }
dnsRecursors := [ ] string { }
for _ , r := range c . DNSRecursors {
x , err := template . Parse ( r )
if err != nil {
return RuntimeConfig { } , fmt . Errorf ( "Invalid DNS recursor template %q: %s" , r , err )
}
for _ , addr := range strings . Fields ( x ) {
if strings . HasPrefix ( addr , "unix://" ) {
return RuntimeConfig { } , fmt . Errorf ( "DNS Recursors cannot be unix sockets: %s" , addr )
}
if uniq [ addr ] {
continue
}
uniq [ addr ] = true
dnsRecursors = append ( dnsRecursors , addr )
}
}
2020-11-20 23:58:45 +00:00
datacenter := strings . ToLower ( stringVal ( c . Datacenter ) )
altDomain := stringVal ( c . DNSAltDomain )
2019-06-27 10:00:37 +00:00
2017-09-25 18:40:42 +00:00
// Create the default set of tagged addresses.
if c . TaggedAddresses == nil {
c . TaggedAddresses = make ( map [ string ] string )
}
2020-01-17 14:54:17 +00:00
c . TaggedAddresses [ structs . TaggedAddressLAN ] = advertiseAddrLAN . IP . String ( )
if advertiseAddrLANIPv4 != nil {
c . TaggedAddresses [ structs . TaggedAddressLANIPv4 ] = advertiseAddrLANIPv4 . IP . String ( )
}
if advertiseAddrLANIPv6 != nil {
c . TaggedAddresses [ structs . TaggedAddressLANIPv6 ] = advertiseAddrLANIPv6 . IP . String ( )
}
c . TaggedAddresses [ structs . TaggedAddressWAN ] = advertiseAddrWAN . IP . String ( )
if advertiseAddrWANIPv4 != nil {
c . TaggedAddresses [ structs . TaggedAddressWANIPv4 ] = advertiseAddrWANIPv4 . IP . String ( )
}
if advertiseAddrWANIPv6 != nil {
c . TaggedAddresses [ structs . TaggedAddressWANIPv6 ] = advertiseAddrWANIPv6 . IP . String ( )
}
2017-09-25 18:40:42 +00:00
// segments
var segments [ ] structs . NetworkSegment
for _ , s := range c . Segments {
2020-11-20 23:58:45 +00:00
name := stringVal ( s . Name )
2017-09-25 18:40:42 +00:00
port := b . portVal ( fmt . Sprintf ( "segments[%s].port" , name ) , s . Port )
2017-10-11 08:15:55 +00:00
if port <= 0 {
return RuntimeConfig { } , fmt . Errorf ( "Port for segment %q cannot be <= 0" , name )
2017-10-11 01:11:21 +00:00
}
2017-09-25 18:40:42 +00:00
bind := b . makeTCPAddr (
b . expandFirstIP ( fmt . Sprintf ( "segments[%s].bind" , name ) , s . Bind ) ,
bindAddr ,
port ,
)
advertise := b . makeTCPAddr (
b . expandFirstIP ( fmt . Sprintf ( "segments[%s].advertise" , name ) , s . Advertise ) ,
advertiseAddrLAN ,
port ,
)
segments = append ( segments , structs . NetworkSegment {
Name : name ,
Bind : bind ,
Advertise : advertise ,
2020-11-20 23:58:45 +00:00
RPCListener : boolVal ( s . RPCListener ) ,
2017-09-25 18:40:42 +00:00
} )
}
// Parse the metric filters
2022-03-31 17:49:37 +00:00
telemetryAllowedPrefixes , telemetryBlockedPrefixes := b . parsePrefixFilter ( & c . Telemetry )
2017-09-25 18:40:42 +00:00
// raft performance scaling
2020-11-20 23:58:45 +00:00
performanceRaftMultiplier := intVal ( c . Performance . RaftMultiplier )
2017-09-25 18:40:42 +00:00
if performanceRaftMultiplier < 1 || uint ( performanceRaftMultiplier ) > consul . MaxRaftMultiplier {
return RuntimeConfig { } , fmt . Errorf ( "performance.raft_multiplier cannot be %d. Must be between 1 and %d" , performanceRaftMultiplier , consul . MaxRaftMultiplier )
}
consulRaftElectionTimeout := b . durationVal ( "consul.raft.election_timeout" , c . Consul . Raft . ElectionTimeout ) * time . Duration ( performanceRaftMultiplier )
consulRaftHeartbeatTimeout := b . durationVal ( "consul.raft.heartbeat_timeout" , c . Consul . Raft . HeartbeatTimeout ) * time . Duration ( performanceRaftMultiplier )
consulRaftLeaderLeaseTimeout := b . durationVal ( "consul.raft.leader_lease_timeout" , c . Consul . Raft . LeaderLeaseTimeout ) * time . Duration ( performanceRaftMultiplier )
2020-08-07 10:02:02 +00:00
// Connect
2020-11-20 23:58:45 +00:00
connectEnabled := boolVal ( c . Connect . Enabled )
connectCAProvider := stringVal ( c . Connect . CAProvider )
2018-06-12 12:25:08 +00:00
connectCAConfig := c . Connect . CAConfig
2022-03-08 18:37:56 +00:00
serverlessPluginEnabled := boolVal ( c . Connect . EnableServerlessPlugin )
2020-08-07 10:02:02 +00:00
// autoEncrypt and autoConfig implicitly turns on connect which is why
// they need to be above other settings that rely on connect.
autoEncryptDNSSAN := [ ] string { }
for _ , d := range c . AutoEncrypt . DNSSAN {
autoEncryptDNSSAN = append ( autoEncryptDNSSAN , d )
}
autoEncryptIPSAN := [ ] net . IP { }
for _ , i := range c . AutoEncrypt . IPSAN {
ip := net . ParseIP ( i )
if ip == nil {
b . warn ( fmt . Sprintf ( "Cannot parse ip %q from AutoEncrypt.IPSAN" , i ) )
continue
}
autoEncryptIPSAN = append ( autoEncryptIPSAN , ip )
}
2020-11-20 23:58:45 +00:00
autoEncryptAllowTLS := boolVal ( c . AutoEncrypt . AllowTLS )
2021-08-19 20:09:42 +00:00
autoConfig := b . autoConfigVal ( c . AutoConfig , stringVal ( c . Partition ) )
2021-06-17 19:41:01 +00:00
if autoEncryptAllowTLS || autoConfig . Enabled {
2020-08-07 10:02:02 +00:00
connectEnabled = true
}
// Connect proxy defaults
2020-11-20 23:58:45 +00:00
connectMeshGatewayWANFederationEnabled := boolVal ( c . Connect . MeshGatewayWANFederationEnabled )
2020-03-09 20:59:02 +00:00
if connectMeshGatewayWANFederationEnabled && ! connectEnabled {
return RuntimeConfig { } , fmt . Errorf ( "'connect.enable_mesh_gateway_wan_federation=true' requires 'connect.enabled=true'" )
}
2018-06-12 12:25:08 +00:00
if connectCAConfig != nil {
2020-05-14 21:02:52 +00:00
// nolint: staticcheck // CA config should be changed to use HookTranslateKeys
2019-04-30 22:19:19 +00:00
lib . TranslateKeys ( connectCAConfig , map [ string ] string {
2018-06-13 08:40:03 +00:00
// Consul CA config
2020-01-17 22:27:13 +00:00
"private_key" : "PrivateKey" ,
"root_cert" : "RootCert" ,
"intermediate_cert_ttl" : "IntermediateCertTTL" ,
2018-06-13 08:40:03 +00:00
// Vault CA config
2022-05-05 02:41:55 +00:00
"address" : "Address" ,
"token" : "Token" ,
"root_pki_path" : "RootPKIPath" ,
"root_pki_namespace" : "RootPKINamespace" ,
"intermediate_pki_path" : "IntermediatePKIPath" ,
"intermediate_pki_namespace" : "IntermediatePKINamespace" ,
"ca_file" : "CAFile" ,
"ca_path" : "CAPath" ,
"cert_file" : "CertFile" ,
"key_file" : "KeyFile" ,
"tls_server_name" : "TLSServerName" ,
"tls_skip_verify" : "TLSSkipVerify" ,
2018-07-16 09:46:10 +00:00
2019-11-21 17:40:29 +00:00
// AWS CA config
"existing_arn" : "ExistingARN" ,
"delete_on_exit" : "DeleteOnExit" ,
2018-07-16 09:46:10 +00:00
// Common CA config
2019-01-22 17:19:36 +00:00
"leaf_cert_ttl" : "LeafCertTTL" ,
"csr_max_per_second" : "CSRMaxPerSecond" ,
"csr_max_concurrent" : "CSRMaxConcurrent" ,
2019-07-30 21:47:39 +00:00
"private_key_type" : "PrivateKeyType" ,
"private_key_bits" : "PrivateKeyBits" ,
2021-11-02 18:02:10 +00:00
"root_cert_ttl" : "RootCertTTL" ,
2018-06-12 12:25:08 +00:00
} )
2018-04-25 18:34:08 +00:00
}
2018-04-16 15:00:20 +00:00
2018-10-19 16:04:07 +00:00
aclsEnabled := false
2020-11-20 23:58:45 +00:00
primaryDatacenter := strings . ToLower ( stringVal ( c . PrimaryDatacenter ) )
2018-10-19 16:04:07 +00:00
if c . ACL . Enabled != nil {
2020-11-20 23:58:45 +00:00
aclsEnabled = boolVal ( c . ACL . Enabled )
2018-10-19 16:04:07 +00:00
}
2020-01-23 15:59:31 +00:00
// Set the primary DC if it wasn't set.
if primaryDatacenter == "" {
primaryDatacenter = datacenter
2018-10-19 16:04:07 +00:00
}
2020-11-20 23:58:45 +00:00
enableRemoteScriptChecks := boolVal ( c . EnableScriptChecks )
enableLocalScriptChecks := boolValWithDefault ( c . EnableLocalScriptChecks , enableRemoteScriptChecks )
2018-10-11 12:22:11 +00:00
2019-04-26 18:25:03 +00:00
var configEntries [ ] structs . ConfigEntry
2019-04-30 14:13:59 +00:00
if len ( c . ConfigEntries . Bootstrap ) > 0 {
for i , rawEntry := range c . ConfigEntries . Bootstrap {
entry , err := structs . DecodeConfigEntry ( rawEntry )
if err != nil {
return RuntimeConfig { } , fmt . Errorf ( "config_entries.bootstrap[%d]: %s" , i , err )
2019-04-26 18:25:03 +00:00
}
2020-08-27 16:37:25 +00:00
if err := entry . Normalize ( ) ; err != nil {
return RuntimeConfig { } , fmt . Errorf ( "config_entries.bootstrap[%d]: %s" , i , err )
}
2019-04-30 14:13:59 +00:00
if err := entry . Validate ( ) ; err != nil {
2021-09-14 17:08:06 +00:00
return RuntimeConfig { } , fmt . Errorf ( "config_entries.bootstrap[%d]: %w" , i , err )
2019-04-30 14:13:59 +00:00
}
configEntries = append ( configEntries , entry )
2019-04-26 18:25:03 +00:00
}
}
2020-05-20 09:31:19 +00:00
serfAllowedCIDRSLAN , err := memberlist . ParseCIDRs ( c . SerfAllowedCIDRsLAN )
if err != nil {
return RuntimeConfig { } , fmt . Errorf ( "serf_lan_allowed_cidrs: %s" , err )
}
serfAllowedCIDRSWAN , err := memberlist . ParseCIDRs ( c . SerfAllowedCIDRsWAN )
if err != nil {
return RuntimeConfig { } , fmt . Errorf ( "serf_wan_allowed_cidrs: %s" , err )
}
2020-09-10 16:25:56 +00:00
// Handle Deprecated UI config fields
if c . UI != nil {
b . warn ( "The 'ui' field is deprecated. Use the 'ui_config.enabled' field instead." )
if c . UIConfig . Enabled == nil {
c . UIConfig . Enabled = c . UI
}
}
if c . UIDir != nil {
b . warn ( "The 'ui_dir' field is deprecated. Use the 'ui_config.dir' field instead." )
if c . UIConfig . Dir == nil {
c . UIConfig . Dir = c . UIDir
}
}
if c . UIContentPath != nil {
b . warn ( "The 'ui_content_path' field is deprecated. Use the 'ui_config.content_path' field instead." )
if c . UIConfig . ContentPath == nil {
c . UIConfig . ContentPath = c . UIContentPath
}
}
2021-02-11 19:04:33 +00:00
serverMode := boolVal ( c . ServerMode )
2017-09-25 18:40:42 +00:00
// ----------------------------------------------------------------
// build runtime config
//
2020-11-20 23:58:45 +00:00
dataDir := stringVal ( c . DataDir )
2017-09-25 18:40:42 +00:00
rt = RuntimeConfig {
// non-user configurable values
AEInterval : b . durationVal ( "ae_interval" , c . AEInterval ) ,
CheckDeregisterIntervalMin : b . durationVal ( "check_deregister_interval_min" , c . CheckDeregisterIntervalMin ) ,
CheckReapInterval : b . durationVal ( "check_reap_interval" , c . CheckReapInterval ) ,
2020-11-20 23:58:45 +00:00
Revision : stringVal ( c . Revision ) ,
SegmentNameLimit : intVal ( c . SegmentNameLimit ) ,
2017-09-25 18:40:42 +00:00
SyncCoordinateIntervalMin : b . durationVal ( "sync_coordinate_interval_min" , c . SyncCoordinateIntervalMin ) ,
2020-11-20 23:58:45 +00:00
SyncCoordinateRateTarget : float64Val ( c . SyncCoordinateRateTarget ) ,
Version : stringVal ( c . Version ) ,
VersionPrerelease : stringVal ( c . VersionPrerelease ) ,
2022-05-05 02:16:18 +00:00
VersionMetadata : stringVal ( c . VersionMetadata ) ,
2022-06-02 02:37:47 +00:00
// What is a sensible default for BuildDate?
2022-06-09 22:55:11 +00:00
BuildDate : timeValWithDefault ( c . BuildDate , time . Date ( 1970 , 1 , 00 , 00 , 00 , 01 , 0 , time . UTC ) ) ,
2017-09-25 18:40:42 +00:00
// consul configuration
2020-11-20 23:58:45 +00:00
ConsulCoordinateUpdateBatchSize : intVal ( c . Consul . Coordinate . UpdateBatchSize ) ,
ConsulCoordinateUpdateMaxBatches : intVal ( c . Consul . Coordinate . UpdateMaxBatches ) ,
2017-09-25 18:40:42 +00:00
ConsulCoordinateUpdatePeriod : b . durationVal ( "consul.coordinate.update_period" , c . Consul . Coordinate . UpdatePeriod ) ,
ConsulRaftElectionTimeout : consulRaftElectionTimeout ,
ConsulRaftHeartbeatTimeout : consulRaftHeartbeatTimeout ,
ConsulRaftLeaderLeaseTimeout : consulRaftLeaderLeaseTimeout ,
ConsulServerHealthInterval : b . durationVal ( "consul.server.health_interval" , c . Consul . Server . HealthInterval ) ,
2018-07-26 15:39:49 +00:00
// gossip configuration
GossipLANGossipInterval : b . durationVal ( "gossip_lan..gossip_interval" , c . GossipLAN . GossipInterval ) ,
2020-11-20 23:58:45 +00:00
GossipLANGossipNodes : intVal ( c . GossipLAN . GossipNodes ) ,
2018-07-26 15:39:49 +00:00
GossipLANProbeInterval : b . durationVal ( "gossip_lan..probe_interval" , c . GossipLAN . ProbeInterval ) ,
GossipLANProbeTimeout : b . durationVal ( "gossip_lan..probe_timeout" , c . GossipLAN . ProbeTimeout ) ,
2020-11-20 23:58:45 +00:00
GossipLANSuspicionMult : intVal ( c . GossipLAN . SuspicionMult ) ,
GossipLANRetransmitMult : intVal ( c . GossipLAN . RetransmitMult ) ,
2018-07-26 15:39:49 +00:00
GossipWANGossipInterval : b . durationVal ( "gossip_wan..gossip_interval" , c . GossipWAN . GossipInterval ) ,
2020-11-20 23:58:45 +00:00
GossipWANGossipNodes : intVal ( c . GossipWAN . GossipNodes ) ,
2018-07-26 15:39:49 +00:00
GossipWANProbeInterval : b . durationVal ( "gossip_wan..probe_interval" , c . GossipWAN . ProbeInterval ) ,
GossipWANProbeTimeout : b . durationVal ( "gossip_wan..probe_timeout" , c . GossipWAN . ProbeTimeout ) ,
2020-11-20 23:58:45 +00:00
GossipWANSuspicionMult : intVal ( c . GossipWAN . SuspicionMult ) ,
GossipWANRetransmitMult : intVal ( c . GossipWAN . RetransmitMult ) ,
2018-07-26 15:39:49 +00:00
2017-09-25 18:40:42 +00:00
// ACL
2021-08-06 22:59:05 +00:00
ACLsEnabled : aclsEnabled ,
ACLResolverSettings : consul . ACLResolverSettings {
ACLsEnabled : aclsEnabled ,
Datacenter : datacenter ,
NodeName : b . nodeName ( c . NodeName ) ,
ACLPolicyTTL : b . durationVal ( "acl.policy_ttl" , c . ACL . PolicyTTL ) ,
2021-09-22 17:38:40 +00:00
ACLTokenTTL : b . durationVal ( "acl.token_ttl" , c . ACL . TokenTTL ) ,
2021-08-06 22:59:05 +00:00
ACLRoleTTL : b . durationVal ( "acl.role_ttl" , c . ACL . RoleTTL ) ,
2021-09-03 22:00:28 +00:00
ACLDownPolicy : stringVal ( c . ACL . DownPolicy ) ,
ACLDefaultPolicy : stringVal ( c . ACL . DefaultPolicy ) ,
2021-08-06 22:59:05 +00:00
} ,
2021-12-07 12:39:28 +00:00
ACLEnableKeyListPolicy : boolVal ( c . ACL . EnableKeyListPolicy ) ,
ACLInitialManagementToken : stringVal ( c . ACL . Tokens . InitialManagement ) ,
2021-08-06 22:59:05 +00:00
2021-09-03 21:42:52 +00:00
ACLTokenReplication : boolVal ( c . ACL . TokenReplication ) ,
2020-08-25 04:10:12 +00:00
ACLTokens : token . Config {
2021-12-07 12:12:47 +00:00
DataDir : dataDir ,
EnablePersistence : boolValWithDefault ( c . ACL . EnableTokenPersistence , false ) ,
ACLDefaultToken : stringVal ( c . ACL . Tokens . Default ) ,
ACLAgentToken : stringVal ( c . ACL . Tokens . Agent ) ,
ACLAgentRecoveryToken : stringVal ( c . ACL . Tokens . AgentRecovery ) ,
ACLReplicationToken : stringVal ( c . ACL . Tokens . Replication ) ,
2020-08-25 04:10:12 +00:00
} ,
2017-09-25 18:40:42 +00:00
// Autopilot
2020-11-20 23:58:45 +00:00
AutopilotCleanupDeadServers : boolVal ( c . Autopilot . CleanupDeadServers ) ,
AutopilotDisableUpgradeMigration : boolVal ( c . Autopilot . DisableUpgradeMigration ) ,
2017-09-25 18:40:42 +00:00
AutopilotLastContactThreshold : b . durationVal ( "autopilot.last_contact_threshold" , c . Autopilot . LastContactThreshold ) ,
2020-11-20 23:58:45 +00:00
AutopilotMaxTrailingLogs : intVal ( c . Autopilot . MaxTrailingLogs ) ,
AutopilotMinQuorum : uintVal ( c . Autopilot . MinQuorum ) ,
AutopilotRedundancyZoneTag : stringVal ( c . Autopilot . RedundancyZoneTag ) ,
2017-09-25 18:40:42 +00:00
AutopilotServerStabilizationTime : b . durationVal ( "autopilot.server_stabilization_time" , c . Autopilot . ServerStabilizationTime ) ,
2020-11-20 23:58:45 +00:00
AutopilotUpgradeVersionTag : stringVal ( c . Autopilot . UpgradeVersionTag ) ,
2017-09-25 18:40:42 +00:00
// DNS
DNSAddrs : dnsAddrs ,
2020-11-20 23:58:45 +00:00
DNSAllowStale : boolVal ( c . DNS . AllowStale ) ,
DNSARecordLimit : intVal ( c . DNS . ARecordLimit ) ,
DNSDisableCompression : boolVal ( c . DNS . DisableCompression ) ,
DNSDomain : stringVal ( c . DNSDomain ) ,
2019-06-27 10:00:37 +00:00
DNSAltDomain : altDomain ,
2020-11-20 23:58:45 +00:00
DNSEnableTruncate : boolVal ( c . DNS . EnableTruncate ) ,
2017-09-25 18:40:42 +00:00
DNSMaxStale : b . durationVal ( "dns_config.max_stale" , c . DNS . MaxStale ) ,
DNSNodeTTL : b . durationVal ( "dns_config.node_ttl" , c . DNS . NodeTTL ) ,
2020-11-20 23:58:45 +00:00
DNSOnlyPassing : boolVal ( c . DNS . OnlyPassing ) ,
2017-09-25 18:40:42 +00:00
DNSPort : dnsPort ,
2021-07-19 22:22:51 +00:00
DNSRecursorStrategy : b . dnsRecursorStrategyVal ( stringVal ( c . DNS . RecursorStrategy ) ) ,
2017-09-25 18:40:42 +00:00
DNSRecursorTimeout : b . durationVal ( "recursor_timeout" , c . DNS . RecursorTimeout ) ,
2017-10-20 13:36:52 +00:00
DNSRecursors : dnsRecursors ,
2017-09-25 18:40:42 +00:00
DNSServiceTTL : dnsServiceTTL ,
Added SOA configuration for DNS settings. (#4714)
This will allow to fine TUNE SOA settings sent by Consul in DNS responses,
for instance to be able to control negative ttl.
Will fix: https://github.com/hashicorp/consul/issues/4713
# Example
Override all settings:
* min_ttl: 0 => 60s
* retry: 600 (10m) => 300s (5 minutes),
* expire: 86400 (24h) => 43200 (12h)
* refresh: 3600 (1h) => 1800 (30 minutes)
```
consul agent -dev -hcl 'dns_config={soa={min_ttl=60,retry=300,expire=43200,refresh=1800}}'
```
Result:
```
dig +multiline @localhost -p 8600 service.consul
; <<>> DiG 9.12.1 <<>> +multiline @localhost -p 8600 service.consul
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 36557
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;service.consul. IN A
;; AUTHORITY SECTION:
consul. 0 IN SOA ns.consul. hostmaster.consul. (
1537959133 ; serial
1800 ; refresh (30 minutes)
300 ; retry (5 minutes)
43200 ; expire (12 hours)
60 ; minimum (1 minute)
)
;; Query time: 4 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Wed Sep 26 12:52:13 CEST 2018
;; MSG SIZE rcvd: 93
```
2018-10-10 19:50:56 +00:00
DNSSOA : soa ,
2020-11-20 23:58:45 +00:00
DNSUDPAnswerLimit : intVal ( c . DNS . UDPAnswerLimit ) ,
DNSNodeMetaTXT : boolValWithDefault ( c . DNS . NodeMetaTXT , true ) ,
DNSUseCache : boolVal ( c . DNS . UseCache ) ,
2019-02-25 19:06:01 +00:00
DNSCacheMaxAge : b . durationVal ( "dns_config.cache_max_age" , c . DNS . CacheMaxAge ) ,
2017-09-25 18:40:42 +00:00
// HTTP
HTTPPort : httpPort ,
HTTPSPort : httpsPort ,
HTTPAddrs : httpAddrs ,
HTTPSAddrs : httpsAddrs ,
HTTPBlockEndpoints : c . HTTPConfig . BlockEndpoints ,
2020-11-20 23:58:45 +00:00
HTTPMaxHeaderBytes : intVal ( c . HTTPConfig . MaxHeaderBytes ) ,
2017-09-25 18:40:42 +00:00
HTTPResponseHeaders : c . HTTPConfig . ResponseHeaders ,
2019-01-10 14:27:26 +00:00
AllowWriteHTTPFrom : b . cidrsVal ( "allow_write_http_from" , c . HTTPConfig . AllowWriteHTTPFrom ) ,
2020-11-20 23:58:45 +00:00
HTTPUseCache : boolValWithDefault ( c . HTTPConfig . UseCache , true ) ,
2017-09-25 18:40:42 +00:00
// Telemetry
2018-06-14 12:52:48 +00:00
Telemetry : lib . TelemetryConfig {
2020-11-20 23:58:45 +00:00
CirconusAPIApp : stringVal ( c . Telemetry . CirconusAPIApp ) ,
CirconusAPIToken : stringVal ( c . Telemetry . CirconusAPIToken ) ,
CirconusAPIURL : stringVal ( c . Telemetry . CirconusAPIURL ) ,
CirconusBrokerID : stringVal ( c . Telemetry . CirconusBrokerID ) ,
CirconusBrokerSelectTag : stringVal ( c . Telemetry . CirconusBrokerSelectTag ) ,
CirconusCheckDisplayName : stringVal ( c . Telemetry . CirconusCheckDisplayName ) ,
CirconusCheckForceMetricActivation : stringVal ( c . Telemetry . CirconusCheckForceMetricActivation ) ,
CirconusCheckID : stringVal ( c . Telemetry . CirconusCheckID ) ,
CirconusCheckInstanceID : stringVal ( c . Telemetry . CirconusCheckInstanceID ) ,
CirconusCheckSearchTag : stringVal ( c . Telemetry . CirconusCheckSearchTag ) ,
CirconusCheckTags : stringVal ( c . Telemetry . CirconusCheckTags ) ,
CirconusSubmissionInterval : stringVal ( c . Telemetry . CirconusSubmissionInterval ) ,
CirconusSubmissionURL : stringVal ( c . Telemetry . CirconusSubmissionURL ) ,
DisableHostname : boolVal ( c . Telemetry . DisableHostname ) ,
DogstatsdAddr : stringVal ( c . Telemetry . DogstatsdAddr ) ,
2018-06-14 12:52:48 +00:00
DogstatsdTags : c . Telemetry . DogstatsdTags ,
2022-05-19 20:03:46 +00:00
RetryFailedConfiguration : boolVal ( c . Telemetry . RetryFailedConfiguration ) ,
2020-11-20 23:58:45 +00:00
FilterDefault : boolVal ( c . Telemetry . FilterDefault ) ,
2018-06-14 12:52:48 +00:00
AllowedPrefixes : telemetryAllowedPrefixes ,
BlockedPrefixes : telemetryBlockedPrefixes ,
2020-11-20 23:58:45 +00:00
MetricsPrefix : stringVal ( c . Telemetry . MetricsPrefix ) ,
StatsdAddr : stringVal ( c . Telemetry . StatsdAddr ) ,
StatsiteAddr : stringVal ( c . Telemetry . StatsiteAddr ) ,
2020-11-16 20:44:47 +00:00
PrometheusOpts : prometheus . PrometheusOpts {
Expiration : b . durationVal ( "prometheus_retention_time" , c . Telemetry . PrometheusRetentionTime ) ,
2021-10-21 20:33:01 +00:00
Name : stringVal ( c . Telemetry . MetricsPrefix ) ,
2020-11-16 20:44:47 +00:00
} ,
2018-06-14 12:52:48 +00:00
} ,
2017-09-25 18:40:42 +00:00
// Agent
2020-10-08 19:02:19 +00:00
AdvertiseAddrLAN : advertiseAddrLAN ,
AdvertiseAddrWAN : advertiseAddrWAN ,
AdvertiseReconnectTimeout : b . durationVal ( "advertise_reconnect_timeout" , c . AdvertiseReconnectTimeout ) ,
BindAddr : bindAddr ,
2020-11-20 23:58:45 +00:00
Bootstrap : boolVal ( c . Bootstrap ) ,
BootstrapExpect : intVal ( c . BootstrapExpect ) ,
2020-07-27 21:11:11 +00:00
Cache : cache . Options {
EntryFetchRate : rate . Limit (
2020-11-20 23:58:45 +00:00
float64ValWithDefault ( c . Cache . EntryFetchRate , float64 ( cache . DefaultEntryFetchRate ) ) ,
2020-07-28 16:24:30 +00:00
) ,
2020-11-20 23:58:45 +00:00
EntryFetchMaxBurst : intValWithDefault (
2020-07-28 16:24:30 +00:00
c . Cache . EntryFetchMaxBurst , cache . DefaultEntryFetchMaxBurst ,
) ,
2020-07-27 21:11:11 +00:00
} ,
2022-03-31 19:11:49 +00:00
AutoReloadConfig : boolVal ( c . AutoReloadConfig ) ,
2020-03-09 20:59:02 +00:00
CheckUpdateInterval : b . durationVal ( "check_update_interval" , c . CheckUpdateInterval ) ,
2020-11-20 23:58:45 +00:00
CheckOutputMaxSize : intValWithDefault ( c . CheckOutputMaxSize , 4096 ) ,
2020-03-09 20:59:02 +00:00
Checks : checks ,
ClientAddrs : clientAddrs ,
ConfigEntryBootstrap : configEntries ,
2021-06-17 19:41:01 +00:00
AutoEncryptTLS : boolVal ( c . AutoEncrypt . TLS ) ,
2020-03-09 20:59:02 +00:00
AutoEncryptDNSSAN : autoEncryptDNSSAN ,
AutoEncryptIPSAN : autoEncryptIPSAN ,
AutoEncryptAllowTLS : autoEncryptAllowTLS ,
2020-08-07 10:02:02 +00:00
AutoConfig : autoConfig ,
2022-09-26 18:58:15 +00:00
Cloud : b . cloudConfigVal ( c . Cloud ) ,
2020-03-09 20:59:02 +00:00
ConnectEnabled : connectEnabled ,
ConnectCAProvider : connectCAProvider ,
ConnectCAConfig : connectCAConfig ,
ConnectMeshGatewayWANFederationEnabled : connectMeshGatewayWANFederationEnabled ,
2022-03-08 18:37:56 +00:00
ConnectServerlessPluginEnabled : serverlessPluginEnabled ,
2020-03-09 20:59:02 +00:00
ConnectSidecarMinPort : sidecarMinPort ,
ConnectSidecarMaxPort : sidecarMaxPort ,
2020-06-10 20:47:35 +00:00
ConnectTestCALeafRootChangeSpread : b . durationVal ( "connect.test_ca_leaf_root_change_spread" , c . Connect . TestCALeafRootChangeSpread ) ,
2020-03-09 20:59:02 +00:00
ExposeMinPort : exposeMinPort ,
ExposeMaxPort : exposeMaxPort ,
2020-08-25 04:10:12 +00:00
DataDir : dataDir ,
2020-03-09 20:59:02 +00:00
Datacenter : datacenter ,
DefaultQueryTime : b . durationVal ( "default_query_time" , c . DefaultQueryTime ) ,
2020-11-20 23:58:45 +00:00
DevMode : boolVal ( b . opts . DevMode ) ,
DisableAnonymousSignature : boolVal ( c . DisableAnonymousSignature ) ,
DisableCoordinates : boolVal ( c . DisableCoordinates ) ,
DisableHostNodeID : boolVal ( c . DisableHostNodeID ) ,
DisableHTTPUnprintableCharFilter : boolVal ( c . DisableHTTPUnprintableCharFilter ) ,
DisableKeyringFile : boolVal ( c . DisableKeyringFile ) ,
DisableRemoteExec : boolVal ( c . DisableRemoteExec ) ,
DisableUpdateCheck : boolVal ( c . DisableUpdateCheck ) ,
DiscardCheckOutput : boolVal ( c . DiscardCheckOutput ) ,
DiscoveryMaxStale : b . durationVal ( "discovery_max_stale" , c . DiscoveryMaxStale ) ,
EnableAgentTLSForChecks : boolVal ( c . EnableAgentTLSForChecks ) ,
EnableCentralServiceConfig : boolVal ( c . EnableCentralServiceConfig ) ,
EnableDebug : boolVal ( c . EnableDebug ) ,
EnableRemoteScriptChecks : enableRemoteScriptChecks ,
EnableLocalScriptChecks : enableLocalScriptChecks ,
EncryptKey : stringVal ( c . EncryptKey ) ,
2021-09-08 15:48:41 +00:00
GRPCAddrs : grpcAddrs ,
2022-08-19 17:07:22 +00:00
GRPCPort : grpcPort ,
GRPCTLSAddrs : grpcTlsAddrs ,
GRPCTLSPort : grpcTlsPort ,
2020-11-20 23:58:45 +00:00
HTTPMaxConnsPerClient : intVal ( c . Limits . HTTPMaxConnsPerClient ) ,
HTTPSHandshakeTimeout : b . durationVal ( "limits.https_handshake_timeout" , c . Limits . HTTPSHandshakeTimeout ) ,
KVMaxValueSize : uint64Val ( c . Limits . KVMaxValueSize ) ,
LeaveDrainTime : b . durationVal ( "performance.leave_drain_time" , c . Performance . LeaveDrainTime ) ,
LeaveOnTerm : leaveOnTerm ,
2022-03-31 19:11:49 +00:00
StaticRuntimeConfig : StaticRuntimeConfig {
EncryptVerifyIncoming : boolVal ( c . EncryptVerifyIncoming ) ,
EncryptVerifyOutgoing : boolVal ( c . EncryptVerifyOutgoing ) ,
} ,
2020-08-19 17:17:05 +00:00
Logging : logging . Config {
2020-11-20 23:58:45 +00:00
LogLevel : stringVal ( c . LogLevel ) ,
LogJSON : boolVal ( c . LogJSON ) ,
LogFilePath : stringVal ( c . LogFile ) ,
EnableSyslog : boolVal ( c . EnableSyslog ) ,
SyslogFacility : stringVal ( c . SyslogFacility ) ,
2020-08-19 17:17:05 +00:00
LogRotateDuration : b . durationVal ( "log_rotate_duration" , c . LogRotateDuration ) ,
2020-11-20 23:58:45 +00:00
LogRotateBytes : intVal ( c . LogRotateBytes ) ,
LogRotateMaxFiles : intVal ( c . LogRotateMaxFiles ) ,
2020-08-19 17:17:05 +00:00
} ,
2022-07-29 21:36:22 +00:00
MaxQueryTime : b . durationVal ( "max_query_time" , c . MaxQueryTime ) ,
NodeID : types . NodeID ( stringVal ( c . NodeID ) ) ,
NodeMeta : c . NodeMeta ,
NodeName : b . nodeName ( c . NodeName ) ,
ReadReplica : boolVal ( c . ReadReplica ) ,
PeeringEnabled : boolVal ( c . Peering . Enabled ) ,
PeeringTestAllowPeerRegistrations : boolValWithDefault ( c . Peering . TestAllowPeerRegistrations , false ) ,
PidFile : stringVal ( c . PidFile ) ,
PrimaryDatacenter : primaryDatacenter ,
PrimaryGateways : b . expandAllOptionalAddrs ( "primary_gateways" , c . PrimaryGateways ) ,
PrimaryGatewaysInterval : b . durationVal ( "primary_gateways_interval" , c . PrimaryGatewaysInterval ) ,
RPCAdvertiseAddr : rpcAdvertiseAddr ,
RPCBindAddr : rpcBindAddr ,
RPCHandshakeTimeout : b . durationVal ( "limits.rpc_handshake_timeout" , c . Limits . RPCHandshakeTimeout ) ,
RPCHoldTimeout : b . durationVal ( "performance.rpc_hold_timeout" , c . Performance . RPCHoldTimeout ) ,
2022-10-18 19:05:09 +00:00
RPCClientTimeout : b . durationVal ( "limits.rpc_client_timeout" , c . Limits . RPCClientTimeout ) ,
2022-07-29 21:36:22 +00:00
RPCMaxBurst : intVal ( c . Limits . RPCMaxBurst ) ,
RPCMaxConnsPerClient : intVal ( c . Limits . RPCMaxConnsPerClient ) ,
RPCProtocol : intVal ( c . RPCProtocol ) ,
RPCRateLimit : rate . Limit ( float64Val ( c . Limits . RPCRate ) ) ,
RPCConfig : consul . RPCConfig { EnableStreaming : boolValWithDefault ( c . RPC . EnableStreaming , serverMode ) } ,
RaftProtocol : intVal ( c . RaftProtocol ) ,
RaftSnapshotThreshold : intVal ( c . RaftSnapshotThreshold ) ,
RaftSnapshotInterval : b . durationVal ( "raft_snapshot_interval" , c . RaftSnapshotInterval ) ,
RaftTrailingLogs : intVal ( c . RaftTrailingLogs ) ,
ReconnectTimeoutLAN : b . durationVal ( "reconnect_timeout" , c . ReconnectTimeoutLAN ) ,
ReconnectTimeoutWAN : b . durationVal ( "reconnect_timeout_wan" , c . ReconnectTimeoutWAN ) ,
RejoinAfterLeave : boolVal ( c . RejoinAfterLeave ) ,
RetryJoinIntervalLAN : b . durationVal ( "retry_interval" , c . RetryJoinIntervalLAN ) ,
RetryJoinIntervalWAN : b . durationVal ( "retry_interval_wan" , c . RetryJoinIntervalWAN ) ,
RetryJoinLAN : b . expandAllOptionalAddrs ( "retry_join" , c . RetryJoinLAN ) ,
RetryJoinMaxAttemptsLAN : intVal ( c . RetryJoinMaxAttemptsLAN ) ,
RetryJoinMaxAttemptsWAN : intVal ( c . RetryJoinMaxAttemptsWAN ) ,
RetryJoinWAN : b . expandAllOptionalAddrs ( "retry_join_wan" , c . RetryJoinWAN ) ,
SegmentName : stringVal ( c . SegmentName ) ,
Segments : segments ,
SegmentLimit : intVal ( c . SegmentLimit ) ,
SerfAdvertiseAddrLAN : serfAdvertiseAddrLAN ,
SerfAdvertiseAddrWAN : serfAdvertiseAddrWAN ,
SerfAllowedCIDRsLAN : serfAllowedCIDRSLAN ,
SerfAllowedCIDRsWAN : serfAllowedCIDRSWAN ,
SerfBindAddrLAN : serfBindAddrLAN ,
SerfBindAddrWAN : serfBindAddrWAN ,
SerfPortLAN : serfPortLAN ,
SerfPortWAN : serfPortWAN ,
ServerMode : serverMode ,
ServerName : stringVal ( c . ServerName ) ,
ServerPort : serverPort ,
Services : services ,
SessionTTLMin : b . durationVal ( "session_ttl_min" , c . SessionTTLMin ) ,
SkipLeaveOnInt : skipLeaveOnInt ,
StartJoinAddrsLAN : b . expandAllOptionalAddrs ( "start_join" , c . StartJoinAddrsLAN ) ,
StartJoinAddrsWAN : b . expandAllOptionalAddrs ( "start_join_wan" , c . StartJoinAddrsWAN ) ,
TaggedAddresses : c . TaggedAddresses ,
TranslateWANAddrs : boolVal ( c . TranslateWANAddrs ) ,
TxnMaxReqLen : uint64Val ( c . Limits . TxnMaxReqLen ) ,
UIConfig : b . uiConfigVal ( c . UIConfig ) ,
UnixSocketGroup : stringVal ( c . UnixSocket . Group ) ,
UnixSocketMode : stringVal ( c . UnixSocket . Mode ) ,
UnixSocketUser : stringVal ( c . UnixSocket . User ) ,
Watches : c . Watches ,
2022-10-14 14:52:00 +00:00
XDSUpdateRateLimit : rate . Limit ( float64Val ( c . XDS . UpdateMaxPerSecond ) ) ,
2022-07-29 21:36:22 +00:00
AutoReloadConfigCoalesceInterval : 1 * time . Second ,
2022-03-18 10:46:58 +00:00
}
rt . TLS , err = b . buildTLSConfig ( rt , c . TLS )
if err != nil {
return RuntimeConfig { } , err
2017-09-25 18:40:42 +00:00
}
2022-11-11 20:29:22 +00:00
// `ports.grpc` previously supported TLS, but this was changed for Consul 1.14.
// This check is done to warn users that a config change is mandatory.
if rt . TLS . GRPC . CertFile != "" || ( rt . TLS . AutoTLS && rt . TLS . GRPC . UseAutoCert ) {
// If only `ports.grpc` is enabled, and the gRPC TLS port is not explicitly defined by the user,
// check the grpc TLS settings for incompatibilities.
if rt . GRPCPort > 0 && c . Ports . GRPCTLS == nil {
return RuntimeConfig { } , fmt . Errorf ( "the `ports.grpc` listener no longer supports TLS. Use `ports.grpc_tls` instead. This message is appearing because GRPC is configured to use TLS, but `ports.grpc_tls` is not defined" )
}
}
2021-04-28 22:56:34 +00:00
rt . UseStreamingBackend = boolValWithDefault ( c . UseStreamingBackend , true )
2020-10-05 21:31:35 +00:00
2021-11-17 23:15:19 +00:00
if c . RaftBoltDBConfig != nil {
rt . RaftBoltDBConfig = * c . RaftBoltDBConfig
}
2020-07-27 21:11:11 +00:00
if rt . Cache . EntryFetchMaxBurst <= 0 {
return RuntimeConfig { } , fmt . Errorf ( "cache.entry_fetch_max_burst must be strictly positive, was: %v" , rt . Cache . EntryFetchMaxBurst )
}
if rt . Cache . EntryFetchRate <= 0 {
return RuntimeConfig { } , fmt . Errorf ( "cache.entry_fetch_rate must be strictly positive, was: %v" , rt . Cache . EntryFetchRate )
}
2020-10-30 21:49:54 +00:00
if rt . UIConfig . MetricsProvider == "prometheus" {
// Handle defaulting for the built-in version of prometheus.
if len ( rt . UIConfig . MetricsProxy . PathAllowlist ) == 0 {
rt . UIConfig . MetricsProxy . PathAllowlist = [ ] string {
"/api/v1/query" ,
"/api/v1/query_range" ,
}
}
}
2020-08-27 17:15:10 +00:00
if err := b . BuildEnterpriseRuntimeConfig ( & rt , & c ) ; err != nil {
return rt , err
2019-12-10 02:26:41 +00:00
}
2017-09-25 18:40:42 +00:00
if rt . BootstrapExpect == 1 {
rt . Bootstrap = true
rt . BootstrapExpect = 0
b . warn ( ` BootstrapExpect is set to 1; this is the same as Bootstrap mode. ` )
}
return rt , nil
}
2020-12-21 22:51:44 +00:00
func advertiseAddrFunc ( opts LoadOpts , advertiseAddr * net . IPAddr ) ( string , func ( ) ( [ ] * net . IPAddr , error ) ) {
switch {
case ipaddr . IsAnyV4 ( advertiseAddr ) :
fn := opts . getPrivateIPv4
if fn == nil {
fn = ipaddr . GetPrivateIPv4
}
return "private IPv4" , fn
case ipaddr . IsAnyV6 ( advertiseAddr ) :
fn := opts . getPublicIPv6
if fn == nil {
fn = ipaddr . GetPublicIPv6
}
return "public IPv6" , fn
default :
panic ( "unsupported net.IPAddr Type" )
}
}
2020-09-17 10:48:14 +00:00
// reBasicName validates that a field contains only lower case alphanumerics,
// underscore and dash and is non-empty.
var reBasicName = regexp . MustCompile ( "^[a-z0-9_-]+$" )
func validateBasicName ( field , value string , allowEmpty bool ) error {
if value == "" {
if allowEmpty {
return nil
}
return fmt . Errorf ( "%s cannot be empty" , field )
}
if ! reBasicName . MatchString ( value ) {
return fmt . Errorf ( "%s can only contain lowercase alphanumeric, - or _ characters." +
" received: %q" , field , value )
}
return nil
}
2021-07-06 22:22:59 +00:00
// validate performs semantic validation of the runtime configuration.
func ( b * builder ) validate ( rt RuntimeConfig ) error {
ui: modify content path (#5950)
* Add ui-content-path flag
* tests complete, regex validator on string, index.html updated
* cleaning up debugging stuff
* ui: Enable ember environment configuration to be set via the go binary at runtime (#5934)
* ui: Only inject {{.ContentPath}} if we are makeing a prod build...
...otherwise we just use the current rootURL
This gets injected into a <base /> node which solves the assets path
problem but not the ember problem
* ui: Pull out the <base href=""> value and inject it into ember env
See previous commit:
The <base href=""> value is 'sometimes' injected from go at index
serve time. We pass this value down to ember by overwriting the ember
config that is injected via a <meta> tag. This has to be done before
ember bootup.
Sometimes (during testing and development, basically not production)
this is injected with the already existing value, in which case this
essentially changes nothing.
The code here is slightly abstracted away from our specific usage to
make it easier for anyone else to use, and also make sure we can cope
with using this same method to pass variables down from the CLI through
to ember in the future.
* ui: We can't use <base /> move everything to javascript (#5941)
Unfortuantely we can't seem to be able to use <base> and rootURL
together as URL paths will get doubled up (`ui/ui/`).
This moves all the things that we need to interpolate with .ContentPath
to the `startup` javascript so we can conditionally print out
`{{.ContentPath}}` in lots of places (now we can't use base)
* fixed when we serve index.html
* ui: For writing a ContentPath, we also need to cope with testing... (#5945)
...and potentially more environments
Testing has more additional things in a separate index.html in `tests/`
This make the entire thing a little saner and uses just javascriopt
template literals instead of a pseudo handbrake synatx for our
templating of these files.
Intead of just templating the entire file this way, we still only
template `{{content-for 'head'}}` and `{{content-for 'body'}}`
in this way to ensure we support other plugins/addons
* build: Loosen up the regex for retrieving the CONSUL_VERSION (#5946)
* build: Loosen up the regex for retrieving the CONSUL_VERSION
1. Previously the `sed` replacement was searching for the CONSUL_VERSION
comment at the start of a line, it no longer does this to allow for
indentation.
2. Both `grep` and `sed` where looking for the omment at the end of the
line. We've removed this restriction here. We don't need to remove it
right now, but if we ever put the comment followed by something here the
searching would break.
3. Added `xargs` for trimming the resulting version string. We aren't
using this already in the rest of the scripts, but we are pretty sure
this is available on most systems.
* ui: Fix erroneous variable, and also force an ember cache clean on build
1. We referenced a variable incorrectly here, this fixes that.
2. We also made sure that every `make` target clears ember's `tmp` cache
to ensure that its not using any caches that have since been edited
everytime we call a `make` target.
* added docs, fixed encoding
* fixed go fmt
* Update agent/config/config.go
Co-Authored-By: R.B. Boyer <public@richardboyer.net>
* Completed Suggestions
* run gofmt on http.go
* fix testsanitize
* fix fullconfig/hcl by setting correct 'want'
* ran gofmt on agent/config/runtime_test.go
* Update website/source/docs/agent/options.html.md
Co-Authored-By: Hans Hasselberg <me@hans.io>
* Update website/source/docs/agent/options.html.md
Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com>
* remove contentpath from redirectFS struct
2019-06-26 16:43:30 +00:00
// validContentPath defines a regexp for a valid content path name.
2021-08-20 16:57:45 +00:00
validContentPath := regexp . MustCompile ( ` ^[A-Za-z0-9/_-]+$ ` )
hasVersion := regexp . MustCompile ( ` ^/v\d+/$ ` )
2017-09-25 18:40:42 +00:00
// ----------------------------------------------------------------
// check required params we cannot recover from first
//
2020-09-25 17:46:38 +00:00
if rt . RaftProtocol != 3 {
return fmt . Errorf ( "raft_protocol version %d is not supported by this version of Consul" , rt . RaftProtocol )
}
2020-09-17 10:48:14 +00:00
if err := validateBasicName ( "datacenter" , rt . Datacenter , false ) ; err != nil {
return err
2017-09-25 18:40:42 +00:00
}
if rt . DataDir == "" && ! rt . DevMode {
return fmt . Errorf ( "data_dir cannot be empty" )
}
ui: modify content path (#5950)
* Add ui-content-path flag
* tests complete, regex validator on string, index.html updated
* cleaning up debugging stuff
* ui: Enable ember environment configuration to be set via the go binary at runtime (#5934)
* ui: Only inject {{.ContentPath}} if we are makeing a prod build...
...otherwise we just use the current rootURL
This gets injected into a <base /> node which solves the assets path
problem but not the ember problem
* ui: Pull out the <base href=""> value and inject it into ember env
See previous commit:
The <base href=""> value is 'sometimes' injected from go at index
serve time. We pass this value down to ember by overwriting the ember
config that is injected via a <meta> tag. This has to be done before
ember bootup.
Sometimes (during testing and development, basically not production)
this is injected with the already existing value, in which case this
essentially changes nothing.
The code here is slightly abstracted away from our specific usage to
make it easier for anyone else to use, and also make sure we can cope
with using this same method to pass variables down from the CLI through
to ember in the future.
* ui: We can't use <base /> move everything to javascript (#5941)
Unfortuantely we can't seem to be able to use <base> and rootURL
together as URL paths will get doubled up (`ui/ui/`).
This moves all the things that we need to interpolate with .ContentPath
to the `startup` javascript so we can conditionally print out
`{{.ContentPath}}` in lots of places (now we can't use base)
* fixed when we serve index.html
* ui: For writing a ContentPath, we also need to cope with testing... (#5945)
...and potentially more environments
Testing has more additional things in a separate index.html in `tests/`
This make the entire thing a little saner and uses just javascriopt
template literals instead of a pseudo handbrake synatx for our
templating of these files.
Intead of just templating the entire file this way, we still only
template `{{content-for 'head'}}` and `{{content-for 'body'}}`
in this way to ensure we support other plugins/addons
* build: Loosen up the regex for retrieving the CONSUL_VERSION (#5946)
* build: Loosen up the regex for retrieving the CONSUL_VERSION
1. Previously the `sed` replacement was searching for the CONSUL_VERSION
comment at the start of a line, it no longer does this to allow for
indentation.
2. Both `grep` and `sed` where looking for the omment at the end of the
line. We've removed this restriction here. We don't need to remove it
right now, but if we ever put the comment followed by something here the
searching would break.
3. Added `xargs` for trimming the resulting version string. We aren't
using this already in the rest of the scripts, but we are pretty sure
this is available on most systems.
* ui: Fix erroneous variable, and also force an ember cache clean on build
1. We referenced a variable incorrectly here, this fixes that.
2. We also made sure that every `make` target clears ember's `tmp` cache
to ensure that its not using any caches that have since been edited
everytime we call a `make` target.
* added docs, fixed encoding
* fixed go fmt
* Update agent/config/config.go
Co-Authored-By: R.B. Boyer <public@richardboyer.net>
* Completed Suggestions
* run gofmt on http.go
* fix testsanitize
* fix fullconfig/hcl by setting correct 'want'
* ran gofmt on agent/config/runtime_test.go
* Update website/source/docs/agent/options.html.md
Co-Authored-By: Hans Hasselberg <me@hans.io>
* Update website/source/docs/agent/options.html.md
Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com>
* remove contentpath from redirectFS struct
2019-06-26 16:43:30 +00:00
2020-09-10 16:25:56 +00:00
if ! validContentPath . MatchString ( rt . UIConfig . ContentPath ) {
return fmt . Errorf ( "ui-content-path can only contain alphanumeric, -, _, or /. received: %q" , rt . UIConfig . ContentPath )
}
if hasVersion . MatchString ( rt . UIConfig . ContentPath ) {
return fmt . Errorf ( "ui-content-path cannot have 'v[0-9]'. received: %q" , rt . UIConfig . ContentPath )
ui: modify content path (#5950)
* Add ui-content-path flag
* tests complete, regex validator on string, index.html updated
* cleaning up debugging stuff
* ui: Enable ember environment configuration to be set via the go binary at runtime (#5934)
* ui: Only inject {{.ContentPath}} if we are makeing a prod build...
...otherwise we just use the current rootURL
This gets injected into a <base /> node which solves the assets path
problem but not the ember problem
* ui: Pull out the <base href=""> value and inject it into ember env
See previous commit:
The <base href=""> value is 'sometimes' injected from go at index
serve time. We pass this value down to ember by overwriting the ember
config that is injected via a <meta> tag. This has to be done before
ember bootup.
Sometimes (during testing and development, basically not production)
this is injected with the already existing value, in which case this
essentially changes nothing.
The code here is slightly abstracted away from our specific usage to
make it easier for anyone else to use, and also make sure we can cope
with using this same method to pass variables down from the CLI through
to ember in the future.
* ui: We can't use <base /> move everything to javascript (#5941)
Unfortuantely we can't seem to be able to use <base> and rootURL
together as URL paths will get doubled up (`ui/ui/`).
This moves all the things that we need to interpolate with .ContentPath
to the `startup` javascript so we can conditionally print out
`{{.ContentPath}}` in lots of places (now we can't use base)
* fixed when we serve index.html
* ui: For writing a ContentPath, we also need to cope with testing... (#5945)
...and potentially more environments
Testing has more additional things in a separate index.html in `tests/`
This make the entire thing a little saner and uses just javascriopt
template literals instead of a pseudo handbrake synatx for our
templating of these files.
Intead of just templating the entire file this way, we still only
template `{{content-for 'head'}}` and `{{content-for 'body'}}`
in this way to ensure we support other plugins/addons
* build: Loosen up the regex for retrieving the CONSUL_VERSION (#5946)
* build: Loosen up the regex for retrieving the CONSUL_VERSION
1. Previously the `sed` replacement was searching for the CONSUL_VERSION
comment at the start of a line, it no longer does this to allow for
indentation.
2. Both `grep` and `sed` where looking for the omment at the end of the
line. We've removed this restriction here. We don't need to remove it
right now, but if we ever put the comment followed by something here the
searching would break.
3. Added `xargs` for trimming the resulting version string. We aren't
using this already in the rest of the scripts, but we are pretty sure
this is available on most systems.
* ui: Fix erroneous variable, and also force an ember cache clean on build
1. We referenced a variable incorrectly here, this fixes that.
2. We also made sure that every `make` target clears ember's `tmp` cache
to ensure that its not using any caches that have since been edited
everytime we call a `make` target.
* added docs, fixed encoding
* fixed go fmt
* Update agent/config/config.go
Co-Authored-By: R.B. Boyer <public@richardboyer.net>
* Completed Suggestions
* run gofmt on http.go
* fix testsanitize
* fix fullconfig/hcl by setting correct 'want'
* ran gofmt on agent/config/runtime_test.go
* Update website/source/docs/agent/options.html.md
Co-Authored-By: Hans Hasselberg <me@hans.io>
* Update website/source/docs/agent/options.html.md
Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com>
* remove contentpath from redirectFS struct
2019-06-26 16:43:30 +00:00
}
2020-09-17 10:48:14 +00:00
if err := validateBasicName ( "ui_config.metrics_provider" , rt . UIConfig . MetricsProvider , true ) ; err != nil {
return err
2020-09-10 16:25:56 +00:00
}
if rt . UIConfig . MetricsProviderOptionsJSON != "" {
// Attempt to parse the JSON to ensure it's valid, parsing into a map
// ensures we get an object.
var dummyMap map [ string ] interface { }
2020-09-17 10:48:14 +00:00
err := json . Unmarshal ( [ ] byte ( rt . UIConfig . MetricsProviderOptionsJSON ) , & dummyMap )
2020-09-10 16:25:56 +00:00
if err != nil {
return fmt . Errorf ( "ui_config.metrics_provider_options_json must be empty " +
"or a string containing a valid JSON object. received: %q" ,
rt . UIConfig . MetricsProviderOptionsJSON )
}
}
if rt . UIConfig . MetricsProxy . BaseURL != "" {
u , err := url . Parse ( rt . UIConfig . MetricsProxy . BaseURL )
if err != nil || ! ( u . Scheme == "http" || u . Scheme == "https" ) {
return fmt . Errorf ( "ui_config.metrics_proxy.base_url must be a valid http" +
" or https URL. received: %q" ,
rt . UIConfig . MetricsProxy . BaseURL )
}
}
2020-10-30 21:49:54 +00:00
for _ , allowedPath := range rt . UIConfig . MetricsProxy . PathAllowlist {
if err := validateAbsoluteURLPath ( allowedPath ) ; err != nil {
return fmt . Errorf ( "ui_config.metrics_proxy.path_allowlist: %v" , err )
}
}
2020-09-10 16:25:56 +00:00
for k , v := range rt . UIConfig . DashboardURLTemplates {
2020-09-17 10:48:14 +00:00
if err := validateBasicName ( "ui_config.dashboard_url_templates key names" , k , false ) ; err != nil {
return err
2020-09-10 16:25:56 +00:00
}
u , err := url . Parse ( v )
if err != nil || ! ( u . Scheme == "http" || u . Scheme == "https" ) {
return fmt . Errorf ( "ui_config.dashboard_url_templates values must be a" +
" valid http or https URL. received: %q" ,
rt . UIConfig . MetricsProxy . BaseURL )
}
ui: modify content path (#5950)
* Add ui-content-path flag
* tests complete, regex validator on string, index.html updated
* cleaning up debugging stuff
* ui: Enable ember environment configuration to be set via the go binary at runtime (#5934)
* ui: Only inject {{.ContentPath}} if we are makeing a prod build...
...otherwise we just use the current rootURL
This gets injected into a <base /> node which solves the assets path
problem but not the ember problem
* ui: Pull out the <base href=""> value and inject it into ember env
See previous commit:
The <base href=""> value is 'sometimes' injected from go at index
serve time. We pass this value down to ember by overwriting the ember
config that is injected via a <meta> tag. This has to be done before
ember bootup.
Sometimes (during testing and development, basically not production)
this is injected with the already existing value, in which case this
essentially changes nothing.
The code here is slightly abstracted away from our specific usage to
make it easier for anyone else to use, and also make sure we can cope
with using this same method to pass variables down from the CLI through
to ember in the future.
* ui: We can't use <base /> move everything to javascript (#5941)
Unfortuantely we can't seem to be able to use <base> and rootURL
together as URL paths will get doubled up (`ui/ui/`).
This moves all the things that we need to interpolate with .ContentPath
to the `startup` javascript so we can conditionally print out
`{{.ContentPath}}` in lots of places (now we can't use base)
* fixed when we serve index.html
* ui: For writing a ContentPath, we also need to cope with testing... (#5945)
...and potentially more environments
Testing has more additional things in a separate index.html in `tests/`
This make the entire thing a little saner and uses just javascriopt
template literals instead of a pseudo handbrake synatx for our
templating of these files.
Intead of just templating the entire file this way, we still only
template `{{content-for 'head'}}` and `{{content-for 'body'}}`
in this way to ensure we support other plugins/addons
* build: Loosen up the regex for retrieving the CONSUL_VERSION (#5946)
* build: Loosen up the regex for retrieving the CONSUL_VERSION
1. Previously the `sed` replacement was searching for the CONSUL_VERSION
comment at the start of a line, it no longer does this to allow for
indentation.
2. Both `grep` and `sed` where looking for the omment at the end of the
line. We've removed this restriction here. We don't need to remove it
right now, but if we ever put the comment followed by something here the
searching would break.
3. Added `xargs` for trimming the resulting version string. We aren't
using this already in the rest of the scripts, but we are pretty sure
this is available on most systems.
* ui: Fix erroneous variable, and also force an ember cache clean on build
1. We referenced a variable incorrectly here, this fixes that.
2. We also made sure that every `make` target clears ember's `tmp` cache
to ensure that its not using any caches that have since been edited
everytime we call a `make` target.
* added docs, fixed encoding
* fixed go fmt
* Update agent/config/config.go
Co-Authored-By: R.B. Boyer <public@richardboyer.net>
* Completed Suggestions
* run gofmt on http.go
* fix testsanitize
* fix fullconfig/hcl by setting correct 'want'
* ran gofmt on agent/config/runtime_test.go
* Update website/source/docs/agent/options.html.md
Co-Authored-By: Hans Hasselberg <me@hans.io>
* Update website/source/docs/agent/options.html.md
Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com>
* remove contentpath from redirectFS struct
2019-06-26 16:43:30 +00:00
}
2017-09-25 18:40:42 +00:00
if ! rt . DevMode {
fi , err := os . Stat ( rt . DataDir )
switch {
case err != nil && ! os . IsNotExist ( err ) :
return fmt . Errorf ( "Error getting info on data_dir: %s" , err )
case err == nil && ! fi . IsDir ( ) :
return fmt . Errorf ( "data_dir %q is not a directory" , rt . DataDir )
}
}
2020-08-17 21:24:49 +00:00
switch {
case rt . NodeName == "" :
2017-09-25 18:40:42 +00:00
return fmt . Errorf ( "node_name cannot be empty" )
2020-08-17 21:24:49 +00:00
case dns . InvalidNameRe . MatchString ( rt . NodeName ) :
b . warn ( "Node name %q will not be discoverable " +
"via DNS due to invalid characters. Valid characters include " +
"all alpha-numerics and dashes." , rt . NodeName )
2022-11-15 00:24:40 +00:00
case consul . InvalidNodeName . MatchString ( rt . NodeName ) :
// todo(kyhavlov): Add stronger validation here for node names.
b . warn ( "Found invalid characters in node name %q - whitespace and quotes " +
"(', \", `) cannot be used with auto-config." , rt . NodeName )
2020-08-17 21:24:49 +00:00
case len ( rt . NodeName ) > dns . MaxLabelLength :
b . warn ( "Node name %q will not be discoverable " +
"via DNS due to it being too long. Valid lengths are between " +
"1 and 63 bytes." , rt . NodeName )
2017-09-25 18:40:42 +00:00
}
2020-08-17 21:24:49 +00:00
2017-09-25 18:40:42 +00:00
if ipaddr . IsAny ( rt . AdvertiseAddrLAN . IP ) {
return fmt . Errorf ( "Advertise address cannot be 0.0.0.0, :: or [::]" )
}
if ipaddr . IsAny ( rt . AdvertiseAddrWAN . IP ) {
return fmt . Errorf ( "Advertise WAN address cannot be 0.0.0.0, :: or [::]" )
}
if err := b . validateSegments ( rt ) ; err != nil {
return err
}
for _ , a := range rt . DNSAddrs {
if _ , ok := a . ( * net . UnixAddr ) ; ok {
return fmt . Errorf ( "DNS address cannot be a unix socket" )
}
}
2017-10-20 18:00:45 +00:00
for _ , a := range rt . DNSRecursors {
if ipaddr . IsAny ( a ) {
return fmt . Errorf ( "DNS recursor address cannot be 0.0.0.0, :: or [::]" )
}
}
2019-06-27 10:00:37 +00:00
if ! isValidAltDomain ( rt . DNSAltDomain , rt . Datacenter ) {
return fmt . Errorf ( "alt_domain cannot start with {service,connect,node,query,addr,%s}" , rt . Datacenter )
}
2017-09-25 18:40:42 +00:00
if rt . Bootstrap && ! rt . ServerMode {
return fmt . Errorf ( "'bootstrap = true' requires 'server = true'" )
}
if rt . BootstrapExpect < 0 {
return fmt . Errorf ( "bootstrap_expect cannot be %d. Must be greater than or equal to zero" , rt . BootstrapExpect )
}
if rt . BootstrapExpect > 0 && ! rt . ServerMode {
return fmt . Errorf ( "'bootstrap_expect > 0' requires 'server = true'" )
}
if rt . BootstrapExpect > 0 && rt . DevMode {
return fmt . Errorf ( "'bootstrap_expect > 0' not allowed in dev mode" )
}
if rt . BootstrapExpect > 0 && rt . Bootstrap {
return fmt . Errorf ( "'bootstrap_expect > 0' and 'bootstrap = true' are mutually exclusive" )
}
2019-06-26 15:43:25 +00:00
if rt . CheckOutputMaxSize < 1 {
return fmt . Errorf ( "check_output_max_size must be positive, to discard check output use the discard_check_output flag" )
}
2017-09-25 18:40:42 +00:00
if rt . AEInterval <= 0 {
return fmt . Errorf ( "ae_interval cannot be %s. Must be positive" , rt . AEInterval )
}
if rt . AutopilotMaxTrailingLogs < 0 {
return fmt . Errorf ( "autopilot.max_trailing_logs cannot be %d. Must be greater than or equal to zero" , rt . AutopilotMaxTrailingLogs )
}
2021-08-06 22:00:58 +00:00
if err := validateBasicName ( "primary_datacenter" , rt . PrimaryDatacenter , true ) ; err != nil {
2020-09-17 10:48:14 +00:00
return err
2017-09-25 18:40:42 +00:00
}
2020-03-31 20:36:20 +00:00
// In DevMode, UI is enabled by default, so to enable rt.UIDir, don't perform this check
2020-09-10 16:25:56 +00:00
if ! rt . DevMode && rt . UIConfig . Enabled && rt . UIConfig . Dir != "" {
2017-09-25 18:40:42 +00:00
return fmt . Errorf (
2020-09-10 16:25:56 +00:00
"Both the ui_config.enabled and ui_config.dir (or -ui and -ui-dir) were specified, please provide only one.\n" +
"If trying to use your own web UI resources, use ui_config.dir or the -ui-dir flag.\n" +
"The web UI is included in the binary so use ui_config.enabled or the -ui flag to enable it" )
2017-09-25 18:40:42 +00:00
}
if rt . DNSUDPAnswerLimit < 0 {
return fmt . Errorf ( "dns_config.udp_answer_limit cannot be %d. Must be greater than or equal to zero" , rt . DNSUDPAnswerLimit )
}
2018-03-06 01:07:42 +00:00
if rt . DNSARecordLimit < 0 {
return fmt . Errorf ( "dns_config.a_record_limit cannot be %d. Must be greater than or equal to zero" , rt . DNSARecordLimit )
}
2020-03-09 20:59:02 +00:00
if err := structs . ValidateNodeMetadata ( rt . NodeMeta , false ) ; err != nil {
2017-09-25 18:40:42 +00:00
return fmt . Errorf ( "node_meta invalid: %v" , err )
}
if rt . EncryptKey != "" {
if _ , err := decodeBytes ( rt . EncryptKey ) ; err != nil {
return fmt . Errorf ( "encrypt has invalid key: %s" , err )
}
}
2020-03-09 20:59:02 +00:00
if rt . ConnectMeshGatewayWANFederationEnabled && ! rt . ServerMode {
return fmt . Errorf ( "'connect.enable_mesh_gateway_wan_federation = true' requires 'server = true'" )
}
if rt . ConnectMeshGatewayWANFederationEnabled && strings . ContainsAny ( rt . NodeName , "/" ) {
return fmt . Errorf ( "'connect.enable_mesh_gateway_wan_federation = true' requires that 'node_name' not contain '/' characters" )
}
if rt . ConnectMeshGatewayWANFederationEnabled {
if len ( rt . StartJoinAddrsWAN ) > 0 {
return fmt . Errorf ( "'start_join_wan' is incompatible with 'connect.enable_mesh_gateway_wan_federation = true'" )
}
if len ( rt . RetryJoinWAN ) > 0 {
return fmt . Errorf ( "'retry_join_wan' is incompatible with 'connect.enable_mesh_gateway_wan_federation = true'" )
}
}
if len ( rt . PrimaryGateways ) > 0 {
if ! rt . ServerMode {
return fmt . Errorf ( "'primary_gateways' requires 'server = true'" )
}
if rt . PrimaryDatacenter == rt . Datacenter {
return fmt . Errorf ( "'primary_gateways' should only be configured in a secondary datacenter" )
}
}
2017-09-25 18:40:42 +00:00
// Check the data dir for signs of an un-migrated Consul 0.5.x or older
// server. Consul refuses to start if this is present to protect a server
// with existing data from starting on a fresh data set.
if rt . ServerMode {
mdbPath := filepath . Join ( rt . DataDir , "mdb" )
if _ , err := os . Stat ( mdbPath ) ; ! os . IsNotExist ( err ) {
if os . IsPermission ( err ) {
return fmt . Errorf (
"CRITICAL: Permission denied for data folder at %q!\n" +
"Consul will refuse to boot without access to this directory.\n" +
"Please correct permissions and try starting again." , mdbPath )
}
return fmt . Errorf ( "CRITICAL: Deprecated data folder found at %q!\n" +
"Consul will refuse to boot with this directory present.\n" +
"See https://www.consul.io/docs/upgrade-specific.html for more information." , mdbPath )
}
}
inuse := map [ string ] string { }
if err := addrsUnique ( inuse , "DNS" , rt . DNSAddrs ) ; err != nil {
// cannot happen since this is the first address
// we leave this for consistency
return err
}
if err := addrsUnique ( inuse , "HTTP" , rt . HTTPAddrs ) ; err != nil {
return err
}
if err := addrsUnique ( inuse , "HTTPS" , rt . HTTPSAddrs ) ; err != nil {
return err
}
if err := addrUnique ( inuse , "RPC Advertise" , rt . RPCAdvertiseAddr ) ; err != nil {
return err
}
if err := addrUnique ( inuse , "Serf Advertise LAN" , rt . SerfAdvertiseAddrLAN ) ; err != nil {
return err
}
2018-03-27 14:44:41 +00:00
// Validate serf WAN advertise address only when its set
if rt . SerfAdvertiseAddrWAN != nil {
if err := addrUnique ( inuse , "Serf Advertise WAN" , rt . SerfAdvertiseAddrWAN ) ; err != nil {
return err
}
2017-09-25 18:40:42 +00:00
}
if b . err != nil {
return b . err
}
2018-05-04 21:10:03 +00:00
// Check for errors in the service definitions
for _ , s := range rt . Services {
if err := s . Validate ( ) ; err != nil {
return fmt . Errorf ( "service %q: %s" , s . Name , err )
}
}
2021-09-14 16:47:52 +00:00
// Check for errors in the node check definitions
for _ , c := range rt . Checks {
if err := c . CheckType ( ) . Validate ( ) ; err != nil {
return fmt . Errorf ( "check %q: %w" , c . Name , err )
}
}
2018-05-04 21:10:03 +00:00
2018-06-13 08:40:03 +00:00
// Validate the given Connect CA provider config
validCAProviders := map [ string ] bool {
2018-09-12 16:07:47 +00:00
"" : true ,
2018-06-13 08:40:03 +00:00
structs . ConsulCAProvider : true ,
structs . VaultCAProvider : true ,
2019-11-21 17:40:29 +00:00
structs . AWSCAProvider : true ,
2018-06-13 08:40:03 +00:00
}
if _ , ok := validCAProviders [ rt . ConnectCAProvider ] ; ! ok {
return fmt . Errorf ( "%s is not a valid CA provider" , rt . ConnectCAProvider )
} else {
switch rt . ConnectCAProvider {
case structs . ConsulCAProvider :
if _ , err := ca . ParseConsulCAConfig ( rt . ConnectCAConfig ) ; err != nil {
return err
}
case structs . VaultCAProvider :
if _ , err := ca . ParseVaultCAConfig ( rt . ConnectCAConfig ) ; err != nil {
return err
}
2019-11-21 17:40:29 +00:00
case structs . AWSCAProvider :
if _ , err := ca . ParseAWSCAConfig ( rt . ConnectCAConfig ) ; err != nil {
return err
}
2018-06-13 08:40:03 +00:00
}
}
2020-04-24 13:51:38 +00:00
if rt . ServerMode && rt . AutoEncryptTLS {
return fmt . Errorf ( "auto_encrypt.tls can only be used on a client." )
}
if ! rt . ServerMode && rt . AutoEncryptAllowTLS {
return fmt . Errorf ( "auto_encrypt.allow_tls can only be used on a server." )
}
2020-10-08 19:02:19 +00:00
if rt . ServerMode && rt . AdvertiseReconnectTimeout != 0 {
return fmt . Errorf ( "advertise_reconnect_timeout can only be used on a client" )
}
2017-09-25 18:40:42 +00:00
// ----------------------------------------------------------------
// warnings
//
if rt . ServerMode && ! rt . DevMode && ! rt . Bootstrap && rt . BootstrapExpect == 2 {
b . warn ( ` bootstrap_expect = 2: A cluster with 2 servers will provide no failure tolerance. See https://www.consul.io/docs/internals/consensus.html#deployment-table ` )
}
if rt . ServerMode && ! rt . Bootstrap && rt . BootstrapExpect > 2 && rt . BootstrapExpect % 2 == 0 {
b . warn ( ` bootstrap_expect is even number: A cluster with an even number of servers does not achieve optimum fault tolerance. See https://www.consul.io/docs/internals/consensus.html#deployment-table ` )
}
if rt . ServerMode && rt . Bootstrap && rt . BootstrapExpect == 0 {
b . warn ( ` bootstrap = true: do not enable unless necessary ` )
}
if rt . ServerMode && ! rt . DevMode && ! rt . Bootstrap && rt . BootstrapExpect > 1 {
b . warn ( "bootstrap_expect > 0: expecting %d servers" , rt . BootstrapExpect )
}
2021-01-08 20:23:23 +00:00
if rt . ServerMode {
if rt . UseStreamingBackend && ! rt . RPCConfig . EnableStreaming {
b . warn ( "use_streaming_backend = true requires rpc.enable_streaming on servers to work properly" )
}
} else if rt . RPCConfig . EnableStreaming {
b . warn ( "rpc.enable_streaming = true has no effect when not running in server mode" )
}
2022-03-18 10:46:58 +00:00
if rt . AutoEncryptAllowTLS && ! rt . TLS . InternalRPC . VerifyIncoming {
b . warn ( "if auto_encrypt.allow_tls is turned on, tls.internal_rpc.verify_incoming should be enabled (either explicitly or via tls.defaults.verify_incoming). It is necessary to turn it off during a migration to TLS, but it should definitely be turned on afterwards." )
2020-02-04 20:58:56 +00:00
}
2020-04-02 07:22:17 +00:00
if err := checkLimitsFromMaxConnsPerClient ( rt . HTTPMaxConnsPerClient ) ; err != nil {
return err
}
2020-07-28 19:31:48 +00:00
if rt . AutoConfig . Enabled && rt . AutoEncryptTLS {
return fmt . Errorf ( "both auto_encrypt.tls and auto_config.enabled cannot be set to true." )
}
2020-06-16 19:03:22 +00:00
if err := b . validateAutoConfig ( rt ) ; err != nil {
return err
}
2020-08-17 21:39:49 +00:00
if err := validateRemoteScriptsChecks ( rt ) ; err != nil {
// TODO: make this an error in a future version
b . warn ( err . Error ( ) )
}
2020-08-27 17:15:10 +00:00
err := b . validateEnterpriseConfig ( rt )
return err
2017-09-25 18:40:42 +00:00
}
// addrUnique checks if the given address is already in use for another
// protocol.
func addrUnique ( inuse map [ string ] string , name string , addr net . Addr ) error {
key := addr . Network ( ) + ":" + addr . String ( )
if other , ok := inuse [ key ] ; ok {
return fmt . Errorf ( "%s address %s already configured for %s" , name , addr . String ( ) , other )
}
inuse [ key ] = name
return nil
}
// addrsUnique checks if any of the give addresses is already in use for
// another protocol.
func addrsUnique ( inuse map [ string ] string , name string , addrs [ ] net . Addr ) error {
for _ , a := range addrs {
if err := addrUnique ( inuse , name , a ) ; err != nil {
return err
}
}
return nil
}
// splitSlicesAndValues moves all slice values defined in c to 'slices'
// and all other values to 'values'.
2020-11-20 19:08:17 +00:00
func splitSlicesAndValues ( c Config ) ( slices , values Config ) {
2017-09-25 18:40:42 +00:00
v , t := reflect . ValueOf ( c ) , reflect . TypeOf ( c )
rs , rv := reflect . New ( t ) , reflect . New ( t )
for i := 0 ; i < t . NumField ( ) ; i ++ {
f := t . Field ( i )
if f . Type . Kind ( ) == reflect . Slice {
rs . Elem ( ) . Field ( i ) . Set ( v . Field ( i ) )
} else {
rv . Elem ( ) . Field ( i ) . Set ( v . Field ( i ) )
}
}
return rs . Elem ( ) . Interface ( ) . ( Config ) , rv . Elem ( ) . Interface ( ) . ( Config )
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) warn ( msg string , args ... interface { } ) {
2017-09-25 18:40:42 +00:00
b . Warnings = append ( b . Warnings , fmt . Sprintf ( msg , args ... ) )
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) checkVal ( v * CheckDefinition ) * structs . CheckDefinition {
2017-09-25 18:40:42 +00:00
if v == nil {
return nil
}
2021-10-07 02:13:01 +00:00
var H2PingUseTLSVal bool
if stringVal ( v . H2PING ) != "" {
H2PingUseTLSVal = boolValWithDefault ( v . H2PingUseTLS , true )
} else {
H2PingUseTLSVal = boolVal ( v . H2PingUseTLS )
}
2020-11-20 23:58:45 +00:00
id := types . CheckID ( stringVal ( v . ID ) )
2017-09-25 18:40:42 +00:00
return & structs . CheckDefinition {
2018-09-12 16:07:47 +00:00
ID : id ,
2020-11-20 23:58:45 +00:00
Name : stringVal ( v . Name ) ,
Notes : stringVal ( v . Notes ) ,
ServiceID : stringVal ( v . ServiceID ) ,
Token : stringVal ( v . Token ) ,
Status : stringVal ( v . Status ) ,
2018-09-12 16:07:47 +00:00
ScriptArgs : v . ScriptArgs ,
2020-11-20 23:58:45 +00:00
HTTP : stringVal ( v . HTTP ) ,
2018-09-12 16:07:47 +00:00
Header : v . Header ,
2020-11-20 23:58:45 +00:00
Method : stringVal ( v . Method ) ,
Body : stringVal ( v . Body ) ,
2022-04-01 21:31:15 +00:00
DisableRedirects : boolVal ( v . DisableRedirects ) ,
2020-11-20 23:58:45 +00:00
TCP : stringVal ( v . TCP ) ,
2022-10-05 19:57:21 +00:00
UDP : stringVal ( v . UDP ) ,
2018-09-12 16:07:47 +00:00
Interval : b . durationVal ( fmt . Sprintf ( "check[%s].interval" , id ) , v . Interval ) ,
2020-11-20 23:58:45 +00:00
DockerContainerID : stringVal ( v . DockerContainerID ) ,
Shell : stringVal ( v . Shell ) ,
GRPC : stringVal ( v . GRPC ) ,
GRPCUseTLS : boolVal ( v . GRPCUseTLS ) ,
2021-02-25 06:35:34 +00:00
TLSServerName : stringVal ( v . TLSServerName ) ,
2020-11-20 23:58:45 +00:00
TLSSkipVerify : boolVal ( v . TLSSkipVerify ) ,
AliasNode : stringVal ( v . AliasNode ) ,
AliasService : stringVal ( v . AliasService ) ,
2018-09-12 16:07:47 +00:00
Timeout : b . durationVal ( fmt . Sprintf ( "check[%s].timeout" , id ) , v . Timeout ) ,
TTL : b . durationVal ( fmt . Sprintf ( "check[%s].ttl" , id ) , v . TTL ) ,
2020-11-20 23:58:45 +00:00
SuccessBeforePassing : intVal ( v . SuccessBeforePassing ) ,
FailuresBeforeCritical : intVal ( v . FailuresBeforeCritical ) ,
2021-09-14 16:47:52 +00:00
FailuresBeforeWarning : intValWithDefault ( v . FailuresBeforeWarning , intVal ( v . FailuresBeforeCritical ) ) ,
2021-04-09 19:12:10 +00:00
H2PING : stringVal ( v . H2PING ) ,
2021-10-07 02:13:01 +00:00
H2PingUseTLS : H2PingUseTLSVal ,
2022-06-07 17:27:14 +00:00
OSService : stringVal ( v . OSService ) ,
2017-09-25 18:40:42 +00:00
DeregisterCriticalServiceAfter : b . durationVal ( fmt . Sprintf ( "check[%s].deregister_critical_service_after" , id ) , v . DeregisterCriticalServiceAfter ) ,
2020-11-20 23:58:45 +00:00
OutputMaxSize : intValWithDefault ( v . OutputMaxSize , checks . DefaultBufSize ) ,
2019-12-10 02:26:41 +00:00
EnterpriseMeta : v . EnterpriseMeta . ToStructs ( ) ,
2017-09-25 18:40:42 +00:00
}
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) svcTaggedAddresses ( v map [ string ] ServiceAddress ) map [ string ] structs . ServiceAddress {
2019-06-17 14:51:50 +00:00
if len ( v ) <= 0 {
return nil
}
svcAddrs := make ( map [ string ] structs . ServiceAddress )
for addrName , addrConf := range v {
addr := structs . ServiceAddress { }
if addrConf . Address != nil {
addr . Address = * addrConf . Address
}
if addrConf . Port != nil {
addr . Port = * addrConf . Port
}
svcAddrs [ addrName ] = addr
}
return svcAddrs
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) serviceVal ( v * ServiceDefinition ) * structs . ServiceDefinition {
2017-09-25 18:40:42 +00:00
if v == nil {
return nil
}
var checks structs . CheckTypes
for _ , check := range v . Checks {
checks = append ( checks , b . checkVal ( & check ) . CheckType ( ) )
}
if v . Check != nil {
checks = append ( checks , b . checkVal ( v . Check ) . CheckType ( ) )
}
2020-03-09 20:59:02 +00:00
kind := b . serviceKindVal ( v . Kind )
2018-04-18 20:18:58 +00:00
meta := make ( map [ string ] string )
2020-03-09 20:59:02 +00:00
if err := structs . ValidateServiceMetadata ( kind , v . Meta , false ) ; err != nil {
2021-12-23 21:30:36 +00:00
b . err = multierror . Append ( b . err , fmt . Errorf ( "invalid meta for service %s: %v" , stringVal ( v . Name ) , err ) )
2018-04-18 20:18:58 +00:00
} else {
meta = v . Meta
}
2018-09-07 14:30:47 +00:00
serviceWeights := & structs . Weights { Passing : 1 , Warning : 1 }
if v . Weights != nil {
if v . Weights . Passing != nil {
serviceWeights . Passing = * v . Weights . Passing
}
if v . Weights . Warning != nil {
serviceWeights . Warning = * v . Weights . Warning
}
}
if err := structs . ValidateWeights ( serviceWeights ) ; err != nil {
2021-12-23 21:30:36 +00:00
b . err = multierror . Append ( b . err , fmt . Errorf ( "Invalid weight definition for service %s: %s" , stringVal ( v . Name ) , err ) )
2018-09-07 14:30:47 +00:00
}
2021-05-04 04:43:55 +00:00
if ( v . Port != nil || v . Address != nil ) && ( v . SocketPath != nil ) {
2021-12-23 21:30:36 +00:00
b . err = multierror . Append ( b . err ,
2021-05-04 04:43:55 +00:00
fmt . Errorf ( "service %s cannot have both socket path %s and address/port" ,
2021-12-23 21:30:36 +00:00
stringVal ( v . Name ) , stringVal ( v . SocketPath ) ) )
2021-05-04 04:43:55 +00:00
}
2017-09-25 18:40:42 +00:00
return & structs . ServiceDefinition {
2020-03-09 20:59:02 +00:00
Kind : kind ,
2020-11-20 23:58:45 +00:00
ID : stringVal ( v . ID ) ,
Name : stringVal ( v . Name ) ,
2017-09-25 18:40:42 +00:00
Tags : v . Tags ,
2020-11-20 23:58:45 +00:00
Address : stringVal ( v . Address ) ,
2019-06-17 14:51:50 +00:00
TaggedAddresses : b . svcTaggedAddresses ( v . TaggedAddresses ) ,
2018-04-18 20:18:58 +00:00
Meta : meta ,
2020-11-20 23:58:45 +00:00
Port : intVal ( v . Port ) ,
2021-05-04 04:43:55 +00:00
SocketPath : stringVal ( v . SocketPath ) ,
2020-11-20 23:58:45 +00:00
Token : stringVal ( v . Token ) ,
EnableTagOverride : boolVal ( v . EnableTagOverride ) ,
2018-09-07 14:30:47 +00:00
Weights : serviceWeights ,
2017-09-25 18:40:42 +00:00
Checks : checks ,
2019-08-09 19:19:30 +00:00
Proxy : b . serviceProxyVal ( v . Proxy ) ,
Connect : b . serviceConnectVal ( v . Connect ) ,
2019-12-10 02:26:41 +00:00
EnterpriseMeta : v . EnterpriseMeta . ToStructs ( ) ,
2017-09-25 18:40:42 +00:00
}
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) serviceKindVal ( v * string ) structs . ServiceKind {
2018-07-25 18:55:41 +00:00
if v == nil {
return structs . ServiceKindTypical
}
switch * v {
case string ( structs . ServiceKindConnectProxy ) :
return structs . ServiceKindConnectProxy
2019-06-18 00:52:01 +00:00
case string ( structs . ServiceKindMeshGateway ) :
return structs . ServiceKindMeshGateway
2020-03-26 16:20:56 +00:00
case string ( structs . ServiceKindTerminatingGateway ) :
return structs . ServiceKindTerminatingGateway
2020-04-16 21:00:48 +00:00
case string ( structs . ServiceKindIngressGateway ) :
return structs . ServiceKindIngressGateway
2018-07-25 18:55:41 +00:00
default :
return structs . ServiceKindTypical
}
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) serviceProxyVal ( v * ServiceProxy ) * structs . ConnectProxyConfig {
2018-09-12 16:07:47 +00:00
if v == nil {
return nil
}
return & structs . ConnectProxyConfig {
2020-11-20 23:58:45 +00:00
DestinationServiceName : stringVal ( v . DestinationServiceName ) ,
DestinationServiceID : stringVal ( v . DestinationServiceID ) ,
LocalServiceAddress : stringVal ( v . LocalServiceAddress ) ,
LocalServicePort : intVal ( v . LocalServicePort ) ,
2021-05-04 04:43:55 +00:00
LocalServiceSocketPath : stringVal ( & v . LocalServiceSocketPath ) ,
2018-09-12 16:07:47 +00:00
Config : v . Config ,
Upstreams : b . upstreamsVal ( v . Upstreams ) ,
2019-07-24 21:01:42 +00:00
MeshGateway : b . meshGatewayConfVal ( v . MeshGateway ) ,
2019-09-26 02:55:52 +00:00
Expose : b . exposeConfVal ( v . Expose ) ,
2021-04-12 15:35:14 +00:00
Mode : b . proxyModeVal ( v . Mode ) ,
TransparentProxy : b . transparentProxyConfVal ( v . TransparentProxy ) ,
2018-09-12 16:07:47 +00:00
}
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) upstreamsVal ( v [ ] Upstream ) structs . Upstreams {
2018-09-12 16:07:47 +00:00
ups := make ( structs . Upstreams , len ( v ) )
for i , u := range v {
ups [ i ] = structs . Upstream {
2020-11-20 23:58:45 +00:00
DestinationType : stringVal ( u . DestinationType ) ,
DestinationNamespace : stringVal ( u . DestinationNamespace ) ,
2021-08-20 16:57:45 +00:00
DestinationPartition : stringVal ( u . DestinationPartition ) ,
2022-04-29 22:12:51 +00:00
DestinationPeer : stringVal ( u . DestinationPeer ) ,
2020-11-20 23:58:45 +00:00
DestinationName : stringVal ( u . DestinationName ) ,
Datacenter : stringVal ( u . Datacenter ) ,
LocalBindAddress : stringVal ( u . LocalBindAddress ) ,
LocalBindPort : intVal ( u . LocalBindPort ) ,
2021-03-26 19:43:57 +00:00
LocalBindSocketPath : stringVal ( u . LocalBindSocketPath ) ,
2021-03-26 20:00:44 +00:00
LocalBindSocketMode : b . unixPermissionsVal ( "local_bind_socket_mode" , u . LocalBindSocketMode ) ,
2018-09-12 16:07:47 +00:00
Config : u . Config ,
2019-07-24 21:01:42 +00:00
MeshGateway : b . meshGatewayConfVal ( u . MeshGateway ) ,
2018-09-12 16:07:47 +00:00
}
if ups [ i ] . DestinationType == "" {
ups [ i ] . DestinationType = structs . UpstreamDestTypeService
}
}
return ups
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) meshGatewayConfVal ( mgConf * MeshGatewayConfig ) structs . MeshGatewayConfig {
2019-07-24 21:01:42 +00:00
cfg := structs . MeshGatewayConfig { Mode : structs . MeshGatewayModeDefault }
if mgConf == nil || mgConf . Mode == nil {
// return defaults
return cfg
}
mode , err := structs . ValidateMeshGatewayMode ( * mgConf . Mode )
if err != nil {
b . err = multierror . Append ( b . err , err )
return cfg
}
cfg . Mode = mode
return cfg
}
2021-07-19 22:22:51 +00:00
func ( b * builder ) dnsRecursorStrategyVal ( v string ) dns . RecursorStrategy {
var out dns . RecursorStrategy
switch dns . RecursorStrategy ( v ) {
case dns . RecursorStrategyRandom :
out = dns . RecursorStrategyRandom
case dns . RecursorStrategySequential , "" :
out = dns . RecursorStrategySequential
default :
b . err = multierror . Append ( b . err , fmt . Errorf ( "dns_config.recursor_strategy: invalid strategy: %q" , v ) )
}
return out
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) exposeConfVal ( v * ExposeConfig ) structs . ExposeConfig {
2019-09-26 02:55:52 +00:00
var out structs . ExposeConfig
if v == nil {
return out
}
2020-11-20 23:58:45 +00:00
out . Checks = boolVal ( v . Checks )
2019-09-26 02:55:52 +00:00
out . Paths = b . pathsVal ( v . Paths )
return out
}
2021-04-12 15:35:14 +00:00
func ( b * builder ) transparentProxyConfVal ( tproxyConf * TransparentProxyConfig ) structs . TransparentProxyConfig {
var out structs . TransparentProxyConfig
if tproxyConf == nil {
return out
}
out . OutboundListenerPort = intVal ( tproxyConf . OutboundListenerPort )
2021-06-09 20:34:17 +00:00
out . DialedDirectly = boolVal ( tproxyConf . DialedDirectly )
2021-04-12 15:35:14 +00:00
return out
}
func ( b * builder ) proxyModeVal ( v * string ) structs . ProxyMode {
if v == nil {
return structs . ProxyModeDefault
}
mode , err := structs . ValidateProxyMode ( * v )
if err != nil {
b . err = multierror . Append ( b . err , err )
}
return mode
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) pathsVal ( v [ ] ExposePath ) [ ] structs . ExposePath {
2019-09-26 02:55:52 +00:00
paths := make ( [ ] structs . ExposePath , len ( v ) )
for i , p := range v {
paths [ i ] = structs . ExposePath {
2020-11-20 23:58:45 +00:00
ListenerPort : intVal ( p . ListenerPort ) ,
Path : stringVal ( p . Path ) ,
LocalPathPort : intVal ( p . LocalPathPort ) ,
Protocol : stringVal ( p . Protocol ) ,
2019-09-26 02:55:52 +00:00
}
}
return paths
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) serviceConnectVal ( v * ServiceConnect ) * structs . ServiceConnect {
2018-04-17 12:29:02 +00:00
if v == nil {
2018-04-16 15:00:20 +00:00
return nil
}
2018-09-27 13:33:12 +00:00
sidecar := b . serviceVal ( v . SidecarService )
if sidecar != nil {
// Sanity checks
if sidecar . ID != "" {
2018-10-09 16:57:26 +00:00
b . err = multierror . Append ( b . err , fmt . Errorf ( "sidecar_service can't specify an ID" ) )
2018-09-27 13:33:12 +00:00
sidecar . ID = ""
}
if sidecar . Connect != nil {
if sidecar . Connect . SidecarService != nil {
b . err = multierror . Append ( b . err , fmt . Errorf ( "sidecar_service can't have a nested sidecar_service" ) )
sidecar . Connect . SidecarService = nil
}
}
}
2018-06-05 17:51:05 +00:00
return & structs . ServiceConnect {
2020-11-20 23:58:45 +00:00
Native : boolVal ( v . Native ) ,
2018-09-27 13:33:12 +00:00
SidecarService : sidecar ,
2017-09-25 18:40:42 +00:00
}
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) uiConfigVal ( v RawUIConfig ) UIConfig {
2020-09-10 16:25:56 +00:00
return UIConfig {
2020-11-20 23:58:45 +00:00
Enabled : boolVal ( v . Enabled ) ,
Dir : stringVal ( v . Dir ) ,
ContentPath : UIPathBuilder ( stringVal ( v . ContentPath ) ) ,
MetricsProvider : stringVal ( v . MetricsProvider ) ,
2020-09-10 16:25:56 +00:00
MetricsProviderFiles : v . MetricsProviderFiles ,
2020-11-20 23:58:45 +00:00
MetricsProviderOptionsJSON : stringVal ( v . MetricsProviderOptionsJSON ) ,
2020-09-10 16:25:56 +00:00
MetricsProxy : b . uiMetricsProxyVal ( v . MetricsProxy ) ,
DashboardURLTemplates : v . DashboardURLTemplates ,
2022-04-15 16:55:52 +00:00
HCPEnabled : os . Getenv ( "CONSUL_HCP_ENABLED" ) == "true" ,
2020-09-10 16:25:56 +00:00
}
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) uiMetricsProxyVal ( v RawUIMetricsProxy ) UIMetricsProxy {
2020-09-10 16:25:56 +00:00
var hdrs [ ] UIMetricsProxyAddHeader
for _ , hdr := range v . AddHeaders {
hdrs = append ( hdrs , UIMetricsProxyAddHeader {
2020-11-20 23:58:45 +00:00
Name : stringVal ( hdr . Name ) ,
Value : stringVal ( hdr . Value ) ,
2020-09-10 16:25:56 +00:00
} )
}
return UIMetricsProxy {
2020-11-20 23:58:45 +00:00
BaseURL : stringVal ( v . BaseURL ) ,
2020-10-30 21:49:54 +00:00
AddHeaders : hdrs ,
PathAllowlist : v . PathAllowlist ,
2020-09-10 16:25:56 +00:00
}
}
2020-11-20 23:58:45 +00:00
func boolValWithDefault ( v * bool , defaultVal bool ) bool {
2017-09-25 18:40:42 +00:00
if v == nil {
2018-10-19 16:04:07 +00:00
return defaultVal
2017-09-25 18:40:42 +00:00
}
return * v
}
2020-11-20 23:58:45 +00:00
func boolVal ( v * bool ) bool {
if v == nil {
return false
}
return * v
2018-06-11 15:49:04 +00:00
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) durationValWithDefault ( name string , v * string , defaultVal time . Duration ) ( d time . Duration ) {
2017-09-25 18:40:42 +00:00
if v == nil {
2018-10-19 16:04:07 +00:00
return defaultVal
2017-09-25 18:40:42 +00:00
}
d , err := time . ParseDuration ( * v )
if err != nil {
2021-12-23 21:30:36 +00:00
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: invalid duration: %q: %s" , name , * v , err ) )
2017-09-25 18:40:42 +00:00
}
return d
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) durationVal ( name string , v * string ) ( d time . Duration ) {
2018-10-19 16:04:07 +00:00
return b . durationValWithDefault ( name , v , 0 )
}
2020-11-20 23:58:45 +00:00
func intValWithDefault ( v * int , defaultVal int ) int {
2017-09-25 18:40:42 +00:00
if v == nil {
2019-06-26 15:43:25 +00:00
return defaultVal
2017-09-25 18:40:42 +00:00
}
return * v
}
2020-11-20 23:58:45 +00:00
func intVal ( v * int ) int {
2019-10-29 14:04:41 +00:00
if v == nil {
2020-11-20 23:58:45 +00:00
return 0
2019-10-29 14:04:41 +00:00
}
return * v
}
2020-11-20 23:58:45 +00:00
func uintVal ( v * uint ) uint {
2019-07-24 21:06:39 +00:00
if v == nil {
2020-11-20 23:58:45 +00:00
return 0
2019-07-24 21:06:39 +00:00
}
return * v
}
2020-11-20 23:58:45 +00:00
func uint64Val ( v * uint64 ) uint64 {
if v == nil {
return 0
}
return * v
2019-07-24 21:06:39 +00:00
}
2021-03-26 20:00:44 +00:00
// Expect an octal permissions string, e.g. 0644
2021-04-14 01:01:30 +00:00
func ( b * builder ) unixPermissionsVal ( name string , v * string ) string {
2021-03-26 20:00:44 +00:00
if v == nil {
2021-04-14 01:01:30 +00:00
return ""
2021-03-26 20:00:44 +00:00
}
2021-04-14 01:01:30 +00:00
if _ , err := strconv . ParseUint ( * v , 8 , 32 ) ; err == nil {
return * v
2021-03-26 20:00:44 +00:00
}
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: invalid mode: %s" , name , * v ) )
2021-04-14 01:01:30 +00:00
return "0"
2021-03-26 20:00:44 +00:00
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) portVal ( name string , v * int ) int {
2017-09-25 18:40:42 +00:00
if v == nil || * v <= 0 {
return - 1
}
if * v > 65535 {
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: invalid port: %d" , name , * v ) )
}
return * v
}
2020-11-20 23:58:45 +00:00
func stringValWithDefault ( v * string , defaultVal string ) string {
2017-09-25 18:40:42 +00:00
if v == nil {
2018-10-19 16:04:07 +00:00
return defaultVal
2017-09-25 18:40:42 +00:00
}
return * v
}
2020-11-20 22:43:32 +00:00
func stringVal ( v * string ) string {
if v == nil {
return ""
}
return * v
}
2022-06-02 02:37:47 +00:00
func timeValWithDefault ( v * time . Time , defaultVal time . Time ) time . Time {
if v == nil {
return defaultVal
}
return * v
}
2020-11-20 23:58:45 +00:00
func float64ValWithDefault ( v * float64 , defaultVal float64 ) float64 {
2017-09-25 18:40:42 +00:00
if v == nil {
2020-07-27 21:11:11 +00:00
return defaultVal
2017-09-25 18:40:42 +00:00
}
return * v
}
2020-11-20 23:58:45 +00:00
func float64Val ( v * float64 ) float64 {
return float64ValWithDefault ( v , 0 )
2020-07-27 21:11:11 +00:00
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) cidrsVal ( name string , v [ ] string ) ( nets [ ] * net . IPNet ) {
2019-01-10 14:27:26 +00:00
if v == nil {
return
}
for _ , p := range v {
_ , net , err := net . ParseCIDR ( strings . TrimSpace ( p ) )
if err != nil {
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: invalid cidr: %s" , name , p ) )
}
nets = append ( nets , net )
}
return
}
2022-03-24 19:32:25 +00:00
func ( b * builder ) tlsVersion ( name string , v * string ) types . TLSVersion {
// Handles unspecified config and empty string case.
//
// This check is not inside types.ValidateTLSVersionString because Envoy config
// distinguishes between an unset empty string which inherits parent config and
// an explicit TLS_AUTO which allows overriding parent config with the proxy
// defaults.
if v == nil || * v == "" {
return types . TLSVersionAuto
}
a := types . TLSVersion ( * v )
err := types . ValidateTLSVersion ( a )
if err != nil {
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: invalid TLS version: %s" , name , err ) )
return types . TLSVersionInvalid
}
return a
}
// validateTLSVersionCipherSuitesCompat checks that the specified TLS version supports
// specifying cipher suites
func validateTLSVersionCipherSuitesCompat ( tlsMinVersion types . TLSVersion ) error {
if tlsMinVersion == types . TLSv1_3 {
return fmt . Errorf ( "TLS 1.3 cipher suites are not configurable" )
}
return nil
}
// tlsCipherSuites parses cipher suites from a comma-separated string into a
// recognized slice
func ( b * builder ) tlsCipherSuites ( name string , v * string , tlsMinVersion types . TLSVersion ) [ ] types . TLSCipherSuite {
2017-09-25 18:40:42 +00:00
if v == nil {
return nil
}
2022-03-24 19:32:25 +00:00
if err := validateTLSVersionCipherSuitesCompat ( tlsMinVersion ) ; err != nil {
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: %s" , name , err ) )
return nil
}
* v = strings . TrimSpace ( * v )
if * v == "" {
return [ ] types . TLSCipherSuite { }
}
ciphers := strings . Split ( * v , "," )
a := make ( [ ] types . TLSCipherSuite , len ( ciphers ) )
for i , cipher := range ciphers {
a [ i ] = types . TLSCipherSuite ( cipher )
}
err := types . ValidateConsulAgentCipherSuites ( a )
2017-09-25 18:40:42 +00:00
if err != nil {
2022-03-24 19:32:25 +00:00
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: invalid TLS cipher suites: %s" , name , err ) )
return [ ] types . TLSCipherSuite { }
2017-09-25 18:40:42 +00:00
}
return a
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) nodeName ( v * string ) string {
2020-11-20 23:58:45 +00:00
nodeName := stringVal ( v )
2017-09-25 18:40:42 +00:00
if nodeName == "" {
2020-11-20 23:29:57 +00:00
fn := b . opts . hostname
2017-09-25 18:40:42 +00:00
if fn == nil {
fn = os . Hostname
}
name , err := fn ( )
if err != nil {
b . err = multierror . Append ( b . err , fmt . Errorf ( "node_name: %s" , err ) )
return ""
}
nodeName = name
}
return strings . TrimSpace ( nodeName )
}
// expandAddrs expands the go-sockaddr template in s and returns the
// result as a list of *net.IPAddr and *net.UnixAddr.
2020-12-21 18:55:53 +00:00
func ( b * builder ) expandAddrs ( name string , s * string ) [ ] net . Addr {
2017-09-25 18:40:42 +00:00
if s == nil || * s == "" {
return nil
}
x , err := template . Parse ( * s )
if err != nil {
2018-07-10 14:52:08 +00:00
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: error parsing %q: %s" , name , * s , err ) )
2017-09-25 18:40:42 +00:00
return nil
}
var addrs [ ] net . Addr
for _ , a := range strings . Fields ( x ) {
switch {
case strings . HasPrefix ( a , "unix://" ) :
addrs = append ( addrs , & net . UnixAddr { Name : a [ len ( "unix://" ) : ] , Net : "unix" } )
default :
// net.ParseIP does not like '[::]'
ip := net . ParseIP ( a )
if a == "[::]" {
ip = net . ParseIP ( "::" )
}
if ip == nil {
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: invalid ip address: %s" , name , a ) )
return nil
}
addrs = append ( addrs , & net . IPAddr { IP : ip } )
}
}
return addrs
}
2018-02-06 13:37:37 +00:00
// expandOptionalAddrs expands the go-sockaddr template in s and returns the
// result as a list of strings. If s does not contain a go-sockaddr template,
// the result list will contain the input string as a single element with no
// error set. In contrast to expandAddrs, expandOptionalAddrs does not validate
// if the result contains valid addresses and returns a list of strings.
// However, if the expansion of the go-sockaddr template fails an error is set.
2020-12-21 18:55:53 +00:00
func ( b * builder ) expandOptionalAddrs ( name string , s * string ) [ ] string {
2018-02-06 13:37:37 +00:00
if s == nil || * s == "" {
return nil
}
x , err := template . Parse ( * s )
if err != nil {
2018-07-10 14:52:08 +00:00
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: error parsing %q: %s" , name , * s , err ) )
2018-02-06 13:37:37 +00:00
return nil
}
if x != * s {
// A template has been expanded, split the results from go-sockaddr
return strings . Fields ( x )
} else {
// No template has been expanded, pass through the input
return [ ] string { * s }
}
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) expandAllOptionalAddrs ( name string , addrs [ ] string ) [ ] string {
2018-05-10 13:30:24 +00:00
out := make ( [ ] string , 0 , len ( addrs ) )
for _ , a := range addrs {
expanded := b . expandOptionalAddrs ( name , & a )
if expanded != nil {
out = append ( out , expanded ... )
}
}
return out
}
2017-09-25 18:40:42 +00:00
// expandIPs expands the go-sockaddr template in s and returns a list of
// *net.IPAddr. If one of the expanded addresses is a unix socket
// address an error is set and nil is returned.
2020-12-21 18:55:53 +00:00
func ( b * builder ) expandIPs ( name string , s * string ) [ ] * net . IPAddr {
2017-09-25 18:40:42 +00:00
if s == nil || * s == "" {
return nil
}
addrs := b . expandAddrs ( name , s )
var x [ ] * net . IPAddr
for _ , addr := range addrs {
switch a := addr . ( type ) {
case * net . IPAddr :
x = append ( x , a )
case * net . UnixAddr :
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s cannot be a unix socket" , name ) )
return nil
default :
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s has invalid address type %T" , name , a ) )
return nil
}
}
return x
}
// expandFirstAddr expands the go-sockaddr template in s and returns the
// first address which is either a *net.IPAddr or a *net.UnixAddr. If
// the template expands to multiple addresses an error is set and nil
// is returned.
2020-12-21 18:55:53 +00:00
func ( b * builder ) expandFirstAddr ( name string , s * string ) net . Addr {
2017-09-25 18:40:42 +00:00
if s == nil || * s == "" {
return nil
}
addrs := b . expandAddrs ( name , s )
if len ( addrs ) == 0 {
return nil
}
if len ( addrs ) > 1 {
var x [ ] string
for _ , a := range addrs {
x = append ( x , a . String ( ) )
}
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s: multiple addresses found: %s" , name , strings . Join ( x , " " ) ) )
return nil
}
return addrs [ 0 ]
}
2018-03-19 16:56:00 +00:00
// expandFirstIP expands the go-sockaddr template in s and returns the
2017-09-25 18:40:42 +00:00
// first address if it is not a unix socket address. If the template
// expands to multiple addresses an error is set and nil is returned.
2020-12-21 18:55:53 +00:00
func ( b * builder ) expandFirstIP ( name string , s * string ) * net . IPAddr {
2017-09-25 18:40:42 +00:00
if s == nil || * s == "" {
return nil
}
addr := b . expandFirstAddr ( name , s )
if addr == nil {
return nil
}
switch a := addr . ( type ) {
case * net . IPAddr :
return a
case * net . UnixAddr :
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s cannot be a unix socket" , name ) )
return nil
default :
b . err = multierror . Append ( b . err , fmt . Errorf ( "%s has invalid address type %T" , name , a ) )
return nil
}
}
2020-11-20 23:58:45 +00:00
func makeIPAddr ( pri * net . IPAddr , sec * net . IPAddr ) * net . IPAddr {
2017-09-25 18:40:42 +00:00
if pri != nil {
return pri
}
return sec
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) makeTCPAddr ( pri * net . IPAddr , sec net . Addr , port int ) * net . TCPAddr {
2017-09-25 18:40:42 +00:00
if pri == nil && reflect . ValueOf ( sec ) . IsNil ( ) || port <= 0 {
return nil
}
addr := pri
if addr == nil {
switch a := sec . ( type ) {
case * net . IPAddr :
addr = a
case * net . TCPAddr :
addr = & net . IPAddr { IP : a . IP }
default :
panic ( fmt . Sprintf ( "makeTCPAddr requires a net.IPAddr or a net.TCPAddr. Got %T" , a ) )
}
}
return & net . TCPAddr { IP : addr . IP , Port : port }
}
// makeAddr creates an *net.TCPAddr or a *net.UnixAddr from either the
// primary or secondary address and the given port. If the port is <= 0
// then the address is considered to be disabled and nil is returned.
2020-12-21 18:55:53 +00:00
func ( b * builder ) makeAddr ( pri , sec net . Addr , port int ) net . Addr {
2017-09-25 18:40:42 +00:00
if reflect . ValueOf ( pri ) . IsNil ( ) && reflect . ValueOf ( sec ) . IsNil ( ) || port <= 0 {
return nil
}
addr := pri
if addr == nil {
addr = sec
}
switch a := addr . ( type ) {
case * net . IPAddr :
return & net . TCPAddr { IP : a . IP , Port : port }
case * net . UnixAddr :
return a
default :
panic ( fmt . Sprintf ( "invalid address type %T" , a ) )
}
}
// makeAddrs creates a list of *net.TCPAddr or *net.UnixAddr entries
// from either the primary or secondary addresses and the given port.
// If the port is <= 0 then the address is considered to be disabled
// and nil is returned.
2020-12-21 18:55:53 +00:00
func ( b * builder ) makeAddrs ( pri [ ] net . Addr , sec [ ] * net . IPAddr , port int ) [ ] net . Addr {
2017-09-25 18:40:42 +00:00
if len ( pri ) == 0 && len ( sec ) == 0 || port <= 0 {
return nil
}
addrs := pri
if len ( addrs ) == 0 {
addrs = [ ] net . Addr { }
for _ , a := range sec {
addrs = append ( addrs , a )
}
}
var x [ ] net . Addr
for _ , a := range addrs {
x = append ( x , b . makeAddr ( a , nil , port ) )
}
return x
}
2021-08-19 20:09:42 +00:00
func ( b * builder ) autoConfigVal ( raw AutoConfigRaw , agentPartition string ) AutoConfig {
2020-06-16 19:03:22 +00:00
var val AutoConfig
2020-11-20 23:58:45 +00:00
val . Enabled = boolValWithDefault ( raw . Enabled , false )
val . IntroToken = stringVal ( raw . IntroToken )
2020-06-19 19:16:00 +00:00
// default the IntroToken to the env variable if specified.
if envToken := os . Getenv ( "CONSUL_INTRO_TOKEN" ) ; envToken != "" {
if val . IntroToken != "" {
b . warn ( "Both auto_config.intro_token and the CONSUL_INTRO_TOKEN environment variable are set. Using the value from the environment variable" )
}
val . IntroToken = envToken
}
2020-11-20 23:58:45 +00:00
val . IntroTokenFile = stringVal ( raw . IntroTokenFile )
2020-06-16 19:03:22 +00:00
// These can be go-discover values and so don't have to resolve fully yet
val . ServerAddresses = b . expandAllOptionalAddrs ( "auto_config.server_addresses" , raw . ServerAddresses )
val . DNSSANs = raw . DNSSANs
for _ , i := range raw . IPSANs {
ip := net . ParseIP ( i )
if ip == nil {
b . warn ( fmt . Sprintf ( "Cannot parse ip %q from auto_config.ip_sans" , i ) )
continue
}
val . IPSANs = append ( val . IPSANs , ip )
}
2021-08-19 20:09:42 +00:00
val . Authorizer = b . autoConfigAuthorizerVal ( raw . Authorization , agentPartition )
2020-06-16 19:03:22 +00:00
return val
}
2021-08-19 20:09:42 +00:00
func ( b * builder ) autoConfigAuthorizerVal ( raw AutoConfigAuthorizationRaw , agentPartition string ) AutoConfigAuthorizer {
2020-06-18 15:16:57 +00:00
// Our config file syntax wraps the static authorizer configuration in a "static" stanza. However
// internally we do not support multiple configured authorization types so the RuntimeConfig just
// inlines the static one. While we can and probably should extend the authorization types in the
// future to support dynamic authorizers (ACL Auth Methods configured via normal APIs) its not
// needed right now so the configuration types will remain simplistic until they need to be otherwise.
2020-06-16 19:03:22 +00:00
var val AutoConfigAuthorizer
2021-08-19 20:09:42 +00:00
entMeta := structs . DefaultEnterpriseMetaInPartition ( agentPartition )
entMeta . Normalize ( )
2020-11-20 23:58:45 +00:00
val . Enabled = boolValWithDefault ( raw . Enabled , false )
2020-06-18 15:16:57 +00:00
val . ClaimAssertions = raw . Static . ClaimAssertions
2020-11-20 23:58:45 +00:00
val . AllowReuse = boolValWithDefault ( raw . Static . AllowReuse , false )
2020-06-16 19:03:22 +00:00
val . AuthMethod = structs . ACLAuthMethod {
2020-06-18 15:16:57 +00:00
Name : "Auto Config Authorizer" ,
Type : "jwt" ,
2021-08-19 20:09:42 +00:00
EnterpriseMeta : * entMeta ,
2020-06-16 19:03:22 +00:00
Config : map [ string ] interface { } {
2020-06-18 15:16:57 +00:00
"JWTSupportedAlgs" : raw . Static . JWTSupportedAlgs ,
"BoundAudiences" : raw . Static . BoundAudiences ,
"ClaimMappings" : raw . Static . ClaimMappings ,
"ListClaimMappings" : raw . Static . ListClaimMappings ,
2020-11-20 23:58:45 +00:00
"OIDCDiscoveryURL" : stringVal ( raw . Static . OIDCDiscoveryURL ) ,
"OIDCDiscoveryCACert" : stringVal ( raw . Static . OIDCDiscoveryCACert ) ,
"JWKSURL" : stringVal ( raw . Static . JWKSURL ) ,
"JWKSCACert" : stringVal ( raw . Static . JWKSCACert ) ,
2020-06-18 15:16:57 +00:00
"JWTValidationPubKeys" : raw . Static . JWTValidationPubKeys ,
2020-11-20 23:58:45 +00:00
"BoundIssuer" : stringVal ( raw . Static . BoundIssuer ) ,
2020-06-18 15:16:57 +00:00
"ExpirationLeeway" : b . durationVal ( "auto_config.authorization.static.expiration_leeway" , raw . Static . ExpirationLeeway ) ,
"NotBeforeLeeway" : b . durationVal ( "auto_config.authorization.static.not_before_leeway" , raw . Static . NotBeforeLeeway ) ,
"ClockSkewLeeway" : b . durationVal ( "auto_config.authorization.static.clock_skew_leeway" , raw . Static . ClockSkewLeeway ) ,
2020-06-16 19:03:22 +00:00
} ,
}
return val
}
2020-12-21 18:55:53 +00:00
func ( b * builder ) validateAutoConfig ( rt RuntimeConfig ) error {
2020-06-16 19:03:22 +00:00
autoconf := rt . AutoConfig
2020-11-20 23:58:45 +00:00
if err := validateAutoConfigAuthorizer ( rt ) ; err != nil {
2020-06-16 19:03:22 +00:00
return err
}
if ! autoconf . Enabled {
return nil
}
2020-06-19 20:38:14 +00:00
// Right now we require TLS as everything we are going to transmit via auto-config is sensitive. Signed Certificates, Tokens
// and other encryption keys. This must be transmitted over a secure connection so we don't allow doing otherwise.
2022-03-18 10:46:58 +00:00
if ! rt . TLS . InternalRPC . VerifyOutgoing {
2020-06-19 20:38:14 +00:00
return fmt . Errorf ( "auto_config.enabled cannot be set without configuring TLS for server communications" )
}
2020-06-16 19:03:22 +00:00
// Auto Config doesn't currently support configuring servers
if rt . ServerMode {
return fmt . Errorf ( "auto_config.enabled cannot be set to true for server agents." )
}
// When both are set we will prefer the given value over the file.
if autoconf . IntroToken != "" && autoconf . IntroTokenFile != "" {
2020-06-19 19:16:00 +00:00
b . warn ( "Both an intro token and intro token file are set. The intro token will be used instead of the file" )
2020-06-16 19:03:22 +00:00
} else if autoconf . IntroToken == "" && autoconf . IntroTokenFile == "" {
2020-06-19 19:16:00 +00:00
return fmt . Errorf ( "One of auto_config.intro_token, auto_config.intro_token_file or the CONSUL_INTRO_TOKEN environment variable must be set to enable auto_config" )
2020-06-16 19:03:22 +00:00
}
if len ( autoconf . ServerAddresses ) == 0 {
// TODO (autoconf) can we/should we infer this from the join/retry join addresses. I think no, as we will potentially
// be overriding those retry join addresses with the autoconf process anyways.
return fmt . Errorf ( "auto_config.enabled is set without providing a list of addresses" )
}
return nil
}
2020-11-20 23:58:45 +00:00
func validateAutoConfigAuthorizer ( rt RuntimeConfig ) error {
2020-06-16 19:03:22 +00:00
authz := rt . AutoConfig . Authorizer
if ! authz . Enabled {
return nil
}
2020-08-07 14:20:27 +00:00
// When in a secondary datacenter with ACLs enabled, we require token replication to be enabled
// as that is what allows us to create the local tokens to distribute to the clients. Otherwise
// we would have to have a token with the ability to create ACL tokens in the primary and make
// RPCs in response to auto config requests.
if rt . ACLsEnabled && rt . PrimaryDatacenter != rt . Datacenter && ! rt . ACLTokenReplication {
return fmt . Errorf ( "Enabling auto-config authorization (auto_config.authorization.enabled) in non primary datacenters with ACLs enabled (acl.enabled) requires also enabling ACL token replication (acl.enable_token_replication)" )
}
2020-06-16 19:03:22 +00:00
// Auto Config Authorization is only supported on servers
if ! rt . ServerMode {
2020-06-18 15:16:57 +00:00
return fmt . Errorf ( "auto_config.authorization.enabled cannot be set to true for client agents" )
2020-06-16 19:03:22 +00:00
}
2020-06-19 20:38:14 +00:00
// Right now we require TLS as everything we are going to transmit via auto-config is sensitive. Signed Certificates, Tokens
// and other encryption keys. This must be transmitted over a secure connection so we don't allow doing otherwise.
2022-03-18 10:46:58 +00:00
if rt . TLS . InternalRPC . CertFile == "" {
2020-06-19 20:38:14 +00:00
return fmt . Errorf ( "auto_config.authorization.enabled cannot be set without providing a TLS certificate for the server" )
}
2020-06-16 19:03:22 +00:00
// build out the validator to ensure that the given configuration was valid
null := hclog . NewNullLogger ( )
validator , err := ssoauth . NewValidator ( null , & authz . AuthMethod )
if err != nil {
2020-06-18 15:16:57 +00:00
return fmt . Errorf ( "auto_config.authorization.static has invalid configuration: %v" , err )
2020-06-16 19:03:22 +00:00
}
// create a blank identity for use to validate the claim assertions.
blankID := validator . NewIdentity ( )
varMap := map [ string ] string {
2021-12-01 19:32:34 +00:00
"node" : "fake" ,
"segment" : "fake" ,
"partition" : "fake" ,
2020-06-16 19:03:22 +00:00
}
// validate all the claim assertions
for _ , raw := range authz . ClaimAssertions {
// validate any HIL
filled , err := libtempl . InterpolateHIL ( raw , varMap , true )
if err != nil {
2020-06-18 15:16:57 +00:00
return fmt . Errorf ( "auto_config.authorization.static.claim_assertion %q is invalid: %v" , raw , err )
2020-06-16 19:03:22 +00:00
}
// validate the bexpr syntax - note that for now all the keys mapped by the claim mappings
// are not validateable due to them being put inside a map. Some bexpr updates to setup keys
// from current map keys would probably be nice here.
if _ , err := bexpr . CreateEvaluatorForType ( filled , nil , blankID . SelectableFields ) ; err != nil {
2020-06-18 15:16:57 +00:00
return fmt . Errorf ( "auto_config.authorization.static.claim_assertion %q is invalid: %v" , raw , err )
2020-06-16 19:03:22 +00:00
}
}
return nil
}
2022-09-26 18:58:15 +00:00
func ( b * builder ) cloudConfigVal ( v * CloudConfigRaw ) ( val hcpconfig . CloudConfig ) {
if v == nil {
return val
}
val . ResourceID = stringVal ( v . ResourceID )
val . ClientID = stringVal ( v . ClientID )
val . ClientSecret = stringVal ( v . ClientSecret )
val . AuthURL = stringVal ( v . AuthURL )
val . Hostname = stringVal ( v . Hostname )
2022-10-13 09:31:28 +00:00
val . ScadaAddress = stringVal ( v . ScadaAddress )
2022-09-26 18:58:15 +00:00
return val
}
2017-09-25 18:40:42 +00:00
// decodeBytes returns the encryption key decoded.
func decodeBytes ( key string ) ( [ ] byte , error ) {
return base64 . StdEncoding . DecodeString ( key )
}
func isIPAddr ( a net . Addr ) bool {
_ , ok := a . ( * net . IPAddr )
return ok
}
func isUnixAddr ( a net . Addr ) bool {
_ , ok := a . ( * net . UnixAddr )
return ok
}
ui: modify content path (#5950)
* Add ui-content-path flag
* tests complete, regex validator on string, index.html updated
* cleaning up debugging stuff
* ui: Enable ember environment configuration to be set via the go binary at runtime (#5934)
* ui: Only inject {{.ContentPath}} if we are makeing a prod build...
...otherwise we just use the current rootURL
This gets injected into a <base /> node which solves the assets path
problem but not the ember problem
* ui: Pull out the <base href=""> value and inject it into ember env
See previous commit:
The <base href=""> value is 'sometimes' injected from go at index
serve time. We pass this value down to ember by overwriting the ember
config that is injected via a <meta> tag. This has to be done before
ember bootup.
Sometimes (during testing and development, basically not production)
this is injected with the already existing value, in which case this
essentially changes nothing.
The code here is slightly abstracted away from our specific usage to
make it easier for anyone else to use, and also make sure we can cope
with using this same method to pass variables down from the CLI through
to ember in the future.
* ui: We can't use <base /> move everything to javascript (#5941)
Unfortuantely we can't seem to be able to use <base> and rootURL
together as URL paths will get doubled up (`ui/ui/`).
This moves all the things that we need to interpolate with .ContentPath
to the `startup` javascript so we can conditionally print out
`{{.ContentPath}}` in lots of places (now we can't use base)
* fixed when we serve index.html
* ui: For writing a ContentPath, we also need to cope with testing... (#5945)
...and potentially more environments
Testing has more additional things in a separate index.html in `tests/`
This make the entire thing a little saner and uses just javascriopt
template literals instead of a pseudo handbrake synatx for our
templating of these files.
Intead of just templating the entire file this way, we still only
template `{{content-for 'head'}}` and `{{content-for 'body'}}`
in this way to ensure we support other plugins/addons
* build: Loosen up the regex for retrieving the CONSUL_VERSION (#5946)
* build: Loosen up the regex for retrieving the CONSUL_VERSION
1. Previously the `sed` replacement was searching for the CONSUL_VERSION
comment at the start of a line, it no longer does this to allow for
indentation.
2. Both `grep` and `sed` where looking for the omment at the end of the
line. We've removed this restriction here. We don't need to remove it
right now, but if we ever put the comment followed by something here the
searching would break.
3. Added `xargs` for trimming the resulting version string. We aren't
using this already in the rest of the scripts, but we are pretty sure
this is available on most systems.
* ui: Fix erroneous variable, and also force an ember cache clean on build
1. We referenced a variable incorrectly here, this fixes that.
2. We also made sure that every `make` target clears ember's `tmp` cache
to ensure that its not using any caches that have since been edited
everytime we call a `make` target.
* added docs, fixed encoding
* fixed go fmt
* Update agent/config/config.go
Co-Authored-By: R.B. Boyer <public@richardboyer.net>
* Completed Suggestions
* run gofmt on http.go
* fix testsanitize
* fix fullconfig/hcl by setting correct 'want'
* ran gofmt on agent/config/runtime_test.go
* Update website/source/docs/agent/options.html.md
Co-Authored-By: Hans Hasselberg <me@hans.io>
* Update website/source/docs/agent/options.html.md
Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com>
* remove contentpath from redirectFS struct
2019-06-26 16:43:30 +00:00
2019-06-27 10:00:37 +00:00
// isValidAltDomain returns true if the given domain is not prefixed
// by keywords used when dispatching DNS requests
func isValidAltDomain ( domain , datacenter string ) bool {
reAltDomain := regexp . MustCompile (
fmt . Sprintf (
"^(service|connect|node|query|addr|%s)\\.(%s\\.)?" ,
datacenter , datacenter ,
) ,
)
return ! reAltDomain . MatchString ( domain )
}
ui: modify content path (#5950)
* Add ui-content-path flag
* tests complete, regex validator on string, index.html updated
* cleaning up debugging stuff
* ui: Enable ember environment configuration to be set via the go binary at runtime (#5934)
* ui: Only inject {{.ContentPath}} if we are makeing a prod build...
...otherwise we just use the current rootURL
This gets injected into a <base /> node which solves the assets path
problem but not the ember problem
* ui: Pull out the <base href=""> value and inject it into ember env
See previous commit:
The <base href=""> value is 'sometimes' injected from go at index
serve time. We pass this value down to ember by overwriting the ember
config that is injected via a <meta> tag. This has to be done before
ember bootup.
Sometimes (during testing and development, basically not production)
this is injected with the already existing value, in which case this
essentially changes nothing.
The code here is slightly abstracted away from our specific usage to
make it easier for anyone else to use, and also make sure we can cope
with using this same method to pass variables down from the CLI through
to ember in the future.
* ui: We can't use <base /> move everything to javascript (#5941)
Unfortuantely we can't seem to be able to use <base> and rootURL
together as URL paths will get doubled up (`ui/ui/`).
This moves all the things that we need to interpolate with .ContentPath
to the `startup` javascript so we can conditionally print out
`{{.ContentPath}}` in lots of places (now we can't use base)
* fixed when we serve index.html
* ui: For writing a ContentPath, we also need to cope with testing... (#5945)
...and potentially more environments
Testing has more additional things in a separate index.html in `tests/`
This make the entire thing a little saner and uses just javascriopt
template literals instead of a pseudo handbrake synatx for our
templating of these files.
Intead of just templating the entire file this way, we still only
template `{{content-for 'head'}}` and `{{content-for 'body'}}`
in this way to ensure we support other plugins/addons
* build: Loosen up the regex for retrieving the CONSUL_VERSION (#5946)
* build: Loosen up the regex for retrieving the CONSUL_VERSION
1. Previously the `sed` replacement was searching for the CONSUL_VERSION
comment at the start of a line, it no longer does this to allow for
indentation.
2. Both `grep` and `sed` where looking for the omment at the end of the
line. We've removed this restriction here. We don't need to remove it
right now, but if we ever put the comment followed by something here the
searching would break.
3. Added `xargs` for trimming the resulting version string. We aren't
using this already in the rest of the scripts, but we are pretty sure
this is available on most systems.
* ui: Fix erroneous variable, and also force an ember cache clean on build
1. We referenced a variable incorrectly here, this fixes that.
2. We also made sure that every `make` target clears ember's `tmp` cache
to ensure that its not using any caches that have since been edited
everytime we call a `make` target.
* added docs, fixed encoding
* fixed go fmt
* Update agent/config/config.go
Co-Authored-By: R.B. Boyer <public@richardboyer.net>
* Completed Suggestions
* run gofmt on http.go
* fix testsanitize
* fix fullconfig/hcl by setting correct 'want'
* ran gofmt on agent/config/runtime_test.go
* Update website/source/docs/agent/options.html.md
Co-Authored-By: Hans Hasselberg <me@hans.io>
* Update website/source/docs/agent/options.html.md
Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com>
* remove contentpath from redirectFS struct
2019-06-26 16:43:30 +00:00
// UIPathBuilder checks to see if there was a path set
// If so, adds beginning and trailing slashes to UI path
func UIPathBuilder ( UIContentString string ) string {
if UIContentString != "" {
var fmtedPath string
fmtedPath = strings . Trim ( UIContentString , "/" )
fmtedPath = "/" + fmtedPath + "/"
return fmtedPath
}
return "/ui/"
}
2020-08-17 21:39:49 +00:00
const remoteScriptCheckSecurityWarning = "using enable-script-checks without ACLs and without allow_write_http_from is DANGEROUS, use enable-local-script-checks instead, see https://www.hashicorp.com/blog/protecting-consul-from-rce-risk-in-specific-configurations/"
// validateRemoteScriptsChecks returns an error if EnableRemoteScriptChecks is
// enabled without other security features, which mitigate the risk of executing
// remote scripts.
func validateRemoteScriptsChecks ( conf RuntimeConfig ) error {
if conf . EnableRemoteScriptChecks && ! conf . ACLsEnabled && len ( conf . AllowWriteHTTPFrom ) == 0 {
return errors . New ( remoteScriptCheckSecurityWarning )
}
return nil
}
2020-10-30 21:49:54 +00:00
func validateAbsoluteURLPath ( p string ) error {
if ! path . IsAbs ( p ) {
return fmt . Errorf ( "path %q is not an absolute path" , p )
}
// A bit more extra validation that these are actually paths.
u , err := url . Parse ( p )
if err != nil ||
u . Scheme != "" ||
u . Opaque != "" ||
u . User != nil ||
u . Host != "" ||
u . RawQuery != "" ||
u . Fragment != "" ||
u . Path != p {
return fmt . Errorf ( "path %q is not an absolute path" , p )
}
return nil
}
2022-03-18 10:46:58 +00:00
func ( b * builder ) buildTLSConfig ( rt RuntimeConfig , t TLS ) ( tlsutil . Config , error ) {
var c tlsutil . Config
// Consul makes no outgoing connections to the public gRPC port (internal gRPC
// traffic goes through the multiplexed internal RPC port) so return an error
// rather than let the user think this setting is going to do anything useful.
if t . GRPC . VerifyOutgoing != nil {
return c , errors . New ( "verify_outgoing is not valid in the tls.grpc stanza" )
}
// Similarly, only the internal RPC configuration honors VerifyServerHostname
// so we call it out here too.
if t . Defaults . VerifyServerHostname != nil || t . GRPC . VerifyServerHostname != nil || t . HTTPS . VerifyServerHostname != nil {
return c , errors . New ( "verify_server_hostname is only valid in the tls.internal_rpc stanza" )
}
2022-08-24 16:31:38 +00:00
// And UseAutoCert right now only applies to external gRPC interface.
if t . Defaults . UseAutoCert != nil || t . HTTPS . UseAutoCert != nil || t . InternalRPC . UseAutoCert != nil {
return c , errors . New ( "use_auto_cert is only valid in the tls.grpc stanza" )
2022-03-18 10:46:58 +00:00
}
2022-03-24 19:32:25 +00:00
defaultTLSMinVersion := b . tlsVersion ( "tls.defaults.tls_min_version" , t . Defaults . TLSMinVersion )
defaultCipherSuites := b . tlsCipherSuites ( "tls.defaults.tls_cipher_suites" , t . Defaults . TLSCipherSuites , defaultTLSMinVersion )
2022-03-18 10:46:58 +00:00
mapCommon := func ( name string , src TLSProtocolConfig , dst * tlsutil . ProtocolConfig ) {
dst . CAPath = stringValWithDefault ( src . CAPath , stringVal ( t . Defaults . CAPath ) )
dst . CAFile = stringValWithDefault ( src . CAFile , stringVal ( t . Defaults . CAFile ) )
dst . CertFile = stringValWithDefault ( src . CertFile , stringVal ( t . Defaults . CertFile ) )
dst . KeyFile = stringValWithDefault ( src . KeyFile , stringVal ( t . Defaults . KeyFile ) )
dst . VerifyIncoming = boolValWithDefault ( src . VerifyIncoming , boolVal ( t . Defaults . VerifyIncoming ) )
// We prevent this from being set explicity in the tls.grpc stanza above, but
// let's also prevent it from getting the tls.defaults value to avoid confusion
// if we decide to support it in the future.
if name != "grpc" {
dst . VerifyOutgoing = boolValWithDefault ( src . VerifyOutgoing , boolVal ( t . Defaults . VerifyOutgoing ) )
}
2022-03-24 19:32:25 +00:00
if src . TLSMinVersion == nil {
dst . TLSMinVersion = defaultTLSMinVersion
} else {
dst . TLSMinVersion = b . tlsVersion (
fmt . Sprintf ( "tls.%s.tls_min_version" , name ) ,
src . TLSMinVersion ,
)
}
2022-03-18 10:46:58 +00:00
if src . TLSCipherSuites == nil {
2022-03-24 19:32:25 +00:00
// If cipher suite config incompatible with a specified TLS min version
// would be inherited, omit it but don't return an error in the builder.
if validateTLSVersionCipherSuitesCompat ( dst . TLSMinVersion ) == nil {
dst . CipherSuites = defaultCipherSuites
}
2022-03-18 10:46:58 +00:00
} else {
dst . CipherSuites = b . tlsCipherSuites (
fmt . Sprintf ( "tls.%s.tls_cipher_suites" , name ) ,
src . TLSCipherSuites ,
2022-03-24 19:32:25 +00:00
dst . TLSMinVersion ,
2022-03-18 10:46:58 +00:00
)
}
}
mapCommon ( "internal_rpc" , t . InternalRPC , & c . InternalRPC )
c . InternalRPC . VerifyServerHostname = boolVal ( t . InternalRPC . VerifyServerHostname )
// Setting only verify_server_hostname is documented to imply verify_outgoing.
// If it doesn't then we risk sending communication over plain TCP when we
// documented it as forcing TLS for RPCs. Enforce this here rather than in
// several different places through the code that need to reason about it.
//
// See: CVE-2018-19653
c . InternalRPC . VerifyOutgoing = c . InternalRPC . VerifyOutgoing || c . InternalRPC . VerifyServerHostname
mapCommon ( "https" , t . HTTPS , & c . HTTPS )
mapCommon ( "grpc" , t . GRPC , & c . GRPC )
2022-08-24 16:31:38 +00:00
c . GRPC . UseAutoCert = boolValWithDefault ( t . GRPC . UseAutoCert , false )
2022-03-18 10:46:58 +00:00
2022-09-16 01:12:10 +00:00
c . ServerMode = rt . ServerMode
2022-03-18 10:46:58 +00:00
c . ServerName = rt . ServerName
c . NodeName = rt . NodeName
c . Domain = rt . DNSDomain
c . EnableAgentTLSForChecks = rt . EnableAgentTLSForChecks
c . AutoTLS = rt . AutoEncryptTLS || rt . AutoConfig . Enabled
return c , nil
}
2022-03-31 17:49:37 +00:00
func ( b * builder ) parsePrefixFilter ( telemetry * Telemetry ) ( [ ] string , [ ] string ) {
var telemetryAllowedPrefixes , telemetryBlockedPrefixes [ ] string
// TODO(FFMMM): Once one twelve style RPC metrics get out of Beta, don't remove them by default.
operatorPassedOneTwelveRPCMetric := false
oneTwelveRPCMetric := * telemetry . MetricsPrefix + "." + strings . Join ( middleware . OneTwelveRPCSummary [ 0 ] . Name , "." )
for _ , rule := range telemetry . PrefixFilter {
if rule == "" {
b . warn ( "Cannot have empty filter rule in prefix_filter" )
continue
}
switch rule [ 0 ] {
case '+' :
if rule [ 1 : ] == oneTwelveRPCMetric {
operatorPassedOneTwelveRPCMetric = true
}
telemetryAllowedPrefixes = append ( telemetryAllowedPrefixes , rule [ 1 : ] )
case '-' :
if rule [ 1 : ] == oneTwelveRPCMetric {
operatorPassedOneTwelveRPCMetric = true
}
telemetryBlockedPrefixes = append ( telemetryBlockedPrefixes , rule [ 1 : ] )
default :
b . warn ( "Filter rule must begin with either '+' or '-': %q" , rule )
}
}
if ! operatorPassedOneTwelveRPCMetric {
telemetryBlockedPrefixes = append ( telemetryBlockedPrefixes , oneTwelveRPCMetric )
}
return telemetryAllowedPrefixes , telemetryBlockedPrefixes
}