enix / x509-certificate-exporter

A Prometheus exporter to monitor x509 certificates expiration in Kubernetes clusters or standalone
MIT License
656 stars 68 forks source link

failed to parse some labels in kubeconfig #27

Closed r0bj closed 2 years ago

r0bj commented 2 years ago

After configure x509-certificate-exporter to parse kubeconfig warning is generated and certificate is marked as failed:

time="2022-01-30T05:51:30Z" level=warning msg="failed to parse \"/mnt/watch/kube-2668e6e60f5eba4364882db368b2e2c9b543596a/var/lib/kubelet-config/kubeconfig\", failed to parse some labels in /mnt/watch/kube-2668e6e60f5eba4364882db368b2e2c9b543596a/var/lib/kubelet-config/kubeconfig (got 1 IDs but 0 certs for \"$.clusters[:].name\")"

kubeconfig content from /var/lib/kubelet-config/kubeconfig:

apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority-data: <redacted base64 encoded cert data>
    server: https://kubernetes-control-plane.example.com:6443
  name: kube-res-dev
contexts:
- context:
    cluster: kube-res-dev
    user: system:node:dev-k8s-worker-r1
  name: default-context
current-context: default-context
users:
- name: system:node:dev-k8s-worker-r1
  user:
    client-certificate-data: <redacted base64 encoded cert data>
    client-key-data: <redacted base64 encoded cert data>

Kubeconfig itself is valid and used by kubernetes components with no issues.

DaemonSet used for cert monitoring:

---
# Source: x509-certificate-exporter/templates/daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: x509-certificate-exporter-nodes
  labels:
    helm.sh/chart: x509-certificate-exporter-1.20.0
    app.kubernetes.io/name: x509-certificate-exporter
    app.kubernetes.io/instance: x509-certificate-exporter
    app.kubernetes.io/version: "2.12.0"
    app.kubernetes.io/managed-by: Helm
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: x509-certificate-exporter
      app.kubernetes.io/instance: x509-certificate-exporter
  template:
    metadata:
      labels:
        helm.sh/chart: x509-certificate-exporter-1.20.0
        app.kubernetes.io/name: x509-certificate-exporter
        app.kubernetes.io/instance: x509-certificate-exporter
        app.kubernetes.io/version: "2.12.0"
        app.kubernetes.io/managed-by: Helm
    spec:
      serviceAccountName: default
      tolerations:
      - operator: Exists
      restartPolicy: Always
      containers:
      - name: x509-certificate-exporter
        securityContext:
          capabilities:
            drop:
            - ALL
          readOnlyRootFilesystem: true
          runAsGroup: 0
          runAsUser: 0
        resources:
          limits:
            cpu: 100m
            memory: 40Mi
          requests:
            cpu: 10m
            memory: 20Mi
        image: docker.io/enix/x509-certificate-exporter:2.12.0
        imagePullPolicy: IfNotPresent
        args:
        - --listen-address=:9793
        - --trim-path-components=3
        - --watch-kubeconf=/mnt/watch/kube-2668e6e60f5eba4364882db368b2e2c9b543596a//var/lib/kubelet-config/kubeconfig
        - --max-cache-duration=300s
        volumeMounts:
        - name: kube-2668e6e60f5eba4364882db368b2e2c9b543596a
          mountPath: /mnt/watch/kube-2668e6e60f5eba4364882db368b2e2c9b543596a//var/lib/kubelet-config
          #subPath: kubeconfig
          readOnly: true
        ports:
        - name: metrics
          containerPort: 9793
      hostNetwork: false
      volumes:
      - name: kube-2668e6e60f5eba4364882db368b2e2c9b543596a
        hostPath:
          path: /var/lib/kubelet-config
          type: Directory
r0bj commented 2 years ago

It seems that it's related to the fact that in this case base64 encoded certificates does not end with new line characters. This is how currently hashicorp vault returns issued certificates.

For example this certificate:

