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