diff --git a/README.md b/README.md index 717e5bd8..f58f8b45 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,8 @@ Usage: x509-certificate-exporter [-hv] [-b value] [--debug] [-d value] [--exclud usage at runtime -s, --secret-type=value one or more kubernetes secret type & key to watch (e.g. - "kubernetes.io/tls:tls.crt" + "kubernetes.io/tls:tls.crt". Value can be a regex pattern + "kubernetes.io/tls:.*.tls") --trim-path-components=value remove leading component(s) from path(s) in label(s) -v, --version show version info and exit diff --git a/internal/kubernetes.go b/internal/kubernetes.go index d242b268..90df44ec 100644 --- a/internal/kubernetes.go +++ b/internal/kubernetes.go @@ -45,14 +45,21 @@ func (exporter *Exporter) parseAllKubeSecrets() ([]*certificateRef, []error) { for _, secret := range secrets { for _, secretType := range exporter.KubeSecretTypes { typeAndKey := strings.Split(secretType, ":") - - if secret.Type == v1.SecretType(typeAndKey[0]) && len(secret.Data[typeAndKey[1]]) > 0 { - output = append(output, &certificateRef{ - path: fmt.Sprintf("k8s/%s/%s", namespace, secret.GetName()), - format: certificateFormatKubeSecret, - kubeSecret: secret, - kubeSecretKey: typeAndKey[1], - }) + kubeSecretKeys, err := getMatchingKeys(secret.Data, typeAndKey[1]) + if err != nil { + outputErrors = append(outputErrors, fmt.Errorf("failed to fetch keys for secret from namespace \"%s\": %s", namespace, err.Error())) + continue + } + for _, kubeSecretKey := range kubeSecretKeys { + + if secret.Type == v1.SecretType(typeAndKey[0]) && len(secret.Data[kubeSecretKey]) > 0 { + output = append(output, &certificateRef{ + path: fmt.Sprintf("k8s/%s/%s", namespace, secret.GetName()), + format: certificateFormatKubeSecret, + kubeSecret: secret, + kubeSecretKey: kubeSecretKey, + }) + } } } } @@ -203,9 +210,14 @@ func (exporter *Exporter) checkHasIncludedType(secret *v1.Secret) (bool, error) if len(typeAndKey) != 2 { return false, fmt.Errorf("malformed kube secret type: \"%s\"", secretType) } - - if secret.Type == v1.SecretType(typeAndKey[0]) && len(secret.Data[typeAndKey[1]]) > 0 { - return true, nil + secretKeys, err := getMatchingKeys(secret.Data, typeAndKey[1]) + if err != nil { + return false, nil + } + for _, secretKey := range secretKeys { + if secret.Type == v1.SecretType(typeAndKey[0]) && len(secret.Data[secretKey]) > 0 { + return true, nil + } } } @@ -224,8 +236,14 @@ func (exporter *Exporter) shrinkSecret(secret v1.Secret) v1.Secret { for _, secretType := range exporter.KubeSecretTypes { typeAndKey := strings.Split(secretType, ":") - if secret.Type == v1.SecretType(typeAndKey[0]) && len(secret.Data[typeAndKey[1]]) > 0 { - result.Data[typeAndKey[1]] = secret.Data[typeAndKey[1]] + secretKeys, err := getMatchingKeys(secret.Data, typeAndKey[1]) + if err != nil { + continue + } + for _, secretKey := range secretKeys { + if secret.Type == v1.SecretType(typeAndKey[0]) && len(secret.Data[secretKey]) > 0 { + result.Data[secretKey] = secret.Data[secretKey] + } } } diff --git a/internal/utility.go b/internal/utility.go index 39cfabfd..89e7c5c6 100644 --- a/internal/utility.go +++ b/internal/utility.go @@ -1,5 +1,9 @@ package internal +import ( + "regexp" +) + func unique(data []*certificateRef) []*certificateRef { output := []*certificateRef{} seen := map[string]bool{} @@ -13,3 +17,18 @@ func unique(data []*certificateRef) []*certificateRef { return output } + +func getMatchingKeys(secretKeyValues map[string][]byte, pattern string) ([]string, error) { + keys := make([]string, 0, len(secretKeyValues)) + regex, err := regexp.Compile(pattern) + if err != nil { + return keys, err + } + + for key := range secretKeyValues { + if regex.MatchString(key) { + keys = append(keys, key) + } + } + return keys, nil +}