1
0
Fork 0
mirror of https://github.com/external-secrets/external-secrets.git synced 2024-12-14 11:57:59 +00:00

Feat/allow keeper to work with complex types (#3016)

* update dependencies (#3005)

Signed-off-by: External Secrets Operator <ExternalSecretsOperator@users.noreply.github.com>
Co-authored-by: External Secrets Operator <ExternalSecretsOperator@users.noreply.github.com>
Co-authored-by: Moritz Johner <moolen@users.noreply.github.com>
Signed-off-by: Pedro Parra Ortega <parraortega.pedro@gmail.com>

* feat: allow keeper to work with complex types

Signed-off-by: Pedro Parra Ortega <parraortega.pedro@gmail.com>

---------

Signed-off-by: External Secrets Operator <ExternalSecretsOperator@users.noreply.github.com>
Signed-off-by: Pedro Parra Ortega <parraortega.pedro@gmail.com>
Co-authored-by: eso-service-account-app[bot] <85832941+eso-service-account-app[bot]@users.noreply.github.com>
Co-authored-by: External Secrets Operator <ExternalSecretsOperator@users.noreply.github.com>
Co-authored-by: Moritz Johner <moolen@users.noreply.github.com>
This commit is contained in:
Pedro Parra Ortega 2024-01-12 00:30:58 +01:00 committed by GitHub
parent 559c773792
commit ba8cf6bde5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 16 deletions

View file

@ -56,8 +56,10 @@ Be sure the `keepersecurity` provider is listed in the `Kind=SecretStore`
* Files: Record's file's Name
* `find.tags` are not supported at this time.
**NOTE:** For complex [types](https://docs.keeper.io/secrets-manager/secrets-manager/about/field-record-types), like name, phone, bankAccount, which does not match with a single string value, external secrets will return the complete json string. Use the json template functions to decode.
### Creating external secret
To create a kubernetes secret from the GCP Secret Manager secret a `Kind=ExternalSecret` is needed.
To create a kubernetes secret from Keeper Secret Manager secret a `Kind=ExternalSecret` is needed.
```yaml
{% include 'keepersecurity-external-secret.yaml' %}

View file

@ -70,4 +70,24 @@ spec:
remoteRef:
key: OqPt3Vd37My7G8rTb-8Q
property: password
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: example
spec:
refreshInterval: 1h # rate SecretManager pulls KeeperSrucity
secretStoreRef:
kind: SecretStore
name: example # name of the SecretStore (or kind specified)
target:
name: secret-to-be-created # name of the k8s Secret to be created
creationPolicy: Owner
template:
engineVersion: v2
data:
username: "{{ (fromJson .name).first }} {{ (fromJson .name).middle }} {{ (fromJson .name).last }}" # decode json string into vars
dataFrom:
- extract:
key: OqPt3Vd37My7G8rTb-8Q # ID of the Keeper Record
{% endraw %}

View file

@ -71,14 +71,14 @@ type SecurityClient interface {
}
type Field struct {
Type string `json:"type"`
Value []string `json:"value"`
Type string `json:"type"`
Value []interface{} `json:"value"`
}
type CustomField struct {
Type string `json:"type"`
Label string `json:"label"`
Value []string `json:"value"`
Type string `json:"type"`
Label string `json:"label"`
Value []interface{} `json:"value"`
}
type File struct {
@ -401,10 +401,25 @@ func (s *Secret) getItems(ref esv1beta1.ExternalSecretDataRemoteRef) (map[string
return secretData, nil
}
func getFieldValue(value []interface{}) []byte {
if len(value) < 1 {
return []byte{}
} else if len(value) == 1 {
res, _ := json.Marshal(value[0])
if str, ok := value[0].(string); ok {
res = []byte(str)
}
return res
} else {
res, _ := json.Marshal(value)
return res
}
}
func (s *Secret) getField(key string) ([]byte, error) {
for _, field := range s.Fields {
if field.Type == key && field.Type != keeperSecurityFileRef && field.Type != keeperSecurityMfa && len(field.Value) > 0 {
return []byte(field.Value[0]), nil
return getFieldValue(field.Value), nil
}
}
@ -415,7 +430,7 @@ func (s *Secret) getFields() map[string][]byte {
secretData := make(map[string][]byte)
for _, field := range s.Fields {
if len(field.Value) > 0 {
secretData[field.Type] = []byte(field.Value[0])
secretData[field.Type] = getFieldValue(field.Value)
}
}
@ -425,7 +440,7 @@ func (s *Secret) getFields() map[string][]byte {
func (s *Secret) getCustomField(key string) ([]byte, error) {
for _, field := range s.Custom {
if field.Label == key && len(field.Value) > 0 {
return []byte(field.Value[0]), nil
return getFieldValue(field.Value), nil
}
}
@ -436,7 +451,7 @@ func (s *Secret) getCustomFields() map[string][]byte {
secretData := make(map[string][]byte)
for _, field := range s.Custom {
if len(field.Value) > 0 {
secretData[field.Label] = []byte(field.Value[0])
secretData[field.Label] = getFieldValue(field.Value)
}
}

View file

@ -33,14 +33,15 @@ const (
folderID = "a8ekf031k"
validExistingRecord = "record0/login"
invalidRecord = "record5/login"
outputRecord0 = "{\"title\":\"record0\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}],\"custom\":null,\"files\":null}"
outputRecord1 = "{\"title\":\"record1\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}],\"custom\":null,\"files\":null}"
outputRecord2 = "{\"title\":\"record2\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}],\"custom\":null,\"files\":null}"
outputRecord0 = "{\"title\":\"record0\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}],\"custom\":[{\"type\":\"host\",\"label\":\"host0\",\"value\":[{\"hostName\":\"mysql\",\"port\":\"3306\"}]}],\"files\":null}"
outputRecord1 = "{\"title\":\"record1\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}],\"custom\":[{\"type\":\"host\",\"label\":\"host1\",\"value\":[{\"hostName\":\"mysql\",\"port\":\"3306\"}]}],\"files\":null}"
outputRecord2 = "{\"title\":\"record2\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}],\"custom\":[{\"type\":\"host\",\"label\":\"host2\",\"value\":[{\"hostName\":\"mysql\",\"port\":\"3306\"}]}],\"files\":null}"
record0 = "record0"
record1 = "record1"
record2 = "record2"
LoginKey = "login"
PasswordKey = "password"
HostKeyFormat = "host%d"
RecordNameFormat = "record%d"
)
@ -412,8 +413,9 @@ func TestClientGetSecretMap(t *testing.T) {
},
},
want: map[string][]byte{
LoginKey: []byte("foo"),
PasswordKey: []byte("bar"),
LoginKey: []byte("foo"),
PasswordKey: []byte("bar"),
fmt.Sprintf(HostKeyFormat, 0): []byte("{\"hostName\":\"mysql\",\"port\":\"3306\"}"),
},
wantErr: false,
},
@ -650,7 +652,7 @@ func generateRecords() []*ksm.Record {
},
}
}
sec := fmt.Sprintf("{\"title\":\"record%d\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}]}", i)
sec := fmt.Sprintf("{\"title\":\"record%d\",\"type\":\"login\",\"fields\":[{\"type\":\"login\",\"value\":[\"foo\"]},{\"type\":\"password\",\"value\":[\"bar\"]}],\"custom\":[{\"type\":\"host\",\"label\":\"host%d\",\"value\":[{\"hostName\":\"mysql\",\"port\":\"3306\"}]}]}", i, i)
record.SetTitle(fmt.Sprintf(RecordNameFormat, i))
record.SetStandardFieldValue(LoginKey, "foo")
record.SetStandardFieldValue(PasswordKey, "bar")