2021-01-06 15:50:16 +00:00
|
|
|
/*
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
2021-03-01 10:13:03 +00:00
|
|
|
|
2021-01-06 15:50:16 +00:00
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
2021-03-01 10:13:03 +00:00
|
|
|
|
2021-01-06 15:50:16 +00:00
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2021-01-27 11:08:28 +00:00
|
|
|
package utils
|
2021-01-06 15:50:16 +00:00
|
|
|
|
2021-09-09 09:14:17 +00:00
|
|
|
import (
|
|
|
|
|
|
|
|
// nolint:gosec
|
|
|
|
"crypto/md5"
|
|
|
|
"fmt"
|
2022-04-07 14:35:22 +00:00
|
|
|
"net"
|
|
|
|
"net/url"
|
2021-09-09 09:14:17 +00:00
|
|
|
"reflect"
|
2022-01-13 17:43:42 +00:00
|
|
|
"strings"
|
2022-04-07 14:35:22 +00:00
|
|
|
"time"
|
2022-03-02 13:09:22 +00:00
|
|
|
"unicode"
|
|
|
|
|
2022-02-17 22:14:39 +00:00
|
|
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
|
|
|
esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
|
2022-01-26 20:05:08 +00:00
|
|
|
)
|
|
|
|
|
2021-06-25 23:56:42 +00:00
|
|
|
// MergeByteMap merges map of byte slices.
|
2021-08-31 21:21:37 +00:00
|
|
|
func MergeByteMap(dst, src map[string][]byte) map[string][]byte {
|
|
|
|
for k, v := range src {
|
|
|
|
dst[k] = v
|
2021-01-06 15:50:16 +00:00
|
|
|
}
|
2021-08-31 21:21:37 +00:00
|
|
|
return dst
|
2021-01-06 15:50:16 +00:00
|
|
|
}
|
2021-06-25 23:56:42 +00:00
|
|
|
|
2022-03-09 09:48:25 +00:00
|
|
|
// ConvertKeys converts a secret map into a valid key.
|
|
|
|
// Replaces any non-alphanumeric characters depending on convert strategy.
|
|
|
|
func ConvertKeys(strategy esv1beta1.ExternalSecretConversionStrategy, in map[string][]byte) (map[string][]byte, error) {
|
2022-03-24 16:09:32 +00:00
|
|
|
out := make(map[string][]byte, len(in))
|
2022-03-09 09:48:25 +00:00
|
|
|
for k, v := range in {
|
2022-03-24 16:09:32 +00:00
|
|
|
key := convert(strategy, k)
|
2022-03-09 16:49:17 +00:00
|
|
|
if _, exists := out[key]; exists {
|
|
|
|
return nil, fmt.Errorf("secret name collision during conversion: %s", key)
|
|
|
|
}
|
|
|
|
out[key] = v
|
2022-03-02 13:09:22 +00:00
|
|
|
}
|
2022-03-09 09:48:25 +00:00
|
|
|
return out, nil
|
2022-03-02 13:09:22 +00:00
|
|
|
}
|
|
|
|
|
2022-03-24 16:09:32 +00:00
|
|
|
func convert(strategy esv1beta1.ExternalSecretConversionStrategy, str string) string {
|
|
|
|
rs := []rune(str)
|
|
|
|
newName := make([]string, len(rs))
|
|
|
|
for rk, rv := range rs {
|
|
|
|
if !unicode.IsNumber(rv) &&
|
|
|
|
!unicode.IsLetter(rv) &&
|
|
|
|
rv != '-' &&
|
|
|
|
rv != '.' &&
|
|
|
|
rv != '_' {
|
|
|
|
switch strategy {
|
|
|
|
case esv1beta1.ExternalSecretConversionDefault:
|
|
|
|
newName[rk] = "_"
|
|
|
|
case esv1beta1.ExternalSecretConversionUnicode:
|
|
|
|
newName[rk] = fmt.Sprintf("_U%04x_", rv)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
newName[rk] = string(rv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(newName, "")
|
|
|
|
}
|
|
|
|
|
2021-06-25 23:56:42 +00:00
|
|
|
// MergeStringMap performs a deep clone from src to dest.
|
|
|
|
func MergeStringMap(dest, src map[string]string) {
|
|
|
|
for k, v := range src {
|
|
|
|
dest[k] = v
|
|
|
|
}
|
|
|
|
}
|
2021-05-19 09:50:36 +00:00
|
|
|
|
|
|
|
// IsNil checks if an Interface is nil.
|
|
|
|
func IsNil(i interface{}) bool {
|
2021-11-26 08:08:56 +00:00
|
|
|
if i == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
value := reflect.ValueOf(i)
|
|
|
|
if value.Type().Kind() == reflect.Ptr {
|
|
|
|
return value.IsNil()
|
|
|
|
}
|
|
|
|
return false
|
2021-05-19 09:50:36 +00:00
|
|
|
}
|
2021-09-09 09:14:17 +00:00
|
|
|
|
|
|
|
// ObjectHash calculates md5 sum of the data contained in the secret.
|
|
|
|
// nolint:gosec
|
|
|
|
func ObjectHash(object interface{}) string {
|
|
|
|
textualVersion := fmt.Sprintf("%+v", object)
|
|
|
|
return fmt.Sprintf("%x", md5.Sum([]byte(textualVersion)))
|
|
|
|
}
|
2022-01-13 17:43:42 +00:00
|
|
|
|
|
|
|
func ErrorContains(out error, want string) bool {
|
|
|
|
if out == nil {
|
|
|
|
return want == ""
|
|
|
|
}
|
|
|
|
if want == "" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return strings.Contains(out.Error(), want)
|
|
|
|
}
|
2022-02-17 22:14:39 +00:00
|
|
|
|
|
|
|
// ValidateSecretSelector just checks if the namespace field is present/absent
|
|
|
|
// depending on the secret store type.
|
|
|
|
// We MUST NOT check the name or key property here. It MAY be defaulted by the provider.
|
|
|
|
func ValidateSecretSelector(store esv1beta1.GenericStore, ref esmeta.SecretKeySelector) error {
|
|
|
|
clusterScope := store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind
|
|
|
|
if clusterScope && ref.Namespace == nil {
|
|
|
|
return fmt.Errorf("cluster scope requires namespace")
|
|
|
|
}
|
|
|
|
if !clusterScope && ref.Namespace != nil {
|
|
|
|
return fmt.Errorf("namespace not allowed with namespaced SecretStore")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ValidateServiceAccountSelector just checks if the namespace field is present/absent
|
|
|
|
// depending on the secret store type.
|
|
|
|
// We MUST NOT check the name or key property here. It MAY be defaulted by the provider.
|
|
|
|
func ValidateServiceAccountSelector(store esv1beta1.GenericStore, ref esmeta.ServiceAccountSelector) error {
|
|
|
|
clusterScope := store.GetObjectKind().GroupVersionKind().Kind == esv1beta1.ClusterSecretStoreKind
|
|
|
|
if clusterScope && ref.Namespace == nil {
|
|
|
|
return fmt.Errorf("cluster scope requires namespace")
|
|
|
|
}
|
|
|
|
if !clusterScope && ref.Namespace != nil {
|
|
|
|
return fmt.Errorf("namespace not allowed with namespaced SecretStore")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2022-04-07 14:35:22 +00:00
|
|
|
|
|
|
|
func NetworkValidate(endpoint string, timeout time.Duration) error {
|
|
|
|
hostname, err := url.Parse(endpoint)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not parse url: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
host, port, err := net.SplitHostPort(hostname.Host)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not find host and port from url: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
url := fmt.Sprintf("%v:%v", host, port)
|
|
|
|
_, err = net.DialTimeout("tcp", url, timeout)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error accessing external store: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|