mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-18 04:27:02 +02:00
Fix JSON encoding adding newlines. This manifested itself when encoding config values, which all map to strings. An extra new line would get added by json.Encode, which caused other things to break with confusing error messagges. Switching to json.Marshal seems to solve the problem.
765 lines
19 KiB
Go
765 lines
19 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/errwrap"
|
|
"github.com/hashicorp/go-multierror"
|
|
"github.com/hashicorp/hcl"
|
|
"github.com/hashicorp/hcl/hcl/ast"
|
|
"github.com/hashicorp/vault/internalshared/configutil"
|
|
"github.com/hashicorp/vault/sdk/helper/parseutil"
|
|
)
|
|
|
|
// Config is the configuration for the vault server.
|
|
type Config struct {
|
|
entConfig
|
|
|
|
*configutil.SharedConfig `hcl:"-"`
|
|
|
|
Storage *Storage `hcl:"-"`
|
|
HAStorage *Storage `hcl:"-"`
|
|
|
|
ServiceRegistration *ServiceRegistration `hcl:"-"`
|
|
|
|
CacheSize int `hcl:"cache_size"`
|
|
DisableCache bool `hcl:"-"`
|
|
DisableCacheRaw interface{} `hcl:"disable_cache"`
|
|
DisablePrintableCheck bool `hcl:"-"`
|
|
DisablePrintableCheckRaw interface{} `hcl:"disable_printable_check"`
|
|
|
|
EnableUI bool `hcl:"-"`
|
|
EnableUIRaw interface{} `hcl:"ui"`
|
|
|
|
MaxLeaseTTL time.Duration `hcl:"-"`
|
|
MaxLeaseTTLRaw interface{} `hcl:"max_lease_ttl"`
|
|
DefaultLeaseTTL time.Duration `hcl:"-"`
|
|
DefaultLeaseTTLRaw interface{} `hcl:"default_lease_ttl"`
|
|
|
|
ClusterCipherSuites string `hcl:"cluster_cipher_suites"`
|
|
|
|
PluginDirectory string `hcl:"plugin_directory"`
|
|
|
|
EnableRawEndpoint bool `hcl:"-"`
|
|
EnableRawEndpointRaw interface{} `hcl:"raw_storage_endpoint"`
|
|
|
|
APIAddr string `hcl:"api_addr"`
|
|
ClusterAddr string `hcl:"cluster_addr"`
|
|
DisableClustering bool `hcl:"-"`
|
|
DisableClusteringRaw interface{} `hcl:"disable_clustering"`
|
|
|
|
DisablePerformanceStandby bool `hcl:"-"`
|
|
DisablePerformanceStandbyRaw interface{} `hcl:"disable_performance_standby"`
|
|
|
|
DisableSealWrap bool `hcl:"-"`
|
|
DisableSealWrapRaw interface{} `hcl:"disable_sealwrap"`
|
|
|
|
DisableIndexing bool `hcl:"-"`
|
|
DisableIndexingRaw interface{} `hcl:"disable_indexing"`
|
|
}
|
|
|
|
// DevConfig is a Config that is used for dev mode of Vault.
|
|
func DevConfig(storageType string) (*Config, error) {
|
|
hclStr := `
|
|
disable_mlock = true
|
|
|
|
listener "tcp" {
|
|
address = "127.0.0.1:8200"
|
|
tls_disable = true
|
|
proxy_protocol_behavior = "allow_authorized"
|
|
proxy_protocol_authorized_addrs = "127.0.0.1:8200"
|
|
}
|
|
|
|
telemetry {
|
|
prometheus_retention_time = "24h"
|
|
disable_hostname = true
|
|
}
|
|
|
|
enable_raw_endpoint = true
|
|
|
|
storage "%s" {
|
|
}
|
|
|
|
enable_ui = true
|
|
`
|
|
|
|
hclStr = fmt.Sprintf(hclStr, storageType)
|
|
parsed, err := ParseConfig(hclStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing dev config: %w", err)
|
|
}
|
|
return parsed, nil
|
|
}
|
|
|
|
// Storage is the underlying storage configuration for the server.
|
|
type Storage struct {
|
|
Type string
|
|
RedirectAddr string
|
|
ClusterAddr string
|
|
DisableClustering bool
|
|
Config map[string]string
|
|
}
|
|
|
|
func (b *Storage) GoString() string {
|
|
return fmt.Sprintf("*%#v", *b)
|
|
}
|
|
|
|
// ServiceRegistration is the optional service discovery for the server.
|
|
type ServiceRegistration struct {
|
|
Type string
|
|
Config map[string]string
|
|
}
|
|
|
|
func (b *ServiceRegistration) GoString() string {
|
|
return fmt.Sprintf("*%#v", *b)
|
|
}
|
|
|
|
func NewConfig() *Config {
|
|
return &Config{
|
|
SharedConfig: new(configutil.SharedConfig),
|
|
}
|
|
}
|
|
|
|
// Merge merges two configurations.
|
|
func (c *Config) Merge(c2 *Config) *Config {
|
|
if c2 == nil {
|
|
return c
|
|
}
|
|
|
|
result := NewConfig()
|
|
|
|
result.SharedConfig = c.SharedConfig
|
|
if c2.SharedConfig != nil {
|
|
result.SharedConfig = c.SharedConfig.Merge(c2.SharedConfig)
|
|
}
|
|
|
|
result.Storage = c.Storage
|
|
if c2.Storage != nil {
|
|
result.Storage = c2.Storage
|
|
}
|
|
|
|
result.HAStorage = c.HAStorage
|
|
if c2.HAStorage != nil {
|
|
result.HAStorage = c2.HAStorage
|
|
}
|
|
|
|
result.ServiceRegistration = c.ServiceRegistration
|
|
if c2.ServiceRegistration != nil {
|
|
result.ServiceRegistration = c2.ServiceRegistration
|
|
}
|
|
|
|
result.CacheSize = c.CacheSize
|
|
if c2.CacheSize != 0 {
|
|
result.CacheSize = c2.CacheSize
|
|
}
|
|
|
|
// merging these booleans via an OR operation
|
|
result.DisableCache = c.DisableCache
|
|
if c2.DisableCache {
|
|
result.DisableCache = c2.DisableCache
|
|
}
|
|
|
|
result.DisablePrintableCheck = c.DisablePrintableCheck
|
|
if c2.DisablePrintableCheckRaw != nil {
|
|
result.DisablePrintableCheck = c2.DisablePrintableCheck
|
|
}
|
|
|
|
// merge these integers via a MAX operation
|
|
result.MaxLeaseTTL = c.MaxLeaseTTL
|
|
if c2.MaxLeaseTTL > result.MaxLeaseTTL {
|
|
result.MaxLeaseTTL = c2.MaxLeaseTTL
|
|
}
|
|
|
|
result.DefaultLeaseTTL = c.DefaultLeaseTTL
|
|
if c2.DefaultLeaseTTL > result.DefaultLeaseTTL {
|
|
result.DefaultLeaseTTL = c2.DefaultLeaseTTL
|
|
}
|
|
|
|
result.ClusterCipherSuites = c.ClusterCipherSuites
|
|
if c2.ClusterCipherSuites != "" {
|
|
result.ClusterCipherSuites = c2.ClusterCipherSuites
|
|
}
|
|
|
|
result.EnableUI = c.EnableUI
|
|
if c2.EnableUI {
|
|
result.EnableUI = c2.EnableUI
|
|
}
|
|
|
|
result.EnableRawEndpoint = c.EnableRawEndpoint
|
|
if c2.EnableRawEndpoint {
|
|
result.EnableRawEndpoint = c2.EnableRawEndpoint
|
|
}
|
|
|
|
result.APIAddr = c.APIAddr
|
|
if c2.APIAddr != "" {
|
|
result.APIAddr = c2.APIAddr
|
|
}
|
|
|
|
result.ClusterAddr = c.ClusterAddr
|
|
if c2.ClusterAddr != "" {
|
|
result.ClusterAddr = c2.ClusterAddr
|
|
}
|
|
|
|
// Retain raw value so that it can be assigned to storage objects
|
|
result.DisableClustering = c.DisableClustering
|
|
result.DisableClusteringRaw = c.DisableClusteringRaw
|
|
if c2.DisableClusteringRaw != nil {
|
|
result.DisableClustering = c2.DisableClustering
|
|
result.DisableClusteringRaw = c2.DisableClusteringRaw
|
|
}
|
|
|
|
result.PluginDirectory = c.PluginDirectory
|
|
if c2.PluginDirectory != "" {
|
|
result.PluginDirectory = c2.PluginDirectory
|
|
}
|
|
|
|
result.DisablePerformanceStandby = c.DisablePerformanceStandby
|
|
if c2.DisablePerformanceStandby {
|
|
result.DisablePerformanceStandby = c2.DisablePerformanceStandby
|
|
}
|
|
|
|
result.DisableSealWrap = c.DisableSealWrap
|
|
if c2.DisableSealWrap {
|
|
result.DisableSealWrap = c2.DisableSealWrap
|
|
}
|
|
|
|
result.DisableIndexing = c.DisableIndexing
|
|
if c2.DisableIndexing {
|
|
result.DisableIndexing = c2.DisableIndexing
|
|
}
|
|
|
|
// Use values from top-level configuration for storage if set
|
|
if storage := result.Storage; storage != nil {
|
|
if result.APIAddr != "" {
|
|
storage.RedirectAddr = result.APIAddr
|
|
}
|
|
if result.ClusterAddr != "" {
|
|
storage.ClusterAddr = result.ClusterAddr
|
|
}
|
|
if result.DisableClusteringRaw != nil {
|
|
storage.DisableClustering = result.DisableClustering
|
|
}
|
|
}
|
|
|
|
if haStorage := result.HAStorage; haStorage != nil {
|
|
if result.APIAddr != "" {
|
|
haStorage.RedirectAddr = result.APIAddr
|
|
}
|
|
if result.ClusterAddr != "" {
|
|
haStorage.ClusterAddr = result.ClusterAddr
|
|
}
|
|
if result.DisableClusteringRaw != nil {
|
|
haStorage.DisableClustering = result.DisableClustering
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// LoadConfig loads the configuration at the given path, regardless if
|
|
// its a file or directory.
|
|
func LoadConfig(path string) (*Config, error) {
|
|
fi, err := os.Stat(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if fi.IsDir() {
|
|
return CheckConfig(LoadConfigDir(path))
|
|
}
|
|
return CheckConfig(LoadConfigFile(path))
|
|
}
|
|
|
|
func CheckConfig(c *Config, e error) (*Config, error) {
|
|
if e != nil {
|
|
return c, e
|
|
}
|
|
|
|
if len(c.Seals) == 2 {
|
|
switch {
|
|
case c.Seals[0].Disabled && c.Seals[1].Disabled:
|
|
return nil, errors.New("seals: two seals provided but both are disabled")
|
|
case !c.Seals[0].Disabled && !c.Seals[1].Disabled:
|
|
return nil, errors.New("seals: two seals provided but neither is disabled")
|
|
}
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// LoadConfigFile loads the configuration from the given file.
|
|
func LoadConfigFile(path string) (*Config, error) {
|
|
// Read the file
|
|
d, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
conf, err := ParseConfig(string(d))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return conf, nil
|
|
}
|
|
|
|
func ParseConfig(d string) (*Config, error) {
|
|
// Parse!
|
|
obj, err := hcl.Parse(d)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Start building the result
|
|
result := NewConfig()
|
|
if err := hcl.DecodeObject(result, obj); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sharedConfig, err := configutil.ParseConfig(d)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result.SharedConfig = sharedConfig
|
|
|
|
if result.MaxLeaseTTLRaw != nil {
|
|
if result.MaxLeaseTTL, err = parseutil.ParseDurationSecond(result.MaxLeaseTTLRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if result.DefaultLeaseTTLRaw != nil {
|
|
if result.DefaultLeaseTTL, err = parseutil.ParseDurationSecond(result.DefaultLeaseTTLRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.EnableUIRaw != nil {
|
|
if result.EnableUI, err = parseutil.ParseBool(result.EnableUIRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.DisableCacheRaw != nil {
|
|
if result.DisableCache, err = parseutil.ParseBool(result.DisableCacheRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.DisablePrintableCheckRaw != nil {
|
|
if result.DisablePrintableCheck, err = parseutil.ParseBool(result.DisablePrintableCheckRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.EnableRawEndpointRaw != nil {
|
|
if result.EnableRawEndpoint, err = parseutil.ParseBool(result.EnableRawEndpointRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.DisableClusteringRaw != nil {
|
|
if result.DisableClustering, err = parseutil.ParseBool(result.DisableClusteringRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.DisablePerformanceStandbyRaw != nil {
|
|
if result.DisablePerformanceStandby, err = parseutil.ParseBool(result.DisablePerformanceStandbyRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.DisableSealWrapRaw != nil {
|
|
if result.DisableSealWrap, err = parseutil.ParseBool(result.DisableSealWrapRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if result.DisableIndexingRaw != nil {
|
|
if result.DisableIndexing, err = parseutil.ParseBool(result.DisableIndexingRaw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
list, ok := obj.Node.(*ast.ObjectList)
|
|
if !ok {
|
|
return nil, fmt.Errorf("error parsing: file doesn't contain a root object")
|
|
}
|
|
|
|
// Look for storage but still support old backend
|
|
if o := list.Filter("storage"); len(o.Items) > 0 {
|
|
if err := ParseStorage(result, o, "storage"); err != nil {
|
|
return nil, errwrap.Wrapf("error parsing 'storage': {{err}}", err)
|
|
}
|
|
} else {
|
|
if o := list.Filter("backend"); len(o.Items) > 0 {
|
|
if err := ParseStorage(result, o, "backend"); err != nil {
|
|
return nil, errwrap.Wrapf("error parsing 'backend': {{err}}", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
if o := list.Filter("ha_storage"); len(o.Items) > 0 {
|
|
if err := parseHAStorage(result, o, "ha_storage"); err != nil {
|
|
return nil, errwrap.Wrapf("error parsing 'ha_storage': {{err}}", err)
|
|
}
|
|
} else {
|
|
if o := list.Filter("ha_backend"); len(o.Items) > 0 {
|
|
if err := parseHAStorage(result, o, "ha_backend"); err != nil {
|
|
return nil, errwrap.Wrapf("error parsing 'ha_backend': {{err}}", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse service discovery
|
|
if o := list.Filter("service_registration"); len(o.Items) > 0 {
|
|
if err := parseServiceRegistration(result, o, "service_registration"); err != nil {
|
|
return nil, errwrap.Wrapf("error parsing 'service_registration': {{err}}", err)
|
|
}
|
|
}
|
|
|
|
entConfig := &(result.entConfig)
|
|
if err := entConfig.parseConfig(list); err != nil {
|
|
return nil, errwrap.Wrapf("error parsing enterprise config: {{err}}", err)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// LoadConfigDir loads all the configurations in the given directory
|
|
// in alphabetical order.
|
|
func LoadConfigDir(dir string) (*Config, error) {
|
|
f, err := os.Open(dir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
fi, err := f.Stat()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !fi.IsDir() {
|
|
return nil, fmt.Errorf("configuration path must be a directory: %q", dir)
|
|
}
|
|
|
|
var files []string
|
|
err = nil
|
|
for err != io.EOF {
|
|
var fis []os.FileInfo
|
|
fis, err = f.Readdir(128)
|
|
if err != nil && err != io.EOF {
|
|
return nil, err
|
|
}
|
|
|
|
for _, fi := range fis {
|
|
// Ignore directories
|
|
if fi.IsDir() {
|
|
continue
|
|
}
|
|
|
|
// Only care about files that are valid to load.
|
|
name := fi.Name()
|
|
skip := true
|
|
if strings.HasSuffix(name, ".hcl") {
|
|
skip = false
|
|
} else if strings.HasSuffix(name, ".json") {
|
|
skip = false
|
|
}
|
|
if skip || isTemporaryFile(name) {
|
|
continue
|
|
}
|
|
|
|
path := filepath.Join(dir, name)
|
|
files = append(files, path)
|
|
}
|
|
}
|
|
|
|
result := NewConfig()
|
|
for _, f := range files {
|
|
config, err := LoadConfigFile(f)
|
|
if err != nil {
|
|
return nil, errwrap.Wrapf(fmt.Sprintf("error loading %q: {{err}}", f), err)
|
|
}
|
|
|
|
if result == nil {
|
|
result = config
|
|
} else {
|
|
result = result.Merge(config)
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// isTemporaryFile returns true or false depending on whether the
|
|
// provided file name is a temporary file for the following editors:
|
|
// emacs or vim.
|
|
func isTemporaryFile(name string) bool {
|
|
return strings.HasSuffix(name, "~") || // vim
|
|
strings.HasPrefix(name, ".#") || // emacs
|
|
(strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#")) // emacs
|
|
}
|
|
|
|
func ParseStorage(result *Config, list *ast.ObjectList, name string) error {
|
|
if len(list.Items) > 1 {
|
|
return fmt.Errorf("only one %q block is permitted", name)
|
|
}
|
|
|
|
// Get our item
|
|
item := list.Items[0]
|
|
|
|
key := name
|
|
if len(item.Keys) > 0 {
|
|
key = item.Keys[0].Token.Value().(string)
|
|
}
|
|
|
|
var config map[string]interface{}
|
|
if err := hcl.DecodeObject(&config, item.Val); err != nil {
|
|
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
|
}
|
|
|
|
m := make(map[string]string)
|
|
for key, val := range config {
|
|
valStr, ok := val.(string)
|
|
if ok {
|
|
m[key] = valStr
|
|
continue
|
|
}
|
|
valBytes, err := json.Marshal(val)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m[key] = string(valBytes)
|
|
}
|
|
|
|
// Pull out the redirect address since it's common to all backends
|
|
var redirectAddr string
|
|
if v, ok := m["redirect_addr"]; ok {
|
|
redirectAddr = v
|
|
delete(m, "redirect_addr")
|
|
} else if v, ok := m["advertise_addr"]; ok {
|
|
redirectAddr = v
|
|
delete(m, "advertise_addr")
|
|
}
|
|
|
|
// Pull out the cluster address since it's common to all backends
|
|
var clusterAddr string
|
|
if v, ok := m["cluster_addr"]; ok {
|
|
clusterAddr = v
|
|
delete(m, "cluster_addr")
|
|
}
|
|
|
|
var disableClustering bool
|
|
var err error
|
|
if v, ok := m["disable_clustering"]; ok {
|
|
disableClustering, err = strconv.ParseBool(v)
|
|
if err != nil {
|
|
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
|
}
|
|
delete(m, "disable_clustering")
|
|
}
|
|
|
|
// Override with top-level values if they are set
|
|
if result.APIAddr != "" {
|
|
redirectAddr = result.APIAddr
|
|
}
|
|
|
|
if result.ClusterAddr != "" {
|
|
clusterAddr = result.ClusterAddr
|
|
}
|
|
|
|
if result.DisableClusteringRaw != nil {
|
|
disableClustering = result.DisableClustering
|
|
}
|
|
|
|
result.Storage = &Storage{
|
|
RedirectAddr: redirectAddr,
|
|
ClusterAddr: clusterAddr,
|
|
DisableClustering: disableClustering,
|
|
Type: strings.ToLower(key),
|
|
Config: m,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseHAStorage(result *Config, list *ast.ObjectList, name string) error {
|
|
if len(list.Items) > 1 {
|
|
return fmt.Errorf("only one %q block is permitted", name)
|
|
}
|
|
|
|
// Get our item
|
|
item := list.Items[0]
|
|
|
|
key := name
|
|
if len(item.Keys) > 0 {
|
|
key = item.Keys[0].Token.Value().(string)
|
|
}
|
|
|
|
var m map[string]string
|
|
if err := hcl.DecodeObject(&m, item.Val); err != nil {
|
|
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
|
}
|
|
|
|
// Pull out the redirect address since it's common to all backends
|
|
var redirectAddr string
|
|
if v, ok := m["redirect_addr"]; ok {
|
|
redirectAddr = v
|
|
delete(m, "redirect_addr")
|
|
} else if v, ok := m["advertise_addr"]; ok {
|
|
redirectAddr = v
|
|
delete(m, "advertise_addr")
|
|
}
|
|
|
|
// Pull out the cluster address since it's common to all backends
|
|
var clusterAddr string
|
|
if v, ok := m["cluster_addr"]; ok {
|
|
clusterAddr = v
|
|
delete(m, "cluster_addr")
|
|
}
|
|
|
|
var disableClustering bool
|
|
var err error
|
|
if v, ok := m["disable_clustering"]; ok {
|
|
disableClustering, err = strconv.ParseBool(v)
|
|
if err != nil {
|
|
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
|
}
|
|
delete(m, "disable_clustering")
|
|
}
|
|
|
|
// Override with top-level values if they are set
|
|
if result.APIAddr != "" {
|
|
redirectAddr = result.APIAddr
|
|
}
|
|
|
|
if result.ClusterAddr != "" {
|
|
clusterAddr = result.ClusterAddr
|
|
}
|
|
|
|
if result.DisableClusteringRaw != nil {
|
|
disableClustering = result.DisableClustering
|
|
}
|
|
|
|
result.HAStorage = &Storage{
|
|
RedirectAddr: redirectAddr,
|
|
ClusterAddr: clusterAddr,
|
|
DisableClustering: disableClustering,
|
|
Type: strings.ToLower(key),
|
|
Config: m,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseServiceRegistration(result *Config, list *ast.ObjectList, name string) error {
|
|
if len(list.Items) > 1 {
|
|
return fmt.Errorf("only one %q block is permitted", name)
|
|
}
|
|
|
|
// Get our item
|
|
item := list.Items[0]
|
|
key := name
|
|
if len(item.Keys) > 0 {
|
|
key = item.Keys[0].Token.Value().(string)
|
|
}
|
|
|
|
var m map[string]string
|
|
if err := hcl.DecodeObject(&m, item.Val); err != nil {
|
|
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
|
}
|
|
|
|
result.ServiceRegistration = &ServiceRegistration{
|
|
Type: strings.ToLower(key),
|
|
Config: m,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Sanitized returns a copy of the config with all values that are considered
|
|
// sensitive stripped. It also strips all `*Raw` values that are mainly
|
|
// used for parsing.
|
|
//
|
|
// Specifically, the fields that this method strips are:
|
|
// - Storage.Config
|
|
// - HAStorage.Config
|
|
// - Seals.Config
|
|
// - Telemetry.CirconusAPIToken
|
|
func (c *Config) Sanitized() map[string]interface{} {
|
|
// Create shared config if it doesn't exist (e.g. in tests) so that map
|
|
// keys are actually populated
|
|
if c.SharedConfig == nil {
|
|
c.SharedConfig = new(configutil.SharedConfig)
|
|
}
|
|
sharedResult := c.SharedConfig.Sanitized()
|
|
result := map[string]interface{}{
|
|
"cache_size": c.CacheSize,
|
|
"disable_cache": c.DisableCache,
|
|
"disable_printable_check": c.DisablePrintableCheck,
|
|
|
|
"enable_ui": c.EnableUI,
|
|
|
|
"max_lease_ttl": c.MaxLeaseTTL,
|
|
"default_lease_ttl": c.DefaultLeaseTTL,
|
|
|
|
"cluster_cipher_suites": c.ClusterCipherSuites,
|
|
|
|
"plugin_directory": c.PluginDirectory,
|
|
|
|
"raw_storage_endpoint": c.EnableRawEndpoint,
|
|
|
|
"api_addr": c.APIAddr,
|
|
"cluster_addr": c.ClusterAddr,
|
|
"disable_clustering": c.DisableClustering,
|
|
|
|
"disable_performance_standby": c.DisablePerformanceStandby,
|
|
|
|
"disable_sealwrap": c.DisableSealWrap,
|
|
|
|
"disable_indexing": c.DisableIndexing,
|
|
}
|
|
for k, v := range sharedResult {
|
|
result[k] = v
|
|
}
|
|
|
|
// Sanitize storage stanza
|
|
if c.Storage != nil {
|
|
sanitizedStorage := map[string]interface{}{
|
|
"type": c.Storage.Type,
|
|
"redirect_addr": c.Storage.RedirectAddr,
|
|
"cluster_addr": c.Storage.ClusterAddr,
|
|
"disable_clustering": c.Storage.DisableClustering,
|
|
}
|
|
result["storage"] = sanitizedStorage
|
|
}
|
|
|
|
// Sanitize HA storage stanza
|
|
if c.HAStorage != nil {
|
|
sanitizedHAStorage := map[string]interface{}{
|
|
"type": c.HAStorage.Type,
|
|
"redirect_addr": c.HAStorage.RedirectAddr,
|
|
"cluster_addr": c.HAStorage.ClusterAddr,
|
|
"disable_clustering": c.HAStorage.DisableClustering,
|
|
}
|
|
result["ha_storage"] = sanitizedHAStorage
|
|
}
|
|
|
|
// Sanitize service_registration stanza
|
|
if c.ServiceRegistration != nil {
|
|
sanitizedServiceRegistration := map[string]interface{}{
|
|
"type": c.ServiceRegistration.Type,
|
|
}
|
|
result["service_registration"] = sanitizedServiceRegistration
|
|
}
|
|
|
|
return result
|
|
}
|