Skip to content

Commit

Permalink
add more TLS metrics (#63)
Browse files Browse the repository at this point in the history
* add more TLS metrics

* add underscore to TLS name

* move to certs.go
  • Loading branch information
rphillips committed Jan 10, 2017
1 parent 37b9b14 commit 61766cd
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 4 deletions.
22 changes: 20 additions & 2 deletions check/check_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func NewHTTPCheck(base *CheckBase) Check {

func (ch *HTTPCheck) parseTLS(cr *CheckResult, resp *http.Response) {
cert := resp.TLS.PeerCertificates[0]
if cert == nil {
return
}
// SERIAL
cr.AddMetric(metric.NewMetric("cert_serial", "", metric.MetricNumber, cert.SerialNumber, ""))
if len(cert.OCSPServer) > 0 {
cr.AddMetric(metric.NewMetric("cert_ocsp", "", metric.MetricNumber, cert.OCSPServer[0], ""))
Expand All @@ -87,6 +91,7 @@ func (ch *HTTPCheck) parseTLS(cr *CheckResult, resp *http.Response) {
cr.AddMetric(metric.NewMetric("cert_bits", "", metric.MetricNumber, "0", ""))
cr.AddMetric(metric.NewMetric("cert_type", "", metric.MetricNumber, "-", ""))
}
// CERT SIG ALGO
cr.AddMetric(metric.NewMetric("cert_sig_algo", "", metric.MetricNumber, strings.ToLower(cert.SignatureAlgorithm.String()), ""))
var sslVersion string
switch resp.TLS.Version {
Expand All @@ -99,10 +104,10 @@ func (ch *HTTPCheck) parseTLS(cr *CheckResult, resp *http.Response) {
case tls.VersionTLS12:
sslVersion = "tls1.2"
}
// SESSION VERSION
cr.AddMetric(metric.NewMetric("ssl_session_version", "", metric.MetricNumber, sslVersion, ""))
var cipherSuite string
switch resp.TLS.CipherSuite {

case tls.TLS_RSA_WITH_RC4_128_SHA:
cipherSuite = "TLS_RSA_WITH_RC4_128_SHA"
case tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
Expand Down Expand Up @@ -140,8 +145,21 @@ func (ch *HTTPCheck) parseTLS(cr *CheckResult, resp *http.Response) {
default:
cipherSuite = "-"
}
// SESSION CIPHER
cr.AddMetric(metric.NewMetric("ssl_session_cipher", "", metric.MetricNumber, cipherSuite, ""))
//TODO Fill in the rest of the SSL info
// ISSUER
if issuer, err := utils.GetDNFromCert(cert.Issuer, "/"); err == nil {
cr.AddMetric(metric.NewMetric("cert_issuer", "", metric.MetricString, issuer, ""))
}
// SUBJECT
if subject, err := utils.GetDNFromCert(cert.Subject, "/"); err == nil {
cr.AddMetric(metric.NewMetric("cert_subject", "", metric.MetricString, subject, ""))
}
// ALTERNATE NAMES
cr.AddMetric(metric.NewMetric("cert_subject_alternate_names", "", metric.MetricString, strings.Join(cert.DNSNames, ", "), ""))
// START TIME
cr.AddMetric(metric.NewMetric("cert_start", "", metric.MetricNumber, cert.NotBefore.Unix(), ""))
cr.AddMetric(metric.NewMetric("cert_end", "", metric.MetricNumber, cert.NotAfter.Unix(), ""))
}

func disableRedirects(req *http.Request, via []*http.Request) error {
Expand Down
51 changes: 49 additions & 2 deletions check/check_http_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//
// Copyright 2016 Rackspace
//
// Copyright 2016 Rackspace //
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand Down Expand Up @@ -292,3 +291,51 @@ func TestHTTPInvalidUrl(t *testing.T) {
t.Fatal("should have errored")
}
}

func TestHTTP_TLS(t *testing.T) {
ts := httptest.NewTLSServer(http.HandlerFunc(staticResponse))
defer ts.Close()

// Create Check
checkData := fmt.Sprintf(`{
"id":"TestTTPTLS",
"zone_id":"pzA",
"details":{"url":"%s"},
"type":"remote.http",
"timeout":1,
"period":30,
"ip_addresses":{"default":"127.0.0.1"},
"target_alias":"default",
"target_hostname":"",
"target_resolver":"",
"disabled":false
}`, ts.URL)
check := check.NewCheck([]byte(checkData), context.Background(), func() {})

// Run check
crs, err := check.Run()
if err != nil {
t.Fatal("should not have errored; %s", err.Error())
}

issuer, _ := crs.Get(0).GetMetric("cert_issuer").ToString()
if issuer != "/O=Acme Co" {
t.Fatal("invalid issuer")
}
subject, _ := crs.Get(0).GetMetric("cert_subject").ToString()
if subject != "/O=Acme Co" {
t.Fatal("invalid subject")
}
cert_start, _ := crs.Get(0).GetMetric("cert_start").ToInt64()
if cert_start != 0 {
t.Fatal("invalid start time")
}
cert_end, _ := crs.Get(0).GetMetric("cert_end").ToInt64()
if cert_end != 3600000000 {
t.Fatal("invalid end time")
}
cert_dns_names, _ := crs.Get(0).GetMetric("cert_subject_alternate_names").ToString()
if cert_dns_names != "example.com" {
t.Fatal("invalid dns names")
}
}
67 changes: 67 additions & 0 deletions utils/certs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// Copyright 2017 Rackspace
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package utils

import (
"crypto/x509/pkix"
"fmt"
"strings"
)

var oid = map[string]string{
"2.5.4.3": "CN",
"2.5.4.4": "SN",
"2.5.4.5": "serialNumber",
"2.5.4.6": "C",
"2.5.4.7": "L",
"2.5.4.8": "ST",
"2.5.4.9": "streetAddress",
"2.5.4.10": "O",
"2.5.4.11": "OU",
"2.5.4.12": "title",
"2.5.4.17": "postalCode",
"2.5.4.42": "GN",
"2.5.4.43": "initials",
"2.5.4.44": "generationQualifier",
"2.5.4.46": "dnQualifier",
"2.5.4.65": "pseudonym",
"0.9.2342.19200300.100.1.25": "DC",
"1.2.840.113549.1.9.1": "emailAddress",
"0.9.2342.19200300.100.1.1": "userid",
}

// Convert a DN to a String
// return the string, or and error
func GetDNFromCert(namespace pkix.Name, sep string) (string, error) {
subject := []string{}
for _, s := range namespace.ToRDNSequence() {
for _, i := range s {
if v, ok := i.Value.(string); ok {
if name, ok := oid[i.Type.String()]; ok {
// <oid name>=<value>
subject = append(subject, fmt.Sprintf("%s=%s", name, v))
} else {
// <oid>=<value> if no <oid name> is found
subject = append(subject, fmt.Sprintf("%s=%s", i.Type.String(), v))
}
} else {
// <oid>=<value in default format> if value is not string
subject = append(subject, fmt.Sprintf("%s=%v", i.Type.String, v))
}
}
}
return sep + strings.Join(subject, sep), nil
}

0 comments on commit 61766cd

Please sign in to comment.