-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
408 additions
and
0 deletions.
There are no files selected for viewing
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
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
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 | ||
``` |
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
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, | ||
} | ||
}) | ||
} |
Oops, something went wrong.