-----BEGIN CERTIFICATE-----
MIIFnTCCA4WgAwIBAgIUIA9iTqvVzqbNGSC13Z/4AzLmYkIwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQVUxDTALBgNVBAgMBHRlc3QxDTALBgNVBAcMBGNpdHkx
EDAOBgNVBAoMB2NvbXBhbnkxEDAOBgNVBAsMB3NlY3Rpb24xDTALBgNVBAMMBG5h
bWUwHhcNMjIwMTMxMDM1MzU2WhcNMjMwMTMxMDM1MzU2WjBeMQswCQYDVQQGEwJB
VTENMAsGA1UECAwEdGVzdDENMAsGA1UEBwwEY2l0eTEQMA4GA1UECgwHY29tcGFu
eTEQMA4GA1UECwwHc2VjdGlvbjENMAsGA1UEAwwEbmFtZTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAL7qSaDB6OKAoxK4vDpI2aXOXc2Rm/MiDfPe6ASJ
LEG9F79h2elZjO8Et7G0qmehRTkiAPXp36G8h/B4uwt75VcglOkIAdZSctEOvaL2
jpfFCgaYZDzXWkih+VOIQS6P2q5YOplHn3OOgGYxCzD2nZOz3jMeMJt1JnBc+9AZ
a2L5UucaOibD6Tie1nTFJVVzaBXsJThGPz4vPX64DzYV50gUlOWHJXpMyotQDkXB
NakkknQWgLMUi0qAaG3yphMsAdnTlRoiu/XthrQDhnUsAS5ZyvGL8FR+g75ONSnE
ZRleL0TYq4tX/Z0EUCafUxjLvmJzIxb+8zi4Nt2Uaj/Zor1XX8pIn2oKiYYeLttB
5k5a3VedXRohbFudvNVySjGUfSxLKumger8MosYssAsr3jrVSWxBngOitynBMLVl
0VDeMWf7sXXCI6H+MLh/todYejESTVT48KIKNOoMpF5QhjuL2QwNIkKICcdpT2Gz
6kCFegBP9vu+vx87X08WZ1QC5KEyJPV+TrJmgXZxyGRf7kYUY5aHS4fEDIuqeDRC
ALJ/l7AMczjQ2PoM9SY3W+NNoL6RoiQTSzVa9cQP2HKYYgE6rWrN8OhUPsOBxA1o
UMuqIppFm3vr0X1EXM67g8qG3M9G6WQDHvYIUakSTC91qt7cgovjl8OO513rwjLt
aswRAgMBAAGjUzBRMB0GA1UdDgQWBBR6algSloZc8IxPcjHOYAK9idxJwDAfBgNV
HSMEGDAWgBR6algSloZc8IxPcjHOYAK9idxJwDAPBgNVHRMBAf8EBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4ICAQCohqOZEayMkUSqVG8+OifQsw6R2/5h+eqZkVbhLOSL
x9WbJ28I2YUC1EnWY1OwvA7TsbURne+Lfm1w7Hz3lkLAZmzZDGBY6zIeDI0BqtbF
KqX7OGhwEp+B8fJeOHljr43Qo8HmTgH6pPBV/qVWDc9Xx2jxHcvfEfA9ZZ8trqx0
8VUR4VLDJjC4gCa9MJZc8XMAUZxjUB7UVcj0/8eHwAZPve6w8n2gpx/CpygyGnHJ
5j2pQ7K4KKyhPjFFTBIlCZ62A4wg0OuubU5mde1GJFW40+176R+rRApvNgnbn/UA
IdAer8y35ZbtcQwsWgUabCAmD3h6/qs2pwkBnVocqt+sgVZp/0KroZOOQvPBKgL0
IPCH6irWtH15NRtHupGEknS7/Tuw6MFa6ECpdUuU/SdnG3razidkQCLnnsoBLCF+
9XAbAIJL25V5zCcRZfh9wRyfzyu40MeV3Clf1xW1kXZFCHlnpaUM8EMJ8bcx3809
VlpWeL0eQDjI5FOH0RhuB3R4REyNkT60xqwG9eDyXcdF65LGLAzX4Pcfz28pZIxA
bXkYGpUvzN02Gmd6Zm45DHJpH1ut3ypqQzb8gCTs5cx8Dy03RZ5bFZK1N3C2p3jd
/TWbCnBVWoJuYIHrvarwwWT9RY6vDH6zT4eiLFnsINsZRuiPdrLo90L/iZqKBLFx
kg==
-----END CERTIFICATE-----

