Created
September 23, 2016 10:48
-
-
Save subuk/8c412d26639f1a41b109e3e76a81cfb7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"crypto/tls" | |
"crypto/x509" | |
"encoding/json" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"net/http" | |
"time" | |
) | |
// PagerDuty API key | |
const PD_SERVICE_KEY = "" | |
// Checks configuration | |
var CHECKS = []CheckConfig{ | |
{Host: "google.com", Port: 443}, | |
} | |
const ( | |
CHECK_OK = iota | |
CHECK_WARN = iota | |
CHECK_FAIL = iota | |
) | |
const ( | |
PD_TRIGGER = iota | |
PD_RESOLVE = iota | |
) | |
type CheckConfig struct { | |
Host string | |
Port int | |
ServerName string | |
} | |
func (c *CheckConfig) SniName() string { | |
if c.ServerName != "" { | |
return c.ServerName | |
} | |
return c.Host | |
} | |
func (c *CheckConfig) String() string { | |
return fmt.Sprintf("%s:%d", c.Host, c.Port) | |
} | |
func IsRevoked(cert *x509.Certificate) error { | |
for _, crlPoint := range cert.CRLDistributionPoints { | |
resp, err := http.Get(crlPoint) | |
if err != nil { | |
return fmt.Errorf("failed to fetch CRL: %s", err) | |
} | |
bodyReader := &io.LimitedReader{resp.Body, 10 * 1024 * 1024} | |
crlBytes, err := ioutil.ReadAll(bodyReader) | |
if err != nil { | |
return fmt.Errorf("failed to fetch CRL: %s", err) | |
} | |
crl, err := x509.ParseCRL(crlBytes) | |
if err != nil { | |
return fmt.Errorf("failed to parse CRL: %s", err) | |
} | |
for _, revokedCert := range crl.TBSCertList.RevokedCertificates { | |
if cert.SerialNumber.Cmp(revokedCert.SerialNumber) == 0 { | |
return fmt.Errorf("certificate revoked at %s", revokedCert.RevocationTime) | |
} | |
} | |
} | |
return nil | |
} | |
func Check(c CheckConfig) error { | |
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", c.Host, c.Port), &tls.Config{ServerName: c.SniName()}) | |
if err != nil { | |
return err | |
} | |
cert := conn.ConnectionState().PeerCertificates[0] | |
if err := IsRevoked(cert); err != nil { | |
return err | |
} | |
if time.Now().Add(time.Hour * 24 * 30).After(cert.NotAfter) { | |
return fmt.Errorf("expire in next month") | |
} | |
if err := conn.Close(); err != nil { | |
return err | |
} | |
return nil | |
} | |
func SetPDIncidentState(eventId, description string, state int) { | |
data := map[string]string{ | |
"service_key": PD_SERVICE_KEY, | |
"incident_key": eventId, | |
"description": description, | |
"client": "go-ssl-cert-checker", | |
} | |
switch state { | |
case PD_TRIGGER: | |
data["event_type"] = "trigger" | |
case PD_RESOLVE: | |
data["event_type"] = "resolve" | |
default: | |
panic(fmt.Errorf("unknown pagerduty state: %d", state)) | |
} | |
body, err := json.Marshal(&data) | |
if err != nil { | |
panic(err) | |
} | |
resp, err := http.Post( | |
"https://events.pagerduty.com/generic/2010-04-15/create_event.json", | |
"application/json", | |
bytes.NewReader(body), | |
) | |
if err != nil { | |
panic(err) | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode > 399 { | |
bodyReader := &io.LimitedReader{resp.Body, 1024 * 1024} | |
data, err := ioutil.ReadAll(bodyReader) | |
if err != nil { | |
panic(err) | |
} | |
panic(fmt.Errorf("Bad response from pagerduty: %s", string(data))) | |
} | |
} | |
func main() { | |
for _, c := range CHECKS { | |
if err := Check(c); err != nil { | |
description := fmt.Sprintf("%s CRIT - %s", c.String(), err.Error()) | |
fmt.Println(description) | |
SetPDIncidentState(c.String(), description, PD_TRIGGER) | |
} else { | |
description := fmt.Sprintf("%s OK", c.String()) | |
fmt.Println(description) | |
SetPDIncidentState(c.String(), description, PD_RESOLVE) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment