diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f419fb6c7..69a6009cfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,14 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. * server: When running single-server mode and `controllers` is not specified in the `worker` block, use `public_cluster_addr` if given ([PR](https://github.com/hashicorp/boundary/pull/904)) +* server: `public_cluster_addr` in the `controller` block can now be specified + as a `file://` or `env://` URL to read the value from a file or env var + ([PR](https://github.com/hashicorp/boundary/pull/907)) * server: Add `read` action to default scope grant ([PR](https://github.com/hashicorp/boundary/pull/913)) +* server: `public_cluster_addr` in the `controller` block can now be specified + as a `file://` or `env://` URL to read the value from a file or env var + ([PR](https://github.com/hashicorp/boundary/pull/907)) ### Bug Fixes diff --git a/docker/config.hcl b/docker/config.hcl index 5da8d041c4..3465e10300 100644 --- a/docker/config.hcl +++ b/docker/config.hcl @@ -1,46 +1,46 @@ +# This is a default configuration provided for our Docker image. It's meant to +# be a starting point and to help new users get started. It's strongly +# recommended that this configuration is not used outside of demonstrations +# because it uses hard coded AEAD keys. + disable_mlock = true controller { - name = "demo-controller-1" - description = "A controller for a demo!" + name = "demo-controller" + description = "A default controller created for demonstration" database { # This configuration setting requires the user to execute the container with the URL as an env var # to connect to the Boundary postgres DB. An example of how this can be done assuming the postgres - # database is running as a container and you're using docker for mac (replace host.docker.internal with - # localhost if you're on linux): + # database is running as a container and you're using Docker for Mac (replace host.docker.internal with + # localhost if you're on Linux): + # # $ docker run -e 'BOUNDARY_POSTGRES_URL=postgresql://postgres:postgres@host.docker.internal:5432/postgres?sslmode=disable' [other options] boundary:[version] url = "env://BOUNDARY_POSTGRES_URL" } + + public_cluster_addr = "env://HOSTNAME" } worker { - name = "demo-worker-1" - description = "A default worker created demonstration" + name = "demo-worker" + description = "A default worker created for demonstration" } listener "tcp" { - # This configuration assumes the docker container hostname is being overridden using the --hostname - # flag. The default configuration of a container uses the ephemeral container ID as the hostname and - # this hostname resolves to the ephemeral IP of the container. We need to bind to the ephemeral IP - # of the container on startup, and need to know the hostname in order to do that. A future improvement - # would be allowing the listener to set `env://HOSTNAME` as its value but that's not a feature at - # the time of this writing. For now, when running boundary in docker you must pass the --hostname - # flag as: - # $ docker run --hostname boundary [other options] boundary:[version] - address = "boundary" + address = "0.0.0.0" purpose = "api" tls_disable = true } listener "tcp" { - address = "boundary" + address = "0.0.0.0" purpose = "cluster" tls_disable = true } listener "tcp" { - address = "boundary" + address = "0.0.0.0" purpose = "proxy" tls_disable = true } diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index f18a8e788c..b776357256 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -637,6 +637,12 @@ func (b *Server) SetupControllerPublicClusterAddress(conf *config.Config, flagVa } } } + } else { + var err error + conf.Controller.PublicClusterAddr, err = config.ParseAddress(conf.Controller.PublicClusterAddr) + if err != nil && err != config.ErrNotAUrl { + return fmt.Errorf("Error parsing public cluster addr: %w", err) + } } host, port, err := net.SplitHostPort(conf.Controller.PublicClusterAddr) if err != nil { @@ -668,6 +674,12 @@ func (b *Server) SetupWorkerPublicAddress(conf *config.Config, flagValue string) } } } + } else { + var err error + conf.Worker.PublicAddr, err = config.ParseAddress(conf.Worker.PublicAddr) + if err != nil && err != config.ErrNotAUrl { + return fmt.Errorf("Error parsing public addr: %w", err) + } } host, port, err := net.SplitHostPort(conf.Worker.PublicAddr) if err != nil { diff --git a/internal/cmd/commands/dev/dev.go b/internal/cmd/commands/dev/dev.go index c70171fa11..0b89591d84 100644 --- a/internal/cmd/commands/dev/dev.go +++ b/internal/cmd/commands/dev/dev.go @@ -297,6 +297,20 @@ func (c *Command) Run(args []string) int { c.Config.PassthroughDirectory = c.flagPassthroughDirectory + if err := c.SetupControllerPublicClusterAddress(c.Config, c.flagControllerPublicClusterAddr); err != nil { + c.UI.Error(err.Error()) + return 1 + } + c.InfoKeys = append(c.InfoKeys, "controller public cluster addr") + c.Info["controller public cluster addr"] = c.Config.Controller.PublicClusterAddr + + if err := c.SetupWorkerPublicAddress(c.Config, c.flagWorkerPublicAddr); err != nil { + c.UI.Error(err.Error()) + return 1 + } + c.InfoKeys = append(c.InfoKeys, "worker public addr") + c.Info["worker public addr"] = c.Config.Worker.PublicAddr + for _, l := range c.Config.Listeners { if len(l.Purpose) != 1 { c.UI.Error("Only one purpose supported for each listener") @@ -367,20 +381,6 @@ func (c *Command) Run(args []string) int { return 1 } - if err := c.SetupControllerPublicClusterAddress(c.Config, c.flagControllerPublicClusterAddr); err != nil { - c.UI.Error(err.Error()) - return 1 - } - c.InfoKeys = append(c.InfoKeys, "controller public cluster addr") - c.Info["controller public cluster addr"] = c.Config.Controller.PublicClusterAddr - - if err := c.SetupWorkerPublicAddress(c.Config, c.flagWorkerPublicAddr); err != nil { - c.UI.Error(err.Error()) - return 1 - } - c.InfoKeys = append(c.InfoKeys, "worker public addr") - c.Info["worker public addr"] = c.Config.Worker.PublicAddr - // Write out the PID to the file now that server has successfully started if err := c.StorePidFile(c.Config.PidFile); err != nil { c.UI.Error(fmt.Errorf("Error storing PID: %w", err).Error()) diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index 441eb381bb..6c95285d07 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -198,6 +198,7 @@ func (c *Command) Run(args []string) int { clusterAddr = lnConfig.Address if clusterAddr == "" { clusterAddr = "127.0.0.1:9201" + lnConfig.Address = clusterAddr } case "api": foundApi = true @@ -222,12 +223,29 @@ func (c *Command) Run(args []string) int { c.UI.Error(`Config activates controller but no listener with "cluster" purpose found`) return 1 } + if err := c.SetupControllerPublicClusterAddress(c.Config, ""); err != nil { + c.UI.Error(err.Error()) + return 1 + } + c.InfoKeys = append(c.InfoKeys, "public cluster addr") + c.Info["public cluster addr"] = c.Config.Controller.PublicClusterAddr } + if c.Config.Worker != nil { if !foundProxy { c.UI.Error(`Config activates worker but no listener with "proxy" purpose found`) return 1 } + + if c.Config.Worker != nil { + if err := c.SetupWorkerPublicAddress(c.Config, ""); err != nil { + c.UI.Error(err.Error()) + return 1 + } + c.InfoKeys = append(c.InfoKeys, "public proxy addr") + c.Info["public proxy addr"] = c.Config.Worker.PublicAddr + } + if c.Config.Controller != nil { switch len(c.Config.Worker.Controllers) { case 0: @@ -293,14 +311,6 @@ func (c *Command) Run(args []string) int { return 1 } - if c.Config.Worker != nil { - if err := c.SetupWorkerPublicAddress(c.Config, ""); err != nil { - c.UI.Error(err.Error()) - return 1 - } - c.InfoKeys = append(c.InfoKeys, "public proxy addr") - c.Info["public proxy addr"] = c.Config.Worker.PublicAddr - } if c.Config.Controller != nil { for _, ln := range c.Config.Listeners { for _, purpose := range ln.Purpose { @@ -325,13 +335,6 @@ func (c *Command) Run(args []string) int { } } } - - if err := c.SetupControllerPublicClusterAddress(c.Config, ""); err != nil { - c.UI.Error(err.Error()) - return 1 - } - c.InfoKeys = append(c.InfoKeys, "public cluster addr") - c.Info["public cluster addr"] = c.Config.Controller.PublicClusterAddr } // Write out the PID to the file now that server has successfully started diff --git a/website/content/docs/configuration/controller.mdx b/website/content/docs/configuration/controller.mdx index 23816ec8ba..86b0ed502f 100644 --- a/website/content/docs/configuration/controller.mdx +++ b/website/content/docs/configuration/controller.mdx @@ -25,27 +25,30 @@ controller { - `description` - Specifies a friendly description of this controller. - `database` - Configuration block with two valid parameters for connecting to Postgres: - - `url` - Configures the URL for connecting to Postgres - - `migration_url` - Can be used to specify a different URL for migrations, as that - usually requires higher privileges. - Either can refer to a file on disk (file://) from which a URL will be read; an env - var (env://) from which the URL will be read; or a direct database URL (postgres://). + - `url` - Configures the URL for connecting to Postgres + - `migration_url` - Can be used to specify a different URL for migrations, as that + usually requires higher privileges. + + Either can refer to a file on disk (file://) from which a URL will be read; an env + var (env://) from which the URL will be read; or a direct database URL (postgres://). - `public_cluster_addr` - Specifies the public host or IP address (and -optionally port) at which the controller can be reached _by workers_. This will be -used by workers after initial connection to controllers via the worker's -`controllers` block. This defaults to the address of the listener marked for -`cluster` purpose. This is especially useful for cloud environments that do not -bind a publicly accessible IP to a NIC on the host directly, such as an Amazon -EIP. + optionally port) at which the controller can be reached _by workers_. This will + be used by workers after initial connection to controllers via the worker's + `controllers` block. This defaults to the address of the listener marked for + `cluster` purpose. This is especially useful for cloud environments that do not + bind a publicly accessible IP to a NIC on the host directly, such as an Amazon + EIP. This value can be a direct address string, can refer to a file on disk (file://) + from which an address will be read; or an env var (env://) from which the + address will be read. - `auth_token_time_to_live` - Maximum time to live (TTL) for all auth tokens globally (pertains -to all tokens from all auth methods). Valid time units are anything specified by Golang's -[ParseDuration()](https://golang.org/pkg/time/#ParseDuration) method. Default is 7 days. + to all tokens from all auth methods). Valid time units are anything specified by Golang's + [ParseDuration()](https://golang.org/pkg/time/#ParseDuration) method. Default is 7 days. - `auth_token_time_to_stale` - Maximum time of inactivity for all auth tokens globally (pertains -to all tokens from all auth methods). Valid time units are anything specified by Golang's -[ParseDuration()](https://golang.org/pkg/time/#ParseDuration) method. Default is 1 day. + to all tokens from all auth methods). Valid time units are anything specified by Golang's + [ParseDuration()](https://golang.org/pkg/time/#ParseDuration) method. Default is 1 day. ## KMS Configuration @@ -88,7 +91,7 @@ kms "aead" { And optionally, a KMS stanza for configuration encryption purpose: ```hcl -# Configuration encryption block: decrypts sensitive values in the +# Configuration encryption block: decrypts sensitive values in the # configuration file. See `boundary config [encrypt|decrypt] -h`. kms "aead" { purpose = "config"` @@ -98,7 +101,7 @@ kms "aead" { ``` Boundary supports many kinds of KMS integrations. For a complete guide to all available -KMS types, see our [KMS documentation](/docs/configuration/kms). +KMS types, see our [KMS documentation](/docs/configuration/kms). # Complete Configuration Example @@ -174,5 +177,3 @@ kms "aead" { key_id = "global_recovery" } ``` - -