Would be encoded without new line character at the end to base64 encoded string:

LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZuVENDQTRXZ0F3SUJBZ0lVSUE5aVRxdlZ6cWJOR1NDMTNaLzRBekxtWWtJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1hqRUxNQWtHQTFVRUJoTUNRVlV4RFRBTEJnTlZCQWdNQkhSbGMzUXhEVEFMQmdOVkJBY01CR05wZEhreApFREFPQmdOVkJBb01CMk52YlhCaGJua3hFREFPQmdOVkJBc01CM05sWTNScGIyNHhEVEFMQmdOVkJBTU1CRzVoCmJXVXdIaGNOTWpJd01UTXhNRE0xTXpVMldoY05Nak13TVRNeE1ETTFNelUyV2pCZU1Rc3dDUVlEVlFRR0V3SkIKVlRFTk1Bc0dBMVVFQ0F3RWRHVnpkREVOTUFzR0ExVUVCd3dFWTJsMGVURVFNQTRHQTFVRUNnd0hZMjl0Y0dGdQplVEVRTUE0R0ExVUVDd3dIYzJWamRHbHZiakVOTUFzR0ExVUVBd3dFYm1GdFpUQ0NBaUl3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMN3FTYURCNk9LQW94SzR2RHBJMmFYT1hjMlJtL01pRGZQZTZBU0oKTEVHOUY3OWgyZWxaak84RXQ3RzBxbWVoUlRraUFQWHAzNkc4aC9CNHV3dDc1VmNnbE9rSUFkWlNjdEVPdmFMMgpqcGZGQ2dhWVpEelhXa2loK1ZPSVFTNlAycTVZT3BsSG4zT09nR1l4Q3pEMm5aT3ozak1lTUp0MUpuQmMrOUFaCmEyTDVVdWNhT2liRDZUaWUxblRGSlZWemFCWHNKVGhHUHo0dlBYNjREellWNTBnVWxPV0hKWHBNeW90UURrWEIKTmFra2tuUVdnTE1VaTBxQWFHM3lwaE1zQWRuVGxSb2l1L1h0aHJRRGhuVXNBUzVaeXZHTDhGUitnNzVPTlNuRQpaUmxlTDBUWXE0dFgvWjBFVUNhZlV4akx2bUp6SXhiKzh6aTROdDJVYWovWm9yMVhYOHBJbjJvS2lZWWVMdHRCCjVrNWEzVmVkWFJvaGJGdWR2TlZ5U2pHVWZTeExLdW1nZXI4TW9zWXNzQXNyM2pyVlNXeEJuZ09pdHluQk1MVmwKMFZEZU1XZjdzWFhDSTZIK01MaC90b2RZZWpFU1RWVDQ4S0lLTk9vTXBGNVFoanVMMlF3TklrS0lDY2RwVDJHego2a0NGZWdCUDl2dSt2eDg3WDA4V1oxUUM1S0V5SlBWK1RySm1nWFp4eUdSZjdrWVVZNWFIUzRmRURJdXFlRFJDCkFMSi9sN0FNY3pqUTJQb005U1kzVytOTm9MNlJvaVFUU3pWYTljUVAySEtZWWdFNnJXck44T2hVUHNPQnhBMW8KVU11cUlwcEZtM3ZyMFgxRVhNNjdnOHFHM005RzZXUURIdllJVWFrU1RDOTFxdDdjZ292amw4T081MTNyd2pMdAphc3dSQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJSNmFsZ1Nsb1pjOEl4UGNqSE9ZQUs5aWR4SndEQWZCZ05WCkhTTUVHREFXZ0JSNmFsZ1Nsb1pjOEl4UGNqSE9ZQUs5aWR4SndEQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BMEcKQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUNvaHFPWkVheU1rVVNxVkc4K09pZlFzdzZSMi81aCtlcVprVmJoTE9TTAp4OVdiSjI4STJZVUMxRW5XWTFPd3ZBN1RzYlVSbmUrTGZtMXc3SHozbGtMQVptelpER0JZNnpJZURJMEJxdGJGCktxWDdPR2h3RXArQjhmSmVPSGxqcjQzUW84SG1UZ0g2cFBCVi9xVldEYzlYeDJqeEhjdmZFZkE5Wlo4dHJxeDAKOFZVUjRWTERKakM0Z0NhOU1KWmM4WE1BVVp4alVCN1VWY2owLzhlSHdBWlB2ZTZ3OG4yZ3B4L0NweWd5R25ISgo1ajJwUTdLNEtLeWhQakZGVEJJbENaNjJBNHdnME91dWJVNW1kZTFHSkZXNDArMTc2UityUkFwdk5nbmJuL1VBCklkQWVyOHkzNVpidGNRd3NXZ1VhYkNBbUQzaDYvcXMycHdrQm5Wb2NxdCtzZ1ZacC8wS3JvWk9PUXZQQktnTDAKSVBDSDZpcld0SDE1TlJ0SHVwR0VrblM3L1R1dzZNRmE2RUNwZFV1VS9TZG5HM3Jhemlka1FDTG5uc29CTENGKwo5WEFiQUlKTDI1VjV6Q2NSWmZoOXdSeWZ6eXU0ME1lVjNDbGYxeFcxa1haRkNIbG5wYVVNOEVNSjhiY3gzODA5ClZscFdlTDBlUURqSTVGT0gwUmh1QjNSNFJFeU5rVDYweHF3RzllRHlYY2RGNjVMR0xBelg0UGNmejI4cFpJeEEKYlhrWUdwVXZ6TjAyR21kNlptNDVESEpwSDF1dDN5cHFRemI4Z0NUczVjeDhEeTAzUlo1YkZaSzFOM0MycDNqZAovVFdiQ25CVldvSnVZSUhydmFyd3dXVDlSWTZ2REg2elQ0ZWlMRm5zSU5zWlJ1aVBkckxvOTBML2lacUtCTEZ4CmtnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==

