1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

feat(configs): vaultCredentialEnvPrefix to support several prefixes (#4745)

* feat(configs): vaultCredentialEnvPrefix to support several prefixes

* minor refactoring

* docs

---------

Co-authored-by: Muhammadali Nazarov <muhammadalinazarov@gmail.com>
This commit is contained in:
Adam Horacek 2024-01-09 00:07:53 -08:00 committed by GitHub
parent 32657c44d7
commit a5ea24dfb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 13 deletions

View File

@ -129,12 +129,16 @@ The `vaultCredentialPath` parameter is the endpoint of your credential path in V
The `vaultCredentialKeys`parameter is a list of credential IDs. The secret value of the credential will be exposed as an environment variable prefixed by "PIPER_VAULTCREDENTIAL_" and transformed to a valid variable name. For a credential ID named `myAppId` the forwarded environment variable to the step will be `PIPER_VAULTCREDENTIAL_MYAPPID` containing the secret. The Base64 encoded secret value will be exposed as environment variable to the step as `PIPER_VAULTCREDENTIAL_MYAPPID_BASE64`. Hyphens will be replaced by underscores and other non-alphanumeric characters will be removed.
!!! hint "Using a custom prefix for test credentials"
By default the prefix for test credentials is `PIPER_VAULTCREDENTIAL_`.
!!! hint "Using a custom prefix for credentials"
By default the prefix for credentials is `PIPER_VAULTCREDENTIAL_`.
It is possible to use a custom prefix by setting for example `vaultCredentialEnvPrefix: MY_CUSTOM_PREFIX` in your configuration.
With this above credential ID named `myAppId` will be populated into an environment variable with the name `MY_CUSTOM_PREFIX_MYAPPID`.
In case you want to use specific prefix for secrets retrieved from different vault folders, pass multiple prefixes as
`vaultCredentialEnvPrefix: ['MY_CUSTOM_PREFIX_1', 'MY_CUSTOM_PREFIX_2']`.
With this above credential ID named `myAppId1` will be populated into an environment variable with the name `MY_CUSTOM_PREFIX_1_MYAPPID1` and `myAppId2` will be populated into an environment variable with name `MY_CUSTOM_PREFIX_2_MYAPPID2`
Extended logging for Vault secret fetching (e.g. found credentials and environment variable names) can be activated via `verbose: true` configuration.
## Using Vault for test credentials (Deprecated : use general purpose and test credentials as above)

View File

@ -175,44 +175,54 @@ func resolveVaultReference(ref *ResourceReference, config *StepConfig, client va
func resolveVaultTestCredentialsWrapper(config *StepConfig, client vaultClient) {
log.Entry().Infof("Resolving test credentials wrapper")
resolveVaultTestCredentialsWrapperBase(config, client, vaultTestCredentialPath, vaultTestCredentialKeys, resolveVaultTestCredentials)
resolveVaultCredentialsWrapperBase(config, client, vaultTestCredentialPath, vaultTestCredentialKeys, vaultTestCredentialEnvPrefix, resolveVaultTestCredentials)
}
func resolveVaultCredentialsWrapper(config *StepConfig, client vaultClient) {
log.Entry().Infof("Resolving credentials wrapper")
resolveVaultTestCredentialsWrapperBase(config, client, vaultCredentialPath, vaultCredentialKeys, resolveVaultCredentials)
resolveVaultCredentialsWrapperBase(config, client, vaultCredentialPath, vaultCredentialKeys, vaultCredentialEnvPrefix, resolveVaultCredentials)
}
func resolveVaultTestCredentialsWrapperBase(
func resolveVaultCredentialsWrapperBase(
config *StepConfig, client vaultClient,
vaultCredPath, vaultCredKeys string,
vaultCredPath, vaultCredKeys, vaultCredEnvPrefix string,
resolveVaultCredentials func(config *StepConfig, client vaultClient),
) {
switch config.Config[vaultCredPath].(type) {
case string:
resolveVaultCredentials(config, client)
case []interface{}:
vaultCredentialPathCopy := config.Config[vaultCredPath]
vaultCredentialKeysCopy := config.Config[vaultCredKeys]
vaultCredentialPathCopy := config.Config[vaultCredPath].([]interface{})
vaultCredentialKeysCopy, keysOk := config.Config[vaultCredKeys].([]interface{})
vaultCredentialEnvPrefixCopy, prefixOk := config.Config[vaultCredEnvPrefix].([]interface{})
if _, ok := vaultCredentialKeysCopy.([]interface{}); !ok {
if !keysOk {
log.Entry().Debugf(" failed, unknown type of keys")
return
}
if len(vaultCredentialKeysCopy.([]interface{})) != len(vaultCredentialPathCopy.([]interface{})) {
if len(vaultCredentialKeysCopy) != len(vaultCredentialPathCopy) {
log.Entry().Debugf(" failed, not same count of values and keys")
return
}
for i := 0; i < len(vaultCredentialPathCopy.([]interface{})); i++ {
config.Config[vaultCredPath] = vaultCredentialPathCopy.([]interface{})[i]
config.Config[vaultCredKeys] = vaultCredentialKeysCopy.([]interface{})[i]
if prefixOk && len(vaultCredentialEnvPrefixCopy) != len(vaultCredentialPathCopy) {
log.Entry().Debugf(" failed, not same count of values and environment prefixes")
return
}
for i := 0; i < len(vaultCredentialPathCopy); i++ {
if prefixOk {
config.Config[vaultCredEnvPrefix] = vaultCredentialEnvPrefixCopy[i]
}
config.Config[vaultCredPath] = vaultCredentialPathCopy[i]
config.Config[vaultCredKeys] = vaultCredentialKeysCopy[i]
resolveVaultCredentials(config, client)
}
config.Config[vaultCredPath] = vaultCredentialPathCopy
config.Config[vaultCredKeys] = vaultCredentialKeysCopy
config.Config[vaultCredEnvPrefix] = vaultCredentialEnvPrefixCopy
default:
log.Entry().Debugf(" failed, unknown type of path")
return

View File

@ -269,6 +269,88 @@ func TestResolveVaultTestCredentialsWrapper(t *testing.T) {
}
})
t.Run("Multiple test credential prefixes", func(t *testing.T) {
t.Parallel()
// init
vaultMock := &mocks.VaultMock{}
envPrefixes := []interface{}{"TEST1_", "TEST2_"}
stepConfig := StepConfig{Config: map[string]interface{}{
"vaultPath": "team1",
"vaultTestCredentialPath": []interface{}{"appCredentials1", "appCredentials2"},
"vaultTestCredentialKeys": []interface{}{[]interface{}{"appUser", "appUserPw"}, []interface{}{"appUser", "appUserPw"}},
"vaultTestCredentialEnvPrefix": envPrefixes,
}}
defer os.Unsetenv("TEST1_APPUSER")
defer os.Unsetenv("TEST1_APPUSERPW")
defer os.Unsetenv("TEST2_APPUSER")
defer os.Unsetenv("TEST2_APPUSERPW")
// mock
vaultData1 := map[string]string{"appUser": "test-user1", "appUserPw": "password1"}
vaultMock.On("GetKvSecret", "team1/appCredentials1").Return(vaultData1, nil)
vaultData2 := map[string]string{"appUser": "test-user2", "appUserPw": "password2"}
vaultMock.On("GetKvSecret", "team1/appCredentials2").Return(vaultData2, nil)
// test
resolveVaultTestCredentialsWrapper(&stepConfig, vaultMock)
// assert
for k, expectedValue := range vaultData1 {
env := envPrefixes[0].(string) + strings.ToUpper(k)
assert.NotEmpty(t, os.Getenv(env))
assert.Equal(t, expectedValue, os.Getenv(env))
}
// assert
for k, expectedValue := range vaultData2 {
env := envPrefixes[1].(string) + strings.ToUpper(k)
assert.NotEmpty(t, os.Getenv(env))
assert.Equal(t, expectedValue, os.Getenv(env))
}
})
t.Run("Multiple custom general purpuse credential environment prefixes", func(t *testing.T) {
t.Parallel()
// init
vaultMock := &mocks.VaultMock{}
envPrefixes := []interface{}{"CUSTOM1_", "CUSTOM2_"}
stepConfig := StepConfig{Config: map[string]interface{}{
"vaultPath": "team1",
"vaultCredentialPath": []interface{}{"appCredentials1", "appCredentials2"},
"vaultCredentialKeys": []interface{}{[]interface{}{"appUser", "appUserPw"}, []interface{}{"appUser", "appUserPw"}},
"vaultCredentialEnvPrefix": envPrefixes,
}}
defer os.Unsetenv("CUSTOM1_APPUSER")
defer os.Unsetenv("CUSTOM1_APPUSERPW")
defer os.Unsetenv("CUSTOM2_APPUSER")
defer os.Unsetenv("CUSTOM2_APPUSERPW")
// mock
vaultData1 := map[string]string{"appUser": "test-user1", "appUserPw": "password1"}
vaultMock.On("GetKvSecret", "team1/appCredentials1").Return(vaultData1, nil)
vaultData2 := map[string]string{"appUser": "test-user2", "appUserPw": "password2"}
vaultMock.On("GetKvSecret", "team1/appCredentials2").Return(vaultData2, nil)
// test
resolveVaultCredentialsWrapper(&stepConfig, vaultMock)
// assert
for k, expectedValue := range vaultData1 {
env := envPrefixes[0].(string) + strings.ToUpper(k)
assert.NotEmpty(t, os.Getenv(env))
assert.Equal(t, expectedValue, os.Getenv(env))
}
// assert
for k, expectedValue := range vaultData2 {
env := envPrefixes[1].(string) + strings.ToUpper(k)
assert.NotEmpty(t, os.Getenv(env))
assert.Equal(t, expectedValue, os.Getenv(env))
}
})
// Test empty and non-empty custom general purpose credential prefix
envPrefixes := []string{"CUSTOM_MYCRED1_", ""}
for idx, envPrefix := range envPrefixes {