open-vault/command/agent/config/config.go

475 lines
12 KiB
Go
Raw Normal View History

2018-07-25 02:02:27 +00:00
package config
import (
"errors"
"fmt"
"io/ioutil"
"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"
2018-07-25 02:02:27 +00:00
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-multierror"
2018-07-25 02:02:27 +00:00
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/helper/parseutil"
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 {
*configutil.SharedConfig `hcl:"-"`
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 *AutoAuth `hcl:"auto_auth"`
ExitAfterAuth bool `hcl:"exit_after_auth"`
Cache *Cache `hcl:"cache"`
Vault *Vault `hcl:"vault"`
Templates []*ctconfig.TemplateConfig `hcl:"templates"`
}
// Vault contains configuration for connecting to Vault servers
type Vault struct {
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"`
TLSServerName string `hcl:"tls_server_name"`
}
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
type Cache struct {
UseAutoAuthTokenRaw interface{} `hcl:"use_auto_auth_token"`
UseAutoAuthToken bool `hcl:"-"`
ForceAutoAuthToken bool `hcl:"-"`
}
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"`
// 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 {
Type string
MountPath string `hcl:"mount_path"`
WrapTTLRaw interface{} `hcl:"wrap_ttl"`
WrapTTL time.Duration `hcl:"-"`
Namespace string `hcl:"namespace"`
2018-07-25 02:02:27 +00:00
Config map[string]interface{}
}
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"`
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{}
}
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.
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
}
// Start building the result
result := NewConfig()
if err := hcl.DecodeObject(result, obj); err != nil {
2018-07-25 02:02:27 +00:00
return nil, err
}
sharedConfig, err := configutil.ParseConfig(string(d))
if err != nil {
return nil, err
}
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")
}
if err := parseAutoAuth(result, list); err != nil {
2018-07-25 02:02:27 +00:00
return nil, errwrap.Wrapf("error parsing 'auto_auth': {{err}}", err)
}
if err := parseCache(result, list); err != nil {
return nil, errwrap.Wrapf("error parsing 'cache':{{err}}", err)
}
if err := parseTemplates(result, list); err != 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
return nil, errwrap.Wrapf("error parsing 'template': {{err}}", err)
}
if result.Cache != nil {
if len(result.Listeners) < 1 {
return nil, fmt.Errorf("at least one listener required when cache enabled")
}
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 {
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")
}
}
err = parseVault(result, list)
if err != nil {
return nil, errwrap.Wrapf("error parsing 'vault':{{err}}", err)
}
return result, nil
2018-07-25 02:02:27 +00:00
}
func parseVault(result *Config, list *ast.ObjectList) error {
name := "vault"
vaultList := list.Filter(name)
if len(vaultList.Items) == 0 {
return nil
}
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
}
if v.TLSSkipVerifyRaw != nil {
v.TLSSkipVerify, err = parseutil.ParseBool(v.TLSSkipVerifyRaw)
if err != nil {
return err
}
}
result.Vault = &v
return nil
}
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
}
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
c.ForceAutoAuthToken = true
default:
return err
}
}
}
result.Cache = &c
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)
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 {
return errwrap.Wrapf("error parsing 'method': {{err}}", err)
}
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 {
return errwrap.Wrapf("error parsing 'sink' stanzas: {{err}}", err)
}
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")
}
}
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
}
// 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 {
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))
}
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
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
}