It seems that in this case x509-certificate-exporter is not treating those certificates as valid. Kubernetes is not complaining about those certificates so I suppose x509-certificate-exporter should also work with them.

r0bj commented 2 years ago

So the easiest way to reproduce this issue is to use kubeconfig I prepared with self signed fake certificates.

config.yaml:

apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZuVENDQTRXZ0F3SUJBZ0lVSUE5aVRxdlZ6cWJOR1NDMTNaLzRBekxtWWtJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1hqRUxNQWtHQTFVRUJoTUNRVlV4RFRBTEJnTlZCQWdNQkhSbGMzUXhEVEFMQmdOVkJBY01CR05wZEhreApFREFPQmdOVkJBb01CMk52YlhCaGJua3hFREFPQmdOVkJBc01CM05sWTNScGIyNHhEVEFMQmdOVkJBTU1CRzVoCmJXVXdIaGNOTWpJd01UTXhNRE0xTXpVMldoY05Nak13TVRNeE1ETTFNelUyV2pCZU1Rc3dDUVlEVlFRR0V3SkIKVlRFTk1Bc0dBMVVFQ0F3RWRHVnpkREVOTUFzR0ExVUVCd3dFWTJsMGVURVFNQTRHQTFVRUNnd0hZMjl0Y0dGdQplVEVRTUE0R0ExVUVDd3dIYzJWamRHbHZiakVOTUFzR0ExVUVBd3dFYm1GdFpUQ0NBaUl3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMN3FTYURCNk9LQW94SzR2RHBJMmFYT1hjMlJtL01pRGZQZTZBU0oKTEVHOUY3OWgyZWxaak84RXQ3RzBxbWVoUlRraUFQWHAzNkc4aC9CNHV3dDc1VmNnbE9rSUFkWlNjdEVPdmFMMgpqcGZGQ2dhWVpEelhXa2loK1ZPSVFTNlAycTVZT3BsSG4zT09nR1l4Q3pEMm5aT3ozak1lTUp0MUpuQmMrOUFaCmEyTDVVdWNhT2liRDZUaWUxblRGSlZWemFCWHNKVGhHUHo0dlBYNjREellWNTBnVWxPV0hKWHBNeW90UURrWEIKTmFra2tuUVdnTE1VaTBxQWFHM3lwaE1zQWRuVGxSb2l1L1h0aHJRRGhuVXNBUzVaeXZHTDhGUitnNzVPTlNuRQpaUmxlTDBUWXE0dFgvWjBFVUNhZlV4akx2bUp6SXhiKzh6aTROdDJVYWovWm9yMVhYOHBJbjJvS2lZWWVMdHRCCjVrNWEzVmVkWFJvaGJGdWR2TlZ5U2pHVWZTeExLdW1nZXI4TW9zWXNzQXNyM2pyVlNXeEJuZ09pdHluQk1MVmwKMFZEZU1XZjdzWFhDSTZIK01MaC90b2RZZWpFU1RWVDQ4S0lLTk9vTXBGNVFoanVMMlF3TklrS0lDY2RwVDJHego2a0NGZWdCUDl2dSt2eDg3WDA4V1oxUUM1S0V5SlBWK1RySm1nWFp4eUdSZjdrWVVZNWFIUzRmRURJdXFlRFJDCkFMSi9sN0FNY3pqUTJQb005U1kzVytOTm9MNlJvaVFUU3pWYTljUVAySEtZWWdFNnJXck44T2hVUHNPQnhBMW8KVU11cUlwcEZtM3ZyMFgxRVhNNjdnOHFHM005RzZXUURIdllJVWFrU1RDOTFxdDdjZ292amw4T081MTNyd2pMdAphc3dSQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJSNmFsZ1Nsb1pjOEl4UGNqSE9ZQUs5aWR4SndEQWZCZ05WCkhTTUVHREFXZ0JSNmFsZ1Nsb1pjOEl4UGNqSE9ZQUs5aWR4SndEQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BMEcKQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUNvaHFPWkVheU1rVVNxVkc4K09pZlFzdzZSMi81aCtlcVprVmJoTE9TTAp4OVdiSjI4STJZVUMxRW5XWTFPd3ZBN1RzYlVSbmUrTGZtMXc3SHozbGtMQVptelpER0JZNnpJZURJMEJxdGJGCktxWDdPR2h3RXArQjhmSmVPSGxqcjQzUW84SG1UZ0g2cFBCVi9xVldEYzlYeDJqeEhjdmZFZkE5Wlo4dHJxeDAKOFZVUjRWTERKakM0Z0NhOU1KWmM4WE1BVVp4alVCN1VWY2owLzhlSHdBWlB2ZTZ3OG4yZ3B4L0NweWd5R25ISgo1ajJwUTdLNEtLeWhQakZGVEJJbENaNjJBNHdnME91dWJVNW1kZTFHSkZXNDArMTc2UityUkFwdk5nbmJuL1VBCklkQWVyOHkzNVpidGNRd3NXZ1VhYkNBbUQzaDYvcXMycHdrQm5Wb2NxdCtzZ1ZacC8wS3JvWk9PUXZQQktnTDAKSVBDSDZpcld0SDE1TlJ0SHVwR0VrblM3L1R1dzZNRmE2RUNwZFV1VS9TZG5HM3Jhemlka1FDTG5uc29CTENGKwo5WEFiQUlKTDI1VjV6Q2NSWmZoOXdSeWZ6eXU0ME1lVjNDbGYxeFcxa1haRkNIbG5wYVVNOEVNSjhiY3gzODA5ClZscFdlTDBlUURqSTVGT0gwUmh1QjNSNFJFeU5rVDYweHF3RzllRHlYY2RGNjVMR0xBelg0UGNmejI4cFpJeEEKYlhrWUdwVXZ6TjAyR21kNlptNDVESEpwSDF1dDN5cHFRemI4Z0NUczVjeDhEeTAzUlo1YkZaSzFOM0MycDNqZAovVFdiQ25CVldvSnVZSUhydmFyd3dXVDlSWTZ2REg2elQ0ZWlMRm5zSU5zWlJ1aVBkckxvOTBML2lacUtCTEZ4CmtnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
    server: https://dev.kubernetes-controller.service.consul:6443
  name: kube-res-dev
