diff --git a/vault/config.go b/vault/config.go index a4fdc1e7c..880ae9b03 100644 --- a/vault/config.go +++ b/vault/config.go @@ -274,6 +274,7 @@ type ConfigLoader struct { ActiveProfile string visitedProfiles []string + sourceChain map[string]bool } func NewConfigLoader(baseConfig ProfileConfig, file *ConfigFile, activeProfile string) *ConfigLoader { @@ -281,6 +282,7 @@ func NewConfigLoader(baseConfig ProfileConfig, file *ConfigFile, activeProfile s BaseConfig: baseConfig, File: file, ActiveProfile: activeProfile, + sourceChain: make(map[string]bool), } } @@ -405,11 +407,6 @@ func (cl *ConfigLoader) populateFromConfigFile(config *ProfileConfig, profileNam if err != nil { return err } - } else if profileName != defaultSectionName { - err := cl.populateFromConfigFile(config, defaultSectionName) - if err != nil { - return err - } } // Ignore source_profile if it recursively refers to the profile @@ -516,6 +513,14 @@ func (cl *ConfigLoader) hydrateSourceConfig(config *ProfileConfig) error { // GetProfileConfig loads the profile from the config file and environment variables into config func (cl *ConfigLoader) GetProfileConfig(profileName string) (*ProfileConfig, error) { + if cl.sourceChain[profileName] { + return nil, fmt.Errorf("Loop detected in source_profile chain for profile '%s'", profileName) + } + cl.sourceChain[profileName] = true + defer func() { + delete(cl.sourceChain, profileName) + }() + config := cl.BaseConfig config.ProfileName = profileName cl.populateFromEnv(&config) diff --git a/vault/config_test.go b/vault/config_test.go index 95671ca3f..882d83e2f 100644 --- a/vault/config_test.go +++ b/vault/config_test.go @@ -253,7 +253,7 @@ func TestIncludeProfile(t *testing.T) { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "") config, err := configLoader.GetProfileConfig("testincludeprofile2") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -273,7 +273,7 @@ func TestIncludeSsoSession(t *testing.T) { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "") config, err := configLoader.GetProfileConfig("with-sso-session") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -368,7 +368,7 @@ source_profile=foo t.Fatalf("Expected '%s', got '%s'", expectedSourceProfile, def.SourceProfile) } - configLoader := &vault.ConfigLoader{File: configFile} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "") config, err := configLoader.GetProfileConfig("foo") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -405,7 +405,7 @@ source_profile=root t.Fatalf("Expected '%s', got '%s'", expectedSourceProfile, def.SourceProfile) } - configLoader := &vault.ConfigLoader{File: configFile} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "") config, err := configLoader.GetProfileConfig("foo") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -495,7 +495,7 @@ transitive_session_tags = tagOne ,tagTwo,tagThree if err != nil { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile, ActiveProfile: "tagged"} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "tagged") config, err := configLoader.GetProfileConfig("tagged") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -532,7 +532,7 @@ transitive_session_tags = tagOne ,tagTwo,tagThree if err != nil { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile, ActiveProfile: "tagged"} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "tagged") config, err := configLoader.GetProfileConfig("tagged") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -577,7 +577,7 @@ source_profile = interim if err != nil { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile, ActiveProfile: "target"} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "target") config, err := configLoader.GetProfileConfig("target") if err != nil { t.Fatalf("Should have found a profile: %v", err) diff --git a/vault/vault_test.go b/vault/vault_test.go index 75812bab3..4d2855509 100644 --- a/vault/vault_test.go +++ b/vault/vault_test.go @@ -19,7 +19,7 @@ web_identity_token_process = oidccli raw if err != nil { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile, ActiveProfile: "role2"} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "role2") config, err := configLoader.GetProfileConfig("role2") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -55,7 +55,7 @@ role_arn=arn:aws:iam::12345678901:role/allow-view-only-access-from-other-account if err != nil { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile, ActiveProfile: "my-shared-base-profile"} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "my-shared-base-profile") config, err := configLoader.GetProfileConfig("my-shared-base-profile") if err != nil { t.Fatalf("Should have found a profile: %v", err) @@ -103,7 +103,7 @@ sso_registration_scopes=sso:account:access if err != nil { t.Fatal(err) } - configLoader := &vault.ConfigLoader{File: configFile, ActiveProfile: "test"} + configLoader := vault.NewConfigLoader(vault.ProfileConfig{}, configFile, "test") config, err := configLoader.GetProfileConfig("test") if err != nil { t.Fatalf("Should have found a profile: %v", err)