github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/structs/config/consul.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "net/http" 6 "strings" 7 "time" 8 9 consul "github.com/hashicorp/consul/api" 10 "github.com/hashicorp/go-secure-stdlib/listenerutil" 11 "github.com/hashicorp/nomad/helper/pointer" 12 ) 13 14 // ConsulConfig contains the configuration information necessary to 15 // communicate with a Consul Agent in order to: 16 // 17 // - Register services and their checks with Consul 18 // 19 // - Bootstrap this Nomad Client with the list of Nomad Servers registered 20 // with Consul 21 // 22 // - Establish how this Nomad Client will resolve Envoy Connect Sidecar 23 // images. 24 // 25 // Both the Agent and the executor need to be able to import ConsulConfig. 26 type ConsulConfig struct { 27 // ServerServiceName is the name of the service that Nomad uses to register 28 // servers with Consul 29 ServerServiceName string `hcl:"server_service_name"` 30 31 // ServerHTTPCheckName is the name of the health check that Nomad uses 32 // to register the server HTTP health check with Consul 33 ServerHTTPCheckName string `hcl:"server_http_check_name"` 34 35 // ServerSerfCheckName is the name of the health check that Nomad uses 36 // to register the server Serf health check with Consul 37 ServerSerfCheckName string `hcl:"server_serf_check_name"` 38 39 // ServerRPCCheckName is the name of the health check that Nomad uses 40 // to register the server RPC health check with Consul 41 ServerRPCCheckName string `hcl:"server_rpc_check_name"` 42 43 // ClientServiceName is the name of the service that Nomad uses to register 44 // clients with Consul 45 ClientServiceName string `hcl:"client_service_name"` 46 47 // ClientHTTPCheckName is the name of the health check that Nomad uses 48 // to register the client HTTP health check with Consul 49 ClientHTTPCheckName string `hcl:"client_http_check_name"` 50 51 // Tags are optional service tags that get registered with the service 52 // in Consul 53 Tags []string `hcl:"tags"` 54 55 // AutoAdvertise determines if this Nomad Agent will advertise its 56 // services via Consul. When true, Nomad Agent will register 57 // services with Consul. 58 AutoAdvertise *bool `hcl:"auto_advertise"` 59 60 // ChecksUseAdvertise specifies that Consul checks should use advertise 61 // address instead of bind address 62 ChecksUseAdvertise *bool `hcl:"checks_use_advertise"` 63 64 // Addr is the HTTP endpoint address of the local Consul agent 65 // 66 // Uses Consul's default and env var. 67 Addr string `hcl:"address"` 68 69 // GRPCAddr is the gRPC endpoint address of the local Consul agent 70 GRPCAddr string `hcl:"grpc_address"` 71 72 // Timeout is used by Consul HTTP Client 73 Timeout time.Duration `hcl:"-"` 74 TimeoutHCL string `hcl:"timeout" json:"-"` 75 76 // Token is used to provide a per-request ACL token. This options overrides 77 // the agent's default token 78 Token string `hcl:"token"` 79 80 // AllowUnauthenticated allows users to submit jobs requiring Consul 81 // Service Identity tokens without providing a Consul token proving they 82 // have access to such policies. 83 AllowUnauthenticated *bool `hcl:"allow_unauthenticated"` 84 85 // Auth is the information to use for http access to Consul agent 86 Auth string `hcl:"auth"` 87 88 // EnableSSL sets the transport scheme to talk to the Consul agent as https 89 // 90 // Uses Consul's default and env var. 91 EnableSSL *bool `hcl:"ssl"` 92 93 // ShareSSL enables Consul Connect Native applications to use the TLS 94 // configuration of the Nomad Client for establishing connections to Consul. 95 // 96 // Does not include sharing of ACL tokens. 97 ShareSSL *bool `hcl:"share_ssl"` 98 99 // VerifySSL enables or disables SSL verification when the transport scheme 100 // for the consul api client is https 101 // 102 // Uses Consul's default and env var. 103 VerifySSL *bool `hcl:"verify_ssl"` 104 105 // CAFile is the path to the ca certificate used for Consul communication. 106 // 107 // Uses Consul's default and env var. 108 CAFile string `hcl:"ca_file"` 109 110 // CertFile is the path to the certificate for Consul communication 111 CertFile string `hcl:"cert_file"` 112 113 // KeyFile is the path to the private key for Consul communication 114 KeyFile string `hcl:"key_file"` 115 116 // ServerAutoJoin enables Nomad servers to find peers by querying Consul and 117 // joining them 118 ServerAutoJoin *bool `hcl:"server_auto_join"` 119 120 // ClientAutoJoin enables Nomad servers to find addresses of Nomad servers 121 // and register with them 122 ClientAutoJoin *bool `hcl:"client_auto_join"` 123 124 // ExtraKeysHCL is used by hcl to surface unexpected keys 125 ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"` 126 127 // Namespace sets the Consul namespace used for all calls against the 128 // Consul API. If this is unset, then Nomad does not specify a consul namespace. 129 Namespace string `hcl:"namespace"` 130 } 131 132 // DefaultConsulConfig returns the canonical defaults for the Nomad 133 // `consul` configuration. Uses Consul's default configuration which reads 134 // environment variables. 135 func DefaultConsulConfig() *ConsulConfig { 136 def := consul.DefaultConfig() 137 return &ConsulConfig{ 138 ServerServiceName: "nomad", 139 ServerHTTPCheckName: "Nomad Server HTTP Check", 140 ServerSerfCheckName: "Nomad Server Serf Check", 141 ServerRPCCheckName: "Nomad Server RPC Check", 142 ClientServiceName: "nomad-client", 143 ClientHTTPCheckName: "Nomad Client HTTP Check", 144 AutoAdvertise: pointer.Of(true), 145 ChecksUseAdvertise: pointer.Of(false), 146 ServerAutoJoin: pointer.Of(true), 147 ClientAutoJoin: pointer.Of(true), 148 AllowUnauthenticated: pointer.Of(true), 149 Timeout: 5 * time.Second, 150 151 // From Consul api package defaults 152 Addr: def.Address, 153 EnableSSL: pointer.Of(def.Scheme == "https"), 154 VerifySSL: pointer.Of(!def.TLSConfig.InsecureSkipVerify), 155 CAFile: def.TLSConfig.CAFile, 156 Namespace: def.Namespace, 157 } 158 } 159 160 // AllowsUnauthenticated returns whether the config allows unauthenticated 161 // creation of Consul Service Identity tokens for Consul Connect enabled Tasks. 162 // 163 // If allow_unauthenticated is false, the operator must provide a token on 164 // job submission (i.e. -consul-token or $CONSUL_HTTP_TOKEN). 165 func (c *ConsulConfig) AllowsUnauthenticated() bool { 166 return c.AllowUnauthenticated != nil && *c.AllowUnauthenticated 167 } 168 169 // Merge merges two Consul Configurations together. 170 func (c *ConsulConfig) Merge(b *ConsulConfig) *ConsulConfig { 171 result := c.Copy() 172 173 if b.ServerServiceName != "" { 174 result.ServerServiceName = b.ServerServiceName 175 } 176 if b.ServerHTTPCheckName != "" { 177 result.ServerHTTPCheckName = b.ServerHTTPCheckName 178 } 179 if b.ServerSerfCheckName != "" { 180 result.ServerSerfCheckName = b.ServerSerfCheckName 181 } 182 if b.ServerRPCCheckName != "" { 183 result.ServerRPCCheckName = b.ServerRPCCheckName 184 } 185 if b.ClientServiceName != "" { 186 result.ClientServiceName = b.ClientServiceName 187 } 188 if b.ClientHTTPCheckName != "" { 189 result.ClientHTTPCheckName = b.ClientHTTPCheckName 190 } 191 result.Tags = append(result.Tags, b.Tags...) 192 if b.AutoAdvertise != nil { 193 result.AutoAdvertise = pointer.Of(*b.AutoAdvertise) 194 } 195 if b.Addr != "" { 196 result.Addr = b.Addr 197 } 198 if b.GRPCAddr != "" { 199 result.GRPCAddr = b.GRPCAddr 200 } 201 if b.Timeout != 0 { 202 result.Timeout = b.Timeout 203 } 204 if b.TimeoutHCL != "" { 205 result.TimeoutHCL = b.TimeoutHCL 206 } 207 if b.Token != "" { 208 result.Token = b.Token 209 } 210 if b.Auth != "" { 211 result.Auth = b.Auth 212 } 213 if b.EnableSSL != nil { 214 result.EnableSSL = pointer.Of(*b.EnableSSL) 215 } 216 if b.VerifySSL != nil { 217 result.VerifySSL = pointer.Of(*b.VerifySSL) 218 } 219 if b.ShareSSL != nil { 220 result.ShareSSL = pointer.Of(*b.ShareSSL) 221 } 222 if b.CAFile != "" { 223 result.CAFile = b.CAFile 224 } 225 if b.CertFile != "" { 226 result.CertFile = b.CertFile 227 } 228 if b.KeyFile != "" { 229 result.KeyFile = b.KeyFile 230 } 231 if b.ServerAutoJoin != nil { 232 result.ServerAutoJoin = pointer.Of(*b.ServerAutoJoin) 233 } 234 if b.ClientAutoJoin != nil { 235 result.ClientAutoJoin = pointer.Of(*b.ClientAutoJoin) 236 } 237 if b.ChecksUseAdvertise != nil { 238 result.ChecksUseAdvertise = pointer.Of(*b.ChecksUseAdvertise) 239 } 240 if b.AllowUnauthenticated != nil { 241 result.AllowUnauthenticated = pointer.Of(*b.AllowUnauthenticated) 242 } 243 if b.Namespace != "" { 244 result.Namespace = b.Namespace 245 } 246 return result 247 } 248 249 // ApiConfig returns a usable Consul config that can be passed directly to 250 // hashicorp/consul/api. NOTE: datacenter is not set 251 func (c *ConsulConfig) ApiConfig() (*consul.Config, error) { 252 // Get the default config from consul to reuse things like the default 253 // http.Transport. 254 config := consul.DefaultConfig() 255 if c.Addr != "" { 256 ipStr, err := listenerutil.ParseSingleIPTemplate(c.Addr) 257 if err != nil { 258 return nil, fmt.Errorf("unable to parse address template %q: %v", c.Addr, err) 259 } 260 config.Address = ipStr 261 } 262 if c.Token != "" { 263 config.Token = c.Token 264 } 265 if c.Timeout != 0 { 266 // Create a custom Client to set the timeout 267 if config.HttpClient == nil { 268 config.HttpClient = &http.Client{} 269 } 270 config.HttpClient.Timeout = c.Timeout 271 config.HttpClient.Transport = config.Transport 272 } 273 if c.Auth != "" { 274 var username, password string 275 if strings.Contains(c.Auth, ":") { 276 split := strings.SplitN(c.Auth, ":", 2) 277 username = split[0] 278 password = split[1] 279 } else { 280 username = c.Auth 281 } 282 283 config.HttpAuth = &consul.HttpBasicAuth{ 284 Username: username, 285 Password: password, 286 } 287 } 288 if c.EnableSSL != nil && *c.EnableSSL { 289 config.Scheme = "https" 290 config.TLSConfig = consul.TLSConfig{ 291 Address: config.Address, 292 CAFile: c.CAFile, 293 CertFile: c.CertFile, 294 KeyFile: c.KeyFile, 295 } 296 if c.VerifySSL != nil { 297 config.TLSConfig.InsecureSkipVerify = !*c.VerifySSL 298 } 299 tlsConfig, err := consul.SetupTLSConfig(&config.TLSConfig) 300 if err != nil { 301 return nil, err 302 } 303 config.Transport.TLSClientConfig = tlsConfig 304 } 305 if c.Namespace != "" { 306 config.Namespace = c.Namespace 307 } 308 return config, nil 309 } 310 311 // Copy returns a copy of this Consul config. 312 func (c *ConsulConfig) Copy() *ConsulConfig { 313 if c == nil { 314 return nil 315 } 316 317 nc := new(ConsulConfig) 318 *nc = *c 319 320 // Copy the bools 321 if nc.AutoAdvertise != nil { 322 nc.AutoAdvertise = pointer.Of(*nc.AutoAdvertise) 323 } 324 if nc.ChecksUseAdvertise != nil { 325 nc.ChecksUseAdvertise = pointer.Of(*nc.ChecksUseAdvertise) 326 } 327 if nc.EnableSSL != nil { 328 nc.EnableSSL = pointer.Of(*nc.EnableSSL) 329 } 330 if nc.VerifySSL != nil { 331 nc.VerifySSL = pointer.Of(*nc.VerifySSL) 332 } 333 if nc.ShareSSL != nil { 334 nc.ShareSSL = pointer.Of(*nc.ShareSSL) 335 } 336 if nc.ServerAutoJoin != nil { 337 nc.ServerAutoJoin = pointer.Of(*nc.ServerAutoJoin) 338 } 339 if nc.ClientAutoJoin != nil { 340 nc.ClientAutoJoin = pointer.Of(*nc.ClientAutoJoin) 341 } 342 if nc.AllowUnauthenticated != nil { 343 nc.AllowUnauthenticated = pointer.Of(*nc.AllowUnauthenticated) 344 } 345 346 return nc 347 }