diff --git a/README.md b/README.md index d247b98..d6015f8 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ Usage: x509-certificate-exporter [-hv] [-b value] [--debug] [-d value] [--exclud --expose-relative-metrics expose additionnal metrics with relative durations instead of absolute timestamps + --expose-secret-label=value + expose selected label from kube secrets as prometheus label -f, --watch-file=value watch one or more x509 certificate file -h, --help show this help message and exit diff --git a/cmd/x509-certificate-exporter/main.go b/cmd/x509-certificate-exporter/main.go index b4b1656..76f281e 100644 --- a/cmd/x509-certificate-exporter/main.go +++ b/cmd/x509-certificate-exporter/main.go @@ -81,6 +81,9 @@ func main() { kubeExcludeLabels := stringArrayFlag{} getopt.FlagLong(&kubeExcludeLabels, "exclude-label", 0, "removes the kube secrets with the given label (or label value if specified) from the watch list (applied after --include-label)") + kubeSecretLabels := stringArrayFlag{} + getopt.FlagLong(&kubeSecretLabels, "expose-secret-label", 0, "expose selected label from kube secrets as prometheus label") + getopt.Parse() if *help { @@ -153,6 +156,7 @@ func main() { KubeExcludeNamespaceLabels: kubeExcludeNamespaceLabels, KubeIncludeLabels: kubeIncludeLabels, KubeExcludeLabels: kubeExcludeLabels, + KubeSecretLabels: kubeSecretLabels, } if getopt.Lookup("expose-labels").Seen() { diff --git a/internal/certificate.go b/internal/certificate.go index 0a0c855..163e549 100644 --- a/internal/certificate.go +++ b/internal/certificate.go @@ -62,13 +62,14 @@ var DefaultYamlPaths = []YAMLCertRef{ } type certificateRef struct { - path string - format certificateFormat - certificates []*parsedCertificate - yamlPaths []YAMLCertRef - kubeSecret v1.Secret - kubeConfigMap v1.ConfigMap - kubeSecretKey string + path string + format certificateFormat + certificates []*parsedCertificate + yamlPaths []YAMLCertRef + kubeSecret v1.Secret + kubeConfigMap v1.ConfigMap + kubeSecretKey string + kubeSecretLabels map[string]string } type parsedCertificate struct { diff --git a/internal/exporter.go b/internal/exporter.go index b603d40..90a6761 100644 --- a/internal/exporter.go +++ b/internal/exporter.go @@ -48,6 +48,7 @@ type Exporter struct { KubeExcludeNamespaceLabels []string KubeIncludeLabels []string KubeExcludeLabels []string + KubeSecretLabels []string kubeClient kubernetes.Interface listener net.Listener @@ -395,6 +396,16 @@ func (exporter *Exporter) compareCertificates( if leftCert.userID != rightCert.userID { return false } + if leftRef.format == certificateFormatKubeSecret { + if len(leftRef.kubeSecretLabels) != len(rightRef.kubeSecretLabels) { + return false + } + for key, leftValue := range leftRef.kubeSecretLabels { + if rightValue, exists := rightRef.kubeSecretLabels[key]; !exists || leftValue != rightValue { + return false + } + } + } return true } @@ -473,6 +484,10 @@ func (exporter *Exporter) getBaseLabels(ref *certificateRef) map[string]string { labels["secret_name"] = filepath.Base(ref.path) labels["secret_namespace"] = strings.Split(ref.path, "/")[1] labels["secret_key"] = ref.kubeSecretKey + for key, value := range ref.kubeSecretLabels { + sanitizedKey := regexp.MustCompile(`[^a-zA-Z0-9_]`).ReplaceAllString(key, "_") + labels["secret_label_"+sanitizedKey] = value + } } return labels diff --git a/internal/kubernetes.go b/internal/kubernetes.go index 7be1245..de5aaef 100644 --- a/internal/kubernetes.go +++ b/internal/kubernetes.go @@ -47,11 +47,18 @@ func (exporter *Exporter) parseAllKubeObjects() ([]*certificateRef, []error) { readCertificatesFromSecrets := func(secrets []v1.Secret) (outputs []*certificateRef) { for _, secret := range secrets { for key := range MatchingSecretKeys(exporter.KubeSecretTypes, &secret) { + filteredLabels := make(map[string]string) + for _, labelKey := range exporter.KubeSecretLabels { + if value, exists := secret.Labels[labelKey]; exists { + filteredLabels[labelKey] = value + } + } output = append(output, &certificateRef{ path: fmt.Sprintf("k8s/%s/%s", secret.GetNamespace(), secret.GetName()), format: certificateFormatKubeSecret, kubeSecret: secret, kubeSecretKey: key, + kubeSecretLabels: filteredLabels, }) } } @@ -265,6 +272,7 @@ func (exporter *Exporter) shrinkSecret(secret v1.Secret) v1.Secret { ObjectMeta: metav1.ObjectMeta{ Name: secret.Name, Namespace: secret.Namespace, + Labels: secret.Labels, }, } for key := range MatchingSecretKeys(exporter.KubeSecretTypes, &secret) {