Skip to content

Commit

Permalink
Adding ssl_cert input plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
jtyr committed Feb 8, 2018
1 parent 89974d9 commit 0691f34
Show file tree
Hide file tree
Showing 4 changed files with 408 additions and 0 deletions.
1 change: 1 addition & 0 deletions plugins/inputs/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/socket_listener"
_ "github.com/influxdata/telegraf/plugins/inputs/solr"
_ "github.com/influxdata/telegraf/plugins/inputs/sqlserver"
_ "github.com/influxdata/telegraf/plugins/inputs/ssl_cert"
_ "github.com/influxdata/telegraf/plugins/inputs/statsd"
_ "github.com/influxdata/telegraf/plugins/inputs/sysstat"
_ "github.com/influxdata/telegraf/plugins/inputs/system"
Expand Down
39 changes: 39 additions & 0 deletions plugins/inputs/ssl_cert/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SSL Cert Input Plugin

This plugin provides information about SSL certificate accessible via local
file or network connection.


### Configuration

```toml
# Reads metrics from a SSL certificate
[[inputs.ssl_cert]]
## List of local SSL files
#files = []
## List of servers
#servers = []
## Timeout for SSL connection
#timeout = 5
```


### Metrics

- `ssl_cert`
- tags:
- `server` (only if `servers` parameter is defined)
- `file` (only if `files` parameter is defined)
- fields:
- `expiry` (int, seconds)
- `age` (int, seconds)
- `startdate` (int, seconds)
- `enddate` (int, seconds)


### Example output

```
ssl_cert,server=google.com:443,host=myhost age=1753627i,expiry=5503972i,startdate=1516092060i,enddate=1523349660i 1517845687000000000
ssl_cert,host=myhost,file=/path/to/the.crt age=7522207i,expiry=308002732i,startdate=1510323480i,enddate=1825848420i 1517845687000000000
```
155 changes: 155 additions & 0 deletions plugins/inputs/ssl_cert/ssl_cert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package ssl_cert

import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"net"
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)

const sampleConfig = `
## List of local SSL files
# files = []
## List of servers
# servers = []
## Timeout for SSL connection
# timeout = 5
`
const description = "Reads metrics from a SSL certificate"

type SSLCert struct {
Servers []string `toml:"servers"`
Files []string `toml:"files"`
Timeout time.Duration `toml:"timeout"`

// For tests
CloseConn bool
}

func (sc *SSLCert) Description() string {
return description
}

func (sc *SSLCert) SampleConfig() string {
return sampleConfig
}

func getRemoteCert(server string, timeout time.Duration, closeConn bool) (*x509.Certificate, error) {
tlsCfg := &tls.Config{
InsecureSkipVerify: true,
}

ipConn, err := net.DialTimeout("tcp", server, timeout)
if err != nil {
return nil, err
}
defer ipConn.Close()

conn := tls.Client(ipConn, tlsCfg)
defer conn.Close()

if closeConn {
conn.Close()
}

hsErr := conn.Handshake()
if hsErr != nil {
return nil, hsErr
}

certs := conn.ConnectionState().PeerCertificates

if certs == nil || len(certs) < 1 {
return nil, errors.New("Couldn't get remote certificate.")
}

return certs[0], nil
}

func getLocalCert(filename string) (*x509.Certificate, error) {
content, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}

block, _ := pem.Decode(content)
if block == nil {
return nil, errors.New("Failed to parse certificate PEM.")
}

cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}

return cert, nil
}

func getMetrics(cert *x509.Certificate, now time.Time) map[string]interface{} {
age := int(now.Sub(cert.NotBefore).Seconds())
expiry := int(cert.NotAfter.Sub(now).Seconds())
startdate := int(cert.NotBefore.Unix())
enddate := int(cert.NotAfter.Unix())

metrics := map[string]interface{}{
"age": age,
"expiry": expiry,
"startdate": startdate,
"enddate": enddate,
}

return metrics
}

func (sc *SSLCert) Gather(acc telegraf.Accumulator) error {
now := time.Now()

for _, server := range sc.Servers {
cert, err := getRemoteCert(server, sc.Timeout*time.Second, sc.CloseConn)
if err != nil {
return errors.New(fmt.Sprintf("Cannot get remote SSL cert: %s", err))
}

tags := map[string]string{
"server": server,
}

fields := getMetrics(cert, now)

acc.AddFields("ssl_cert", fields, tags)
}

for _, file := range sc.Files {
cert, err := getLocalCert(file)
if err != nil {
return errors.New(fmt.Sprintf("Cannot get local SSL cert: %s", err))
}

tags := map[string]string{
"file": file,
}

fields := getMetrics(cert, now)

acc.AddFields("ssl_cert", fields, tags)
}

return nil
}

func init() {
inputs.Add("ssl_cert", func() telegraf.Input {
return &SSLCert{
Files: []string{},
Servers: []string{},
Timeout: 5,
}
})
}
Loading

0 comments on commit 0691f34

Please sign in to comment.