joe-elliott / cert-exporter

A Prometheus exporter that publishes cert expirations on disk and in Kubernetes secrets
Apache License 2.0
316 stars 87 forks source link

Supporting CRL #77

Open manicole opened 3 years ago

manicole commented 3 years ago

Hi, Does cert-exporter supports CRL (Certificate Revocation List) ?

I tried it using 2 ways :

  1. Add CRL in .pem format in my CA Secret I created my Secret with

    kubectl create secret generic ca --from-file=ca.crt=ca.crt --from-file=ca.crl=crl.pem --namespace ingress-nginx 

    As a result in cert-exporter Pod, I got the following logs :

    I0325 10:58:50.549648       1 periodicSecretChecker.go:109] Reviewing secret ca in ingress-nginx
    I0325 10:58:50.549673       1 periodicSecretChecker.go:126] Annotations matched. Parsing Secret.
    I0325 10:58:50.549680       1 periodicSecretChecker.go:158] Publishing ca/ingress-nginx metrics ca.crl
    E0325 10:58:50.549719       1 periodicSecretChecker.go:161] Error exporting secret asn1: structure error: tags don't match (16 vs {class:0 tag:23 length:13 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} validity @100

    💡 The ca.crt of my CA Secret is successfully recognized by cert-exporter.

  2. Add CRL in .pem format as an independant Secret I created my Secret with

    kubectl create secret generic crl --from-file=crl.pem -n ingress-nginx

    As a result in cert-exporter Pod, I got the following logs :

    I0325 10:58:50.549886       1 periodicSecretChecker.go:109] Reviewing secret crl in ingress-nginx
    I0325 10:58:50.549899       1 periodicSecretChecker.go:126] Annotations matched. Parsing Secret.
    I0325 10:58:50.549939       1 periodicSecretChecker.go:158] Publishing crl/ingress-nginx metrics crl.pem
    E0325 10:58:50.549972       1 periodicSecretChecker.go:161] Error exporting secret asn1: structure error: tags don't match (16 vs {class:0 tag:23 length:13 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} validity @100

My cert-exporter deployment is

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cert-exporter
  labels:
    app: cert-exporter
    name: cert-exporter
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: cert-exporter
  template:
    metadata:
      annotations:
        prometheus.io/port: "8080"
        prometheus.io/scrape: "true"
      labels:
        app: cert-exporter
    spec:
      serviceAccountName: cert-exporter
      containers:
      - image: joeelliott/cert-exporter:v2.5.0
        name: cert-exporter
        command: ["./app"]
        args:
        - --secrets-include-glob=*.crt
        - --secrets-include-glob=*.crl
        - --secrets-include-glob=*.pem
        - --logtostderr
        ports:
          - name: metrics
            containerPort: 8080
            protocol: TCP

A CRL format looks like

-----BEGIN X509 CRL-----
...
-----END X509 CRL-----

Thanks for your help!

joe-elliott commented 3 years ago

It appears we do not. I believe this is the line that is failing:

https://github.com/joe-elliott/cert-exporter/blob/master/src/exporters/certHelpers.go#L61

If go has a method for parsing the CRL format perhaps we could add it here. Are you able to submit a PR?

manicole commented 3 years ago

Thanks for your quick answer! I can't submit a PR at the moment, I was looking for an already implemented way to do it. It could be an enhancement then ... but I doubt I'll have the opportunity to provide a solution, sorry :/

joe-elliott commented 3 years ago

It appears that there is support in Go for parsing CRL:

https://golang.org/pkg/crypto/x509/#ParseCRL

but looking at the return value I'm not sure what'd you want reported out of this?

manicole commented 3 years ago

No it won't do ... I hoped to get the expiry time out of such a parser, but I can't find one in this list.

The thing is that if the CRL expires, all certs will be blocked temporarily unless CRL is regenerated. Not revoked, but still blocked. Which is really annoying when in production as you can imagine :/

BernhardGruen commented 1 year ago

Hey,

ParseRecovationList and its type RevocationList (there the attribute NextUpdate) should solve this. If NextUpdate is smaller than current time the CRL is expired.

I am currently looking for a solution to this problem as well and came across this issue - not using cert-exporter myself for the moment.

joe-elliott commented 1 year ago

If either of you is able to put together a PR to add this ability to cert-exporter, I would be happy to merge. I personally don't have the environment to test these changes or understand what a valuable solution would look like.

If neither of you feel comfortable with Go maybe you could coach me through the change?

BernhardGruen commented 1 year ago

Hey,

I am happy to provide a few files to make tests possible for you. First you need a Secret that contains the ca.crl as data (I will use stringData in this example to make it easier to use and shorter too). I created the date in ca.crl using the Easy-RSA script and the provided quick start guide and then executing the gen-crl command. This results in a file pki/crl.pem which will later be part of the Secret (besides the Certificate of the CA in ca.crt) that should ideally be scanned by cert-exporter. For even better tests I created two CAs and also two CRLs (both in the same Secret). The CAs are called "Easy-RSA CA" and "Another Easy-RSA CA". Both CRLs will need their next update on 2023-06-08 (info can also be read out with openssl -text -in crl.pem and is found in the field "Next Update").

I have attached a TGZ file that contains nginx-test.yaml and ca-secret.yaml. They can be directly applied to a cluster and apply into namespace default. A running ingress-nginx is needed to actually show the working Client Authentication (this is configured using annotations for the Ingress). I also included the CA (including the Easy-RSA script). For test purposes the CA does not have a password which makes it easy to create a newer CRL for example.

ca-secret.txt nginx-test.txt

Unfortunately I can't add the TGZ file and I had to rename the yaml files to .txt

In case you need any more information I am happy to provide them.