Support reading multiple configuration files(#2504)

feat(config): Support multiple files

This updates the three subcommands that take a `-config` flag to
to support multiple config files via a repeated `-config` flag.
It updates the following subcommands:

- `server`
- `database init`
- `database migrate`

Note that the multiple file support only works if all config files are
HCL, not JSON. Also note that the config files are concatenated
together. There is no attempt to merge config files, so having the same
stanza in multiple files can yield unexpected results, with only one of
the stanzas being used.

When used with these limitations understood, this provides a way to take
different actions for different kinds of dynamic configuration changes.
An example would be when using consul-template to render the
configuration files for boundary. With the multi file support
consul-template can render one config file for the controller stanza,
and provide boundary with a dynamic database credential via vault. Then
when the credential is rotated, consul-template can send boundary a
SIGHUP to switch to the new credential without a restart. A separate
template could be used to render a config for a stanza that does not
support SIGHUP, such as the events stanza that gets its values via
consul's KV. If these values change, consul-template can restart
boundary so the new configuration is used.

Co-authored-by: Timothy Messier <tim.messier@gmail.com>
Co-authored-by: Jeff Mitchell <jeffrey.mitchell@gmail.com>
This commit is contained in:
Timothy MessierandJeff Mitchell authored and GitHub committed 2022-09-29 09:01:33 -04:00
1 parent 441ca59ea3
commit d896f37493
22 files changed
+2279 -178

No files matched your search

+3 -52
View File
@@ -5,19 +5,12 @@ import (
"fmt"
"os"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/types/scope"
kms_plugin_assets "github.com/hashicorp/boundary/plugins/kms"
"github.com/hashicorp/boundary/sdk/wrapper"
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-secure-stdlib/configutil/v2"
"github.com/hashicorp/go-secure-stdlib/mlock"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
@@ -41,7 +34,7 @@ type InitCommand struct {
// deferred function on the Run method.
configWrapperCleanupFunc func() error
flagConfig string
flagConfig []string
flagConfigKms string
flagLogLevel string
flagLogFormat string
@@ -87,7 +80,7 @@ func (c *InitCommand) Flags() *base.FlagSets {
f := set.NewFlagSet("Command Options")
f.StringVar(&base.StringVar{
f.StringSliceVar(&base.StringSliceVar{
Name: "config",
Target: &c.flagConfig,
Completion: complete.PredictOr(
@@ -475,49 +468,7 @@ func (c *InitCommand) ParseFlagsAndConfig(args []string) int {
return base.CommandUserError
}
wrapperPath := c.flagConfig
if c.flagConfigKms != "" {
wrapperPath = c.flagConfigKms
}
wrapper, cleanupFunc, err := wrapper.GetWrapperFromPath(
c.Context,
wrapperPath,
globals.KmsPurposeConfig,
configutil.WithPluginOptions(
pluginutil.WithPluginsMap(kms_plugin_assets.BuiltinKmsPlugins()),
pluginutil.WithPluginsFilesystem(kms_plugin_assets.KmsPluginPrefix, kms_plugin_assets.FileSystem()),
),
// TODO: How would we want to expose this kind of log to users when
// using recovery configs? Generally with normal CLI commands we
// don't print out all of these logs. We may want a logger with a
// custom writer behind our existing gate where we print nothing
// unless there is an error, then dump all of it.
configutil.WithLogger(hclog.NewNullLogger()),
)
if err != nil {
c.UI.Error(err.Error())
return base.CommandUserError
}
if wrapper != nil {
c.configWrapperCleanupFunc = cleanupFunc
if ifWrapper, ok := wrapper.(wrapping.InitFinalizer); ok {
if err := ifWrapper.Init(c.Context); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
c.UI.Error(fmt.Errorf("Could not initialize kms: %w", err).Error())
return base.CommandUserError
}
c.configWrapperCleanupFunc = func() error {
if err := ifWrapper.Finalize(context.Background()); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
c.UI.Warn(fmt.Errorf("Could not finalize kms: %w", err).Error())
}
if cleanupFunc != nil {
return cleanupFunc()
}
return nil
}
}
}
c.Config, err = config.LoadFile(c.flagConfig, wrapper)
c.Config, err = config.Load(c.Context, c.flagConfig, c.flagConfigKms)
if err != nil {
c.UI.Error("Error parsing config: " + err.Error())
return base.CommandUserError
+3 -52
View File
@@ -1,25 +1,18 @@
package database
import (
"context"
"fmt"
"os"
"strconv"
"strings"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/observability/event"
host_plugin_assets "github.com/hashicorp/boundary/plugins/host"
kms_plugin_assets "github.com/hashicorp/boundary/plugins/kms"
external_host_plugins "github.com/hashicorp/boundary/sdk/plugins/host"
"github.com/hashicorp/boundary/sdk/wrapper"
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-secure-stdlib/configutil/v2"
"github.com/hashicorp/go-secure-stdlib/mlock"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
@@ -49,7 +42,7 @@ type MigrateCommand struct {
selectedRepairs schema.RepairMigrations
flagConfig string
flagConfig []string
flagConfigKms string
flagLogLevel string
flagLogFormat string
@@ -79,7 +72,7 @@ func (c *MigrateCommand) Flags() *base.FlagSets {
f := set.NewFlagSet("Command options")
f.StringVar(&base.StringVar{
f.StringSliceVar(&base.StringSliceVar{
Name: "config",
Target: &c.flagConfig,
Completion: complete.PredictOr(
@@ -320,49 +313,7 @@ func (c *MigrateCommand) ParseFlagsAndConfig(args []string) int {
return base.CommandUserError
}
wrapperPath := c.flagConfig
if c.flagConfigKms != "" {
wrapperPath = c.flagConfigKms
}
wrapper, cleanupFunc, err := wrapper.GetWrapperFromPath(
c.Context,
wrapperPath,
globals.KmsPurposeConfig,
configutil.WithPluginOptions(
pluginutil.WithPluginsMap(kms_plugin_assets.BuiltinKmsPlugins()),
pluginutil.WithPluginsFilesystem(kms_plugin_assets.KmsPluginPrefix, kms_plugin_assets.FileSystem()),
),
// TODO: How would we want to expose this kind of log to users when
// using recovery configs? Generally with normal CLI commands we
// don't print out all of these logs. We may want a logger with a
// custom writer behind our existing gate where we print nothing
// unless there is an error, then dump all of it.
configutil.WithLogger(hclog.NewNullLogger()),
)
if err != nil {
c.UI.Error(err.Error())
return base.CommandUserError
}
if wrapper != nil {
c.configWrapperCleanupFunc = cleanupFunc
if ifWrapper, ok := wrapper.(wrapping.InitFinalizer); ok {
if err := ifWrapper.Init(c.Context); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
c.UI.Error(fmt.Errorf("Could not initialize kms: %w", err).Error())
return base.CommandUserError
}
c.configWrapperCleanupFunc = func() error {
if err := ifWrapper.Finalize(context.Background()); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
c.UI.Warn(fmt.Errorf("Could not finalize kms: %w", err).Error())
}
if cleanupFunc != nil {
return cleanupFunc()
}
return nil
}
}
}
c.Config, err = config.LoadFile(c.flagConfig, wrapper)
c.Config, err = config.Load(c.Context, c.flagConfig, c.flagConfigKms)
if err != nil {
c.UI.Error("Error parsing config: " + err.Error())
return base.CommandUserError
+12 -63
View File
@@ -23,15 +23,10 @@ import (
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/observability/event"
kms_plugin_assets "github.com/hashicorp/boundary/plugins/kms"
"github.com/hashicorp/boundary/sdk/wrapper"
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/configutil/v2"
"github.com/hashicorp/go-secure-stdlib/mlock"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
"github.com/hashicorp/go-uuid"
"github.com/mitchellh/cli"
"github.com/posener/complete"
@@ -56,7 +51,7 @@ type Command struct {
controller *controller.Controller
worker *worker.Worker
flagConfig string
flagConfig []string
flagConfigKms string
flagLogLevel string
flagLogFormat string
@@ -90,14 +85,14 @@ func (c *Command) Flags() *base.FlagSets {
f := set.NewFlagSet("Command Options")
f.StringVar(&base.StringVar{
f.StringSliceVar(&base.StringSliceVar{
Name: "config",
Target: &c.flagConfig,
Completion: complete.PredictOr(
complete.PredictFiles("*.hcl"),
complete.PredictFiles("*.json"),
),
Usage: "Path to the configuration file.",
Usage: "Path to the configuration file. Can be specified multiple times for multiple configuration files (only if using HCL format).",
})
f.StringVar(&base.StringVar{
@@ -548,63 +543,17 @@ func (c *Command) reloadConfig() (*config.Config, int) {
switch {
case c.presetConfig != nil:
cfg, err = config.Parse(c.presetConfig.Load())
if err != nil {
event.WriteError(c.Context, op, err, event.WithInfoMsg("could not parse presetConfig", "config", c.presetConfig))
return nil, base.CommandUserError
}
default:
wrapperPath := c.flagConfig
if c.flagConfigKms != "" {
wrapperPath = c.flagConfigKms
cfg, err = config.Load(c.Context, c.flagConfig, c.flagConfigKms)
if err != nil {
c.UI.Error("Error parsing config: " + err.Error())
return nil, base.CommandUserError
}
var configWrapper wrapping.Wrapper
var ifWrapper wrapping.InitFinalizer
var cleanupFunc func() error
if wrapperPath != "" {
configWrapper, cleanupFunc, err = wrapper.GetWrapperFromPath(
c.Context,
wrapperPath,
globals.KmsPurposeConfig,
configutil.WithPluginOptions(
pluginutil.WithPluginsMap(kms_plugin_assets.BuiltinKmsPlugins()),
pluginutil.WithPluginsFilesystem(kms_plugin_assets.KmsPluginPrefix, kms_plugin_assets.FileSystem()),
),
// TODO: How would we want to expose this kind of log to users when
// using recovery configs? Generally with normal CLI commands we
// don't print out all of these logs. We may want a logger with a
// custom writer behind our existing gate where we print nothing
// unless there is an error, then dump all of it.
configutil.WithLogger(hclog.NewNullLogger()),
)
if err != nil {
event.WriteError(c.Context, op, err, event.WithInfoMsg("could not get kms wrapper from config", "path", c.flagConfig))
return nil, base.CommandUserError
}
if cleanupFunc != nil {
defer func() {
if err := cleanupFunc(); err != nil {
event.WriteError(c.Context, op, err, event.WithInfoMsg("could not clean up kms wrapper", "path", c.flagConfig))
}
}()
}
if configWrapper != nil {
ifWrapper, _ = configWrapper.(wrapping.InitFinalizer)
}
}
if ifWrapper != nil {
if err := ifWrapper.Init(c.Context); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
event.WriteError(c.Context, op, err, event.WithInfoMsg("could not initialize kms", "path", c.flagConfig))
return nil, base.CommandCliError
}
}
cfg, err = config.LoadFile(c.flagConfig, configWrapper)
if ifWrapper != nil {
if err := ifWrapper.Finalize(context.Background()); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
event.WriteError(context.Background(), op, err, event.WithInfoMsg("could not finalize kms", "path", c.flagConfig))
return nil, base.CommandCliError
}
}
}
if err != nil {
event.WriteError(c.Context, op, err, event.WithInfoMsg("could not parse config", "path", c.flagConfig))
return nil, base.CommandUserError
}
return cfg, 0
}
@@ -754,7 +703,7 @@ func (c *Command) WaitForInterrupt() int {
var newConf *config.Config
var out int
if c.flagConfig == "" && c.presetConfig == nil {
if len(c.flagConfig) == 0 && c.presetConfig == nil {
goto RUNRELOADFUNCS
}
+93 -10
View File
@@ -2,25 +2,31 @@ package config
import (
"bytes"
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"reflect"
"strconv"
"strings"
"time"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/observability/event"
kms_plugin_assets "github.com/hashicorp/boundary/plugins/kms"
"github.com/hashicorp/boundary/sdk/wrapper"
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
configutil "github.com/hashicorp/go-secure-stdlib/configutil/v2"
"github.com/hashicorp/go-secure-stdlib/listenerutil"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
@@ -324,23 +330,100 @@ func New() *Config {
}
}
// LoadFile loads the configuration from the given file.
func LoadFile(path string, wrapper wrapping.Wrapper) (*Config, error) {
d, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
// Load will create a Config from the given config files. It concatenates the
// contents of the files together. This allows for composing a config from
// separate files, but notably does not attempt any merging of configs. Thus it
// is possible that the concatenation results in an invalid config file. This
// also supports decrypting the config, either with a kms block in one of the
// given files, or as a separate file in wrapperPath.
//
// Note that having multiple config files is only supported properly if they are
// all hcl files. If they are json files, only the first file is used. A mix of
// hcl and json will result in an error.
func Load(ctx context.Context, paths []string, wrapperPath string) (*Config, error) {
const op = "config.Load"
var err error
var cfg *Config
configStrs := make([]string, 0, len(paths))
for _, path := range paths {
fileBytes, err := os.ReadFile(path)
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("could not read config file", "path", path, "error", err))
return nil, err
}
configStrs = append(configStrs, string(fileBytes))
}
configString := strings.Join(configStrs, "\n")
wrapperString := configString
if wrapperPath != "" {
wrapperBytes, err := os.ReadFile(wrapperPath)
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("could not read kms config file", "path", wrapperPath, "error", err))
return nil, err
}
wrapperString = string(wrapperBytes)
}
raw := string(d)
var configWrapper wrapping.Wrapper
var ifWrapper wrapping.InitFinalizer
var cleanupFunc func() error
if wrapperString != "" {
configWrapper, cleanupFunc, err = wrapper.GetWrapperFromHcl(
ctx,
wrapperString,
globals.KmsPurposeConfig,
configutil.WithPluginOptions(
pluginutil.WithPluginsMap(kms_plugin_assets.BuiltinKmsPlugins()),
pluginutil.WithPluginsFilesystem(kms_plugin_assets.KmsPluginPrefix, kms_plugin_assets.FileSystem()),
),
// TODO: How would we want to expose this kind of log to users when
// using recovery configs? Generally with normal CLI commands we
// don't print out all of these logs. We may want a logger with a
// custom writer behind our existing gate where we print nothing
// unless there is an error, then dump all of it.
configutil.WithLogger(hclog.NewNullLogger()),
)
if err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("could not get kms wrapper from config", "path", wrapperPath))
return nil, err
}
if cleanupFunc != nil {
defer func() {
if err := cleanupFunc(); err != nil {
event.WriteError(ctx, op, err, event.WithInfoMsg("could not clean up kms wrapper", "path", wrapperPath))
}
}()
}
if configWrapper != nil {
ifWrapper, _ = configWrapper.(wrapping.InitFinalizer)
}
}
if ifWrapper != nil {
if err := ifWrapper.Init(ctx); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
event.WriteError(ctx, op, err, event.WithInfoMsg("could not initialize kms", "path", wrapperPath))
return nil, err
}
}
if wrapper != nil {
raw, err = configutil.EncryptDecrypt(raw, true, true, wrapper)
if configWrapper != nil {
configString, err = configutil.EncryptDecrypt(configString, true, true, configWrapper)
if err != nil {
return nil, err
}
}
return Parse(raw)
cfg, err = Parse(configString)
if ifWrapper != nil {
if err := ifWrapper.Finalize(context.Background()); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
event.WriteError(context.Background(), op, err, event.WithInfoMsg("could not finalize kms", "path", wrapperPath))
return nil, err
}
}
return cfg, err
}
func Parse(d string) (*Config, error) {
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,28 @@
disable_mlock = true
controller {
name = "controller0"
description = "A controller"
database {
url = "env://LOAD_TEST_BOUNDARY_POSTGRES_URL"
}
}
listener "tcp" {
address = "boundary"
purpose = "api"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "cluster"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "ops"
tls_disable = true
}
@@ -0,0 +1,12 @@
worker {
name = "worker0"
description = "A worker"
address = "boundary"
initial_upstreams = ["boundary:9201"]
}
listener "tcp" {
address = "boundary"
purpose = "proxy"
tls_disable = true
}
@@ -0,0 +1,20 @@
kms "aead" {
purpose = "root"
aead_type = "aes-gcm"
key = "sP1fnF5Xz85RrXyELHFeZg9Ad2qt4Z4bgNHVGtD6ung="
key_id = "global_root"
}
kms "aead" {
purpose = "worker-auth"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_worker-auth"
}
kms "aead" {
purpose = "recovery"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_recovery"
}
@@ -0,0 +1,28 @@
disable_mlock = true
controller {
name = "controller0"
description = "A controller"
database {
url = "env://LOAD_TEST_BOUNDARY_POSTGRES_URL"
}
}
listener "tcp" {
address = "boundary"
purpose = "api"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "cluster"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "ops"
tls_disable = true
}
@@ -0,0 +1,8 @@
controller {
name = "controller0"
description = "A controller but duplicated"
database {
url = "env://LOAD_TEST_BOUNDARY_POSTGRES_URL"
}
}
@@ -0,0 +1,12 @@
worker {
name = "worker0"
description = "A worker"
address = "boundary"
initial_upstreams = ["boundary:9201"]
}
listener "tcp" {
address = "boundary"
purpose = "proxy"
tls_disable = true
}
@@ -0,0 +1,20 @@
kms "aead" {
purpose = "root"
aead_type = "aes-gcm"
key = "sP1fnF5Xz85RrXyELHFeZg9Ad2qt4Z4bgNHVGtD6ung="
key_id = "global_root"
}
kms "aead" {
purpose = "worker-auth"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_worker-auth"
}
kms "aead" {
purpose = "recovery"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_recovery"
}
@@ -0,0 +1,14 @@
{
"disable_mlock": true,
"controller": [
{
"database": [
{
"url": "env://LOAD_TEST_BOUNDARY_POSTGRES_URL"
}
],
"description": "A controller",
"name": "controller0"
}
]
}
@@ -0,0 +1,12 @@
{
"worker": [
{
"address": "boundary",
"description": "A worker",
"initial_upstreams": [
"boundary:9201"
],
"name": "worker0"
}
]
}
@@ -0,0 +1,28 @@
{
"kms": [
{
"aead": {
"aead_type": "aes-gcm",
"key": "sP1fnF5Xz85RrXyELHFeZg9Ad2qt4Z4bgNHVGtD6ung=",
"key_id": "global_root",
"purpose": "root"
}
},
{
"aead": {
"aead_type": "aes-gcm",
"key": "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=",
"key_id": "global_worker-auth",
"purpose": "worker-auth"
}
},
{
"aead": {
"aead_type": "aes-gcm",
"key": "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=",
"key_id": "global_recovery",
"purpose": "recovery"
}
}
]
}
@@ -0,0 +1,32 @@
{
"listener": [
{
"tcp": {
"address": "boundary",
"purpose": "api",
"tls_disable": true
}
},
{
"tcp": {
"address": "boundary",
"purpose": "cluster",
"tls_disable": true
}
},
{
"tcp": {
"address": "boundary",
"purpose": "ops",
"tls_disable": true
}
},
{
"tcp": {
"address": "boundary",
"purpose": "proxy",
"tls_disable": true
}
}
]
}
@@ -0,0 +1,28 @@
disable_mlock = true
controller {
name = "controller0"
description = "A controller"
database {
url = "env://LOAD_TEST_BOUNDARY_POSTGRES_URL"
}
}
listener "tcp" {
address = "boundary"
purpose = "api"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "cluster"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "ops"
tls_disable = true
}
@@ -0,0 +1,12 @@
{
"worker": [
{
"address": "boundary",
"description": "A worker",
"initial_upstreams": [
"boundary:9201"
],
"name": "worker0"
}
]
}
@@ -0,0 +1,20 @@
kms "aead" {
purpose = "root"
aead_type = "aes-gcm"
key = "sP1fnF5Xz85RrXyELHFeZg9Ad2qt4Z4bgNHVGtD6ung="
key_id = "global_root"
}
kms "aead" {
purpose = "worker-auth"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_worker-auth"
}
kms "aead" {
purpose = "recovery"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_recovery"
}
@@ -0,0 +1,62 @@
disable_mlock = true
controller {
name = "controller0"
description = "A controller"
database {
url = "env://LOAD_TEST_BOUNDARY_POSTGRES_URL"
}
}
worker {
name = "worker0"
description = "A worker"
address = "boundary"
initial_upstreams = ["boundary:9201"]
}
listener "tcp" {
address = "boundary"
purpose = "api"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "cluster"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "proxy"
tls_disable = true
}
listener "tcp" {
address = "boundary"
purpose = "ops"
tls_disable = true
}
kms "aead" {
purpose = "root"
aead_type = "aes-gcm"
key = "sP1fnF5Xz85RrXyELHFeZg9Ad2qt4Z4bgNHVGtD6ung="
key_id = "global_root"
}
kms "aead" {
purpose = "worker-auth"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_worker-auth"
}
kms "aead" {
purpose = "recovery"
aead_type = "aes-gcm"
key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
key_id = "global_recovery"
}
@@ -0,0 +1,80 @@
{
"controller": [
{
"database": [
{
"url": "env://LOAD_TEST_BOUNDARY_POSTGRES_URL"
}
],
"description": "A controller",
"name": "controller0"
}
],
"disable_mlock": true,
"kms": [
{
"aead": {
"aead_type": "aes-gcm",
"key": "sP1fnF5Xz85RrXyELHFeZg9Ad2qt4Z4bgNHVGtD6ung=",
"key_id": "global_root",
"purpose": "root"
}
},
{
"aead": {
"aead_type": "aes-gcm",
"key": "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=",
"key_id": "global_worker-auth",
"purpose": "worker-auth"
}
},
{
"aead": {
"aead_type": "aes-gcm",
"key": "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=",
"key_id": "global_recovery",
"purpose": "recovery"
}
}
],
"listener": [
{
"tcp": {
"address": "boundary",
"purpose": "api",
"tls_disable": true
}
},
{
"tcp": {
"address": "boundary",
"purpose": "cluster",
"tls_disable": true
}
},
{
"tcp": {
"address": "boundary",
"purpose": "proxy",
"tls_disable": true
}
},
{
"tcp": {
"address": "boundary",
"purpose": "ops",
"tls_disable": true
}
}
],
"worker": [
{
"address": "boundary",
"description": "A worker",
"initial_upstreams": [
"boundary:9201"
],
"name": "worker0"
}
]
}