2018-07-25 02:02:27 +00:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2021-10-16 00:22:19 +00:00
|
|
|
"context"
|
2018-07-25 02:02:27 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2021-10-16 00:22:19 +00:00
|
|
|
"net"
|
2018-07-25 02:02:27 +00:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
ctconfig "github.com/hashicorp/consul-template/config"
|
2019-03-15 18:58:53 +00:00
|
|
|
"github.com/hashicorp/go-multierror"
|
2021-07-16 00:17:31 +00:00
|
|
|
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/hcl"
|
|
|
|
"github.com/hashicorp/hcl/hcl/ast"
|
2019-07-03 07:33:20 +00:00
|
|
|
"github.com/hashicorp/vault/helper/namespace"
|
2020-10-13 23:38:21 +00:00
|
|
|
"github.com/hashicorp/vault/internalshared/configutil"
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
"github.com/mitchellh/mapstructure"
|
2018-07-25 02:02:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Config is the configuration for the vault server.
|
|
|
|
type Config struct {
|
2020-05-14 13:19:27 +00:00
|
|
|
*configutil.SharedConfig `hcl:"-"`
|
|
|
|
|
2021-06-21 23:10:15 +00:00
|
|
|
AutoAuth *AutoAuth `hcl:"auto_auth"`
|
|
|
|
ExitAfterAuth bool `hcl:"exit_after_auth"`
|
|
|
|
Cache *Cache `hcl:"cache"`
|
|
|
|
Vault *Vault `hcl:"vault"`
|
|
|
|
TemplateConfig *TemplateConfig `hcl:"template_config"`
|
|
|
|
Templates []*ctconfig.TemplateConfig `hcl:"templates"`
|
2021-03-18 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 19:47:56 +00:00
|
|
|
func (c *Config) Prune() {
|
|
|
|
for _, l := range c.Listeners {
|
|
|
|
l.RawConfig = nil
|
2021-06-17 18:09:37 +00:00
|
|
|
l.Profiling.UnusedKeys = nil
|
|
|
|
l.Telemetry.UnusedKeys = nil
|
2021-10-13 15:06:33 +00:00
|
|
|
l.CustomResponseHeaders = nil
|
2021-05-04 19:47:56 +00:00
|
|
|
}
|
|
|
|
c.FoundKeys = nil
|
|
|
|
c.UnusedKeys = nil
|
|
|
|
c.SharedConfig.FoundKeys = nil
|
|
|
|
c.SharedConfig.UnusedKeys = nil
|
|
|
|
if c.Telemetry != nil {
|
|
|
|
c.Telemetry.FoundKeys = nil
|
|
|
|
c.Telemetry.UnusedKeys = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-18 18:14:09 +00:00
|
|
|
type Retry struct {
|
|
|
|
NumRetries int `hcl:"num_retries"`
|
2019-02-28 22:29:28 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 21:26:06 +00:00
|
|
|
// Vault contains configuration for connecting to Vault servers
|
2019-02-28 22:29:28 +00:00
|
|
|
type Vault struct {
|
2019-04-13 07:44:06 +00:00
|
|
|
Address string `hcl:"address"`
|
|
|
|
CACert string `hcl:"ca_cert"`
|
|
|
|
CAPath string `hcl:"ca_path"`
|
|
|
|
TLSSkipVerify bool `hcl:"-"`
|
|
|
|
TLSSkipVerifyRaw interface{} `hcl:"tls_skip_verify"`
|
|
|
|
ClientCert string `hcl:"client_cert"`
|
|
|
|
ClientKey string `hcl:"client_key"`
|
2019-10-29 13:11:01 +00:00
|
|
|
TLSServerName string `hcl:"tls_server_name"`
|
2021-03-18 18:14:09 +00:00
|
|
|
Retry *Retry `hcl:"retry"`
|
2019-02-15 01:10:36 +00:00
|
|
|
}
|
|
|
|
|
2021-10-16 00:22:19 +00:00
|
|
|
// transportDialer is an interface that allows passing a custom dialer function
|
|
|
|
// to an HTTP client's transport config
|
|
|
|
type transportDialer interface {
|
|
|
|
// Dial is intended to match https://pkg.go.dev/net#Dialer.Dial
|
|
|
|
Dial(network, address string) (net.Conn, error)
|
|
|
|
|
|
|
|
// DialContext is intended to match https://pkg.go.dev/net#Dialer.DialContext
|
|
|
|
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
|
|
|
}
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
// Cache contains any configuration needed for Cache mode
|
2019-02-15 01:10:36 +00:00
|
|
|
type Cache struct {
|
2021-10-16 00:22:19 +00:00
|
|
|
UseAutoAuthTokenRaw interface{} `hcl:"use_auto_auth_token"`
|
|
|
|
UseAutoAuthToken bool `hcl:"-"`
|
|
|
|
ForceAutoAuthToken bool `hcl:"-"`
|
|
|
|
EnforceConsistency string `hcl:"enforce_consistency"`
|
|
|
|
WhenInconsistent string `hcl:"when_inconsistent"`
|
|
|
|
Persist *Persist `hcl:"persist"`
|
|
|
|
InProcDialer transportDialer `hcl:"-"`
|
2021-03-03 22:01:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Persist contains configuration needed for persistent caching
|
|
|
|
type Persist struct {
|
|
|
|
Type string
|
|
|
|
Path string `hcl:"path"`
|
|
|
|
KeepAfterImport bool `hcl:"keep_after_import"`
|
|
|
|
ExitOnErr bool `hcl:"exit_on_err"`
|
|
|
|
ServiceAccountTokenFile string `hcl:"service_account_token_file"`
|
2019-02-15 01:10:36 +00:00
|
|
|
}
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
// AutoAuth is the configured authentication method and sinks
|
2018-07-25 02:02:27 +00:00
|
|
|
type AutoAuth struct {
|
|
|
|
Method *Method `hcl:"-"`
|
|
|
|
Sinks []*Sink `hcl:"sinks"`
|
2018-10-27 17:45:55 +00:00
|
|
|
|
|
|
|
// NOTE: This is unsupported outside of testing and may disappear at any
|
|
|
|
// time.
|
|
|
|
EnableReauthOnNewCredentials bool `hcl:"enable_reauth_on_new_credentials"`
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
// Method represents the configuration for the authentication backend
|
2018-07-25 02:02:27 +00:00
|
|
|
type Method struct {
|
2021-02-23 20:04:21 +00:00
|
|
|
Type string
|
|
|
|
MountPath string `hcl:"mount_path"`
|
|
|
|
WrapTTLRaw interface{} `hcl:"wrap_ttl"`
|
|
|
|
WrapTTL time.Duration `hcl:"-"`
|
2022-04-29 16:31:32 +00:00
|
|
|
MinBackoffRaw interface{} `hcl:"min_backoff"`
|
|
|
|
MinBackoff time.Duration `hcl:"-"`
|
2021-02-23 20:04:21 +00:00
|
|
|
MaxBackoffRaw interface{} `hcl:"max_backoff"`
|
|
|
|
MaxBackoff time.Duration `hcl:"-"`
|
|
|
|
Namespace string `hcl:"namespace"`
|
|
|
|
Config map[string]interface{}
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
// Sink defines a location to write the authenticated token
|
2018-07-25 02:02:27 +00:00
|
|
|
type Sink struct {
|
|
|
|
Type string
|
|
|
|
WrapTTLRaw interface{} `hcl:"wrap_ttl"`
|
|
|
|
WrapTTL time.Duration `hcl:"-"`
|
|
|
|
DHType string `hcl:"dh_type"`
|
2020-08-17 16:36:16 +00:00
|
|
|
DeriveKey bool `hcl:"derive_key"`
|
2018-07-25 02:02:27 +00:00
|
|
|
DHPath string `hcl:"dh_path"`
|
|
|
|
AAD string `hcl:"aad"`
|
|
|
|
AADEnvVar string `hcl:"aad_env_var"`
|
|
|
|
Config map[string]interface{}
|
|
|
|
}
|
|
|
|
|
2021-06-21 23:10:15 +00:00
|
|
|
// TemplateConfig defines global behaviors around template
|
|
|
|
type TemplateConfig struct {
|
2021-06-24 19:40:31 +00:00
|
|
|
ExitOnRetryFailure bool `hcl:"exit_on_retry_failure"`
|
|
|
|
StaticSecretRenderIntRaw interface{} `hcl:"static_secret_render_interval"`
|
|
|
|
StaticSecretRenderInt time.Duration `hcl:"-"`
|
2021-06-21 23:10:15 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
func NewConfig() *Config {
|
|
|
|
return &Config{
|
|
|
|
SharedConfig: new(configutil.SharedConfig),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
// LoadConfig loads the configuration at the given path, regardless if
|
|
|
|
// its a file or directory.
|
2019-09-19 20:03:30 +00:00
|
|
|
func LoadConfig(path string) (*Config, error) {
|
2018-07-25 02:02:27 +00:00
|
|
|
fi, err := os.Stat(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if fi.IsDir() {
|
|
|
|
return nil, fmt.Errorf("location is a directory, not a file")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the file
|
|
|
|
d, err := ioutil.ReadFile(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse!
|
|
|
|
obj, err := hcl.Parse(string(d))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-04 19:47:56 +00:00
|
|
|
// Attribute
|
|
|
|
ast.Walk(obj, func(n ast.Node) (ast.Node, bool) {
|
|
|
|
if k, ok := n.(*ast.ObjectKey); ok {
|
|
|
|
k.Token.Pos.Filename = path
|
|
|
|
}
|
|
|
|
return n, true
|
|
|
|
})
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
// Start building the result
|
2020-05-14 13:19:27 +00:00
|
|
|
result := NewConfig()
|
|
|
|
if err := hcl.DecodeObject(result, obj); err != nil {
|
2018-07-25 02:02:27 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
sharedConfig, err := configutil.ParseConfig(string(d))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-10-13 15:06:33 +00:00
|
|
|
|
|
|
|
// Pruning custom headers for Agent for now
|
|
|
|
for _, ln := range sharedConfig.Listeners {
|
|
|
|
ln.CustomResponseHeaders = nil
|
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
result.SharedConfig = sharedConfig
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
list, ok := obj.Node.(*ast.ObjectList)
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("error parsing: file doesn't contain a root object")
|
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
if err := parseAutoAuth(result, list); err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return nil, fmt.Errorf("error parsing 'auto_auth': %w", err)
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
if err := parseCache(result, list); err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return nil, fmt.Errorf("error parsing 'cache':%w", err)
|
2019-02-15 01:10:36 +00:00
|
|
|
}
|
|
|
|
|
2021-06-21 23:10:15 +00:00
|
|
|
if err := parseTemplateConfig(result, list); err != nil {
|
|
|
|
return nil, fmt.Errorf("error parsing 'template_config': %w", err)
|
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
if err := parseTemplates(result, list); err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return nil, fmt.Errorf("error parsing 'template': %w", err)
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 18:58:53 +00:00
|
|
|
if result.Cache != nil {
|
2021-10-16 00:22:19 +00:00
|
|
|
if len(result.Listeners) < 1 && len(result.Templates) < 1 {
|
|
|
|
return nil, fmt.Errorf("enabling the cache requires at least 1 template or 1 listener to be defined")
|
2019-03-15 18:58:53 +00:00
|
|
|
}
|
|
|
|
|
2019-04-05 20:12:54 +00:00
|
|
|
if result.Cache.UseAutoAuthToken {
|
|
|
|
if result.AutoAuth == nil {
|
|
|
|
return nil, fmt.Errorf("cache.use_auto_auth_token is true but auto_auth not configured")
|
|
|
|
}
|
|
|
|
if result.AutoAuth.Method.WrapTTL > 0 {
|
|
|
|
return nil, fmt.Errorf("cache.use_auto_auth_token is true and auto_auth uses wrapping")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.AutoAuth != nil {
|
2020-05-26 17:52:14 +00:00
|
|
|
if len(result.AutoAuth.Sinks) == 0 &&
|
|
|
|
(result.Cache == nil || !result.Cache.UseAutoAuthToken) &&
|
|
|
|
len(result.Templates) == 0 {
|
|
|
|
return nil, fmt.Errorf("auto_auth requires at least one sink or at least one template or cache.use_auto_auth_token=true")
|
2019-03-15 18:58:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
err = parseVault(result, list)
|
2019-02-28 22:29:28 +00:00
|
|
|
if err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return nil, fmt.Errorf("error parsing 'vault':%w", err)
|
2019-02-28 22:29:28 +00:00
|
|
|
}
|
|
|
|
|
2021-03-18 18:14:09 +00:00
|
|
|
if result.Vault == nil {
|
|
|
|
result.Vault = &Vault{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set defaults
|
|
|
|
if result.Vault.Retry == nil {
|
|
|
|
result.Vault.Retry = &Retry{}
|
|
|
|
}
|
|
|
|
switch result.Vault.Retry.NumRetries {
|
|
|
|
case 0:
|
|
|
|
result.Vault.Retry.NumRetries = ctconfig.DefaultRetryAttempts
|
|
|
|
case -1:
|
|
|
|
result.Vault.Retry.NumRetries = 0
|
2021-01-25 19:00:17 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 13:19:27 +00:00
|
|
|
return result, nil
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 22:29:28 +00:00
|
|
|
func parseVault(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "vault"
|
|
|
|
|
|
|
|
vaultList := list.Filter(name)
|
2019-03-01 17:23:00 +00:00
|
|
|
if len(vaultList.Items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-28 22:29:28 +00:00
|
|
|
if len(vaultList.Items) > 1 {
|
|
|
|
return fmt.Errorf("one and only one %q block is required", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
item := vaultList.Items[0]
|
|
|
|
|
|
|
|
var v Vault
|
|
|
|
err := hcl.DecodeObject(&v, item.Val)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-04-13 07:44:06 +00:00
|
|
|
if v.TLSSkipVerifyRaw != nil {
|
|
|
|
v.TLSSkipVerify, err = parseutil.ParseBool(v.TLSSkipVerifyRaw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-28 22:29:28 +00:00
|
|
|
result.Vault = &v
|
|
|
|
|
2021-03-18 18:14:09 +00:00
|
|
|
subs, ok := item.Val.(*ast.ObjectType)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("could not parse %q as an object", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := parseRetry(result, subs.List); err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return fmt.Errorf("error parsing 'retry': %w", err)
|
2021-03-18 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 22:29:28 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-25 19:00:17 +00:00
|
|
|
func parseRetry(result *Config, list *ast.ObjectList) error {
|
2021-03-18 18:14:09 +00:00
|
|
|
name := "retry"
|
2021-01-25 19:00:17 +00:00
|
|
|
|
|
|
|
retryList := list.Filter(name)
|
|
|
|
if len(retryList.Items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(retryList.Items) > 1 {
|
|
|
|
return fmt.Errorf("one and only one %q block is required", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
item := retryList.Items[0]
|
|
|
|
|
2021-03-18 18:14:09 +00:00
|
|
|
var r Retry
|
2021-01-25 19:00:17 +00:00
|
|
|
err := hcl.DecodeObject(&r, item.Val)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-03-18 18:14:09 +00:00
|
|
|
result.Vault.Retry = &r
|
2021-01-25 19:00:17 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-15 01:10:36 +00:00
|
|
|
func parseCache(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "cache"
|
|
|
|
|
|
|
|
cacheList := list.Filter(name)
|
|
|
|
if len(cacheList.Items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(cacheList.Items) > 1 {
|
|
|
|
return fmt.Errorf("one and only one %q block is required", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
item := cacheList.Items[0]
|
|
|
|
|
|
|
|
var c Cache
|
|
|
|
err := hcl.DecodeObject(&c, item.Val)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-01-30 15:08:42 +00:00
|
|
|
if c.UseAutoAuthTokenRaw != nil {
|
|
|
|
c.UseAutoAuthToken, err = parseutil.ParseBool(c.UseAutoAuthTokenRaw)
|
|
|
|
if err != nil {
|
|
|
|
// Could be a value of "force" instead of "true"/"false"
|
|
|
|
switch c.UseAutoAuthTokenRaw.(type) {
|
|
|
|
case string:
|
|
|
|
v := c.UseAutoAuthTokenRaw.(string)
|
|
|
|
|
|
|
|
if !strings.EqualFold(v, "force") {
|
|
|
|
return fmt.Errorf("value of 'use_auto_auth_token' can be either true/false/force, %q is an invalid option", c.UseAutoAuthTokenRaw)
|
|
|
|
}
|
|
|
|
c.UseAutoAuthToken = true
|
2020-02-14 21:48:12 +00:00
|
|
|
c.ForceAutoAuthToken = true
|
2020-01-30 15:08:42 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-15 01:10:36 +00:00
|
|
|
result.Cache = &c
|
2021-03-03 22:01:33 +00:00
|
|
|
|
|
|
|
subs, ok := item.Val.(*ast.ObjectType)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("could not parse %q as an object", name)
|
|
|
|
}
|
|
|
|
subList := subs.List
|
|
|
|
if err := parsePersist(result, subList); err != nil {
|
|
|
|
return fmt.Errorf("error parsing persist: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func parsePersist(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "persist"
|
|
|
|
|
|
|
|
persistList := list.Filter(name)
|
|
|
|
if len(persistList.Items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(persistList.Items) > 1 {
|
|
|
|
return fmt.Errorf("only one %q block is required", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
item := persistList.Items[0]
|
|
|
|
|
|
|
|
var p Persist
|
|
|
|
err := hcl.DecodeObject(&p, item.Val)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.Type == "" {
|
|
|
|
if len(item.Keys) == 1 {
|
|
|
|
p.Type = strings.ToLower(item.Keys[0].Token.Value().(string))
|
|
|
|
}
|
|
|
|
if p.Type == "" {
|
|
|
|
return errors.New("persist type must be specified")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result.Cache.Persist = &p
|
|
|
|
|
2019-02-15 01:10:36 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
func parseAutoAuth(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "auto_auth"
|
|
|
|
|
|
|
|
autoAuthList := list.Filter(name)
|
2019-03-15 18:58:53 +00:00
|
|
|
if len(autoAuthList.Items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if len(autoAuthList.Items) > 1 {
|
|
|
|
return fmt.Errorf("at most one %q block is allowed", name)
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get our item
|
|
|
|
item := autoAuthList.Items[0]
|
|
|
|
|
|
|
|
var a AutoAuth
|
|
|
|
if err := hcl.DecodeObject(&a, item.Val); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
result.AutoAuth = &a
|
|
|
|
|
|
|
|
subs, ok := item.Val.(*ast.ObjectType)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("could not parse %q as an object", name)
|
|
|
|
}
|
|
|
|
subList := subs.List
|
|
|
|
|
|
|
|
if err := parseMethod(result, subList); err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return fmt.Errorf("error parsing 'method': %w", err)
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
2019-04-01 20:26:41 +00:00
|
|
|
if a.Method == nil {
|
|
|
|
return fmt.Errorf("no 'method' block found")
|
|
|
|
}
|
2018-07-25 02:02:27 +00:00
|
|
|
|
|
|
|
if err := parseSinks(result, subList); err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return fmt.Errorf("error parsing 'sink' stanzas: %w", err)
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
2019-04-05 20:12:54 +00:00
|
|
|
if result.AutoAuth.Method.WrapTTL > 0 {
|
|
|
|
if len(result.AutoAuth.Sinks) != 1 {
|
|
|
|
return fmt.Errorf("error parsing auto_auth: wrapping enabled on auth method and 0 or many sinks defined")
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.AutoAuth.Sinks[0].WrapTTL > 0 {
|
|
|
|
return fmt.Errorf("error parsing auto_auth: wrapping enabled both on auth method and sink")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-23 20:04:21 +00:00
|
|
|
if result.AutoAuth.Method.MaxBackoffRaw != nil {
|
|
|
|
var err error
|
|
|
|
if result.AutoAuth.Method.MaxBackoff, err = parseutil.ParseDurationSecond(result.AutoAuth.Method.MaxBackoffRaw); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
result.AutoAuth.Method.MaxBackoffRaw = nil
|
|
|
|
}
|
|
|
|
|
2022-04-29 16:31:32 +00:00
|
|
|
if result.AutoAuth.Method.MinBackoffRaw != nil {
|
|
|
|
var err error
|
|
|
|
if result.AutoAuth.Method.MinBackoff, err = parseutil.ParseDurationSecond(result.AutoAuth.Method.MinBackoffRaw); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
result.AutoAuth.Method.MinBackoffRaw = nil
|
|
|
|
}
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseMethod(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "method"
|
|
|
|
|
|
|
|
methodList := list.Filter(name)
|
|
|
|
if len(methodList.Items) != 1 {
|
|
|
|
return fmt.Errorf("one and only one %q block is required", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get our item
|
|
|
|
item := methodList.Items[0]
|
|
|
|
|
|
|
|
var m Method
|
|
|
|
if err := hcl.DecodeObject(&m, item.Val); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if m.Type == "" {
|
|
|
|
if len(item.Keys) == 1 {
|
|
|
|
m.Type = strings.ToLower(item.Keys[0].Token.Value().(string))
|
|
|
|
}
|
|
|
|
if m.Type == "" {
|
|
|
|
return errors.New("method type must be specified")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default to Vault's default
|
|
|
|
if m.MountPath == "" {
|
|
|
|
m.MountPath = fmt.Sprintf("auth/%s", m.Type)
|
|
|
|
}
|
|
|
|
// Standardize on no trailing slash
|
|
|
|
m.MountPath = strings.TrimSuffix(m.MountPath, "/")
|
|
|
|
|
|
|
|
if m.WrapTTLRaw != nil {
|
|
|
|
var err error
|
|
|
|
if m.WrapTTL, err = parseutil.ParseDurationSecond(m.WrapTTLRaw); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
m.WrapTTLRaw = nil
|
|
|
|
}
|
|
|
|
|
2019-07-03 07:33:20 +00:00
|
|
|
// Canonicalize namespace path if provided
|
|
|
|
m.Namespace = namespace.Canonicalize(m.Namespace)
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
result.AutoAuth.Method = &m
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseSinks(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "sink"
|
|
|
|
|
|
|
|
sinkList := list.Filter(name)
|
|
|
|
if len(sinkList.Items) < 1 {
|
2019-04-01 20:26:41 +00:00
|
|
|
return nil
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var ts []*Sink
|
|
|
|
|
|
|
|
for _, item := range sinkList.Items {
|
|
|
|
var s Sink
|
|
|
|
if err := hcl.DecodeObject(&s, item.Val); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Type == "" {
|
|
|
|
if len(item.Keys) == 1 {
|
|
|
|
s.Type = strings.ToLower(item.Keys[0].Token.Value().(string))
|
|
|
|
}
|
|
|
|
if s.Type == "" {
|
|
|
|
return errors.New("sink type must be specified")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.WrapTTLRaw != nil {
|
|
|
|
var err error
|
|
|
|
if s.WrapTTL, err = parseutil.ParseDurationSecond(s.WrapTTLRaw); err != nil {
|
|
|
|
return multierror.Prefix(err, fmt.Sprintf("sink.%s", s.Type))
|
|
|
|
}
|
|
|
|
s.WrapTTLRaw = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
switch s.DHType {
|
|
|
|
case "":
|
|
|
|
case "curve25519":
|
|
|
|
default:
|
|
|
|
return multierror.Prefix(errors.New("invalid value for 'dh_type'"), fmt.Sprintf("sink.%s", s.Type))
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.AADEnvVar != "" {
|
|
|
|
s.AAD = os.Getenv(s.AADEnvVar)
|
|
|
|
s.AADEnvVar = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case s.DHPath == "" && s.DHType == "":
|
|
|
|
if s.AAD != "" {
|
|
|
|
return multierror.Prefix(errors.New("specifying AAD data without 'dh_type' does not make sense"), fmt.Sprintf("sink.%s", s.Type))
|
|
|
|
}
|
2020-08-17 16:36:16 +00:00
|
|
|
if s.DeriveKey {
|
|
|
|
return multierror.Prefix(errors.New("specifying 'derive_key' data without 'dh_type' does not make sense"), fmt.Sprintf("sink.%s", s.Type))
|
|
|
|
}
|
2018-07-25 02:02:27 +00:00
|
|
|
case s.DHPath != "" && s.DHType != "":
|
|
|
|
default:
|
|
|
|
return multierror.Prefix(errors.New("'dh_type' and 'dh_path' must be specified together"), fmt.Sprintf("sink.%s", s.Type))
|
|
|
|
}
|
|
|
|
|
|
|
|
ts = append(ts, &s)
|
|
|
|
}
|
|
|
|
|
|
|
|
result.AutoAuth.Sinks = ts
|
|
|
|
return nil
|
|
|
|
}
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
|
2021-06-21 23:10:15 +00:00
|
|
|
func parseTemplateConfig(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "template_config"
|
|
|
|
|
|
|
|
templateConfigList := list.Filter(name)
|
|
|
|
if len(templateConfigList.Items) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(templateConfigList.Items) > 1 {
|
|
|
|
return fmt.Errorf("at most one %q block is allowed", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get our item
|
|
|
|
item := templateConfigList.Items[0]
|
|
|
|
|
|
|
|
var cfg TemplateConfig
|
|
|
|
if err := hcl.DecodeObject(&cfg, item.Val); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
result.TemplateConfig = &cfg
|
|
|
|
|
2021-06-24 19:40:31 +00:00
|
|
|
if result.TemplateConfig.StaticSecretRenderIntRaw != nil {
|
|
|
|
var err error
|
|
|
|
if result.TemplateConfig.StaticSecretRenderInt, err = parseutil.ParseDurationSecond(result.TemplateConfig.StaticSecretRenderIntRaw); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
result.TemplateConfig.StaticSecretRenderIntRaw = nil
|
|
|
|
}
|
|
|
|
|
2021-06-21 23:10:15 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
func parseTemplates(result *Config, list *ast.ObjectList) error {
|
|
|
|
name := "template"
|
|
|
|
|
|
|
|
templateList := list.Filter(name)
|
|
|
|
if len(templateList.Items) < 1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var tcs []*ctconfig.TemplateConfig
|
|
|
|
|
|
|
|
for _, item := range templateList.Items {
|
|
|
|
var shadow interface{}
|
|
|
|
if err := hcl.DecodeObject(&shadow, item.Val); err != nil {
|
|
|
|
return fmt.Errorf("error decoding config: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert to a map and flatten the keys we want to flatten
|
|
|
|
parsed, ok := shadow.(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
return errors.New("error converting config")
|
|
|
|
}
|
|
|
|
|
|
|
|
// flatten the wait field. The initial "wait" value, if given, is a
|
|
|
|
// []map[string]interface{}, but we need it to be map[string]interface{}.
|
|
|
|
// Consul Template has a method flattenKeys that walks all of parsed and
|
|
|
|
// flattens every key. For Vault Agent, we only care about the wait input.
|
|
|
|
// Only one wait stanza is supported, however Consul Template does not error
|
|
|
|
// with multiple instead it flattens them down, with last value winning.
|
|
|
|
// Here we take the last element of the parsed["wait"] slice to keep
|
|
|
|
// consistency with Consul Template behavior.
|
|
|
|
wait, ok := parsed["wait"].([]map[string]interface{})
|
|
|
|
if ok {
|
|
|
|
parsed["wait"] = wait[len(wait)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
var tc ctconfig.TemplateConfig
|
|
|
|
|
|
|
|
// Use mapstructure to populate the basic config fields
|
|
|
|
var md mapstructure.Metadata
|
|
|
|
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
|
|
|
DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
|
|
|
ctconfig.StringToFileModeFunc(),
|
|
|
|
ctconfig.StringToWaitDurationHookFunc(),
|
|
|
|
mapstructure.StringToSliceHookFunc(","),
|
|
|
|
mapstructure.StringToTimeDurationHookFunc(),
|
|
|
|
),
|
|
|
|
ErrorUnused: true,
|
|
|
|
Metadata: &md,
|
|
|
|
Result: &tc,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return errors.New("mapstructure decoder creation failed")
|
|
|
|
}
|
|
|
|
if err := decoder.Decode(parsed); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
tcs = append(tcs, &tc)
|
|
|
|
}
|
|
|
|
result.Templates = tcs
|
|
|
|
return nil
|
|
|
|
}
|