-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #363 from cyberark/343_retrieve_secrets
Retrieve Secrets for secrets group
- Loading branch information
Showing
5 changed files
with
236 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package pushtofile | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/cyberark/conjur-authn-k8s-client/pkg/access_token" | ||
"github.com/cyberark/conjur-authn-k8s-client/pkg/log" | ||
"github.com/cyberark/secrets-provider-for-k8s/pkg/log/messages" | ||
"github.com/cyberark/secrets-provider-for-k8s/pkg/secrets/clients/conjur" | ||
) | ||
|
||
type secret struct { | ||
Alias string | ||
Value string | ||
} | ||
type fetcher interface { | ||
SecretFetcher(secretIds []string) (map[string][]byte, error) | ||
} | ||
|
||
type conjurSecretFetch struct { | ||
accessToken access_token.AccessToken | ||
} | ||
|
||
func (s conjurSecretFetch) SecretFetcher(secretIds []string) (map[string][]byte, error) { | ||
accessTokenData, err := s.accessToken.Read() | ||
if err != nil { | ||
return nil, log.RecordedError(messages.CSPFK002E) | ||
} | ||
return conjur.RetrieveConjurSecrets(accessTokenData, secretIds) | ||
} | ||
|
||
// FetchSecretsForGroups parses the SecretsGroup, gets | ||
// the secrets from Conjur and updates the SecretsGroup with the secret | ||
func FetchSecretsForGroups(secretGroups *SecretGroups, | ||
accessToken access_token.AccessToken) (map[string][]*secret, error) { | ||
var conjurSecretFetcher = conjurSecretFetch{accessToken} | ||
return fetchSecretsForGroups(conjurSecretFetcher, secretGroups) | ||
} | ||
|
||
func getAllIds(secretGroups *SecretGroups) []string { | ||
ids := []string{} | ||
for _, group := range *secretGroups { | ||
for _, spec := range group.SecretSpecs { | ||
ids = append(ids, spec.Id) | ||
} | ||
} | ||
return ids | ||
} | ||
|
||
func fetchSecretsForGroups(secretsFetcherFunc fetcher, | ||
secretGroups *SecretGroups, | ||
) (map[string][]*secret, error) { | ||
|
||
secretsValues := map[string][]*secret{} | ||
|
||
ids := getAllIds(secretGroups) | ||
retrieved, err := secretsFetcherFunc.SecretFetcher(ids) | ||
if err != nil { | ||
return nil, log.RecordedError(messages.CSPFK052E, err.Error()) | ||
} | ||
for _, group := range *secretGroups { | ||
for _, spec := range group.SecretSpecs { | ||
for id, retSecret := range retrieved { | ||
if strings.Contains(id, spec.Id) { | ||
fetchedSecret := new(secret) | ||
fetchedSecret.Alias = spec.Alias | ||
fetchedSecret.Value = string(retSecret) | ||
secretsValues[group.Label] = append(secretsValues[group.Label], fetchedSecret) | ||
} | ||
} | ||
} | ||
} | ||
return secretsValues, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package pushtofile | ||
|
||
import ( | ||
"testing" | ||
|
||
conjurMocks "github.com/cyberark/secrets-provider-for-k8s/pkg/secrets/clients/conjur/mocks" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
type retrieveSecretsTestCase struct { | ||
description string | ||
secretSpecs map[string][]SecretSpec | ||
assert func(t *testing.T, result map[string][]*secret, err error) | ||
} | ||
|
||
func (tc retrieveSecretsTestCase) Run(t *testing.T, mockSecretFetch MockSecretFetch) { | ||
t.Run(tc.description, func(t *testing.T) { | ||
s := createSecretGroups(tc.secretSpecs) | ||
ret, err := fetchSecretsForGroups(mockSecretFetch, &s) | ||
tc.assert(t, ret, err) | ||
}) | ||
} | ||
|
||
func createSecretGroups(groupSpecs map[string][]SecretSpec) SecretGroups { | ||
secretGroups := SecretGroups{} | ||
for label, secretSpecs := range groupSpecs { | ||
secretGroup := SecretGroup{ | ||
Label: label, | ||
SecretSpecs: secretSpecs, | ||
} | ||
secretGroups = append(secretGroups, secretGroup) | ||
} | ||
return secretGroups | ||
} | ||
|
||
func findGroupValues(group map[string][]*secret, label string) []*secret { | ||
for key, secretGroup := range group { | ||
if key == label { | ||
return secretGroup | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func assertGoodResults(expectedGroupValues map[string][]*secret) func(*testing.T, map[string][]*secret, error) { | ||
return func(t *testing.T, result map[string][]*secret, err error) { | ||
|
||
if !assert.NoError(t, err) { | ||
return | ||
} | ||
for groupLabel, expValues := range expectedGroupValues { | ||
actualValues := findGroupValues(result, groupLabel) | ||
assert.NotNil(t, actualValues) | ||
assert.True(t, assert.EqualValues(t, actualValues, expValues)) | ||
} | ||
} | ||
} | ||
|
||
var retrieveSecretsTestCases = []retrieveSecretsTestCase{ | ||
{ | ||
description: "Happy Case", | ||
secretSpecs: map[string][]SecretSpec{ | ||
"cache": []SecretSpec{ | ||
{Alias: "api-url", Id: "dev/openshift/api-url"}, | ||
{Alias: "username", Id: "dev/openshift/username"}, | ||
{Alias: "password", Id: "dev/openshift/password"}, | ||
}, | ||
"db": []SecretSpec{ | ||
{Alias: "api-url", Id: "ci/openshift/api-url"}, | ||
{Alias: "username", Id: "ci/openshift/username"}, | ||
{Alias: "password", Id: "ci/openshift/password"}, | ||
}, | ||
}, | ||
assert: assertGoodResults(map[string][]*secret{ | ||
"cache": []*secret{ | ||
{Alias: "api-url", Value: "https://postgres.example.com"}, | ||
{Alias: "username", Value: "admin"}, | ||
{Alias: "password", Value: "open-$e$ame"}, | ||
}, | ||
"db": []*secret{ | ||
{Alias: "api-url", Value: "https://ci.postgres.example.com"}, | ||
{Alias: "username", Value: "administrator"}, | ||
{Alias: "password", Value: "open-$e$ame"}, | ||
}, | ||
}), | ||
}, | ||
{ | ||
description: "Bad ID", | ||
secretSpecs: map[string][]SecretSpec{ | ||
"cache": []SecretSpec{ | ||
{Alias: "api-url", Id: "foo/openshift/bar"}, | ||
{Alias: "username", Id: "dev/openshift/username"}, | ||
{Alias: "password", Id: "dev/openshift/password"}, | ||
}, | ||
"db": []SecretSpec{ | ||
{Alias: "api-url", Id: "ci/openshift/api-url"}, | ||
{Alias: "username", Id: "ci/openshift/username"}, | ||
{Alias: "password", Id: "ci/openshift/password"}, | ||
}, | ||
}, | ||
assert: func(t *testing.T, result map[string][]*secret, err error) { | ||
assert.Contains(t, err.Error(), "Failed to retrieve secrets") | ||
}, | ||
}, | ||
} | ||
|
||
type MockSecretFetch struct { | ||
accessToken conjurMocks.MockAccessToken | ||
conjurMockClient conjurMocks.ConjurMockClient | ||
} | ||
|
||
func (s MockSecretFetch) SecretFetcher(secretIds []string) (map[string][]byte, error) { | ||
|
||
accessTokenData, _ := s.accessToken.Read() | ||
return s.conjurMockClient.RetrieveSecrets(accessTokenData, secretIds) | ||
} | ||
|
||
func mockInit(s *MockSecretFetch) { | ||
s.conjurMockClient = conjurMocks.NewConjurMockClient() | ||
mockSecrets := map[string]string{ | ||
"dev/openshift/api-url": "https://postgres.example.com", | ||
"dev/openshift/username": "admin", | ||
"dev/openshift/password": "open-$e$ame", | ||
"ci/openshift/api-url": "https://ci.postgres.example.com", | ||
"ci/openshift/username": "administrator", | ||
"ci/openshift/password": "open-$e$ame", | ||
} | ||
s.conjurMockClient.AddSecret(mockSecrets) | ||
} | ||
|
||
func TestRetrieveSecrets(t *testing.T) { | ||
var mockSecretFetch MockSecretFetch | ||
mockInit(&mockSecretFetch) | ||
for _, tc := range retrieveSecretsTestCases { | ||
tc.Run(t, mockSecretFetch) | ||
} | ||
} |