contexts:
- context:
    cluster: kube-res-dev
    user: system:node:dev-k8s-worker-r1
  name: default-context
current-context: default-context
users:
- name: system:node:dev-k8s-worker-r1
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZuVENDQTRXZ0F3SUJBZ0lVSUE5aVRxdlZ6cWJOR1NDMTNaLzRBekxtWWtJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1hqRUxNQWtHQTFVRUJoTUNRVlV4RFRBTEJnTlZCQWdNQkhSbGMzUXhEVEFMQmdOVkJBY01CR05wZEhreApFREFPQmdOVkJBb01CMk52YlhCaGJua3hFREFPQmdOVkJBc01CM05sWTNScGIyNHhEVEFMQmdOVkJBTU1CRzVoCmJXVXdIaGNOTWpJd01UTXhNRE0xTXpVMldoY05Nak13TVRNeE1ETTFNelUyV2pCZU1Rc3dDUVlEVlFRR0V3SkIKVlRFTk1Bc0dBMVVFQ0F3RWRHVnpkREVOTUFzR0ExVUVCd3dFWTJsMGVURVFNQTRHQTFVRUNnd0hZMjl0Y0dGdQplVEVRTUE0R0ExVUVDd3dIYzJWamRHbHZiakVOTUFzR0ExVUVBd3dFYm1GdFpUQ0NBaUl3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMN3FTYURCNk9LQW94SzR2RHBJMmFYT1hjMlJtL01pRGZQZTZBU0oKTEVHOUY3OWgyZWxaak84RXQ3RzBxbWVoUlRraUFQWHAzNkc4aC9CNHV3dDc1VmNnbE9rSUFkWlNjdEVPdmFMMgpqcGZGQ2dhWVpEelhXa2loK1ZPSVFTNlAycTVZT3BsSG4zT09nR1l4Q3pEMm5aT3ozak1lTUp0MUpuQmMrOUFaCmEyTDVVdWNhT2liRDZUaWUxblRGSlZWemFCWHNKVGhHUHo0dlBYNjREellWNTBnVWxPV0hKWHBNeW90UURrWEIKTmFra2tuUVdnTE1VaTBxQWFHM3lwaE1zQWRuVGxSb2l1L1h0aHJRRGhuVXNBUzVaeXZHTDhGUitnNzVPTlNuRQpaUmxlTDBUWXE0dFgvWjBFVUNhZlV4akx2bUp6SXhiKzh6aTROdDJVYWovWm9yMVhYOHBJbjJvS2lZWWVMdHRCCjVrNWEzVmVkWFJvaGJGdWR2TlZ5U2pHVWZTeExLdW1nZXI4TW9zWXNzQXNyM2pyVlNXeEJuZ09pdHluQk1MVmwKMFZEZU1XZjdzWFhDSTZIK01MaC90b2RZZWpFU1RWVDQ4S0lLTk9vTXBGNVFoanVMMlF3TklrS0lDY2RwVDJHego2a0NGZWdCUDl2dSt2eDg3WDA4V1oxUUM1S0V5SlBWK1RySm1nWFp4eUdSZjdrWVVZNWFIUzRmRURJdXFlRFJDCkFMSi9sN0FNY3pqUTJQb005U1kzVytOTm9MNlJvaVFUU3pWYTljUVAySEtZWWdFNnJXck44T2hVUHNPQnhBMW8KVU11cUlwcEZtM3ZyMFgxRVhNNjdnOHFHM005RzZXUURIdllJVWFrU1RDOTFxdDdjZ292amw4T081MTNyd2pMdAphc3dSQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJSNmFsZ1Nsb1pjOEl4UGNqSE9ZQUs5aWR4SndEQWZCZ05WCkhTTUVHREFXZ0JSNmFsZ1Nsb1pjOEl4UGNqSE9ZQUs5aWR4SndEQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01BMEcKQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUNvaHFPWkVheU1rVVNxVkc4K09pZlFzdzZSMi81aCtlcVprVmJoTE9TTAp4OVdiSjI4STJZVUMxRW5XWTFPd3ZBN1RzYlVSbmUrTGZtMXc3SHozbGtMQVptelpER0JZNnpJZURJMEJxdGJGCktxWDdPR2h3RXArQjhmSmVPSGxqcjQzUW84SG1UZ0g2cFBCVi9xVldEYzlYeDJqeEhjdmZFZkE5Wlo4dHJxeDAKOFZVUjRWTERKakM0Z0NhOU1KWmM4WE1BVVp4alVCN1VWY2owLzhlSHdBWlB2ZTZ3OG4yZ3B4L0NweWd5R25ISgo1ajJwUTdLNEtLeWhQakZGVEJJbENaNjJBNHdnME91dWJVNW1kZTFHSkZXNDArMTc2UityUkFwdk5nbmJuL1VBCklkQWVyOHkzNVpidGNRd3NXZ1VhYkNBbUQzaDYvcXMycHdrQm5Wb2NxdCtzZ1ZacC8wS3JvWk9PUXZQQktnTDAKSVBDSDZpcld0SDE1TlJ0SHVwR0VrblM3L1R1dzZNRmE2RUNwZFV1VS9TZG5HM3Jhemlka1FDTG5uc29CTENGKwo5WEFiQUlKTDI1VjV6Q2NSWmZoOXdSeWZ6eXU0ME1lVjNDbGYxeFcxa1haRkNIbG5wYVVNOEVNSjhiY3gzODA5ClZscFdlTDBlUURqSTVGT0gwUmh1QjNSNFJFeU5rVDYweHF3RzllRHlYY2RGNjVMR0xBelg0UGNmejI4cFpJeEEKYlhrWUdwVXZ6TjAyR21kNlptNDVESEpwSDF1dDN5cHFRemI4Z0NUczVjeDhEeTAzUlo1YkZaSzFOM0MycDNqZAovVFdiQ25CVldvSnVZSUhydmFyd3dXVDlSWTZ2REg2elQ0ZWlMRm5zSU5zWlJ1aVBkckxvOTBML2lacUtCTEZ4CmtnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
    client-key-data: bG9sCg==

