1
0
mirror of https://github.com/Luzifer/promcertcheck.git synced 2024-09-19 17:32:57 +00:00
promcertcheck/main.go

144 lines
3.6 KiB
Go
Raw Normal View History

2015-09-04 14:27:44 +00:00
package main // import "github.com/Luzifer/promcertcheck"
2015-09-04 13:36:49 +00:00
import (
"crypto/x509"
"fmt"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/Luzifer/rconfig"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus"
"github.com/robfig/cron"
)
var (
config = struct {
Debug bool `flag:"debug" default:"false" description:"Output debugging data"`
ExpireWarning time.Duration `flag:"expire-warning" default:"744h" description:"When to warn about a soon expiring certificate"`
Probes []string `flag:"probe" default:"" description:"URLs to check for certificate issues"`
2015-09-04 13:36:49 +00:00
}{}
version = "dev"
probeMonitors = map[string]*probeMonitor{}
)
type probeMonitor struct {
2015-09-04 13:54:08 +00:00
IsValid prometheus.Gauge `json:"-"`
Expires prometheus.Gauge `json:"-"`
2015-09-04 13:36:49 +00:00
Status probeResult
Certificate *x509.Certificate
}
type redirectFoundError struct{}
func (r redirectFoundError) Error() string {
return "Found a redirect."
}
func init() {
if err := rconfig.Parse(&config); err != nil {
log.Fatalf("Unable to parse CLI parameters: %s", err)
2015-09-04 13:36:49 +00:00
}
}
func main() {
http.DefaultClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return redirectFoundError{}
}
registerProbes()
refreshCertificateStatus()
2015-09-04 13:46:43 +00:00
fmt.Printf("PromCertcheck %s...\nStarting to listen on 0.0.0.0:3000\n", version)
2015-09-04 13:36:49 +00:00
c := cron.New()
c.AddFunc("0 0 * * * *", refreshCertificateStatus)
c.Start()
r := mux.NewRouter()
r.Handle("/metrics", prometheus.Handler())
2015-09-04 13:54:08 +00:00
r.HandleFunc("/", htmlHandler)
r.HandleFunc("/httpStatus", httpStatusHandler)
2015-09-04 13:54:08 +00:00
r.HandleFunc("/results.json", jsonHandler)
2015-09-04 13:36:49 +00:00
http.ListenAndServe(":3000", r)
}
func registerProbes() {
for _, probe := range config.Probes {
probeURL, _ := url.Parse(probe)
monitors := &probeMonitor{}
monitors.Expires = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "certcheck_expires",
Help: "Expiration date in unix timestamp (UTC)",
ConstLabels: prometheus.Labels{
"host": probeURL.Host,
},
})
monitors.IsValid = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "certcheck_valid",
Help: "Validity of the certificate (0/1)",
ConstLabels: prometheus.Labels{
"host": probeURL.Host,
},
})
prometheus.MustRegister(monitors.Expires)
prometheus.MustRegister(monitors.IsValid)
probeMonitors[probeURL.Host] = monitors
}
}
func refreshCertificateStatus() {
for _, probe := range config.Probes {
probeURL, _ := url.Parse(probe)
verificationResult, verifyCert := checkCertificate(probeURL)
if config.Debug {
fmt.Printf("---\nProbe: %s\nResult: %s\n",
probeURL.Host,
verificationResult,
)
if verifyCert != nil {
fmt.Printf("Version: %d\nSerial: %d\nSubject: %s\nExpires: %s\nIssuer: %s\nAlt Names: %s\n",
verifyCert.Version,
verifyCert.SerialNumber,
verifyCert.Subject.CommonName,
verifyCert.NotAfter,
verifyCert.Issuer.CommonName,
strings.Join(verifyCert.DNSNames, ", "),
)
}
}
2016-01-25 23:36:08 +00:00
if verifyCert != nil {
probeMonitors[probeURL.Host].Expires.Set(float64(verifyCert.NotAfter.UTC().Unix()))
}
2015-09-04 13:36:49 +00:00
switch verificationResult {
case certificateExpiresSoon, certificateOK:
probeMonitors[probeURL.Host].IsValid.Set(1)
case certificateInvalid, certificateNotFound:
probeMonitors[probeURL.Host].IsValid.Set(0)
default:
probeMonitors[probeURL.Host].IsValid.Set(0)
}
probeMonitors[probeURL.Host].Status = verificationResult
probeMonitors[probeURL.Host].Certificate = verifyCert
}
}
func inSlice(slice []string, needle string) bool {
for _, i := range slice {
if i == needle {
return true
}
}
return false
}