Fix bug with merging vault agent configs that set template_config (#29680)

* fix bug with merging configs with TemplateConfig and add test

* add changelog
This commit is contained in:
Jenny Deng
2025-02-24 10:56:03 -08:00
committed by GitHub
parent 4783eb9d75
commit b93e8e817c
4 changed files with 69 additions and 4 deletions

4
changelog/29680.txt Normal file
View File

@@ -0,0 +1,4 @@
```release-note:bug
agent: Fixed an issue where giving the agent multiple config files could cause the merged config to be incorrect
when `template_config` is set in one of the config files.
```

View File

@@ -181,6 +181,9 @@ type ExecConfig struct {
func NewConfig() *Config {
return &Config{
SharedConfig: new(configutil.SharedConfig),
TemplateConfig: &TemplateConfig{
MaxConnectionsPerHost: DefaultTemplateConfigMaxConnsPerHost,
},
}
}
@@ -248,8 +251,13 @@ func (c *Config) Merge(c2 *Config) *Config {
result.DisableKeepAlivesTemplating = c2.DisableKeepAlivesTemplating
}
// Instead of checking if TemplateConfig is not nil, we compare against the default value
// that is set in NewConfig to determine if a TemplateConfig was specified in the config
defaultConfig := TemplateConfig{
MaxConnectionsPerHost: DefaultTemplateConfigMaxConnsPerHost,
}
result.TemplateConfig = c.TemplateConfig
if c2.TemplateConfig != nil {
if *c2.TemplateConfig != defaultConfig {
result.TemplateConfig = c2.TemplateConfig
}
@@ -1104,9 +1112,6 @@ func parseTemplateConfig(result *Config, list *ast.ObjectList) error {
templateConfigList := list.Filter(name)
if len(templateConfigList.Items) == 0 {
result.TemplateConfig = &TemplateConfig{
MaxConnectionsPerHost: DefaultTemplateConfigMaxConnsPerHost,
}
return nil
}

View File

@@ -1100,6 +1100,55 @@ func TestLoadConfigFile_TemplateConfig(t *testing.T) {
}
}
// TestLoadConfigFile_TemplateConfig_MergeConfigs tests that in the case of multiple config files,
// a provided TemplateConfig in one file is properly preserved in the merged config
func TestLoadConfigFile_TemplateConfig_MergeConfigs(t *testing.T) {
configPaths := []string{
"./test-fixtures/config-template_config.hcl",
"./test-fixtures/config-template-min-no-auth.hcl",
}
expected := &Config{
SharedConfig: &configutil.SharedConfig{},
Vault: &Vault{
Address: "http://127.0.0.1:1111",
Retry: &Retry{
NumRetries: 5,
},
},
TemplateConfig: &TemplateConfig{
ExitOnRetryFailure: true,
StaticSecretRenderInt: 1 * time.Minute,
MaxConnectionsPerHost: 100,
LeaseRenewalThreshold: FloatPtr(0.8),
},
Templates: []*ctconfig.TemplateConfig{
{
Source: pointerutil.StringPtr("/path/on/disk/to/template.ctmpl"),
Destination: pointerutil.StringPtr("/path/on/disk/where/template/will/render.txt"),
},
{
Source: pointerutil.StringPtr("/path/on/disk/to/template2.ctmpl"),
Destination: pointerutil.StringPtr("/path/on/disk/where/template/will/render2.txt"),
},
},
}
cfg := NewConfig()
for _, path := range configPaths {
configFromPath, err := LoadConfigFile(path)
if err != nil {
t.Fatal(err)
}
cfg = cfg.Merge(configFromPath)
}
cfg.Prune()
if diff := deep.Equal(cfg, expected); diff != nil {
t.Fatal(diff)
}
}
// TestLoadConfigFile_Template tests template definitions in Vault Agent
func TestLoadConfigFile_Template(t *testing.T) {
testCases := map[string]struct {

View File

@@ -0,0 +1,7 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
template {
source = "/path/on/disk/to/template2.ctmpl"
destination = "/path/on/disk/where/template/will/render2.txt"
}