1package config
2
3import (
4	"encoding/base64"
5	"encoding/json"
6	"errors"
7	"fmt"
8	"io/ioutil"
9	"net"
10	"net/url"
11	"os"
12	"path"
13	"path/filepath"
14	"reflect"
15	"regexp"
16	"sort"
17	"strconv"
18	"strings"
19	"time"
20
21	"github.com/armon/go-metrics/prometheus"
22	"github.com/hashicorp/go-bexpr"
23	"github.com/hashicorp/go-hclog"
24	"github.com/hashicorp/go-multierror"
25	"github.com/hashicorp/go-sockaddr/template"
26	"github.com/hashicorp/memberlist"
27	"golang.org/x/time/rate"
28
29	"github.com/hashicorp/consul/agent/cache"
30	"github.com/hashicorp/consul/agent/checks"
31	"github.com/hashicorp/consul/agent/connect/ca"
32	"github.com/hashicorp/consul/agent/consul"
33	"github.com/hashicorp/consul/agent/consul/authmethod/ssoauth"
34	"github.com/hashicorp/consul/agent/dns"
35	"github.com/hashicorp/consul/agent/structs"
36	"github.com/hashicorp/consul/agent/token"
37	"github.com/hashicorp/consul/ipaddr"
38	"github.com/hashicorp/consul/lib"
39	libtempl "github.com/hashicorp/consul/lib/template"
40	"github.com/hashicorp/consul/logging"
41	"github.com/hashicorp/consul/tlsutil"
42	"github.com/hashicorp/consul/types"
43)
44
45// LoadOpts used by Load to construct and validate a RuntimeConfig.
46type LoadOpts struct {
47	// FlagValues contains the command line arguments that can also be set
48	// in a config file.
49	FlagValues Config
50
51	// ConfigFiles is a slice of paths to config files and directories that will
52	// be loaded.
53	ConfigFiles []string
54
55	// ConfigFormat forces all config files to be interpreted as this format
56	// independent of their extension. Value may be `hcl` or `json`.
57	ConfigFormat string
58
59	// DevMode indicates whether the agent should be started in development
60	// mode. This cannot be configured in a config file.
61	DevMode *bool
62
63	// HCL is a slice of config data in hcl format. Each one will be loaded as
64	// if it were the source of a config file. Values from HCL will override
65	// values from ConfigFiles and FlagValues.
66	HCL []string
67
68	// DefaultConfig is an optional source that is applied after other defaults
69	// but before ConfigFiles and all other user specified config.
70	DefaultConfig Source
71
72	// Overrides are optional config sources that are applied as the very last
73	// config source so they can override any previous values.
74	Overrides []Source
75
76	// hostname is a shim for testing, allowing tests to specify a replacement
77	// for os.Hostname.
78	hostname func() (string, error)
79
80	// getPrivateIPv4 and getPublicIPv6 are shims for testing, allowing tests to
81	// specify a replacement for ipaddr.GetPrivateIPv4 and ipaddr.GetPublicIPv6.
82	getPrivateIPv4 func() ([]*net.IPAddr, error)
83	getPublicIPv6  func() ([]*net.IPAddr, error)
84}
85
86// Load will build the configuration including the config source injected
87// after all other defaults but before any user supplied configuration and the overrides
88// source injected as the final source in the configuration parsing chain.
89//
90// The caller is responsible for handling any warnings in LoadResult.Warnings.
91func Load(opts LoadOpts) (LoadResult, error) {
92	r := LoadResult{}
93	b, err := newBuilder(opts)
94	if err != nil {
95		return r, err
96	}
97	cfg, err := b.BuildAndValidate()
98	if err != nil {
99		return r, err
100	}
101	return LoadResult{RuntimeConfig: &cfg, Warnings: b.Warnings}, nil
102}
103
104// LoadResult is the result returned from Load. The caller is responsible for
105// handling any warnings.
106type LoadResult struct {
107	RuntimeConfig *RuntimeConfig
108	Warnings      []string
109}
110
111// builder constructs and validates a runtime configuration from multiple
112// configuration sources.
113//
114// The sources are merged in the following order:
115//
116//  * default configuration
117//  * config files in alphabetical order
118//  * command line arguments
119//  * overrides
120//
121// The config sources are merged sequentially and later values overwrite
122// previously set values. Slice values are merged by concatenating the two slices.
123// Map values are merged by over-laying the later maps on top of earlier ones.
124type builder struct {
125	opts LoadOpts
126
127	// Head, Sources, and Tail are used to manage the order of the
128	// config sources, as described in the comments above.
129	Head    []Source
130	Sources []Source
131	Tail    []Source
132
133	// Warnings contains the warnings encountered when
134	// parsing the configuration.
135	Warnings []string
136
137	// err contains the first error that occurred during
138	// building the runtime configuration.
139	err error
140}
141
142// newBuilder returns a new configuration Builder from the LoadOpts.
143func newBuilder(opts LoadOpts) (*builder, error) {
144	configFormat := opts.ConfigFormat
145	if configFormat != "" && configFormat != "json" && configFormat != "hcl" {
146		return nil, fmt.Errorf("config: -config-format must be either 'hcl' or 'json'")
147	}
148
149	b := &builder{
150		opts: opts,
151		Head: []Source{DefaultSource(), DefaultEnterpriseSource()},
152	}
153
154	if boolVal(opts.DevMode) {
155		b.Head = append(b.Head, DevSource())
156	}
157
158	// Since the merge logic is to overwrite all fields with later
159	// values except slices which are merged by appending later values
160	// we need to merge all slice values defined in flags before we
161	// merge the config files since the flag values for slices are
162	// otherwise appended instead of prepended.
163	slices, values := splitSlicesAndValues(opts.FlagValues)
164	b.Head = append(b.Head, LiteralSource{Name: "flags.slices", Config: slices})
165	if opts.DefaultConfig != nil {
166		b.Head = append(b.Head, opts.DefaultConfig)
167	}
168
169	for _, path := range opts.ConfigFiles {
170		sources, err := b.sourcesFromPath(path, opts.ConfigFormat)
171		if err != nil {
172			return nil, err
173		}
174		b.Sources = append(b.Sources, sources...)
175	}
176	b.Tail = append(b.Tail, LiteralSource{Name: "flags.values", Config: values})
177	for i, s := range opts.HCL {
178		b.Tail = append(b.Tail, FileSource{
179			Name:   fmt.Sprintf("flags-%d.hcl", i),
180			Format: "hcl",
181			Data:   s,
182		})
183	}
184	b.Tail = append(b.Tail, NonUserSource(), DefaultConsulSource(), OverrideEnterpriseSource(), defaultVersionSource())
185	if boolVal(opts.DevMode) {
186		b.Tail = append(b.Tail, DevConsulSource())
187	}
188	if len(opts.Overrides) != 0 {
189		b.Tail = append(b.Tail, opts.Overrides...)
190	}
191	return b, nil
192}
193
194// sourcesFromPath reads a single config file or all files in a directory (but
195// not its sub-directories) and returns Sources created from the
196// files.
197func (b *builder) sourcesFromPath(path string, format string) ([]Source, error) {
198	f, err := os.Open(path)
199	if err != nil {
200		return nil, fmt.Errorf("config: Open failed on %s. %s", path, err)
201	}
202	defer f.Close()
203
204	fi, err := f.Stat()
205	if err != nil {
206		return nil, fmt.Errorf("config: Stat failed on %s. %s", path, err)
207	}
208
209	if !fi.IsDir() {
210		if !shouldParseFile(path, format) {
211			b.warn("skipping file %v, extension must be .hcl or .json, or config format must be set", path)
212			return nil, nil
213		}
214
215		src, err := newSourceFromFile(path, format)
216		if err != nil {
217			return nil, err
218		}
219		return []Source{src}, nil
220	}
221
222	fis, err := f.Readdir(-1)
223	if err != nil {
224		return nil, fmt.Errorf("config: Readdir failed on %s. %s", path, err)
225	}
226
227	// sort files by name
228	sort.Sort(byName(fis))
229
230	var sources []Source
231	for _, fi := range fis {
232		fp := filepath.Join(path, fi.Name())
233		// check for a symlink and resolve the path
234		if fi.Mode()&os.ModeSymlink > 0 {
235			var err error
236			fp, err = filepath.EvalSymlinks(fp)
237			if err != nil {
238				return nil, err
239			}
240			fi, err = os.Stat(fp)
241			if err != nil {
242				return nil, err
243			}
244		}
245		// do not recurse into sub dirs
246		if fi.IsDir() {
247			continue
248		}
249
250		if !shouldParseFile(fp, format) {
251			b.warn("skipping file %v, extension must be .hcl or .json, or config format must be set", fp)
252			continue
253		}
254		src, err := newSourceFromFile(fp, format)
255		if err != nil {
256			return nil, err
257		}
258		sources = append(sources, src)
259	}
260	return sources, nil
261}
262
263// newSourceFromFile creates a Source from the contents of the file at path.
264func newSourceFromFile(path string, format string) (Source, error) {
265	data, err := ioutil.ReadFile(path)
266	if err != nil {
267		return nil, fmt.Errorf("config: failed to read %s: %s", path, err)
268	}
269	if format == "" {
270		format = formatFromFileExtension(path)
271	}
272	return FileSource{Name: path, Data: string(data), Format: format}, nil
273}
274
275// shouldParse file determines whether the file to be read is of a supported extension
276func shouldParseFile(path string, configFormat string) bool {
277	srcFormat := formatFromFileExtension(path)
278	return configFormat != "" || srcFormat == "hcl" || srcFormat == "json"
279}
280
281func formatFromFileExtension(name string) string {
282	switch {
283	case strings.HasSuffix(name, ".json"):
284		return "json"
285	case strings.HasSuffix(name, ".hcl"):
286		return "hcl"
287	default:
288		return ""
289	}
290}
291
292type byName []os.FileInfo
293
294func (a byName) Len() int           { return len(a) }
295func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
296func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }
297
298func (b *builder) BuildAndValidate() (RuntimeConfig, error) {
299	rt, err := b.Build()
300	if err != nil {
301		return RuntimeConfig{}, err
302	}
303	if err := b.Validate(rt); err != nil {
304		return RuntimeConfig{}, err
305	}
306	return rt, nil
307}
308
309// Build constructs the runtime configuration from the config sources
310// and the command line flags. The config sources are processed in the
311// order they were added with the flags being processed last to give
312// precedence over the other sources. If the error is nil then
313// warnings can still contain deprecation or format warnings that should
314// be presented to the user.
315func (b *builder) Build() (rt RuntimeConfig, err error) {
316	srcs := make([]Source, 0, len(b.Head)+len(b.Sources)+len(b.Tail))
317	srcs = append(srcs, b.Head...)
318	srcs = append(srcs, b.Sources...)
319	srcs = append(srcs, b.Tail...)
320
321	// parse the config sources into a configuration
322	var c Config
323	for _, s := range srcs {
324
325		c2, md, err := s.Parse()
326		switch {
327		case err == ErrNoData:
328			continue
329		case err != nil:
330			return RuntimeConfig{}, fmt.Errorf("failed to parse %v: %w", s.Source(), err)
331		}
332
333		var unusedErr error
334		for _, k := range md.Unused {
335			switch k {
336			case "acl_enforce_version_8":
337				b.warn("config key %q is deprecated and should be removed", k)
338			default:
339				unusedErr = multierror.Append(unusedErr, fmt.Errorf("invalid config key %s", k))
340			}
341		}
342		if unusedErr != nil {
343			return RuntimeConfig{}, fmt.Errorf("failed to parse %v: %s", s.Source(), unusedErr)
344		}
345
346		for _, err := range validateEnterpriseConfigKeys(&c2) {
347			b.warn("%s", err)
348		}
349
350		// if we have a single 'check' or 'service' we need to add them to the
351		// list of checks and services first since we cannot merge them
352		// generically and later values would clobber earlier ones.
353		if c2.Check != nil {
354			c2.Checks = append(c2.Checks, *c2.Check)
355			c2.Check = nil
356		}
357		if c2.Service != nil {
358			c2.Services = append(c2.Services, *c2.Service)
359			c2.Service = nil
360		}
361
362		c = Merge(c, c2)
363	}
364
365	// ----------------------------------------------------------------
366	// process/merge some complex values
367	//
368
369	var dnsServiceTTL = map[string]time.Duration{}
370	for k, v := range c.DNS.ServiceTTL {
371		dnsServiceTTL[k] = b.durationVal(fmt.Sprintf("dns_config.service_ttl[%q]", k), &v)
372	}
373
374	soa := RuntimeSOAConfig{Refresh: 3600, Retry: 600, Expire: 86400, Minttl: 0}
375	if c.DNS.SOA != nil {
376		if c.DNS.SOA.Expire != nil {
377			soa.Expire = *c.DNS.SOA.Expire
378		}
379		if c.DNS.SOA.Minttl != nil {
380			soa.Minttl = *c.DNS.SOA.Minttl
381		}
382		if c.DNS.SOA.Refresh != nil {
383			soa.Refresh = *c.DNS.SOA.Refresh
384		}
385		if c.DNS.SOA.Retry != nil {
386			soa.Retry = *c.DNS.SOA.Retry
387		}
388	}
389
390	leaveOnTerm := !boolVal(c.ServerMode)
391	if c.LeaveOnTerm != nil {
392		leaveOnTerm = boolVal(c.LeaveOnTerm)
393	}
394
395	skipLeaveOnInt := boolVal(c.ServerMode)
396	if c.SkipLeaveOnInt != nil {
397		skipLeaveOnInt = boolVal(c.SkipLeaveOnInt)
398	}
399
400	// ----------------------------------------------------------------
401	// checks and services
402	//
403
404	var checks []*structs.CheckDefinition
405	if c.Check != nil {
406		checks = append(checks, b.checkVal(c.Check))
407	}
408	for _, check := range c.Checks {
409		checks = append(checks, b.checkVal(&check))
410	}
411
412	var services []*structs.ServiceDefinition
413	for _, service := range c.Services {
414		services = append(services, b.serviceVal(&service))
415	}
416	if c.Service != nil {
417		services = append(services, b.serviceVal(c.Service))
418	}
419
420	// ----------------------------------------------------------------
421	// addresses
422	//
423
424	// determine port values and replace values <= 0 and > 65535 with -1
425	dnsPort := b.portVal("ports.dns", c.Ports.DNS)
426	httpPort := b.portVal("ports.http", c.Ports.HTTP)
427	httpsPort := b.portVal("ports.https", c.Ports.HTTPS)
428	serverPort := b.portVal("ports.server", c.Ports.Server)
429	grpcPort := b.portVal("ports.grpc", c.Ports.GRPC)
430	serfPortLAN := b.portVal("ports.serf_lan", c.Ports.SerfLAN)
431	serfPortWAN := b.portVal("ports.serf_wan", c.Ports.SerfWAN)
432	proxyMinPort := b.portVal("ports.proxy_min_port", c.Ports.ProxyMinPort)
433	proxyMaxPort := b.portVal("ports.proxy_max_port", c.Ports.ProxyMaxPort)
434	sidecarMinPort := b.portVal("ports.sidecar_min_port", c.Ports.SidecarMinPort)
435	sidecarMaxPort := b.portVal("ports.sidecar_max_port", c.Ports.SidecarMaxPort)
436	exposeMinPort := b.portVal("ports.expose_min_port", c.Ports.ExposeMinPort)
437	exposeMaxPort := b.portVal("ports.expose_max_port", c.Ports.ExposeMaxPort)
438	if proxyMaxPort < proxyMinPort {
439		return RuntimeConfig{}, fmt.Errorf(
440			"proxy_min_port must be less than proxy_max_port. To disable, set both to zero.")
441	}
442	if sidecarMaxPort < sidecarMinPort {
443		return RuntimeConfig{}, fmt.Errorf(
444			"sidecar_min_port must be less than sidecar_max_port. To disable, set both to zero.")
445	}
446	if exposeMaxPort < exposeMinPort {
447		return RuntimeConfig{}, fmt.Errorf(
448			"expose_min_port must be less than expose_max_port. To disable, set both to zero.")
449	}
450
451	// determine the default bind and advertise address
452	//
453	// First check whether the user provided an ANY address or whether
454	// the expanded template results in an ANY address. In that case we
455	// derive an advertise address from the current network
456	// configuration since we can listen on an ANY address for incoming
457	// traffic but cannot advertise it as the address on which the
458	// server can be reached.
459
460	bindAddrs := b.expandAddrs("bind_addr", c.BindAddr)
461	if len(bindAddrs) == 0 {
462		return RuntimeConfig{}, fmt.Errorf("bind_addr cannot be empty")
463	}
464	if len(bindAddrs) > 1 {
465		return RuntimeConfig{}, fmt.Errorf("bind_addr cannot contain multiple addresses. Use 'addresses.{dns,http,https}' instead.")
466	}
467	if isUnixAddr(bindAddrs[0]) {
468		return RuntimeConfig{}, fmt.Errorf("bind_addr cannot be a unix socket")
469	}
470	if !isIPAddr(bindAddrs[0]) {
471		return RuntimeConfig{}, fmt.Errorf("bind_addr must be an ip address")
472	}
473	if ipaddr.IsAny(stringVal(c.AdvertiseAddrLAN)) {
474		return RuntimeConfig{}, fmt.Errorf("Advertise address cannot be 0.0.0.0, :: or [::]")
475	}
476	if ipaddr.IsAny(stringVal(c.AdvertiseAddrWAN)) {
477		return RuntimeConfig{}, fmt.Errorf("Advertise WAN address cannot be 0.0.0.0, :: or [::]")
478	}
479
480	bindAddr := bindAddrs[0].(*net.IPAddr)
481	advertiseAddr := makeIPAddr(b.expandFirstIP("advertise_addr", c.AdvertiseAddrLAN), bindAddr)
482
483	if ipaddr.IsAny(advertiseAddr) {
484		addrtyp, detect := advertiseAddrFunc(b.opts, advertiseAddr)
485		advertiseAddrs, err := detect()
486		if err != nil {
487			return RuntimeConfig{}, fmt.Errorf("Error detecting %s address: %s", addrtyp, err)
488		}
489		if len(advertiseAddrs) == 0 {
490			return RuntimeConfig{}, fmt.Errorf("No %s address found", addrtyp)
491		}
492		if len(advertiseAddrs) > 1 {
493			return RuntimeConfig{}, fmt.Errorf("Multiple %s addresses found. Please configure one with 'bind' and/or 'advertise'.", addrtyp)
494		}
495		advertiseAddr = advertiseAddrs[0]
496	}
497
498	// derive other bind addresses from the bindAddr
499	rpcBindAddr := b.makeTCPAddr(bindAddr, nil, serverPort)
500	serfBindAddrLAN := b.makeTCPAddr(b.expandFirstIP("serf_lan", c.SerfBindAddrLAN), bindAddr, serfPortLAN)
501
502	// Only initialize serf WAN bind address when its enabled
503	var serfBindAddrWAN *net.TCPAddr
504	if serfPortWAN >= 0 {
505		serfBindAddrWAN = b.makeTCPAddr(b.expandFirstIP("serf_wan", c.SerfBindAddrWAN), bindAddr, serfPortWAN)
506	}
507
508	// derive other advertise addresses from the advertise address
509	advertiseAddrLAN := makeIPAddr(b.expandFirstIP("advertise_addr", c.AdvertiseAddrLAN), advertiseAddr)
510	advertiseAddrIsV6 := advertiseAddr.IP.To4() == nil
511	var advertiseAddrV4, advertiseAddrV6 *net.IPAddr
512	if !advertiseAddrIsV6 {
513		advertiseAddrV4 = advertiseAddr
514	} else {
515		advertiseAddrV6 = advertiseAddr
516	}
517	advertiseAddrLANIPv4 := makeIPAddr(b.expandFirstIP("advertise_addr_ipv4", c.AdvertiseAddrLANIPv4), advertiseAddrV4)
518	if advertiseAddrLANIPv4 != nil && advertiseAddrLANIPv4.IP.To4() == nil {
519		return RuntimeConfig{}, fmt.Errorf("advertise_addr_ipv4 must be an ipv4 address")
520	}
521	advertiseAddrLANIPv6 := makeIPAddr(b.expandFirstIP("advertise_addr_ipv6", c.AdvertiseAddrLANIPv6), advertiseAddrV6)
522	if advertiseAddrLANIPv6 != nil && advertiseAddrLANIPv6.IP.To4() != nil {
523		return RuntimeConfig{}, fmt.Errorf("advertise_addr_ipv6 must be an ipv6 address")
524	}
525
526	advertiseAddrWAN := makeIPAddr(b.expandFirstIP("advertise_addr_wan", c.AdvertiseAddrWAN), advertiseAddrLAN)
527	advertiseAddrWANIsV6 := advertiseAddrWAN.IP.To4() == nil
528	var advertiseAddrWANv4, advertiseAddrWANv6 *net.IPAddr
529	if !advertiseAddrWANIsV6 {
530		advertiseAddrWANv4 = advertiseAddrWAN
531	} else {
532		advertiseAddrWANv6 = advertiseAddrWAN
533	}
534	advertiseAddrWANIPv4 := makeIPAddr(b.expandFirstIP("advertise_addr_wan_ipv4", c.AdvertiseAddrWANIPv4), advertiseAddrWANv4)
535	if advertiseAddrWANIPv4 != nil && advertiseAddrWANIPv4.IP.To4() == nil {
536		return RuntimeConfig{}, fmt.Errorf("advertise_addr_wan_ipv4 must be an ipv4 address")
537	}
538	advertiseAddrWANIPv6 := makeIPAddr(b.expandFirstIP("advertise_addr_wan_ipv6", c.AdvertiseAddrWANIPv6), advertiseAddrWANv6)
539	if advertiseAddrWANIPv6 != nil && advertiseAddrWANIPv6.IP.To4() != nil {
540		return RuntimeConfig{}, fmt.Errorf("advertise_addr_wan_ipv6 must be an ipv6 address")
541	}
542
543	rpcAdvertiseAddr := &net.TCPAddr{IP: advertiseAddrLAN.IP, Port: serverPort}
544	serfAdvertiseAddrLAN := &net.TCPAddr{IP: advertiseAddrLAN.IP, Port: serfPortLAN}
545	// Only initialize serf WAN advertise address when its enabled
546	var serfAdvertiseAddrWAN *net.TCPAddr
547	if serfPortWAN >= 0 {
548		serfAdvertiseAddrWAN = &net.TCPAddr{IP: advertiseAddrWAN.IP, Port: serfPortWAN}
549	}
550
551	// determine client addresses
552	clientAddrs := b.expandIPs("client_addr", c.ClientAddr)
553	dnsAddrs := b.makeAddrs(b.expandAddrs("addresses.dns", c.Addresses.DNS), clientAddrs, dnsPort)
554	httpAddrs := b.makeAddrs(b.expandAddrs("addresses.http", c.Addresses.HTTP), clientAddrs, httpPort)
555	httpsAddrs := b.makeAddrs(b.expandAddrs("addresses.https", c.Addresses.HTTPS), clientAddrs, httpsPort)
556	grpcAddrs := b.makeAddrs(b.expandAddrs("addresses.grpc", c.Addresses.GRPC), clientAddrs, grpcPort)
557
558	for _, a := range dnsAddrs {
559		if x, ok := a.(*net.TCPAddr); ok {
560			dnsAddrs = append(dnsAddrs, &net.UDPAddr{IP: x.IP, Port: x.Port})
561		}
562	}
563
564	// expand dns recursors
565	uniq := map[string]bool{}
566	dnsRecursors := []string{}
567	for _, r := range c.DNSRecursors {
568		x, err := template.Parse(r)
569		if err != nil {
570			return RuntimeConfig{}, fmt.Errorf("Invalid DNS recursor template %q: %s", r, err)
571		}
572		for _, addr := range strings.Fields(x) {
573			if strings.HasPrefix(addr, "unix://") {
574				return RuntimeConfig{}, fmt.Errorf("DNS Recursors cannot be unix sockets: %s", addr)
575			}
576			if uniq[addr] {
577				continue
578			}
579			uniq[addr] = true
580			dnsRecursors = append(dnsRecursors, addr)
581		}
582	}
583
584	datacenter := strings.ToLower(stringVal(c.Datacenter))
585	altDomain := stringVal(c.DNSAltDomain)
586
587	// Create the default set of tagged addresses.
588	if c.TaggedAddresses == nil {
589		c.TaggedAddresses = make(map[string]string)
590	}
591
592	c.TaggedAddresses[structs.TaggedAddressLAN] = advertiseAddrLAN.IP.String()
593	if advertiseAddrLANIPv4 != nil {
594		c.TaggedAddresses[structs.TaggedAddressLANIPv4] = advertiseAddrLANIPv4.IP.String()
595	}
596	if advertiseAddrLANIPv6 != nil {
597		c.TaggedAddresses[structs.TaggedAddressLANIPv6] = advertiseAddrLANIPv6.IP.String()
598	}
599
600	c.TaggedAddresses[structs.TaggedAddressWAN] = advertiseAddrWAN.IP.String()
601	if advertiseAddrWANIPv4 != nil {
602		c.TaggedAddresses[structs.TaggedAddressWANIPv4] = advertiseAddrWANIPv4.IP.String()
603	}
604	if advertiseAddrWANIPv6 != nil {
605		c.TaggedAddresses[structs.TaggedAddressWANIPv6] = advertiseAddrWANIPv6.IP.String()
606	}
607
608	// segments
609	var segments []structs.NetworkSegment
610	for _, s := range c.Segments {
611		name := stringVal(s.Name)
612		port := b.portVal(fmt.Sprintf("segments[%s].port", name), s.Port)
613		if port <= 0 {
614			return RuntimeConfig{}, fmt.Errorf("Port for segment %q cannot be <= 0", name)
615		}
616
617		bind := b.makeTCPAddr(
618			b.expandFirstIP(fmt.Sprintf("segments[%s].bind", name), s.Bind),
619			bindAddr,
620			port,
621		)
622
623		advertise := b.makeTCPAddr(
624			b.expandFirstIP(fmt.Sprintf("segments[%s].advertise", name), s.Advertise),
625			advertiseAddrLAN,
626			port,
627		)
628
629		segments = append(segments, structs.NetworkSegment{
630			Name:        name,
631			Bind:        bind,
632			Advertise:   advertise,
633			RPCListener: boolVal(s.RPCListener),
634		})
635	}
636
637	// Parse the metric filters
638	var telemetryAllowedPrefixes, telemetryBlockedPrefixes []string
639	for _, rule := range c.Telemetry.PrefixFilter {
640		if rule == "" {
641			b.warn("Cannot have empty filter rule in prefix_filter")
642			continue
643		}
644		switch rule[0] {
645		case '+':
646			telemetryAllowedPrefixes = append(telemetryAllowedPrefixes, rule[1:])
647		case '-':
648			telemetryBlockedPrefixes = append(telemetryBlockedPrefixes, rule[1:])
649		default:
650			b.warn("Filter rule must begin with either '+' or '-': %q", rule)
651		}
652	}
653
654	// raft performance scaling
655	performanceRaftMultiplier := intVal(c.Performance.RaftMultiplier)
656	if performanceRaftMultiplier < 1 || uint(performanceRaftMultiplier) > consul.MaxRaftMultiplier {
657		return RuntimeConfig{}, fmt.Errorf("performance.raft_multiplier cannot be %d. Must be between 1 and %d", performanceRaftMultiplier, consul.MaxRaftMultiplier)
658	}
659	consulRaftElectionTimeout := b.durationVal("consul.raft.election_timeout", c.Consul.Raft.ElectionTimeout) * time.Duration(performanceRaftMultiplier)
660	consulRaftHeartbeatTimeout := b.durationVal("consul.raft.heartbeat_timeout", c.Consul.Raft.HeartbeatTimeout) * time.Duration(performanceRaftMultiplier)
661	consulRaftLeaderLeaseTimeout := b.durationVal("consul.raft.leader_lease_timeout", c.Consul.Raft.LeaderLeaseTimeout) * time.Duration(performanceRaftMultiplier)
662
663	// Connect
664	connectEnabled := boolVal(c.Connect.Enabled)
665	connectCAProvider := stringVal(c.Connect.CAProvider)
666	connectCAConfig := c.Connect.CAConfig
667
668	// autoEncrypt and autoConfig implicitly turns on connect which is why
669	// they need to be above other settings that rely on connect.
670	autoEncryptTLS := boolVal(c.AutoEncrypt.TLS)
671	autoEncryptDNSSAN := []string{}
672	for _, d := range c.AutoEncrypt.DNSSAN {
673		autoEncryptDNSSAN = append(autoEncryptDNSSAN, d)
674	}
675	autoEncryptIPSAN := []net.IP{}
676	for _, i := range c.AutoEncrypt.IPSAN {
677		ip := net.ParseIP(i)
678		if ip == nil {
679			b.warn(fmt.Sprintf("Cannot parse ip %q from AutoEncrypt.IPSAN", i))
680			continue
681		}
682		autoEncryptIPSAN = append(autoEncryptIPSAN, ip)
683
684	}
685	autoEncryptAllowTLS := boolVal(c.AutoEncrypt.AllowTLS)
686
687	if autoEncryptAllowTLS {
688		connectEnabled = true
689	}
690
691	autoConfig := b.autoConfigVal(c.AutoConfig)
692	if autoConfig.Enabled {
693		connectEnabled = true
694	}
695
696	// Connect proxy defaults
697	connectMeshGatewayWANFederationEnabled := boolVal(c.Connect.MeshGatewayWANFederationEnabled)
698	if connectMeshGatewayWANFederationEnabled && !connectEnabled {
699		return RuntimeConfig{}, fmt.Errorf("'connect.enable_mesh_gateway_wan_federation=true' requires 'connect.enabled=true'")
700	}
701	if connectCAConfig != nil {
702		// nolint: staticcheck // CA config should be changed to use HookTranslateKeys
703		lib.TranslateKeys(connectCAConfig, map[string]string{
704			// Consul CA config
705			"private_key":           "PrivateKey",
706			"root_cert":             "RootCert",
707			"intermediate_cert_ttl": "IntermediateCertTTL",
708
709			// Vault CA config
710			"address":               "Address",
711			"token":                 "Token",
712			"root_pki_path":         "RootPKIPath",
713			"intermediate_pki_path": "IntermediatePKIPath",
714			"ca_file":               "CAFile",
715			"ca_path":               "CAPath",
716			"cert_file":             "CertFile",
717			"key_file":              "KeyFile",
718			"tls_server_name":       "TLSServerName",
719			"tls_skip_verify":       "TLSSkipVerify",
720
721			// AWS CA config
722			"existing_arn":   "ExistingARN",
723			"delete_on_exit": "DeleteOnExit",
724
725			// Common CA config
726			"leaf_cert_ttl":      "LeafCertTTL",
727			"csr_max_per_second": "CSRMaxPerSecond",
728			"csr_max_concurrent": "CSRMaxConcurrent",
729			"private_key_type":   "PrivateKeyType",
730			"private_key_bits":   "PrivateKeyBits",
731		})
732	}
733
734	aclsEnabled := false
735	primaryDatacenter := strings.ToLower(stringVal(c.PrimaryDatacenter))
736	if c.ACLDatacenter != nil {
737		b.warn("The 'acl_datacenter' field is deprecated. Use the 'primary_datacenter' field instead.")
738
739		if primaryDatacenter == "" {
740			primaryDatacenter = strings.ToLower(stringVal(c.ACLDatacenter))
741		}
742
743		// when the acl_datacenter config is used it implicitly enables acls
744		aclsEnabled = true
745	}
746
747	if c.ACL.Enabled != nil {
748		aclsEnabled = boolVal(c.ACL.Enabled)
749	}
750
751	// Set the primary DC if it wasn't set.
752	if primaryDatacenter == "" {
753		primaryDatacenter = datacenter
754	}
755
756	enableTokenReplication := false
757	if c.ACLReplicationToken != nil {
758		enableTokenReplication = true
759	}
760
761	boolValWithDefault(c.ACL.TokenReplication, boolValWithDefault(c.EnableACLReplication, enableTokenReplication))
762
763	enableRemoteScriptChecks := boolVal(c.EnableScriptChecks)
764	enableLocalScriptChecks := boolValWithDefault(c.EnableLocalScriptChecks, enableRemoteScriptChecks)
765
766	// VerifyServerHostname implies VerifyOutgoing
767	verifyServerName := boolVal(c.VerifyServerHostname)
768	verifyOutgoing := boolVal(c.VerifyOutgoing)
769	if verifyServerName {
770		// Setting only verify_server_hostname is documented to imply
771		// verify_outgoing. If it doesn't then we risk sending communication over TCP
772		// when we documented it as forcing TLS for RPCs. Enforce this here rather
773		// than in several different places through the code that need to reason
774		// about it. (See CVE-2018-19653)
775		verifyOutgoing = true
776	}
777
778	var configEntries []structs.ConfigEntry
779
780	if len(c.ConfigEntries.Bootstrap) > 0 {
781		for i, rawEntry := range c.ConfigEntries.Bootstrap {
782			entry, err := structs.DecodeConfigEntry(rawEntry)
783			if err != nil {
784				return RuntimeConfig{}, fmt.Errorf("config_entries.bootstrap[%d]: %s", i, err)
785			}
786			if err := entry.Normalize(); err != nil {
787				return RuntimeConfig{}, fmt.Errorf("config_entries.bootstrap[%d]: %s", i, err)
788			}
789			if err := entry.Validate(); err != nil {
790				return RuntimeConfig{}, fmt.Errorf("config_entries.bootstrap[%d]: %s", i, err)
791			}
792			configEntries = append(configEntries, entry)
793		}
794	}
795
796	serfAllowedCIDRSLAN, err := memberlist.ParseCIDRs(c.SerfAllowedCIDRsLAN)
797	if err != nil {
798		return RuntimeConfig{}, fmt.Errorf("serf_lan_allowed_cidrs: %s", err)
799	}
800	serfAllowedCIDRSWAN, err := memberlist.ParseCIDRs(c.SerfAllowedCIDRsWAN)
801	if err != nil {
802		return RuntimeConfig{}, fmt.Errorf("serf_wan_allowed_cidrs: %s", err)
803	}
804
805	// Handle Deprecated UI config fields
806	if c.UI != nil {
807		b.warn("The 'ui' field is deprecated. Use the 'ui_config.enabled' field instead.")
808		if c.UIConfig.Enabled == nil {
809			c.UIConfig.Enabled = c.UI
810		}
811	}
812	if c.UIDir != nil {
813		b.warn("The 'ui_dir' field is deprecated. Use the 'ui_config.dir' field instead.")
814		if c.UIConfig.Dir == nil {
815			c.UIConfig.Dir = c.UIDir
816		}
817	}
818	if c.UIContentPath != nil {
819		b.warn("The 'ui_content_path' field is deprecated. Use the 'ui_config.content_path' field instead.")
820		if c.UIConfig.ContentPath == nil {
821			c.UIConfig.ContentPath = c.UIContentPath
822		}
823	}
824
825	serverMode := boolVal(c.ServerMode)
826
827	// ----------------------------------------------------------------
828	// build runtime config
829	//
830	dataDir := stringVal(c.DataDir)
831	rt = RuntimeConfig{
832		// non-user configurable values
833		ACLDisabledTTL:             b.durationVal("acl.disabled_ttl", c.ACL.DisabledTTL),
834		AEInterval:                 b.durationVal("ae_interval", c.AEInterval),
835		CheckDeregisterIntervalMin: b.durationVal("check_deregister_interval_min", c.CheckDeregisterIntervalMin),
836		CheckReapInterval:          b.durationVal("check_reap_interval", c.CheckReapInterval),
837		Revision:                   stringVal(c.Revision),
838		SegmentLimit:               intVal(c.SegmentLimit),
839		SegmentNameLimit:           intVal(c.SegmentNameLimit),
840		SyncCoordinateIntervalMin:  b.durationVal("sync_coordinate_interval_min", c.SyncCoordinateIntervalMin),
841		SyncCoordinateRateTarget:   float64Val(c.SyncCoordinateRateTarget),
842		Version:                    stringVal(c.Version),
843		VersionPrerelease:          stringVal(c.VersionPrerelease),
844
845		// consul configuration
846		ConsulCoordinateUpdateBatchSize:  intVal(c.Consul.Coordinate.UpdateBatchSize),
847		ConsulCoordinateUpdateMaxBatches: intVal(c.Consul.Coordinate.UpdateMaxBatches),
848		ConsulCoordinateUpdatePeriod:     b.durationVal("consul.coordinate.update_period", c.Consul.Coordinate.UpdatePeriod),
849		ConsulRaftElectionTimeout:        consulRaftElectionTimeout,
850		ConsulRaftHeartbeatTimeout:       consulRaftHeartbeatTimeout,
851		ConsulRaftLeaderLeaseTimeout:     consulRaftLeaderLeaseTimeout,
852		ConsulServerHealthInterval:       b.durationVal("consul.server.health_interval", c.Consul.Server.HealthInterval),
853
854		// gossip configuration
855		GossipLANGossipInterval: b.durationVal("gossip_lan..gossip_interval", c.GossipLAN.GossipInterval),
856		GossipLANGossipNodes:    intVal(c.GossipLAN.GossipNodes),
857		GossipLANProbeInterval:  b.durationVal("gossip_lan..probe_interval", c.GossipLAN.ProbeInterval),
858		GossipLANProbeTimeout:   b.durationVal("gossip_lan..probe_timeout", c.GossipLAN.ProbeTimeout),
859		GossipLANSuspicionMult:  intVal(c.GossipLAN.SuspicionMult),
860		GossipLANRetransmitMult: intVal(c.GossipLAN.RetransmitMult),
861		GossipWANGossipInterval: b.durationVal("gossip_wan..gossip_interval", c.GossipWAN.GossipInterval),
862		GossipWANGossipNodes:    intVal(c.GossipWAN.GossipNodes),
863		GossipWANProbeInterval:  b.durationVal("gossip_wan..probe_interval", c.GossipWAN.ProbeInterval),
864		GossipWANProbeTimeout:   b.durationVal("gossip_wan..probe_timeout", c.GossipWAN.ProbeTimeout),
865		GossipWANSuspicionMult:  intVal(c.GossipWAN.SuspicionMult),
866		GossipWANRetransmitMult: intVal(c.GossipWAN.RetransmitMult),
867
868		// ACL
869		ACLsEnabled:            aclsEnabled,
870		ACLDatacenter:          primaryDatacenter,
871		ACLDefaultPolicy:       stringValWithDefault(c.ACL.DefaultPolicy, stringVal(c.ACLDefaultPolicy)),
872		ACLDownPolicy:          stringValWithDefault(c.ACL.DownPolicy, stringVal(c.ACLDownPolicy)),
873		ACLEnableKeyListPolicy: boolValWithDefault(c.ACL.EnableKeyListPolicy, boolVal(c.ACLEnableKeyListPolicy)),
874		ACLMasterToken:         stringValWithDefault(c.ACL.Tokens.Master, stringVal(c.ACLMasterToken)),
875		ACLTokenTTL:            b.durationValWithDefault("acl.token_ttl", c.ACL.TokenTTL, b.durationVal("acl_ttl", c.ACLTTL)),
876		ACLPolicyTTL:           b.durationVal("acl.policy_ttl", c.ACL.PolicyTTL),
877		ACLRoleTTL:             b.durationVal("acl.role_ttl", c.ACL.RoleTTL),
878		ACLTokenReplication:    boolValWithDefault(c.ACL.TokenReplication, boolValWithDefault(c.EnableACLReplication, enableTokenReplication)),
879
880		ACLTokens: token.Config{
881			DataDir:             dataDir,
882			EnablePersistence:   boolValWithDefault(c.ACL.EnableTokenPersistence, false),
883			ACLDefaultToken:     stringValWithDefault(c.ACL.Tokens.Default, stringVal(c.ACLToken)),
884			ACLAgentToken:       stringValWithDefault(c.ACL.Tokens.Agent, stringVal(c.ACLAgentToken)),
885			ACLAgentMasterToken: stringValWithDefault(c.ACL.Tokens.AgentMaster, stringVal(c.ACLAgentMasterToken)),
886			ACLReplicationToken: stringValWithDefault(c.ACL.Tokens.Replication, stringVal(c.ACLReplicationToken)),
887		},
888
889		// Autopilot
890		AutopilotCleanupDeadServers:      boolVal(c.Autopilot.CleanupDeadServers),
891		AutopilotDisableUpgradeMigration: boolVal(c.Autopilot.DisableUpgradeMigration),
892		AutopilotLastContactThreshold:    b.durationVal("autopilot.last_contact_threshold", c.Autopilot.LastContactThreshold),
893		AutopilotMaxTrailingLogs:         intVal(c.Autopilot.MaxTrailingLogs),
894		AutopilotMinQuorum:               uintVal(c.Autopilot.MinQuorum),
895		AutopilotRedundancyZoneTag:       stringVal(c.Autopilot.RedundancyZoneTag),
896		AutopilotServerStabilizationTime: b.durationVal("autopilot.server_stabilization_time", c.Autopilot.ServerStabilizationTime),
897		AutopilotUpgradeVersionTag:       stringVal(c.Autopilot.UpgradeVersionTag),
898
899		// DNS
900		DNSAddrs:              dnsAddrs,
901		DNSAllowStale:         boolVal(c.DNS.AllowStale),
902		DNSARecordLimit:       intVal(c.DNS.ARecordLimit),
903		DNSDisableCompression: boolVal(c.DNS.DisableCompression),
904		DNSDomain:             stringVal(c.DNSDomain),
905		DNSAltDomain:          altDomain,
906		DNSEnableTruncate:     boolVal(c.DNS.EnableTruncate),
907		DNSMaxStale:           b.durationVal("dns_config.max_stale", c.DNS.MaxStale),
908		DNSNodeTTL:            b.durationVal("dns_config.node_ttl", c.DNS.NodeTTL),
909		DNSOnlyPassing:        boolVal(c.DNS.OnlyPassing),
910		DNSPort:               dnsPort,
911		DNSRecursorTimeout:    b.durationVal("recursor_timeout", c.DNS.RecursorTimeout),
912		DNSRecursors:          dnsRecursors,
913		DNSServiceTTL:         dnsServiceTTL,
914		DNSSOA:                soa,
915		DNSUDPAnswerLimit:     intVal(c.DNS.UDPAnswerLimit),
916		DNSNodeMetaTXT:        boolValWithDefault(c.DNS.NodeMetaTXT, true),
917		DNSUseCache:           boolVal(c.DNS.UseCache),
918		DNSCacheMaxAge:        b.durationVal("dns_config.cache_max_age", c.DNS.CacheMaxAge),
919
920		// HTTP
921		HTTPPort:            httpPort,
922		HTTPSPort:           httpsPort,
923		HTTPAddrs:           httpAddrs,
924		HTTPSAddrs:          httpsAddrs,
925		HTTPBlockEndpoints:  c.HTTPConfig.BlockEndpoints,
926		HTTPMaxHeaderBytes:  intVal(c.HTTPConfig.MaxHeaderBytes),
927		HTTPResponseHeaders: c.HTTPConfig.ResponseHeaders,
928		AllowWriteHTTPFrom:  b.cidrsVal("allow_write_http_from", c.HTTPConfig.AllowWriteHTTPFrom),
929		HTTPUseCache:        boolValWithDefault(c.HTTPConfig.UseCache, true),
930
931		// Telemetry
932		Telemetry: lib.TelemetryConfig{
933			CirconusAPIApp:                     stringVal(c.Telemetry.CirconusAPIApp),
934			CirconusAPIToken:                   stringVal(c.Telemetry.CirconusAPIToken),
935			CirconusAPIURL:                     stringVal(c.Telemetry.CirconusAPIURL),
936			CirconusBrokerID:                   stringVal(c.Telemetry.CirconusBrokerID),
937			CirconusBrokerSelectTag:            stringVal(c.Telemetry.CirconusBrokerSelectTag),
938			CirconusCheckDisplayName:           stringVal(c.Telemetry.CirconusCheckDisplayName),
939			CirconusCheckForceMetricActivation: stringVal(c.Telemetry.CirconusCheckForceMetricActivation),
940			CirconusCheckID:                    stringVal(c.Telemetry.CirconusCheckID),
941			CirconusCheckInstanceID:            stringVal(c.Telemetry.CirconusCheckInstanceID),
942			CirconusCheckSearchTag:             stringVal(c.Telemetry.CirconusCheckSearchTag),
943			CirconusCheckTags:                  stringVal(c.Telemetry.CirconusCheckTags),
944			CirconusSubmissionInterval:         stringVal(c.Telemetry.CirconusSubmissionInterval),
945			CirconusSubmissionURL:              stringVal(c.Telemetry.CirconusSubmissionURL),
946			DisableCompatOneNine:               boolVal(c.Telemetry.DisableCompatOneNine),
947			DisableHostname:                    boolVal(c.Telemetry.DisableHostname),
948			DogstatsdAddr:                      stringVal(c.Telemetry.DogstatsdAddr),
949			DogstatsdTags:                      c.Telemetry.DogstatsdTags,
950			FilterDefault:                      boolVal(c.Telemetry.FilterDefault),
951			AllowedPrefixes:                    telemetryAllowedPrefixes,
952			BlockedPrefixes:                    telemetryBlockedPrefixes,
953			MetricsPrefix:                      stringVal(c.Telemetry.MetricsPrefix),
954			StatsdAddr:                         stringVal(c.Telemetry.StatsdAddr),
955			StatsiteAddr:                       stringVal(c.Telemetry.StatsiteAddr),
956			PrometheusOpts: prometheus.PrometheusOpts{
957				Expiration: b.durationVal("prometheus_retention_time", c.Telemetry.PrometheusRetentionTime),
958			},
959		},
960
961		// Agent
962		AdvertiseAddrLAN:          advertiseAddrLAN,
963		AdvertiseAddrWAN:          advertiseAddrWAN,
964		AdvertiseReconnectTimeout: b.durationVal("advertise_reconnect_timeout", c.AdvertiseReconnectTimeout),
965		BindAddr:                  bindAddr,
966		Bootstrap:                 boolVal(c.Bootstrap),
967		BootstrapExpect:           intVal(c.BootstrapExpect),
968		Cache: cache.Options{
969			EntryFetchRate: rate.Limit(
970				float64ValWithDefault(c.Cache.EntryFetchRate, float64(cache.DefaultEntryFetchRate)),
971			),
972			EntryFetchMaxBurst: intValWithDefault(
973				c.Cache.EntryFetchMaxBurst, cache.DefaultEntryFetchMaxBurst,
974			),
975		},
976		CAFile:                                 stringVal(c.CAFile),
977		CAPath:                                 stringVal(c.CAPath),
978		CertFile:                               stringVal(c.CertFile),
979		CheckUpdateInterval:                    b.durationVal("check_update_interval", c.CheckUpdateInterval),
980		CheckOutputMaxSize:                     intValWithDefault(c.CheckOutputMaxSize, 4096),
981		Checks:                                 checks,
982		ClientAddrs:                            clientAddrs,
983		ConfigEntryBootstrap:                   configEntries,
984		AutoEncryptTLS:                         autoEncryptTLS,
985		AutoEncryptDNSSAN:                      autoEncryptDNSSAN,
986		AutoEncryptIPSAN:                       autoEncryptIPSAN,
987		AutoEncryptAllowTLS:                    autoEncryptAllowTLS,
988		AutoConfig:                             autoConfig,
989		ConnectEnabled:                         connectEnabled,
990		ConnectCAProvider:                      connectCAProvider,
991		ConnectCAConfig:                        connectCAConfig,
992		ConnectMeshGatewayWANFederationEnabled: connectMeshGatewayWANFederationEnabled,
993		ConnectSidecarMinPort:                  sidecarMinPort,
994		ConnectSidecarMaxPort:                  sidecarMaxPort,
995		ConnectTestCALeafRootChangeSpread:      b.durationVal("connect.test_ca_leaf_root_change_spread", c.Connect.TestCALeafRootChangeSpread),
996		ExposeMinPort:                          exposeMinPort,
997		ExposeMaxPort:                          exposeMaxPort,
998		DataDir:                                dataDir,
999		Datacenter:                             datacenter,
1000		DefaultQueryTime:                       b.durationVal("default_query_time", c.DefaultQueryTime),
1001		DevMode:                                boolVal(b.opts.DevMode),
1002		DisableAnonymousSignature:              boolVal(c.DisableAnonymousSignature),
1003		DisableCoordinates:                     boolVal(c.DisableCoordinates),
1004		DisableHostNodeID:                      boolVal(c.DisableHostNodeID),
1005		DisableHTTPUnprintableCharFilter:       boolVal(c.DisableHTTPUnprintableCharFilter),
1006		DisableKeyringFile:                     boolVal(c.DisableKeyringFile),
1007		DisableRemoteExec:                      boolVal(c.DisableRemoteExec),
1008		DisableUpdateCheck:                     boolVal(c.DisableUpdateCheck),
1009		DiscardCheckOutput:                     boolVal(c.DiscardCheckOutput),
1010
1011		DiscoveryMaxStale:          b.durationVal("discovery_max_stale", c.DiscoveryMaxStale),
1012		EnableAgentTLSForChecks:    boolVal(c.EnableAgentTLSForChecks),
1013		EnableCentralServiceConfig: boolVal(c.EnableCentralServiceConfig),
1014		EnableDebug:                boolVal(c.EnableDebug),
1015		EnableRemoteScriptChecks:   enableRemoteScriptChecks,
1016		EnableLocalScriptChecks:    enableLocalScriptChecks,
1017		EncryptKey:                 stringVal(c.EncryptKey),
1018		EncryptVerifyIncoming:      boolVal(c.EncryptVerifyIncoming),
1019		EncryptVerifyOutgoing:      boolVal(c.EncryptVerifyOutgoing),
1020		GRPCPort:                   grpcPort,
1021		GRPCAddrs:                  grpcAddrs,
1022		HTTPMaxConnsPerClient:      intVal(c.Limits.HTTPMaxConnsPerClient),
1023		HTTPSHandshakeTimeout:      b.durationVal("limits.https_handshake_timeout", c.Limits.HTTPSHandshakeTimeout),
1024		KeyFile:                    stringVal(c.KeyFile),
1025		KVMaxValueSize:             uint64Val(c.Limits.KVMaxValueSize),
1026		LeaveDrainTime:             b.durationVal("performance.leave_drain_time", c.Performance.LeaveDrainTime),
1027		LeaveOnTerm:                leaveOnTerm,
1028		Logging: logging.Config{
1029			LogLevel:          stringVal(c.LogLevel),
1030			LogJSON:           boolVal(c.LogJSON),
1031			LogFilePath:       stringVal(c.LogFile),
1032			EnableSyslog:      boolVal(c.EnableSyslog),
1033			SyslogFacility:    stringVal(c.SyslogFacility),
1034			LogRotateDuration: b.durationVal("log_rotate_duration", c.LogRotateDuration),
1035			LogRotateBytes:    intVal(c.LogRotateBytes),
1036			LogRotateMaxFiles: intVal(c.LogRotateMaxFiles),
1037		},
1038		MaxQueryTime:                b.durationVal("max_query_time", c.MaxQueryTime),
1039		NodeID:                      types.NodeID(stringVal(c.NodeID)),
1040		NodeMeta:                    c.NodeMeta,
1041		NodeName:                    b.nodeName(c.NodeName),
1042		ReadReplica:                 boolVal(c.ReadReplica),
1043		PidFile:                     stringVal(c.PidFile),
1044		PrimaryDatacenter:           primaryDatacenter,
1045		PrimaryGateways:             b.expandAllOptionalAddrs("primary_gateways", c.PrimaryGateways),
1046		PrimaryGatewaysInterval:     b.durationVal("primary_gateways_interval", c.PrimaryGatewaysInterval),
1047		RPCAdvertiseAddr:            rpcAdvertiseAddr,
1048		RPCBindAddr:                 rpcBindAddr,
1049		RPCHandshakeTimeout:         b.durationVal("limits.rpc_handshake_timeout", c.Limits.RPCHandshakeTimeout),
1050		RPCHoldTimeout:              b.durationVal("performance.rpc_hold_timeout", c.Performance.RPCHoldTimeout),
1051		RPCMaxBurst:                 intVal(c.Limits.RPCMaxBurst),
1052		RPCMaxConnsPerClient:        intVal(c.Limits.RPCMaxConnsPerClient),
1053		RPCProtocol:                 intVal(c.RPCProtocol),
1054		RPCRateLimit:                rate.Limit(float64Val(c.Limits.RPCRate)),
1055		RPCConfig:                   consul.RPCConfig{EnableStreaming: boolValWithDefault(c.RPC.EnableStreaming, serverMode)},
1056		RaftProtocol:                intVal(c.RaftProtocol),
1057		RaftSnapshotThreshold:       intVal(c.RaftSnapshotThreshold),
1058		RaftSnapshotInterval:        b.durationVal("raft_snapshot_interval", c.RaftSnapshotInterval),
1059		RaftTrailingLogs:            intVal(c.RaftTrailingLogs),
1060		ReconnectTimeoutLAN:         b.durationVal("reconnect_timeout", c.ReconnectTimeoutLAN),
1061		ReconnectTimeoutWAN:         b.durationVal("reconnect_timeout_wan", c.ReconnectTimeoutWAN),
1062		RejoinAfterLeave:            boolVal(c.RejoinAfterLeave),
1063		RetryJoinIntervalLAN:        b.durationVal("retry_interval", c.RetryJoinIntervalLAN),
1064		RetryJoinIntervalWAN:        b.durationVal("retry_interval_wan", c.RetryJoinIntervalWAN),
1065		RetryJoinLAN:                b.expandAllOptionalAddrs("retry_join", c.RetryJoinLAN),
1066		RetryJoinMaxAttemptsLAN:     intVal(c.RetryJoinMaxAttemptsLAN),
1067		RetryJoinMaxAttemptsWAN:     intVal(c.RetryJoinMaxAttemptsWAN),
1068		RetryJoinWAN:                b.expandAllOptionalAddrs("retry_join_wan", c.RetryJoinWAN),
1069		SegmentName:                 stringVal(c.SegmentName),
1070		Segments:                    segments,
1071		SerfAdvertiseAddrLAN:        serfAdvertiseAddrLAN,
1072		SerfAdvertiseAddrWAN:        serfAdvertiseAddrWAN,
1073		SerfAllowedCIDRsLAN:         serfAllowedCIDRSLAN,
1074		SerfAllowedCIDRsWAN:         serfAllowedCIDRSWAN,
1075		SerfBindAddrLAN:             serfBindAddrLAN,
1076		SerfBindAddrWAN:             serfBindAddrWAN,
1077		SerfPortLAN:                 serfPortLAN,
1078		SerfPortWAN:                 serfPortWAN,
1079		ServerMode:                  serverMode,
1080		ServerName:                  stringVal(c.ServerName),
1081		ServerPort:                  serverPort,
1082		Services:                    services,
1083		SessionTTLMin:               b.durationVal("session_ttl_min", c.SessionTTLMin),
1084		SkipLeaveOnInt:              skipLeaveOnInt,
1085		StartJoinAddrsLAN:           b.expandAllOptionalAddrs("start_join", c.StartJoinAddrsLAN),
1086		StartJoinAddrsWAN:           b.expandAllOptionalAddrs("start_join_wan", c.StartJoinAddrsWAN),
1087		TLSCipherSuites:             b.tlsCipherSuites("tls_cipher_suites", c.TLSCipherSuites),
1088		TLSMinVersion:               stringVal(c.TLSMinVersion),
1089		TLSPreferServerCipherSuites: boolVal(c.TLSPreferServerCipherSuites),
1090		TaggedAddresses:             c.TaggedAddresses,
1091		TranslateWANAddrs:           boolVal(c.TranslateWANAddrs),
1092		TxnMaxReqLen:                uint64Val(c.Limits.TxnMaxReqLen),
1093		UIConfig:                    b.uiConfigVal(c.UIConfig),
1094		UnixSocketGroup:             stringVal(c.UnixSocket.Group),
1095		UnixSocketMode:              stringVal(c.UnixSocket.Mode),
1096		UnixSocketUser:              stringVal(c.UnixSocket.User),
1097		VerifyIncoming:              boolVal(c.VerifyIncoming),
1098		VerifyIncomingHTTPS:         boolVal(c.VerifyIncomingHTTPS),
1099		VerifyIncomingRPC:           boolVal(c.VerifyIncomingRPC),
1100		VerifyOutgoing:              verifyOutgoing,
1101		VerifyServerHostname:        verifyServerName,
1102		Watches:                     c.Watches,
1103	}
1104
1105	rt.UseStreamingBackend = boolValWithDefault(c.UseStreamingBackend, true)
1106
1107	if rt.Cache.EntryFetchMaxBurst <= 0 {
1108		return RuntimeConfig{}, fmt.Errorf("cache.entry_fetch_max_burst must be strictly positive, was: %v", rt.Cache.EntryFetchMaxBurst)
1109	}
1110	if rt.Cache.EntryFetchRate <= 0 {
1111		return RuntimeConfig{}, fmt.Errorf("cache.entry_fetch_rate must be strictly positive, was: %v", rt.Cache.EntryFetchRate)
1112	}
1113
1114	if rt.UIConfig.MetricsProvider == "prometheus" {
1115		// Handle defaulting for the built-in version of prometheus.
1116		if len(rt.UIConfig.MetricsProxy.PathAllowlist) == 0 {
1117			rt.UIConfig.MetricsProxy.PathAllowlist = []string{
1118				"/api/v1/query",
1119				"/api/v1/query_range",
1120			}
1121		}
1122	}
1123
1124	if err := b.BuildEnterpriseRuntimeConfig(&rt, &c); err != nil {
1125		return rt, err
1126	}
1127
1128	if rt.BootstrapExpect == 1 {
1129		rt.Bootstrap = true
1130		rt.BootstrapExpect = 0
1131		b.warn(`BootstrapExpect is set to 1; this is the same as Bootstrap mode.`)
1132	}
1133
1134	return rt, nil
1135}
1136
1137func advertiseAddrFunc(opts LoadOpts, advertiseAddr *net.IPAddr) (string, func() ([]*net.IPAddr, error)) {
1138	switch {
1139	case ipaddr.IsAnyV4(advertiseAddr):
1140		fn := opts.getPrivateIPv4
1141		if fn == nil {
1142			fn = ipaddr.GetPrivateIPv4
1143		}
1144		return "private IPv4", fn
1145
1146	case ipaddr.IsAnyV6(advertiseAddr):
1147		fn := opts.getPublicIPv6
1148		if fn == nil {
1149			fn = ipaddr.GetPublicIPv6
1150		}
1151		return "public IPv6", fn
1152
1153	default:
1154		panic("unsupported net.IPAddr Type")
1155	}
1156}
1157
1158// reBasicName validates that a field contains only lower case alphanumerics,
1159// underscore and dash and is non-empty.
1160var reBasicName = regexp.MustCompile("^[a-z0-9_-]+$")
1161
1162func validateBasicName(field, value string, allowEmpty bool) error {
1163	if value == "" {
1164		if allowEmpty {
1165			return nil
1166		}
1167		return fmt.Errorf("%s cannot be empty", field)
1168	}
1169	if !reBasicName.MatchString(value) {
1170		return fmt.Errorf("%s can only contain lowercase alphanumeric, - or _ characters."+
1171			" received: %q", field, value)
1172	}
1173	return nil
1174}
1175
1176// Validate performs semantic validation of the runtime configuration.
1177func (b *builder) Validate(rt RuntimeConfig) error {
1178
1179	// validContentPath defines a regexp for a valid content path name.
1180	var validContentPath = regexp.MustCompile(`^[A-Za-z0-9/_-]+$`)
1181	var hasVersion = regexp.MustCompile(`^/v\d+/$`)
1182	// ----------------------------------------------------------------
1183	// check required params we cannot recover from first
1184	//
1185
1186	if rt.RaftProtocol != 3 {
1187		return fmt.Errorf("raft_protocol version %d is not supported by this version of Consul", rt.RaftProtocol)
1188	}
1189
1190	if err := validateBasicName("datacenter", rt.Datacenter, false); err != nil {
1191		return err
1192	}
1193	if rt.DataDir == "" && !rt.DevMode {
1194		return fmt.Errorf("data_dir cannot be empty")
1195	}
1196
1197	if !validContentPath.MatchString(rt.UIConfig.ContentPath) {
1198		return fmt.Errorf("ui-content-path can only contain alphanumeric, -, _, or /. received: %q", rt.UIConfig.ContentPath)
1199	}
1200
1201	if hasVersion.MatchString(rt.UIConfig.ContentPath) {
1202		return fmt.Errorf("ui-content-path cannot have 'v[0-9]'. received: %q", rt.UIConfig.ContentPath)
1203	}
1204
1205	if err := validateBasicName("ui_config.metrics_provider", rt.UIConfig.MetricsProvider, true); err != nil {
1206		return err
1207	}
1208	if rt.UIConfig.MetricsProviderOptionsJSON != "" {
1209		// Attempt to parse the JSON to ensure it's valid, parsing into a map
1210		// ensures we get an object.
1211		var dummyMap map[string]interface{}
1212		err := json.Unmarshal([]byte(rt.UIConfig.MetricsProviderOptionsJSON), &dummyMap)
1213		if err != nil {
1214			return fmt.Errorf("ui_config.metrics_provider_options_json must be empty "+
1215				"or a string containing a valid JSON object. received: %q",
1216				rt.UIConfig.MetricsProviderOptionsJSON)
1217		}
1218	}
1219	if rt.UIConfig.MetricsProxy.BaseURL != "" {
1220		u, err := url.Parse(rt.UIConfig.MetricsProxy.BaseURL)
1221		if err != nil || !(u.Scheme == "http" || u.Scheme == "https") {
1222			return fmt.Errorf("ui_config.metrics_proxy.base_url must be a valid http"+
1223				" or https URL. received: %q",
1224				rt.UIConfig.MetricsProxy.BaseURL)
1225		}
1226	}
1227	for _, allowedPath := range rt.UIConfig.MetricsProxy.PathAllowlist {
1228		if err := validateAbsoluteURLPath(allowedPath); err != nil {
1229			return fmt.Errorf("ui_config.metrics_proxy.path_allowlist: %v", err)
1230		}
1231	}
1232	for k, v := range rt.UIConfig.DashboardURLTemplates {
1233		if err := validateBasicName("ui_config.dashboard_url_templates key names", k, false); err != nil {
1234			return err
1235		}
1236		u, err := url.Parse(v)
1237		if err != nil || !(u.Scheme == "http" || u.Scheme == "https") {
1238			return fmt.Errorf("ui_config.dashboard_url_templates values must be a"+
1239				" valid http or https URL. received: %q",
1240				rt.UIConfig.MetricsProxy.BaseURL)
1241		}
1242	}
1243
1244	if !rt.DevMode {
1245		fi, err := os.Stat(rt.DataDir)
1246		switch {
1247		case err != nil && !os.IsNotExist(err):
1248			return fmt.Errorf("Error getting info on data_dir: %s", err)
1249		case err == nil && !fi.IsDir():
1250			return fmt.Errorf("data_dir %q is not a directory", rt.DataDir)
1251		}
1252	}
1253
1254	switch {
1255	case rt.NodeName == "":
1256		return fmt.Errorf("node_name cannot be empty")
1257	case dns.InvalidNameRe.MatchString(rt.NodeName):
1258		b.warn("Node name %q will not be discoverable "+
1259			"via DNS due to invalid characters. Valid characters include "+
1260			"all alpha-numerics and dashes.", rt.NodeName)
1261	case len(rt.NodeName) > dns.MaxLabelLength:
1262		b.warn("Node name %q will not be discoverable "+
1263			"via DNS due to it being too long. Valid lengths are between "+
1264			"1 and 63 bytes.", rt.NodeName)
1265	}
1266
1267	if ipaddr.IsAny(rt.AdvertiseAddrLAN.IP) {
1268		return fmt.Errorf("Advertise address cannot be 0.0.0.0, :: or [::]")
1269	}
1270	if ipaddr.IsAny(rt.AdvertiseAddrWAN.IP) {
1271		return fmt.Errorf("Advertise WAN address cannot be 0.0.0.0, :: or [::]")
1272	}
1273	if err := b.validateSegments(rt); err != nil {
1274		return err
1275	}
1276	for _, a := range rt.DNSAddrs {
1277		if _, ok := a.(*net.UnixAddr); ok {
1278			return fmt.Errorf("DNS address cannot be a unix socket")
1279		}
1280	}
1281	for _, a := range rt.DNSRecursors {
1282		if ipaddr.IsAny(a) {
1283			return fmt.Errorf("DNS recursor address cannot be 0.0.0.0, :: or [::]")
1284		}
1285	}
1286	if !isValidAltDomain(rt.DNSAltDomain, rt.Datacenter) {
1287		return fmt.Errorf("alt_domain cannot start with {service,connect,node,query,addr,%s}", rt.Datacenter)
1288	}
1289	if rt.Bootstrap && !rt.ServerMode {
1290		return fmt.Errorf("'bootstrap = true' requires 'server = true'")
1291	}
1292	if rt.BootstrapExpect < 0 {
1293		return fmt.Errorf("bootstrap_expect cannot be %d. Must be greater than or equal to zero", rt.BootstrapExpect)
1294	}
1295	if rt.BootstrapExpect > 0 && !rt.ServerMode {
1296		return fmt.Errorf("'bootstrap_expect > 0' requires 'server = true'")
1297	}
1298	if rt.BootstrapExpect > 0 && rt.DevMode {
1299		return fmt.Errorf("'bootstrap_expect > 0' not allowed in dev mode")
1300	}
1301	if rt.BootstrapExpect > 0 && rt.Bootstrap {
1302		return fmt.Errorf("'bootstrap_expect > 0' and 'bootstrap = true' are mutually exclusive")
1303	}
1304	if rt.CheckOutputMaxSize < 1 {
1305		return fmt.Errorf("check_output_max_size must be positive, to discard check output use the discard_check_output flag")
1306	}
1307	if rt.AEInterval <= 0 {
1308		return fmt.Errorf("ae_interval cannot be %s. Must be positive", rt.AEInterval)
1309	}
1310	if rt.AutopilotMaxTrailingLogs < 0 {
1311		return fmt.Errorf("autopilot.max_trailing_logs cannot be %d. Must be greater than or equal to zero", rt.AutopilotMaxTrailingLogs)
1312	}
1313	if err := validateBasicName("acl_datacenter", rt.ACLDatacenter, true); err != nil {
1314		return err
1315	}
1316	// In DevMode, UI is enabled by default, so to enable rt.UIDir, don't perform this check
1317	if !rt.DevMode && rt.UIConfig.Enabled && rt.UIConfig.Dir != "" {
1318		return fmt.Errorf(
1319			"Both the ui_config.enabled and ui_config.dir (or -ui and -ui-dir) were specified, please provide only one.\n" +
1320				"If trying to use your own web UI resources, use ui_config.dir or the -ui-dir flag.\n" +
1321				"The web UI is included in the binary so use ui_config.enabled or the -ui flag to enable it")
1322	}
1323	if rt.DNSUDPAnswerLimit < 0 {
1324		return fmt.Errorf("dns_config.udp_answer_limit cannot be %d. Must be greater than or equal to zero", rt.DNSUDPAnswerLimit)
1325	}
1326	if rt.DNSARecordLimit < 0 {
1327		return fmt.Errorf("dns_config.a_record_limit cannot be %d. Must be greater than or equal to zero", rt.DNSARecordLimit)
1328	}
1329	if err := structs.ValidateNodeMetadata(rt.NodeMeta, false); err != nil {
1330		return fmt.Errorf("node_meta invalid: %v", err)
1331	}
1332	if rt.EncryptKey != "" {
1333		if _, err := decodeBytes(rt.EncryptKey); err != nil {
1334			return fmt.Errorf("encrypt has invalid key: %s", err)
1335		}
1336	}
1337
1338	if rt.ConnectMeshGatewayWANFederationEnabled && !rt.ServerMode {
1339		return fmt.Errorf("'connect.enable_mesh_gateway_wan_federation = true' requires 'server = true'")
1340	}
1341	if rt.ConnectMeshGatewayWANFederationEnabled && strings.ContainsAny(rt.NodeName, "/") {
1342		return fmt.Errorf("'connect.enable_mesh_gateway_wan_federation = true' requires that 'node_name' not contain '/' characters")
1343	}
1344	if rt.ConnectMeshGatewayWANFederationEnabled {
1345		if len(rt.StartJoinAddrsWAN) > 0 {
1346			return fmt.Errorf("'start_join_wan' is incompatible with 'connect.enable_mesh_gateway_wan_federation = true'")
1347		}
1348		if len(rt.RetryJoinWAN) > 0 {
1349			return fmt.Errorf("'retry_join_wan' is incompatible with 'connect.enable_mesh_gateway_wan_federation = true'")
1350		}
1351	}
1352	if len(rt.PrimaryGateways) > 0 {
1353		if !rt.ServerMode {
1354			return fmt.Errorf("'primary_gateways' requires 'server = true'")
1355		}
1356		if rt.PrimaryDatacenter == rt.Datacenter {
1357			return fmt.Errorf("'primary_gateways' should only be configured in a secondary datacenter")
1358		}
1359	}
1360
1361	// Check the data dir for signs of an un-migrated Consul 0.5.x or older
1362	// server. Consul refuses to start if this is present to protect a server
1363	// with existing data from starting on a fresh data set.
1364	if rt.ServerMode {
1365		mdbPath := filepath.Join(rt.DataDir, "mdb")
1366		if _, err := os.Stat(mdbPath); !os.IsNotExist(err) {
1367			if os.IsPermission(err) {
1368				return fmt.Errorf(
1369					"CRITICAL: Permission denied for data folder at %q!\n"+
1370						"Consul will refuse to boot without access to this directory.\n"+
1371						"Please correct permissions and try starting again.", mdbPath)
1372			}
1373			return fmt.Errorf("CRITICAL: Deprecated data folder found at %q!\n"+
1374				"Consul will refuse to boot with this directory present.\n"+
1375				"See https://www.consul.io/docs/upgrade-specific.html for more information.", mdbPath)
1376		}
1377	}
1378
1379	inuse := map[string]string{}
1380	if err := addrsUnique(inuse, "DNS", rt.DNSAddrs); err != nil {
1381		// cannot happen since this is the first address
1382		// we leave this for consistency
1383		return err
1384	}
1385	if err := addrsUnique(inuse, "HTTP", rt.HTTPAddrs); err != nil {
1386		return err
1387	}
1388	if err := addrsUnique(inuse, "HTTPS", rt.HTTPSAddrs); err != nil {
1389		return err
1390	}
1391	if err := addrUnique(inuse, "RPC Advertise", rt.RPCAdvertiseAddr); err != nil {
1392		return err
1393	}
1394	if err := addrUnique(inuse, "Serf Advertise LAN", rt.SerfAdvertiseAddrLAN); err != nil {
1395		return err
1396	}
1397	// Validate serf WAN advertise address only when its set
1398	if rt.SerfAdvertiseAddrWAN != nil {
1399		if err := addrUnique(inuse, "Serf Advertise WAN", rt.SerfAdvertiseAddrWAN); err != nil {
1400			return err
1401		}
1402	}
1403	if b.err != nil {
1404		return b.err
1405	}
1406
1407	// Check for errors in the service definitions
1408	for _, s := range rt.Services {
1409		if err := s.Validate(); err != nil {
1410			return fmt.Errorf("service %q: %s", s.Name, err)
1411		}
1412	}
1413
1414	// Validate the given Connect CA provider config
1415	validCAProviders := map[string]bool{
1416		"":                       true,
1417		structs.ConsulCAProvider: true,
1418		structs.VaultCAProvider:  true,
1419		structs.AWSCAProvider:    true,
1420	}
1421	if _, ok := validCAProviders[rt.ConnectCAProvider]; !ok {
1422		return fmt.Errorf("%s is not a valid CA provider", rt.ConnectCAProvider)
1423	} else {
1424		switch rt.ConnectCAProvider {
1425		case structs.ConsulCAProvider:
1426			if _, err := ca.ParseConsulCAConfig(rt.ConnectCAConfig); err != nil {
1427				return err
1428			}
1429		case structs.VaultCAProvider:
1430			if _, err := ca.ParseVaultCAConfig(rt.ConnectCAConfig); err != nil {
1431				return err
1432			}
1433		case structs.AWSCAProvider:
1434			if _, err := ca.ParseAWSCAConfig(rt.ConnectCAConfig); err != nil {
1435				return err
1436			}
1437		}
1438	}
1439
1440	if rt.ServerMode && rt.AutoEncryptTLS {
1441		return fmt.Errorf("auto_encrypt.tls can only be used on a client.")
1442	}
1443	if !rt.ServerMode && rt.AutoEncryptAllowTLS {
1444		return fmt.Errorf("auto_encrypt.allow_tls can only be used on a server.")
1445	}
1446
1447	if rt.ServerMode && rt.AdvertiseReconnectTimeout != 0 {
1448		return fmt.Errorf("advertise_reconnect_timeout can only be used on a client")
1449	}
1450
1451	// ----------------------------------------------------------------
1452	// warnings
1453	//
1454
1455	if rt.ServerMode && !rt.DevMode && !rt.Bootstrap && rt.BootstrapExpect == 2 {
1456		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`)
1457	}
1458
1459	if rt.ServerMode && !rt.Bootstrap && rt.BootstrapExpect > 2 && rt.BootstrapExpect%2 == 0 {
1460		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`)
1461	}
1462
1463	if rt.ServerMode && rt.Bootstrap && rt.BootstrapExpect == 0 {
1464		b.warn(`bootstrap = true: do not enable unless necessary`)
1465	}
1466
1467	if rt.ServerMode && !rt.DevMode && !rt.Bootstrap && rt.BootstrapExpect > 1 {
1468		b.warn("bootstrap_expect > 0: expecting %d servers", rt.BootstrapExpect)
1469	}
1470
1471	if rt.ServerMode {
1472		if rt.UseStreamingBackend && !rt.RPCConfig.EnableStreaming {
1473			b.warn("use_streaming_backend = true requires rpc.enable_streaming on servers to work properly")
1474		}
1475	} else if rt.RPCConfig.EnableStreaming {
1476		b.warn("rpc.enable_streaming = true has no effect when not running in server mode")
1477	}
1478
1479	if rt.AutoEncryptAllowTLS {
1480		if !rt.VerifyIncoming && !rt.VerifyIncomingRPC {
1481			b.warn("if auto_encrypt.allow_tls is turned on, either verify_incoming or verify_incoming_rpc should be enabled. It is necessary to turn it off during a migration to TLS, but it should definitely be turned on afterwards.")
1482		}
1483	}
1484
1485	if err := checkLimitsFromMaxConnsPerClient(rt.HTTPMaxConnsPerClient); err != nil {
1486		return err
1487	}
1488
1489	if rt.AutoConfig.Enabled && rt.AutoEncryptTLS {
1490		return fmt.Errorf("both auto_encrypt.tls and auto_config.enabled cannot be set to true.")
1491	}
1492
1493	if err := b.validateAutoConfig(rt); err != nil {
1494		return err
1495	}
1496
1497	if err := validateRemoteScriptsChecks(rt); err != nil {
1498		// TODO: make this an error in a future version
1499		b.warn(err.Error())
1500	}
1501
1502	err := b.validateEnterpriseConfig(rt)
1503	return err
1504}
1505
1506// addrUnique checks if the given address is already in use for another
1507// protocol.
1508func addrUnique(inuse map[string]string, name string, addr net.Addr) error {
1509	key := addr.Network() + ":" + addr.String()
1510	if other, ok := inuse[key]; ok {
1511		return fmt.Errorf("%s address %s already configured for %s", name, addr.String(), other)
1512	}
1513	inuse[key] = name
1514	return nil
1515}
1516
1517// addrsUnique checks if any of the give addresses is already in use for
1518// another protocol.
1519func addrsUnique(inuse map[string]string, name string, addrs []net.Addr) error {
1520	for _, a := range addrs {
1521		if err := addrUnique(inuse, name, a); err != nil {
1522			return err
1523		}
1524	}
1525	return nil
1526}
1527
1528// splitSlicesAndValues moves all slice values defined in c to 'slices'
1529// and all other values to 'values'.
1530func splitSlicesAndValues(c Config) (slices, values Config) {
1531	v, t := reflect.ValueOf(c), reflect.TypeOf(c)
1532	rs, rv := reflect.New(t), reflect.New(t)
1533
1534	for i := 0; i < t.NumField(); i++ {
1535		f := t.Field(i)
1536		if f.Type.Kind() == reflect.Slice {
1537			rs.Elem().Field(i).Set(v.Field(i))
1538		} else {
1539			rv.Elem().Field(i).Set(v.Field(i))
1540		}
1541	}
1542	return rs.Elem().Interface().(Config), rv.Elem().Interface().(Config)
1543}
1544
1545func (b *builder) warn(msg string, args ...interface{}) {
1546	b.Warnings = append(b.Warnings, fmt.Sprintf(msg, args...))
1547}
1548
1549func (b *builder) checkVal(v *CheckDefinition) *structs.CheckDefinition {
1550	if v == nil {
1551		return nil
1552	}
1553
1554	id := types.CheckID(stringVal(v.ID))
1555
1556	return &structs.CheckDefinition{
1557		ID:                             id,
1558		Name:                           stringVal(v.Name),
1559		Notes:                          stringVal(v.Notes),
1560		ServiceID:                      stringVal(v.ServiceID),
1561		Token:                          stringVal(v.Token),
1562		Status:                         stringVal(v.Status),
1563		ScriptArgs:                     v.ScriptArgs,
1564		HTTP:                           stringVal(v.HTTP),
1565		Header:                         v.Header,
1566		Method:                         stringVal(v.Method),
1567		Body:                           stringVal(v.Body),
1568		TCP:                            stringVal(v.TCP),
1569		Interval:                       b.durationVal(fmt.Sprintf("check[%s].interval", id), v.Interval),
1570		DockerContainerID:              stringVal(v.DockerContainerID),
1571		Shell:                          stringVal(v.Shell),
1572		GRPC:                           stringVal(v.GRPC),
1573		GRPCUseTLS:                     boolVal(v.GRPCUseTLS),
1574		TLSServerName:                  stringVal(v.TLSServerName),
1575		TLSSkipVerify:                  boolVal(v.TLSSkipVerify),
1576		AliasNode:                      stringVal(v.AliasNode),
1577		AliasService:                   stringVal(v.AliasService),
1578		Timeout:                        b.durationVal(fmt.Sprintf("check[%s].timeout", id), v.Timeout),
1579		TTL:                            b.durationVal(fmt.Sprintf("check[%s].ttl", id), v.TTL),
1580		SuccessBeforePassing:           intVal(v.SuccessBeforePassing),
1581		FailuresBeforeCritical:         intVal(v.FailuresBeforeCritical),
1582		H2PING:                         stringVal(v.H2PING),
1583		DeregisterCriticalServiceAfter: b.durationVal(fmt.Sprintf("check[%s].deregister_critical_service_after", id), v.DeregisterCriticalServiceAfter),
1584		OutputMaxSize:                  intValWithDefault(v.OutputMaxSize, checks.DefaultBufSize),
1585		EnterpriseMeta:                 v.EnterpriseMeta.ToStructs(),
1586	}
1587}
1588
1589func (b *builder) svcTaggedAddresses(v map[string]ServiceAddress) map[string]structs.ServiceAddress {
1590	if len(v) <= 0 {
1591		return nil
1592	}
1593
1594	svcAddrs := make(map[string]structs.ServiceAddress)
1595	for addrName, addrConf := range v {
1596		addr := structs.ServiceAddress{}
1597		if addrConf.Address != nil {
1598			addr.Address = *addrConf.Address
1599		}
1600		if addrConf.Port != nil {
1601			addr.Port = *addrConf.Port
1602		}
1603
1604		svcAddrs[addrName] = addr
1605	}
1606	return svcAddrs
1607}
1608
1609func (b *builder) serviceVal(v *ServiceDefinition) *structs.ServiceDefinition {
1610	if v == nil {
1611		return nil
1612	}
1613
1614	var checks structs.CheckTypes
1615	for _, check := range v.Checks {
1616		checks = append(checks, b.checkVal(&check).CheckType())
1617	}
1618	if v.Check != nil {
1619		checks = append(checks, b.checkVal(v.Check).CheckType())
1620	}
1621
1622	kind := b.serviceKindVal(v.Kind)
1623
1624	meta := make(map[string]string)
1625	if err := structs.ValidateServiceMetadata(kind, v.Meta, false); err != nil {
1626		b.err = multierror.Append(fmt.Errorf("invalid meta for service %s: %v", stringVal(v.Name), err))
1627	} else {
1628		meta = v.Meta
1629	}
1630	serviceWeights := &structs.Weights{Passing: 1, Warning: 1}
1631	if v.Weights != nil {
1632		if v.Weights.Passing != nil {
1633			serviceWeights.Passing = *v.Weights.Passing
1634		}
1635		if v.Weights.Warning != nil {
1636			serviceWeights.Warning = *v.Weights.Warning
1637		}
1638	}
1639
1640	if err := structs.ValidateWeights(serviceWeights); err != nil {
1641		b.err = multierror.Append(fmt.Errorf("Invalid weight definition for service %s: %s", stringVal(v.Name), err))
1642	}
1643
1644	if (v.Port != nil || v.Address != nil) && (v.SocketPath != nil) {
1645		b.err = multierror.Append(
1646			fmt.Errorf("service %s cannot have both socket path %s and address/port",
1647				stringVal(v.Name), stringVal(v.SocketPath)), b.err)
1648
1649	}
1650
1651	return &structs.ServiceDefinition{
1652		Kind:              kind,
1653		ID:                stringVal(v.ID),
1654		Name:              stringVal(v.Name),
1655		Tags:              v.Tags,
1656		Address:           stringVal(v.Address),
1657		TaggedAddresses:   b.svcTaggedAddresses(v.TaggedAddresses),
1658		Meta:              meta,
1659		Port:              intVal(v.Port),
1660		SocketPath:        stringVal(v.SocketPath),
1661		Token:             stringVal(v.Token),
1662		EnableTagOverride: boolVal(v.EnableTagOverride),
1663		Weights:           serviceWeights,
1664		Checks:            checks,
1665		Proxy:             b.serviceProxyVal(v.Proxy),
1666		Connect:           b.serviceConnectVal(v.Connect),
1667		EnterpriseMeta:    v.EnterpriseMeta.ToStructs(),
1668	}
1669}
1670
1671func (b *builder) serviceKindVal(v *string) structs.ServiceKind {
1672	if v == nil {
1673		return structs.ServiceKindTypical
1674	}
1675	switch *v {
1676	case string(structs.ServiceKindConnectProxy):
1677		return structs.ServiceKindConnectProxy
1678	case string(structs.ServiceKindMeshGateway):
1679		return structs.ServiceKindMeshGateway
1680	case string(structs.ServiceKindTerminatingGateway):
1681		return structs.ServiceKindTerminatingGateway
1682	case string(structs.ServiceKindIngressGateway):
1683		return structs.ServiceKindIngressGateway
1684	default:
1685		return structs.ServiceKindTypical
1686	}
1687}
1688
1689func (b *builder) serviceProxyVal(v *ServiceProxy) *structs.ConnectProxyConfig {
1690	if v == nil {
1691		return nil
1692	}
1693
1694	return &structs.ConnectProxyConfig{
1695		DestinationServiceName: stringVal(v.DestinationServiceName),
1696		DestinationServiceID:   stringVal(v.DestinationServiceID),
1697		LocalServiceAddress:    stringVal(v.LocalServiceAddress),
1698		LocalServicePort:       intVal(v.LocalServicePort),
1699		LocalServiceSocketPath: stringVal(&v.LocalServiceSocketPath),
1700		Config:                 v.Config,
1701		Upstreams:              b.upstreamsVal(v.Upstreams),
1702		MeshGateway:            b.meshGatewayConfVal(v.MeshGateway),
1703		Expose:                 b.exposeConfVal(v.Expose),
1704		Mode:                   b.proxyModeVal(v.Mode),
1705		TransparentProxy:       b.transparentProxyConfVal(v.TransparentProxy),
1706	}
1707}
1708
1709func (b *builder) upstreamsVal(v []Upstream) structs.Upstreams {
1710	ups := make(structs.Upstreams, len(v))
1711	for i, u := range v {
1712		ups[i] = structs.Upstream{
1713			DestinationType:      stringVal(u.DestinationType),
1714			DestinationNamespace: stringVal(u.DestinationNamespace),
1715			DestinationName:      stringVal(u.DestinationName),
1716			Datacenter:           stringVal(u.Datacenter),
1717			LocalBindAddress:     stringVal(u.LocalBindAddress),
1718			LocalBindPort:        intVal(u.LocalBindPort),
1719			LocalBindSocketPath:  stringVal(u.LocalBindSocketPath),
1720			LocalBindSocketMode:  b.unixPermissionsVal("local_bind_socket_mode", u.LocalBindSocketMode),
1721			Config:               u.Config,
1722			MeshGateway:          b.meshGatewayConfVal(u.MeshGateway),
1723		}
1724		if ups[i].DestinationType == "" {
1725			ups[i].DestinationType = structs.UpstreamDestTypeService
1726		}
1727	}
1728	return ups
1729}
1730
1731func (b *builder) meshGatewayConfVal(mgConf *MeshGatewayConfig) structs.MeshGatewayConfig {
1732	cfg := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeDefault}
1733	if mgConf == nil || mgConf.Mode == nil {
1734		// return defaults
1735		return cfg
1736	}
1737
1738	mode, err := structs.ValidateMeshGatewayMode(*mgConf.Mode)
1739	if err != nil {
1740		b.err = multierror.Append(b.err, err)
1741		return cfg
1742	}
1743
1744	cfg.Mode = mode
1745	return cfg
1746}
1747
1748func (b *builder) exposeConfVal(v *ExposeConfig) structs.ExposeConfig {
1749	var out structs.ExposeConfig
1750	if v == nil {
1751		return out
1752	}
1753
1754	out.Checks = boolVal(v.Checks)
1755	out.Paths = b.pathsVal(v.Paths)
1756	return out
1757}
1758
1759func (b *builder) transparentProxyConfVal(tproxyConf *TransparentProxyConfig) structs.TransparentProxyConfig {
1760	var out structs.TransparentProxyConfig
1761	if tproxyConf == nil {
1762		return out
1763	}
1764
1765	out.OutboundListenerPort = intVal(tproxyConf.OutboundListenerPort)
1766	out.DialedDirectly = boolVal(tproxyConf.DialedDirectly)
1767	return out
1768}
1769
1770func (b *builder) proxyModeVal(v *string) structs.ProxyMode {
1771	if v == nil {
1772		return structs.ProxyModeDefault
1773	}
1774
1775	mode, err := structs.ValidateProxyMode(*v)
1776	if err != nil {
1777		b.err = multierror.Append(b.err, err)
1778	}
1779	return mode
1780}
1781
1782func (b *builder) pathsVal(v []ExposePath) []structs.ExposePath {
1783	paths := make([]structs.ExposePath, len(v))
1784	for i, p := range v {
1785		paths[i] = structs.ExposePath{
1786			ListenerPort:  intVal(p.ListenerPort),
1787			Path:          stringVal(p.Path),
1788			LocalPathPort: intVal(p.LocalPathPort),
1789			Protocol:      stringVal(p.Protocol),
1790		}
1791	}
1792	return paths
1793}
1794
1795func (b *builder) serviceConnectVal(v *ServiceConnect) *structs.ServiceConnect {
1796	if v == nil {
1797		return nil
1798	}
1799
1800	sidecar := b.serviceVal(v.SidecarService)
1801	if sidecar != nil {
1802		// Sanity checks
1803		if sidecar.ID != "" {
1804			b.err = multierror.Append(b.err, fmt.Errorf("sidecar_service can't specify an ID"))
1805			sidecar.ID = ""
1806		}
1807		if sidecar.Connect != nil {
1808			if sidecar.Connect.SidecarService != nil {
1809				b.err = multierror.Append(b.err, fmt.Errorf("sidecar_service can't have a nested sidecar_service"))
1810				sidecar.Connect.SidecarService = nil
1811			}
1812		}
1813	}
1814
1815	return &structs.ServiceConnect{
1816		Native:         boolVal(v.Native),
1817		SidecarService: sidecar,
1818	}
1819}
1820
1821func (b *builder) uiConfigVal(v RawUIConfig) UIConfig {
1822	return UIConfig{
1823		Enabled:                    boolVal(v.Enabled),
1824		Dir:                        stringVal(v.Dir),
1825		ContentPath:                UIPathBuilder(stringVal(v.ContentPath)),
1826		MetricsProvider:            stringVal(v.MetricsProvider),
1827		MetricsProviderFiles:       v.MetricsProviderFiles,
1828		MetricsProviderOptionsJSON: stringVal(v.MetricsProviderOptionsJSON),
1829		MetricsProxy:               b.uiMetricsProxyVal(v.MetricsProxy),
1830		DashboardURLTemplates:      v.DashboardURLTemplates,
1831	}
1832}
1833
1834func (b *builder) uiMetricsProxyVal(v RawUIMetricsProxy) UIMetricsProxy {
1835	var hdrs []UIMetricsProxyAddHeader
1836
1837	for _, hdr := range v.AddHeaders {
1838		hdrs = append(hdrs, UIMetricsProxyAddHeader{
1839			Name:  stringVal(hdr.Name),
1840			Value: stringVal(hdr.Value),
1841		})
1842	}
1843
1844	return UIMetricsProxy{
1845		BaseURL:       stringVal(v.BaseURL),
1846		AddHeaders:    hdrs,
1847		PathAllowlist: v.PathAllowlist,
1848	}
1849}
1850
1851func boolValWithDefault(v *bool, defaultVal bool) bool {
1852	if v == nil {
1853		return defaultVal
1854	}
1855	return *v
1856}
1857
1858func boolVal(v *bool) bool {
1859	if v == nil {
1860		return false
1861	}
1862	return *v
1863}
1864
1865func (b *builder) durationValWithDefault(name string, v *string, defaultVal time.Duration) (d time.Duration) {
1866	if v == nil {
1867		return defaultVal
1868	}
1869	d, err := time.ParseDuration(*v)
1870	if err != nil {
1871		b.err = multierror.Append(fmt.Errorf("%s: invalid duration: %q: %s", name, *v, err))
1872	}
1873	return d
1874}
1875
1876func (b *builder) durationVal(name string, v *string) (d time.Duration) {
1877	return b.durationValWithDefault(name, v, 0)
1878}
1879
1880func intValWithDefault(v *int, defaultVal int) int {
1881	if v == nil {
1882		return defaultVal
1883	}
1884	return *v
1885}
1886
1887func intVal(v *int) int {
1888	if v == nil {
1889		return 0
1890	}
1891	return *v
1892}
1893
1894func uintVal(v *uint) uint {
1895	if v == nil {
1896		return 0
1897	}
1898	return *v
1899}
1900
1901func uint64Val(v *uint64) uint64 {
1902	if v == nil {
1903		return 0
1904	}
1905	return *v
1906}
1907
1908// Expect an octal permissions string, e.g. 0644
1909func (b *builder) unixPermissionsVal(name string, v *string) string {
1910	if v == nil {
1911		return ""
1912	}
1913	if _, err := strconv.ParseUint(*v, 8, 32); err == nil {
1914		return *v
1915	}
1916	b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid mode: %s", name, *v))
1917	return "0"
1918}
1919
1920func (b *builder) portVal(name string, v *int) int {
1921	if v == nil || *v <= 0 {
1922		return -1
1923	}
1924	if *v > 65535 {
1925		b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid port: %d", name, *v))
1926	}
1927	return *v
1928}
1929
1930func stringValWithDefault(v *string, defaultVal string) string {
1931	if v == nil {
1932		return defaultVal
1933	}
1934	return *v
1935}
1936
1937func stringVal(v *string) string {
1938	if v == nil {
1939		return ""
1940	}
1941	return *v
1942}
1943
1944func float64ValWithDefault(v *float64, defaultVal float64) float64 {
1945	if v == nil {
1946		return defaultVal
1947	}
1948	return *v
1949}
1950
1951func float64Val(v *float64) float64 {
1952	return float64ValWithDefault(v, 0)
1953}
1954
1955func (b *builder) cidrsVal(name string, v []string) (nets []*net.IPNet) {
1956	if v == nil {
1957		return
1958	}
1959
1960	for _, p := range v {
1961		_, net, err := net.ParseCIDR(strings.TrimSpace(p))
1962		if err != nil {
1963			b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid cidr: %s", name, p))
1964		}
1965		nets = append(nets, net)
1966	}
1967
1968	return
1969}
1970
1971func (b *builder) tlsCipherSuites(name string, v *string) []uint16 {
1972	if v == nil {
1973		return nil
1974	}
1975
1976	var a []uint16
1977	a, err := tlsutil.ParseCiphers(*v)
1978	if err != nil {
1979		b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid tls cipher suites: %s", name, err))
1980	}
1981	return a
1982}
1983
1984func (b *builder) nodeName(v *string) string {
1985	nodeName := stringVal(v)
1986	if nodeName == "" {
1987		fn := b.opts.hostname
1988		if fn == nil {
1989			fn = os.Hostname
1990		}
1991		name, err := fn()
1992		if err != nil {
1993			b.err = multierror.Append(b.err, fmt.Errorf("node_name: %s", err))
1994			return ""
1995		}
1996		nodeName = name
1997	}
1998	return strings.TrimSpace(nodeName)
1999}
2000
2001// expandAddrs expands the go-sockaddr template in s and returns the
2002// result as a list of *net.IPAddr and *net.UnixAddr.
2003func (b *builder) expandAddrs(name string, s *string) []net.Addr {
2004	if s == nil || *s == "" {
2005		return nil
2006	}
2007
2008	x, err := template.Parse(*s)
2009	if err != nil {
2010		b.err = multierror.Append(b.err, fmt.Errorf("%s: error parsing %q: %s", name, *s, err))
2011		return nil
2012	}
2013
2014	var addrs []net.Addr
2015	for _, a := range strings.Fields(x) {
2016		switch {
2017		case strings.HasPrefix(a, "unix://"):
2018			addrs = append(addrs, &net.UnixAddr{Name: a[len("unix://"):], Net: "unix"})
2019		default:
2020			// net.ParseIP does not like '[::]'
2021			ip := net.ParseIP(a)
2022			if a == "[::]" {
2023				ip = net.ParseIP("::")
2024			}
2025			if ip == nil {
2026				b.err = multierror.Append(b.err, fmt.Errorf("%s: invalid ip address: %s", name, a))
2027				return nil
2028			}
2029			addrs = append(addrs, &net.IPAddr{IP: ip})
2030		}
2031	}
2032
2033	return addrs
2034}
2035
2036// expandOptionalAddrs expands the go-sockaddr template in s and returns the
2037// result as a list of strings. If s does not contain a go-sockaddr template,
2038// the result list will contain the input string as a single element with no
2039// error set. In contrast to expandAddrs, expandOptionalAddrs does not validate
2040// if the result contains valid addresses and returns a list of strings.
2041// However, if the expansion of the go-sockaddr template fails an error is set.
2042func (b *builder) expandOptionalAddrs(name string, s *string) []string {
2043	if s == nil || *s == "" {
2044		return nil
2045	}
2046
2047	x, err := template.Parse(*s)
2048	if err != nil {
2049		b.err = multierror.Append(b.err, fmt.Errorf("%s: error parsing %q: %s", name, *s, err))
2050		return nil
2051	}
2052
2053	if x != *s {
2054		// A template has been expanded, split the results from go-sockaddr
2055		return strings.Fields(x)
2056	} else {
2057		// No template has been expanded, pass through the input
2058		return []string{*s}
2059	}
2060}
2061
2062func (b *builder) expandAllOptionalAddrs(name string, addrs []string) []string {
2063	out := make([]string, 0, len(addrs))
2064	for _, a := range addrs {
2065		expanded := b.expandOptionalAddrs(name, &a)
2066		if expanded != nil {
2067			out = append(out, expanded...)
2068		}
2069	}
2070	return out
2071}
2072
2073// expandIPs expands the go-sockaddr template in s and returns a list of
2074// *net.IPAddr. If one of the expanded addresses is a unix socket
2075// address an error is set and nil is returned.
2076func (b *builder) expandIPs(name string, s *string) []*net.IPAddr {
2077	if s == nil || *s == "" {
2078		return nil
2079	}
2080
2081	addrs := b.expandAddrs(name, s)
2082	var x []*net.IPAddr
2083	for _, addr := range addrs {
2084		switch a := addr.(type) {
2085		case *net.IPAddr:
2086			x = append(x, a)
2087		case *net.UnixAddr:
2088			b.err = multierror.Append(b.err, fmt.Errorf("%s cannot be a unix socket", name))
2089			return nil
2090		default:
2091			b.err = multierror.Append(b.err, fmt.Errorf("%s has invalid address type %T", name, a))
2092			return nil
2093		}
2094	}
2095	return x
2096}
2097
2098// expandFirstAddr expands the go-sockaddr template in s and returns the
2099// first address which is either a *net.IPAddr or a *net.UnixAddr. If
2100// the template expands to multiple addresses an error is set and nil
2101// is returned.
2102func (b *builder) expandFirstAddr(name string, s *string) net.Addr {
2103	if s == nil || *s == "" {
2104		return nil
2105	}
2106
2107	addrs := b.expandAddrs(name, s)
2108	if len(addrs) == 0 {
2109		return nil
2110	}
2111	if len(addrs) > 1 {
2112		var x []string
2113		for _, a := range addrs {
2114			x = append(x, a.String())
2115		}
2116		b.err = multierror.Append(b.err, fmt.Errorf("%s: multiple addresses found: %s", name, strings.Join(x, " ")))
2117		return nil
2118	}
2119	return addrs[0]
2120}
2121
2122// expandFirstIP expands the go-sockaddr template in s and returns the
2123// first address if it is not a unix socket address. If the template
2124// expands to multiple addresses an error is set and nil is returned.
2125func (b *builder) expandFirstIP(name string, s *string) *net.IPAddr {
2126	if s == nil || *s == "" {
2127		return nil
2128	}
2129
2130	addr := b.expandFirstAddr(name, s)
2131	if addr == nil {
2132		return nil
2133	}
2134	switch a := addr.(type) {
2135	case *net.IPAddr:
2136		return a
2137	case *net.UnixAddr:
2138		b.err = multierror.Append(b.err, fmt.Errorf("%s cannot be a unix socket", name))
2139		return nil
2140	default:
2141		b.err = multierror.Append(b.err, fmt.Errorf("%s has invalid address type %T", name, a))
2142		return nil
2143	}
2144}
2145
2146func makeIPAddr(pri *net.IPAddr, sec *net.IPAddr) *net.IPAddr {
2147	if pri != nil {
2148		return pri
2149	}
2150	return sec
2151}
2152
2153func (b *builder) makeTCPAddr(pri *net.IPAddr, sec net.Addr, port int) *net.TCPAddr {
2154	if pri == nil && reflect.ValueOf(sec).IsNil() || port <= 0 {
2155		return nil
2156	}
2157	addr := pri
2158	if addr == nil {
2159		switch a := sec.(type) {
2160		case *net.IPAddr:
2161			addr = a
2162		case *net.TCPAddr:
2163			addr = &net.IPAddr{IP: a.IP}
2164		default:
2165			panic(fmt.Sprintf("makeTCPAddr requires a net.IPAddr or a net.TCPAddr. Got %T", a))
2166		}
2167	}
2168	return &net.TCPAddr{IP: addr.IP, Port: port}
2169}
2170
2171// makeAddr creates an *net.TCPAddr or a *net.UnixAddr from either the
2172// primary or secondary address and the given port. If the port is <= 0
2173// then the address is considered to be disabled and nil is returned.
2174func (b *builder) makeAddr(pri, sec net.Addr, port int) net.Addr {
2175	if reflect.ValueOf(pri).IsNil() && reflect.ValueOf(sec).IsNil() || port <= 0 {
2176		return nil
2177	}
2178	addr := pri
2179	if addr == nil {
2180		addr = sec
2181	}
2182	switch a := addr.(type) {
2183	case *net.IPAddr:
2184		return &net.TCPAddr{IP: a.IP, Port: port}
2185	case *net.UnixAddr:
2186		return a
2187	default:
2188		panic(fmt.Sprintf("invalid address type %T", a))
2189	}
2190}
2191
2192// makeAddrs creates a list of *net.TCPAddr or *net.UnixAddr entries
2193// from either the primary or secondary addresses and the given port.
2194// If the port is <= 0 then the address is considered to be disabled
2195// and nil is returned.
2196func (b *builder) makeAddrs(pri []net.Addr, sec []*net.IPAddr, port int) []net.Addr {
2197	if len(pri) == 0 && len(sec) == 0 || port <= 0 {
2198		return nil
2199	}
2200	addrs := pri
2201	if len(addrs) == 0 {
2202		addrs = []net.Addr{}
2203		for _, a := range sec {
2204			addrs = append(addrs, a)
2205		}
2206	}
2207	var x []net.Addr
2208	for _, a := range addrs {
2209		x = append(x, b.makeAddr(a, nil, port))
2210	}
2211	return x
2212}
2213
2214func (b *builder) autoConfigVal(raw AutoConfigRaw) AutoConfig {
2215	var val AutoConfig
2216
2217	val.Enabled = boolValWithDefault(raw.Enabled, false)
2218	val.IntroToken = stringVal(raw.IntroToken)
2219
2220	// default the IntroToken to the env variable if specified.
2221	if envToken := os.Getenv("CONSUL_INTRO_TOKEN"); envToken != "" {
2222		if val.IntroToken != "" {
2223			b.warn("Both auto_config.intro_token and the CONSUL_INTRO_TOKEN environment variable are set. Using the value from the environment variable")
2224		}
2225
2226		val.IntroToken = envToken
2227	}
2228	val.IntroTokenFile = stringVal(raw.IntroTokenFile)
2229	// These can be go-discover values and so don't have to resolve fully yet
2230	val.ServerAddresses = b.expandAllOptionalAddrs("auto_config.server_addresses", raw.ServerAddresses)
2231	val.DNSSANs = raw.DNSSANs
2232
2233	for _, i := range raw.IPSANs {
2234		ip := net.ParseIP(i)
2235		if ip == nil {
2236			b.warn(fmt.Sprintf("Cannot parse ip %q from auto_config.ip_sans", i))
2237			continue
2238		}
2239		val.IPSANs = append(val.IPSANs, ip)
2240	}
2241
2242	val.Authorizer = b.autoConfigAuthorizerVal(raw.Authorization)
2243
2244	return val
2245}
2246
2247func (b *builder) autoConfigAuthorizerVal(raw AutoConfigAuthorizationRaw) AutoConfigAuthorizer {
2248	// Our config file syntax wraps the static authorizer configuration in a "static" stanza. However
2249	// internally we do not support multiple configured authorization types so the RuntimeConfig just
2250	// inlines the static one. While we can and probably should extend the authorization types in the
2251	// future to support dynamic authorizers (ACL Auth Methods configured via normal APIs) its not
2252	// needed right now so the configuration types will remain simplistic until they need to be otherwise.
2253	var val AutoConfigAuthorizer
2254
2255	val.Enabled = boolValWithDefault(raw.Enabled, false)
2256	val.ClaimAssertions = raw.Static.ClaimAssertions
2257	val.AllowReuse = boolValWithDefault(raw.Static.AllowReuse, false)
2258	val.AuthMethod = structs.ACLAuthMethod{
2259		Name:           "Auto Config Authorizer",
2260		Type:           "jwt",
2261		EnterpriseMeta: *structs.DefaultEnterpriseMeta(),
2262		Config: map[string]interface{}{
2263			"JWTSupportedAlgs":     raw.Static.JWTSupportedAlgs,
2264			"BoundAudiences":       raw.Static.BoundAudiences,
2265			"ClaimMappings":        raw.Static.ClaimMappings,
2266			"ListClaimMappings":    raw.Static.ListClaimMappings,
2267			"OIDCDiscoveryURL":     stringVal(raw.Static.OIDCDiscoveryURL),
2268			"OIDCDiscoveryCACert":  stringVal(raw.Static.OIDCDiscoveryCACert),
2269			"JWKSURL":              stringVal(raw.Static.JWKSURL),
2270			"JWKSCACert":           stringVal(raw.Static.JWKSCACert),
2271			"JWTValidationPubKeys": raw.Static.JWTValidationPubKeys,
2272			"BoundIssuer":          stringVal(raw.Static.BoundIssuer),
2273			"ExpirationLeeway":     b.durationVal("auto_config.authorization.static.expiration_leeway", raw.Static.ExpirationLeeway),
2274			"NotBeforeLeeway":      b.durationVal("auto_config.authorization.static.not_before_leeway", raw.Static.NotBeforeLeeway),
2275			"ClockSkewLeeway":      b.durationVal("auto_config.authorization.static.clock_skew_leeway", raw.Static.ClockSkewLeeway),
2276		},
2277	}
2278
2279	return val
2280}
2281
2282func (b *builder) validateAutoConfig(rt RuntimeConfig) error {
2283	autoconf := rt.AutoConfig
2284
2285	if err := validateAutoConfigAuthorizer(rt); err != nil {
2286		return err
2287	}
2288
2289	if !autoconf.Enabled {
2290		return nil
2291	}
2292
2293	// Right now we require TLS as everything we are going to transmit via auto-config is sensitive. Signed Certificates, Tokens
2294	// and other encryption keys. This must be transmitted over a secure connection so we don't allow doing otherwise.
2295	if !rt.VerifyOutgoing {
2296		return fmt.Errorf("auto_config.enabled cannot be set without configuring TLS for server communications")
2297	}
2298
2299	// Auto Config doesn't currently support configuring servers
2300	if rt.ServerMode {
2301		return fmt.Errorf("auto_config.enabled cannot be set to true for server agents.")
2302	}
2303
2304	// When both are set we will prefer the given value over the file.
2305	if autoconf.IntroToken != "" && autoconf.IntroTokenFile != "" {
2306		b.warn("Both an intro token and intro token file are set. The intro token will be used instead of the file")
2307	} else if autoconf.IntroToken == "" && autoconf.IntroTokenFile == "" {
2308		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")
2309	}
2310
2311	if len(autoconf.ServerAddresses) == 0 {
2312		// TODO (autoconf) can we/should we infer this from the join/retry join addresses. I think no, as we will potentially
2313		// be overriding those retry join addresses with the autoconf process anyways.
2314		return fmt.Errorf("auto_config.enabled is set without providing a list of addresses")
2315	}
2316
2317	return nil
2318}
2319
2320func validateAutoConfigAuthorizer(rt RuntimeConfig) error {
2321	authz := rt.AutoConfig.Authorizer
2322
2323	if !authz.Enabled {
2324		return nil
2325	}
2326
2327	// When in a secondary datacenter with ACLs enabled, we require token replication to be enabled
2328	// as that is what allows us to create the local tokens to distribute to the clients. Otherwise
2329	// we would have to have a token with the ability to create ACL tokens in the primary and make
2330	// RPCs in response to auto config requests.
2331	if rt.ACLsEnabled && rt.PrimaryDatacenter != rt.Datacenter && !rt.ACLTokenReplication {
2332		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)")
2333	}
2334
2335	// Auto Config Authorization is only supported on servers
2336	if !rt.ServerMode {
2337		return fmt.Errorf("auto_config.authorization.enabled cannot be set to true for client agents")
2338	}
2339
2340	// Right now we require TLS as everything we are going to transmit via auto-config is sensitive. Signed Certificates, Tokens
2341	// and other encryption keys. This must be transmitted over a secure connection so we don't allow doing otherwise.
2342	if rt.CertFile == "" {
2343		return fmt.Errorf("auto_config.authorization.enabled cannot be set without providing a TLS certificate for the server")
2344	}
2345
2346	// build out the validator to ensure that the given configuration was valid
2347	null := hclog.NewNullLogger()
2348	validator, err := ssoauth.NewValidator(null, &authz.AuthMethod)
2349
2350	if err != nil {
2351		return fmt.Errorf("auto_config.authorization.static has invalid configuration: %v", err)
2352	}
2353
2354	// create a blank identity for use to validate the claim assertions.
2355	blankID := validator.NewIdentity()
2356	varMap := map[string]string{
2357		"node":    "fake",
2358		"segment": "fake",
2359	}
2360
2361	// validate all the claim assertions
2362	for _, raw := range authz.ClaimAssertions {
2363		// validate any HIL
2364		filled, err := libtempl.InterpolateHIL(raw, varMap, true)
2365		if err != nil {
2366			return fmt.Errorf("auto_config.authorization.static.claim_assertion %q is invalid: %v", raw, err)
2367		}
2368
2369		// validate the bexpr syntax - note that for now all the keys mapped by the claim mappings
2370		// are not validateable due to them being put inside a map. Some bexpr updates to setup keys
2371		// from current map keys would probably be nice here.
2372		if _, err := bexpr.CreateEvaluatorForType(filled, nil, blankID.SelectableFields); err != nil {
2373			return fmt.Errorf("auto_config.authorization.static.claim_assertion %q is invalid: %v", raw, err)
2374		}
2375	}
2376	return nil
2377}
2378
2379// decodeBytes returns the encryption key decoded.
2380func decodeBytes(key string) ([]byte, error) {
2381	return base64.StdEncoding.DecodeString(key)
2382}
2383
2384func isIPAddr(a net.Addr) bool {
2385	_, ok := a.(*net.IPAddr)
2386	return ok
2387}
2388
2389func isUnixAddr(a net.Addr) bool {
2390	_, ok := a.(*net.UnixAddr)
2391	return ok
2392}
2393
2394// isValidAltDomain returns true if the given domain is not prefixed
2395// by keywords used when dispatching DNS requests
2396func isValidAltDomain(domain, datacenter string) bool {
2397	reAltDomain := regexp.MustCompile(
2398		fmt.Sprintf(
2399			"^(service|connect|node|query|addr|%s)\\.(%s\\.)?",
2400			datacenter, datacenter,
2401		),
2402	)
2403	return !reAltDomain.MatchString(domain)
2404}
2405
2406// UIPathBuilder checks to see if there was a path set
2407// If so, adds beginning and trailing slashes to UI path
2408func UIPathBuilder(UIContentString string) string {
2409	if UIContentString != "" {
2410		var fmtedPath string
2411		fmtedPath = strings.Trim(UIContentString, "/")
2412		fmtedPath = "/" + fmtedPath + "/"
2413		return fmtedPath
2414
2415	}
2416	return "/ui/"
2417}
2418
2419const 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/"
2420
2421// validateRemoteScriptsChecks returns an error if EnableRemoteScriptChecks is
2422// enabled without other security features, which mitigate the risk of executing
2423// remote scripts.
2424func validateRemoteScriptsChecks(conf RuntimeConfig) error {
2425	if conf.EnableRemoteScriptChecks && !conf.ACLsEnabled && len(conf.AllowWriteHTTPFrom) == 0 {
2426		return errors.New(remoteScriptCheckSecurityWarning)
2427	}
2428	return nil
2429}
2430
2431func validateAbsoluteURLPath(p string) error {
2432	if !path.IsAbs(p) {
2433		return fmt.Errorf("path %q is not an absolute path", p)
2434	}
2435
2436	// A bit more extra validation that these are actually paths.
2437	u, err := url.Parse(p)
2438	if err != nil ||
2439		u.Scheme != "" ||
2440		u.Opaque != "" ||
2441		u.User != nil ||
2442		u.Host != "" ||
2443		u.RawQuery != "" ||
2444		u.Fragment != "" ||
2445		u.Path != p {
2446		return fmt.Errorf("path %q is not an absolute path", p)
2447	}
2448
2449	return nil
2450}
2451