Execute:

$ docker run -it -v $(pwd):/data docker.io/enix/x509-certificate-exporter:2.12.1 --watch-kubeconf=/data/config.yaml
INFO[0000] starting x509-certificate-exporter version 2-12-1
WARN[0000] failed to parse "/data/config.yaml", failed to parse some labels in /data/config.yaml (got 1 IDs but 0 certs for "$.clusters[:].name")
INFO[0000] parsed 0 certificates (1 read failures)
INFO[0000] listening on :9793
r0bj commented 2 years ago

It seems that issue is related to the way base64.StdEncoding.Decode works. I'm not sure why but using base64.StdEncoding.DecodeString instead of base64.StdEncoding.Decode fixes the problem.

This is my proof of concept patch to fix this issue:

diff --git a/internal/certificate.go b/internal/certificate.go
index a1c9a49..bfcc1c4 100644
--- a/internal/certificate.go
+++ b/internal/certificate.go
@@ -132,8 +132,12 @@ func readAndParseYAMLFile(filePath string, yamlPaths []YAMLCertRef) ([]*parsedCe

                var decodedCerts []byte
                if exprs.Format == YAMLCertFormatBase64 {
-                       decodedCerts = make([]byte, base64.StdEncoding.DecodedLen(len(rawCerts)))
-                       base64.StdEncoding.Decode(decodedCerts, []byte(rawCerts))
+                       decodedCertsStr, err := base64.StdEncoding.DecodeString(rawCerts)
+                       if err != nil {
+                               return nil, err
+                       }
+                       decodedCerts = []byte(decodedCertsStr)
                } else if exprs.Format == YAMLCertFormatFile {
                        rawCertPaths := strings.TrimRight(string(rawCerts), "\n")
arcln commented 2 years ago

Hi, thank you very much for doing all the troubleshooting for me. Indeed the exporter is not properly handling certificates not ending by a newline. I've pushed a fix on master based on your suggestions. We will be releasing a new version with this fix within the next days.

arcln commented 2 years ago

Hi, we are working on a new release pipeline because the current one is missing pre-releases. We will then be able to publish our latest changes without the fear of breaking the end-users. This fix will then be published in the upcoming version 3.0.0-beta.1 (which contains a single very little user-facing change).

arcln commented 2 years ago

Fixed in v3.0.0.