Monitoring certificate transparency logs with the certspotter API
If you manage your DNS using Cloudflare, you can benefit from their Certificate Transparency Monitoring service, currently in beta, which alerts you via email whenever a new certificate appears in CT logs for your domain. This however requires your domain to be hosted on Cloudflare, which is unfortunate as it is a great service. Perhaps once the beta is over they would extend the service to non-Cloudflare domains.
Other alternatives are the Facebook Certificate Transparency Monitoring tool and SSLMate Cert Spotter. Facebook’s offering is free, but requires a Facebook account and email notifications enabled (which may or may not enable other email notifications). This leaves Cert Spotter, which isn’t free and $15/month can be a lot if you only need to monitor a couple of domains.
Luckily, Cert Spotter has a free API offering that is enough for light use. I have created a small utility using the Cert Spotter API: ct-monitor. What it does is pretty simple: for a given domain, get the ID of the last discovered issuance from the positions file if it exists, then query the Cert Spotter API for any new issuances, send a notification, and save the last discovered issuance to the positions file. Queries for all issuances are only done during the first run where there are no positions file.
The tool can be run standalone or wrapped into a systemd file, or it can be run as a CronJob
in Kubernetes, which is what I intended to use it for.
Using it is as simple as copying over the sample manifests and editing it as necessary, especially for the secrets.yaml
and config.toml
files.
In order to stay within the Cert Spotter API limits, it is recommended to run the CronJob
once per hour.
cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: ct-monitor
labels:
app.kubernetes.io/name: ct-monitor
spec:
schedule: "0 * * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 60
jobTemplate:
spec:
template:
spec:
containers:
- name: ct-monitor
image: quay.io/hsn723/ct-monitor:0.1
volumeMounts:
- name: config-volume
mountPath: /etc/ct-monitor/config.toml
subPath: config.toml
- name: positions-volume
mountPath: /var/log/ct-monitor
envFrom:
- secretRef:
name: ct-monitor-secrets
volumes:
- name: positions-volume
persistentVolumeClaim:
claimName: ct-monitor-position
- name: config-volume
configMap:
name: ct-monitor-config
restartPolicy: OnFailure
As the Pod
created for the Job
gets deleted every CronJob
run, we want to keep state (the positions file) using a small PersistentVolumeClaim
.
pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ct-monitor-position
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Mi
ct-monitor
expects a token for the Cert Spotter API provided in the config.toml
, as a command-line argument, or using the environment variable CERTSPOTTER_TOKEN
(recommended). Is is recommended to place such Secrets
in another repository, or make use of SealedSecrets
.
Other environment variables that may be required depending on the chosen way to send report emails. For instance, Sendgrid expects a SENDGRID_TOKEN
environment variable and Amazon SES expects an access key ID and secret access key as environment variables:
- Access Key ID:
AWS_ACCESS_KEY_ID
orAWS_ACCESS_KEY
- Secret Access Key:
AWS_SECRET_ACCESS_KEY
orAWS_SECRET_KEY
Once everything is set up and applied, we will start receiving emails like the following:
ct-monitor has observed the issuance of the following certificate(s) for the festivaljapon.com domain:
Issuer: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3
DNS Names: [monitor-2.festivaljapon.com]
Validity: 2020-07-28T18:07:30-00:00 - 2020-10-26T18:07:30-00:00
SHA256: 946881b2cd9e7fbc55c0172070a7dcb872ade10a374a5b5120aaf74f6081d0c6
Issuance type: cert
Issuer: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3
DNS Names: [status.festivaljapon.com]
Validity: 2020-07-29T14:36:27-00:00 - 2020-10-27T14:36:27-00:00
SHA256: f0bc7da52ce02856bfadf79bae599a87fe37672f939a5d6fd29d05867d03d294
Issuance type: cert
Issuer: C=US, O="Cloudflare, Inc.", CN=Cloudflare Inc ECC CA-3
DNS Names: [*.festivaljapon.com festivaljapon.com sni.cloudflaressl.com]
Validity: 2020-08-10T00:00:00-00:00 - 2021-08-10T12:00:00-00:00
SHA256: 3b62cdaaf584d39e7844cdccac9c0bd5fe46eb9fe65b4df72c38165d149b2f58
Issuance type: cert